Augmented reality: a physics engine for mobile - part 1

by James Diacono 19. January 2011 06:01

TheFARM has recently been working intensively on an AR (augmented reality) app for the iPhone.  We were tasked with overlaying geopoints on the phone’s screen, like all these apps do.

So, given a geolocation x (containing a latitude, longitude and altitude), how does that end up on the screen in the right place?  This is how we did it:

1. Given x and the phone’s current geoposition, compute the vector x, which describes x’s position relative to the phone.  x consists of a heading, an elevation and a distance.

RelativePosition


2. Find the orientation of the phone’s camera, c, which consists of a heading, an elevation and a rotation (this rotation being what makes a photo portrait or landscape).

CameraOrientation


3. Find the screen vector s, which is the deviation of x’s direction relative to cs consists of a deviation (the angle between x and c) and a rotation (x’s rotation around c).  This allows you to deal with positions on the screen in a very natural way, leaving pixels to the last moment.

ScreenVector


4. Render x on the screen using x, c and s.

FieldOfView'


I’m going to be writing this up in Objective-C (the language of iOS/iPhone and OSX) but its very general stuff.

So! First things first. 

1. Type definitions

typedef struct {
double heading;
double elevation;
double distance;
} RelativePosition;

typedef struct {
double heading;
double elevation;
double rotation;
} CameraOrientation;

typedef struct {
double rotation;
double deviation;
} ScreenVector;

2. Interface

@interface Utilities : NSObject

+ (RelativePosition) getRelativePositionOfB:(CLLocation *)b
toA:(CLLocation *)a;

+ (CameraOrientation) getCameraOrientationFromMotion:(CMMotionManager *)motionManager
andHeading:(CLHeading *)heading;

+ (ScreenVector) getScreenVectorOfPosition:(RelativePosition)position
fromCamera:(CameraOrientation)camera;

+ (void) renderView:(UIView *)view
inFrame:(CGRect)frame
fromRelativePosition:(RelativePosition)position
andCameraOrientation:(CameraOrientation)camera
andScreenVector:(ScreenVector)screenVector;


@end

 
3. Implementation
…That’s part 2.  Still, having this structure makes things a breeze.  Happy augmenting!
Categories: iPhone

Vertically centring multi-line text with CSS

by James Diacono 18. November 2010 06:34

So you have a fixed height container, and you want your text to be vertically centred, whether it be one line or many lines of text.  In every browser.   This is possible, as I just learned from this article.

For all modern browsers, and IE8 and IE9, the method uses display:table-cell.  For IE6 and IE7, the method described in the above article is used, which takes advantage of a height bug.

You HTML looks like this:

<div id="container">
	<div id="wrapper">
		<div id="content">
			Stuff and things
		</div>
	</div>
</div>

Your CSS looks like this:

#container
{
	width:200px;
	height:50px;
	background-color:red;
	*position:relative;
}
#wrapper
{
	background-color:green;
	height:inherit;
	display:table-cell;
	vertical-align:middle;
	*height:auto;
	*position:absolute;
	*top:50%;
}
#content
{
	background-color:blue;
	*position:relative;
	*top:-50%;
	color:white;
}

The result looks like this:

IE6

ie6-multilineie6-singleline

IE7

ie7-multilineie7-singleline

IE8

ie8-multilineie8-singleline

IE9 Beta

ie9-multilineie9-singleline

Google Chrome

chrome-multilinechrome-singleline

And of course, this is not just constrained to text.  #content can be any variable-height block...

Categories: CSS

Mixing percentage and pixel dimensions in CSS

by James Diacono 9. November 2010 05:32

Okay, so there is no trick to actually compute these dimensions (except in IE).  However, there is a little known technique in CSS which is supported in all browsers and solves most of these problems.

Most usually, the desire to mix the two units comes about when one wants column A to fill the page except for column B, which has a fixed pixel width.  The problem becomes more formidable when doing the same thing with rows, the reason being that while a block element will naturally expand to fit its container’s width, there is no parallel behaviour for height.

The misconception: when positioning absolutely, two positions and two dimensions should be set.  I.E., top, left, width, height.

The truth: many combinations of position and dimension may be used.  Want to fill the page except for a 300px bar on the right?  Sure:

html, body {
    height: 100%;
}

#content {
    position:absolute;
    top:0;
    right:300px;
    bottom:0;
    left:0;
}

Turns out you don't even need to specify dimensions, they can be implied by positions. This is actually really old-school stuff which is supported by IE of old, back when it couldn't deal with flowing layouts very well. If you want to start combining percentages with pixels, just mess around with this technique and some containers.

Tags:
Categories: CSS

Using ClientDependency with MVC 3 beta's Razor view engine

by James Diacono 28. October 2010 11:06

ClientDependency already has full support for MVC...but how do you get it work with the Razor view engine?

Razor and helpers: what’s the deal man?

@Html.HelperA()

@{
	Html.HelperB();
}

In the above code, the first example is equivalent to

<%:Html.HelperA() %>

(the HTML escaped version of <%=Html.HelperA() %>) and the second to

<% Html.HelperB() %>

Client “Deep”-endancy

As such, I assumed ClientDependency would look something like this in Razor world:

@{
    Html.RequiresCss("Site.css", "Styles");
    Html.RequiresJs("Site.js", "Scripts");
}

@Html.RenderCssHere(new List<IClientDependencyPath>() {
    new BasicPath("Styles", "/Content/Css")
})

@Html.RenderJsHere(new List<IClientDependencyPath>() { 
    new BasicPath("Scripts", "/Scripts")
})

Sadly not. I got a compilation error: CS1061: 'System.Web.Mvc.HtmlHelper<object>' does not contain a definition for 'RequiresCss' and no extension method 'RequiresCss' accepting a first argument of type 'System.Web.Mvc.HtmlHelper<object>' could be found (are you missing a using directive or an assembly reference?)

Okay, so I need to include the ClientDependency helpers in the page namespace config. My Web.config (the one in the "Views" folder) turned out looking like this:

<configuration>
    <system.web.webpages.razor>
        <host factorytype="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <pages pagebasetype="System.Web.Mvc.WebViewPage">
            <namespaces>
                <add namespace="System.Web.Mvc" />
                <add namespace="System.Web.Mvc.Ajax" />
                <add namespace="System.Web.Mvc.Html" />
                <add namespace="System.Web.Routing" />
                <add namespace="ClientDependency.Core" />
                <add namespace="ClientDependency.Core.Mvc" />
                <add namespace="MySite.Web.Views.Helpers" />
            </namespaces>
        </pages>
    </system.web.webpages.razor>
</configuration>

So I tried running it again, but the @Html.RenderCssHere() and @Html.RenderJsHere() methods had resulted in this

<!--[Css:Name="StandardRenderer"]//-->

<!--[Javascript:Name="StandardRenderer"]//-->

Yuck.

Razor automatically HTML escapes anything returned by a helper when called in the @Html.HelperA() style, unless that helper returns an HtmlString type.  Hence the Html.RenderCssHere and Html.RenderJsHere need to be wrapped by an HTML string.  Shannon provided this solution in a comment below:

@MvcHtmlString.Create(Html.RenderCssHere(new List<IClientDependencyPath>() {
    new BasicPath("Styles", "/Content/Css")
}))

@MvcHtmlString.Create(Html.RenderJsHere(new List<IClientDependencyPath>() { 
    new BasicPath("Scripts", "/Scripts")
}))

and voila! The best, of the best, of the best.

Tags: ,
Categories: .Net | ClientDependency

Styling XML with CSS

by James Diacono 23. April 2010 05:26

I’m sure you’ve heard of XSLT (DON'T GO AWAY I'M NOT SUPPORTING XSLT!). XSLT is used to transform XML into different XML – for example, rendering XML as HTML.  An example:

The XSLT method

<album>
	<title>Funkentelechy Vs. The Placebo Syndrome</title>
	<artist>Parliament</artist> 
	<year>1976</year> 
	<funkativity>10</funkativity> 
</album>

can be transformed (using XSLT) to this:

<div class="album">
	<h1>Funkentelechy Vs. The Placebo Syndrome</h1>
	<p class="artist">Parliament</p>
	<p class="year">1976</p>
	<p class="funkativity">This album has a funkativity rating of 10/10</p>
</div>

Now the question is, "is h1 a better tagname for the artist of the album than artist?". I'm pretty sure the answer is no. However, the HTML engine has no idea how to display an artist tag - it treats every unknown tag like a span tag.

The pure CSS method

So display information has to come from somewhere else. Some people may find the idea of markup depending entirely on CSS for display abhorrent. I do not. I maintain that reading the source of the album XML block makes just as much sense as reading the rendered HTML version. And screenreaders...if I was a screenreader I'd want concise and descriptive XML, rather than having to wade through a bunch of HTML crap. And let's be real: everyone's web client supports CSS.

Styling XML with CSS is actually very simple and very robust. The first thing to understand is that HTML is just a custom namespace of XML. The second thing to understand is you can have multiple namespaces present in any XML document. That means you can use both HTML and, say, a custom namespace...which you can define and set styling rules.

I won't blather much more. I'll just fill you in on how CSS targets namespaces.

The CSS @namespace declaration

In short, I can write up a stylesheet which targets a specific namespace and only a specific namespace. My XML file would look like this:

<?xml version="1.0" encoding="UTF-8" ?>
<albums xmlns="http://jdiacono.org/music">
	<album>
		<title>Funkentelechy Vs. The Placebo Syndrome</title>
		<artist>Parliament</artist> 
		<year>1976</year> 
		<funkativity>10</funkativity> 
	</album>
<albums>

Here I declare that the XML inside and including the albums block is of the namespace http://jdiacono.org/music. Don't be misled by the namespace looking like a URL...I haven't even registered jdiacono.org and this is still valid. This is because namespaces are actually just unique, case-sensitive strings, and URLs tend to be unique and full of information. Let it be known that this block is all there is. It is a completely self descriptive block of pure data, which references nothing external.

Now to style this...here is my CSS:

@namespace url("http://jdiacono.org/music");

albums {
	display:block;
	}
	
album {
	display:list-item;
	list-style-type:decimal;
	margin-bottom:0.5em;
	padding:0.5em;
	border:1px solid;
	}
	
album title {
	display:block;
	font-size:2em;
	font-weight:bold;
	border-bottom:1px dashed;
	}
	
album artist {
	display:block;
	font-size:0.9em;
	}
	
album year {
	display:block;
	font-weight:bold;
	letter-spacing:0.4em;
	color:Green;
	}
	
album funkativity {
	display:block;
	font-style:italic;
	}
	
album funkativity:before {
	content: "This album has a funkativity rating of ";
	}
	
album funkativity:after {
	content: "/10";
	}

Now I have another example that is much more nourishing, which uses HTML and a custom XML namespace in the same page. You will need a browser other than IE to view this.

farmcode.org/sourcecode/cssNamespaces/cssNamespaces.xml

UPDATE: Looks like IE9 is supporting this!

Categories: CSS

CSS3: Using the fun stuff in real life

by James Diacono 19. April 2010 12:08

Sweep IE6 under the carpet

Do whatever you can to remove IE6 support from your website’s build spec. Proper CSS selectors like the direct child (ul > li), the :hover state for elements other than anchors, and attribute selectors (a[href*=”http://”]do not work in IE6. Then, add ie6updatein a conditional comment and voila! IE6 users see a totally legit looking alert bar across the top of their screen telling them that the page below looks horrible because they have an old browser and need to upgrade. Now you are ready to begin.

CSS3 is only sort of supported

CSS3 is currently a working draft. Microsoft hence decided to implement barely any of its features in IE8, and as a result your CSS3 magic is restricted to ‘modern’ (real) rendering engines, like WebKit (Google Chrome, Safari) and Gecko (Firefox). However, the developers of these engines understand that CSS3 is a draft and as such the interface can be changed without warning. As a safeguard they apply a prefix to the drafted properties they want to support. These are known as:

Vendor-specific extensions

If you’ve ever seen anything like -moz-border-radius: 6px; you know what I mean. Vendor-specific extensions are a standardised and accepted (however occasionally non-validating) way of implementing future rules without fear of breaking anything. If you want to use CSS3 properties you will most likely have to include the same property with a prefix right after (excepting the few properties like opacity and border-radius). Your rules will look something like this:

.box {
	-webkit-box-shadow:2px 2px 5px gray;
	-moz-box-shadow:2px 2px 5px gray;
	box-shadow:2px 2px 5px gray;
	}

I know that hurts, but at least your repitition of code is localised.  And it is future-friendly – as browsers start supporting CSS3 your advanced styles will begin to appear!  A shadow on a header here, a rounded corner there, an opacity somewhere. Patience. 

You’ll notice there’s no -ie-border-radius property above. This is very sad. This leads us to our next restriction in using CSS3:

Don't force a design

Think about it - why must the design for a site look the same in IE as Chrome? What if they looked different? Someone who sees the site in IE is not going to know what they're missing. If a design feature can't be implemented in IE that's no reason not to implement it in WebKit, so long as it degrades gracefully.

For this to work you need to be close to the designers (or be the designer) and have laid back superiors - it can't really be done when you're dealing with long chains of design approval. Convince everyone that the site is going to look better in Chrome (happy face!), not worse in IE (ANGRY FACE).

Validating CSS3

By default, the W3C's CSS Validator does not recognise CSS3. You must specify that you are validating CSS3 by clicking "More Options" on the validator page and selecting the CSS level 3 profile.

That’s it! Go forth and play:

CSS3 Goodies you have got to check out:

Note on this site

This post is pretty much a press release for the recent redesign of FARMCode.org – CSS3 allowed me to code the site exactly how I wanted in Google Chrome, translate it across to Firefox in like 5 minutes and then conduct quick damage control for IE (no rounded corners there).

Categories: CSS

sIFR vs. cufón: Text replacement and you

by James Diacono 31. March 2010 10:40

There are two reasons I use dynamic text replacement:

  1. Plain text in a browser window is never as smooth as it is in the design (except in Safari),
  2. The designs I'm given almost always use fancy (non-web based) fonts for headings, intro text etc.

Currently I subscribe to two solutions, both client-side: sIFR and cufón. If you want a quick answer to "what should I use?" then here it is: if you want replacement for long sentences and headings, use sIFR. If you want replacement for a few words on a button or in a menu, use cufón. If you want to know more, read on...

sIFR

How sIFR works

sIFR uses javascript to dynamically embed a Flash object in the place of specified HTML text elements. The Flash object is essentially an empty SWF (compiled Flash file) which includes the characters of the font you want to use. When javascript embeds the SWF in the HTML, it passes the SWF arguments such as text-content, font-size, color, rollover behaviour and many more. Some of these properties javascript takes from the CSS applied to the text, and some are overridden by sifr-config.js, which is a human-readable config file containing additional formatting tweaks.

How to use sIFR

  1. Download the source (only sifr.js, sifr-config.js and sifr.css are actually needed).
  2. Generate a font SWF from a True Type Font file. You can do this manually with Adobe Flash (like this) but it is easier to use this online generation tool.
  3. Link to sifr.css in the head of your HTML page.
  4. Link to both scripts in the head of your HTML page, first sifr.js, then sifr-config.js
  5. Edit sifr-config.js to read in the font SWF you created and use CSS selector syntax to select the HTML text elements you want to replace.
  6. Tweak away in sifr-config.js until the text looks right when sIFR is both enabled and disabled, in case the user is missing Flash (iPhones don't have Flash as of early 2010!).

cufón

How cufón works

cufón is entirely javascript and works in all major browsers (including IE6). You still need to generate a font file, but this is output to a javascript file similar in size to the equivalent sIFR SWF font file. cufón looks at selected blocks of text and replaces each word with a dynamically generated image (using the HTML <canvas> tag), or in IE's case, a VML object (Vector Markup Language). As a consquence of this, increasing the text size of the page either doesn't affect cufón-replaced text or expands the image, blurring it. Except in IE, which scales the text perfectly.

How to use cufón

  1. Download the source (all you need is cufon-yui.js)
  2. Generate a font file from a True Type Font. You are unfortunately dependent on this online generator.
  3. Link to cufon-yui.js in the head of your HTML page. Beneath it, link to any font files you've generated.
  4. You may also want to create another file, cufon-config.js, to hold selector information much the same way as sifr-config.js does.
  5. Populate cufon-config.js with what HTML text elements you want to replace.

Legality

Font foundaries are seemingly run by people who are very freaked out that their fonts are going to leak for free. Hence, the vast majority of fonts can't legally be embedded directly into the CSS (what, you didn't know about that? It's been around a while in some form or another - the @font-face directive allows you to supply the font file for obscure font-families - but it's only legal with open source fonts).

Because sIFR uses Flash, and Adobe has a cordial agreement with the font foundaries in Switzerland (or wherever) which allows anyone to embed pretty much any font in a .swf, sIFR is totally legal. cufón... cufón not so much. Although both supply a compiled/obfuscated font resource in .swf/.js format respectively, and are basically the same from the font foundaries' point of view, they haven't got around to adding "Allows embedding using javascript methods" to their fonts' terms of use agreements. And I wouldn't count on it...

So in short, use cufón. Go on, it's young and fresh and rad! Push the font foundaries to legalise it! But remember: you read that in a blog post...I'm not going to be your lawyer if they come after you.

Comparison

sIFR cufón
Core file-size (not including fonts) 30KB 18KB
Independent of Flash ×
Resizes nicely ×
Cursor-selectable text ×
Doesn't flicker on load ×
Independent of online font-generator ×
Online font-generator supports Open fonts (.otf) ×
Supported in all browsers
Degrades gracefully
Legal ×
Categories: Flash | JavaScript