March 13, 2010 3

Google Maps Flash API & Selectable Copyright Text

By duncanhall in Actionscript

When using the Google Maps Flash API you are required to display the relevant copyright notice for the tiles currently being shown. This is handled internally by the API and is generally not a problem. However, the current version of the SWC provided (1.18) chooses to handle the copyright text as selectable, meaning that the text cursor is displayed when the mouse is anywhere near the bottom 30px of the map. See below for an example


While I’m not sure if this is necessarily ‘as designed’, it doesn’t seem unreasonable to want to make the text unselectable. I’ve registered it as a bug, but for now I’ve also created a workaround in the hope this will be changed in the next release.

After investigating the display list of a Map object, it seems one of the sub-children is an object of type com.google.maps.controls.CopyrightView. This class is not publicly exposed in the API so I’m unsure of the implications of altering it in this way. The terms of use state that:

[you must not] delete, obscure, or in any manner alter any warning, notice (including but not limited to any copyright or other proprietary rights notice), or link that appears in the Products or the Content

We’re certainly not deleting or obscuring it, and we’re not actually altering the notice itself, just the interactive properties it has when displayed. In any case, the solution is presented below:

Update 15/02/2010: It seems the CopyrightView object is not always contained at position 0 in the parents display list. To rectify this, I have ammended the solution below to explicitly find the CopyrightView via its qualified class name.

//_map is an instance of a com.google.maps.interfaces.IMap object
_map.addEventListener(MapEvent.MAP_READY, map_readyHandler);
 
 
/**
 * Wait for the map to initialize and add an ENTER_FRAME event listener 
 */
function map_readyHandler (event:MapEvent) : void
{
    addEventListener(Event.ENTER_FRAME, setCopyrightToUnselectable);
}
 
 
/**
 * Locate the copyright textfield and change its selectable property
 */
function setCopyrightToUnselectable (event:Event) : void
{
    removeEventListener(Event.ENTER_FRAME, setCopyrightToUnselectable);
 
    var container:DisplayObjectContainer = _map.getChildAt(5) as DisplayObjectContainer;
    var numChildren:int = container.numChildren;
    var child:*;
 
    for (var i:int = 0; i < numChildren; i++)
    {
        child = container.getChildAt(i);
        if (getQualifiedClassName(child) == "com.google.maps.controls::CopyrightView")
        {
            var textfield:TextField = child.getChildAt(0) as TextField;
            textfield.selectable = false;	
            break;
        }
    }
}

Even when the MapEvent.MAP_READY event is fired, it seems the CopyrightView object has not yet been added to its parent (or has not been initialized). To get around this, a 1 frame delay is added, at which point the problematic TextField can be targeted and we can set the selectable property to false. This solution gives us exactly what we’re after, without altering the text or effecting the ‘terms of use’ link.

I’m hoping this isn’t an intended feature and that it will change in the next SWC, and in the meantime that the above solution isn’t violating any terms of use.

Tags: ,

March 6, 2010 1

Actionscript Path Correction Part 2

By duncanhall in Actionscript

After my initial success in removing dead ends and backtracking from a directed path, I realised I was only half way to solving the problem. In the original post, points A, B and C were all single point digressions away from the main path.

With the addition of the new points at D, the previous solution would only have removed the segments marked in green, still leaving a large part of D that we don’t want.

To remedy this, I have made 2 additions to the original solution. First, I created a method that allows me to recursively check the corrected path, with the corrected points being fed back into the correction algorithm a specified number of times. Initially I thought this would be all I needed, but I was still getting problem points left along the path. The key was to check the distance between the 2 points left remaining after an adjoining point had been removed. If it is below a certain distance, the next point along the path is also culled from the new route. The example below shows correction of a path with some complex faults:


Recursive path correction example swf

I’m quite pleased with this solution, so far its proved to eliminate every one of the features I’ve sought to remove. I can’t go into my own uses for it yet, but it’s applications could vary from optimising a route through a maze to auto correcting a shape drawn from user input.

I have created the DirectedPath class to encapsulate the 2 methods I created.

DirectedPath.correctPath()
Removes dead ends and vertices that double back on themselves from a path of consecutive points. The threshold value specifies the minimum allowable angle between any 3 consecutive points.

var correctedPath:Array = DirectedPath.correctPath(arrayOfPoint, 12);

DirectedPath.correctPathRecursive()
If the path is found to find faults, the path is recursively corrected until no more faults are found, or the maxLevels parameter is reached.

var correctedPath:Array = DirectedPath.correctPathRecursive(arrayOfPoint, 12, 10, 4);

View source for DirectedPath.as
Download DirectedPath.as
View DirectedPath Documentatation

March 3, 2010 2

Actionscript Path Correction – No Going Back!

By duncanhall in Actionscript

Update: See the improved solution

For a project I’m currently working on, I needed a way to remove extremities from a path of consecutive points. The extremities represent points or segments of the path that we want to remove from the route (usually “going back on yourself”), while maintaining the intended course as much possible.

Path Correct Example Image 1

Given the path in black above, the points A, B and C represent the types of feature we want to remove. Continuous curves would veer the path too far from the original, and in most cases would still leave an unacceptable ‘quirk’ in the path. My searches took me from Line Generalization to Line Simplification and Line Smoothing, with smoothing getting closest to what I was after.

All of them however, alter too many of the points along the path, and generally leave a fairly recognisable footprint of the feature we are trying to remove. To get the result we’re after, we need to explicitly identify the points that are causing a problem. With this in mind, the solution actually turns out to be somewhat simpler than those required above.


Each point along the path is tested against the point immediately before and after it. The angle given by the point in question is put through a high pass filter, with those that fail not making it into the new path. The threshold value specifies the lowest allowable angle derived from any 3 adjacent points. The first and last points of the original line always remain unaltered. (In the example above, the threshold was set to 12)

I won’t brother wrapping this up in a class, as it’s only one method, so here it is, to do with what you please.
I’ve since updated this original version and it’s now available in the DirectedPath class. I’ll leave the code below as a reference, as the update does not alter the basic premise of the solution.

function correctPath (points:Array, threshold:Number) : Array
{
	var numPoints:int = points.length;
	var corrected:Array = [];
	corrected.push(points[0]);
 
	var p0:Point;
	var p1:Point;
	var p2:Point;
	var da:Number;
	var db:Number
	var dc:Number;
	var c:Number;
	var n:int = numPoints - 1;
 
	for (var i:int = 1; i < n; i++)
	{
		p0 = points[i - 1];
		p1 = points[i];
		p2 = points[i + 1];
		da = Point.distance(p0, p1);
		db = Point.distance(p1, p2);
		dc = Point.distance(p0, p2);
		c = Math.acos((da * da + db * db - dc * dc) / (2 * da * db));
 
		if ((c * 180 / Math.PI) >= threshold) corrected.push(p1);
	}
 
	corrected.push(points[numPoints - 1]);
	return corrected;
}

Tags: , , , ,