[转]在Flex中画等值线(isolining package for ActionScript 3)
A week or so back I wrote about a package I ported/modified to create the Delaunay triangulation in Flash with a few AS3 classes. As I noted there, such a triangulated irregular network (TIN) allows us to interpolate isolines — lines of constant value (aka isarithms, commonly called contours).
So, given a field of points (weather stations, say)…
…with one or more attributes attached (temperature, say)…
…a TIN can be constructed.
With the above TIN, values can be interpolated along each edge between the points of known values (control points). The interpolation is strictly linear (that is, the value 50 would be interpolated halfway along an edge whose control points were valued 48 and 52).
With a given contouring interval (I’m using 4 degrees F here), we can connect some of these interpolated points, creating our contour lines.
With the previous steps stripped away, this creates a passable isoline map.
The lines are rigid, though, and should be smoothed for presentation. I allow two methods for this. You can use the “simple” method, which just uses the built-in graphics method curveTo between the midpoint of each isoline segment (below with the isoline interval decreased to 3 degrees).
The above looks alright, but the curves are not continuous, closed loops can still have hard corners, and the isolines no longer pass through the interpolated points (we have therefore generalized an already-inaccurate interpolation). My compatriot Andy Woodruff, author of the glorious new Cartogrammar blog, offered to write a nice continuous curve method that ensured isolines would still pass through the interpolated values. You can read about the method in his post. Here she blows:
Bringing it all together, then, and incorporating the only extra feature I wrote (tinting of isolines), here’s a nice finished isoline map of temperature across the U.S.
My new isolining package for Flash/ActionScript3 accomplishes all of the above, requiring only an array of point data with attribute values attached. The above example, was accomplished with the following lines of code (after drawing the U.S. states from a shapefile).
//first, generate the array of triangles (ITriangle objects) from the point data var triangles:Array = Delaunay.triangulate(points); Delaunay.drawDelaunay(triangles, points, triClip, false); //comment this out if you don't want to draw the triangulation //generate an array of isolines (isoline objects) var isos:Array = IsoUtils.isoline(triangles, points, triClip, 3, 0); //create color and class arrays for tinting the isolines var classesArray:Array = new Array(40, 44, 48, 52, 56, 60, 64, 68, 72, 76); var colorsArray:Array = new Array(0x051CFD, 0x4602FD, 0x6D0EEB, 0x8400FF, 0xC400FF, 0xEA00FF, 0xFF00E2, 0xFF0095, 0xFF0030, 0xFF0015, 0xFB3507); //then, actually draw them, using a continuous curve IsoUtils.drawIsolines(isos, triClip, "continuous", colorsArray, classesArray, .5, .95);
The full example is included in the .zip distribution. Get that here:
- the full .zip thing (in addition to my isolines class and an example, the archive includes my delaunay triangulation package, Andy Woodruff’s cubicBezier class, and a slightly modded version of Edvin van Rijkom’s shp classes, which are used to draw the shapefile in the example .fla)
- or, for you browsers, the main IsoUtils.as class
Keep in mind: triangulation is just one interpolation method, and is many ways the least technical (and accurate). More accurate interpolation techniques include inverse-distance and kriging. ***If you’re having trouble, and your isoline interval is not an integer, check out the comment at line 171 of isoUtils.as. Please fix that, BTW.
I meant to add other features, but since I started work this past week, I’m posting the package as-is, and invite others to modify. On my wishlist:
- hypsometric tinting, or color between the lines, would allow for more effective terrain or temperature mapping
- support for projections and other coordinate conversions in the drawIsolines method. I have packages for converting lat/long to a number of map projections, but currently the drawIsolines method doesn’t have support for passing a point coordinate conversion method.
- an animated demo. This thing’s lightning-fast, so why not?
- something that would be super wicked would be if someone would implement Tanaka’s illuminated contours [pdf] method, that thickens/thins and darkens/lightens lines like so…
…creating beautiful relief maps like the one below
If you add anything to the package, feel free to post a link to your revised version in the comments.