Friday, August 19, 2011

ArcGIS Lite API for Flex

The ArcGIS API for Flex is pretty amazing and very powerful, but it is very GIS centric. Flex Programmers have to know for example the difference between mercator and geographical coordinates systems and have to understand the concepts of map layers, etc….
Programmers just want to put dots on maps at a specific latitude and longitude. This is very easy to do say for example using the google map API and folks have been asking for something like that for a while. So, I am please to tell you about an open source project that we have launched on github that is exactly that. A simple mapping API that is based on the core API to enable Flex developers to build mapping applications. The idea to open source the project is to let you see how some high level functions are implemented using the low level API. Here is a quick sample:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark"
               xmlns:mx="library://ns.adobe.com/flex/mx"
               xmlns:views="com.esri.views.*">
    <fx:Script>
        <![CDATA[
            import com.esri.ags.events.MapEvent;

            private function map_loadHandler(event:MapEvent):void
            {
                map.setCenter([ 40.736072, -73.992062 ])
            }
        ]]>
    </fx:Script>
    <views:ESRIMap id="map" load="map_loadHandler(event)"/>
</s:Application>

In addition, the API is mobile friendly. You can build Android and iOS mapping applications using the Flex API. Here is a mobile sample:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark"
               xmlns:views="com.esri.views.*">
    <fx:Style source="stylesheet.css"/>
    <fx:Script>
        <![CDATA[
            import com.esri.ags.events.MapEvent;
            import com.esri.events.GeolocationUpdateEvent;

            private function map_geolocationUpdateHandler(event:GeolocationUpdateEvent):void
            {
                map.locationToAddress(event.mapPoint, 50.0);
            }

            private function map_loadHandler(event:MapEvent):void
            {
                map.whereAmI();
            }
        ]]>
    </fx:Script>
    <views:ESRIMobileMap id="map"
                         geolocationUpdate="map_geolocationUpdateHandler(event)"
                         load="map_loadHandler(event)"/>
</s:Application>

As mentioned earlier, the project is on github. So you can clone it, compile it with the core API swc and learn how geocoding or routing is implemented.

The project can use more documentation as, I do write self documenting code! LOL - Sorry, that was not funny since this is supposed to be a stepping stone to the core API that _is_ very well documented. So, I will have to spend more time on this and add more high level functions like “driveTimePolygon”.

Anyway, “git clone” the project and tell me what you think.

Want to give credit where credit is due - Andy Gup started this initiative with his great Starter Project Template.

Just to clarify an important point. This API is for very simple mapping purposes and is NOT maintained by the core team.

Tuesday, March 29, 2011

Hacking the Kinect with Flash in a Mapping Application

At this year's DevSummit, I did a couple of demo theater presentations. One of them was about hacking the Microsoft Kinect using the Flash platform in a mapping application. Here is a video.
Kinect is a very successful and important product for Microsoft. And if you ever played with it using an XBox, you will understand why it is a very neat piece of technology.
Now, have you see the movie "Minority Report" ? Remember in the beginning of the movie when Tom Cruise step up to a console and started waving his hands to manipulate images (video)? One of the gestures that most fascinated me was the one where he twisted his wrist while his fingers were pretending to grab a baseball size object. That twisting gesture moved a sequence of images through time. Twist to the right and the sequence moves forward in time. Twist to the left and the sequence moves back in time. In the movie, he went back and forth to detect a pattern in that time sequence. Now, wouldn't be cool if we can do the same with Flash and a Kinect?
A couple of months back, I was working on a project that visualized levels of flash flood data from hurricane Hermine over Austin, TX. The data is temporal and is localized to nodes of a virtual grid on top of Austin with a cell size of about one and half kilometers. Using a Flex interface to Kinect, I want to detect rotation gestures that my hands will be performing to animate back and forth the flash flood levels over a time period.
My flood data was stored in a DBF file. Using the most excellent DBF library from Edwin van Rijkom, I was able to parse and load the data into memory. This data is about 71 Megabytes, as it spans an area of about 25 by 25 kilometers for about 4 days worth of hourly information. All that data is loaded into memory and bucketed by space and time in such that for each hour, I can know instantly what is the flood level value at any location.
Next, to make this spatial data morph itself over time visually and efficiently using the ArcGIS API for Flex, I created my own custom temporal layer. This custom layer, relies heavily on the bitmap capabilities of the Flash Player. At the application startup time, I create a base bitmap that is proportional to the map pixel width and height. Then, at each frame refresh during the life cycle of the application, I advance or retard an hour index value. For an hour index value, I can lookup all the nodes and their values and convert them to small rectangular bitmaps whose pixel width and height values are adjusted proportionally to the map scale based on about 1.5 square Km area. Each bitmap is filled with a color picked from a color ramp proportional to the range of the loaded flood level values. Blue on the lower end. Red on the upper end. Each bitmap is bit-blit'ed on the base bitmap who is then bit-blit'ed onto the flash player display. By repeating this process over time, each location varies its color, giving the illusion of motion as a color traverses from one node to another. Cool, eh?
In my MVC implementation of the application, my hour index was a bindable property in my model and my temporal layer was bound to this property in such a way that whenever that property changes, the layer reflected that change by bit-blitting the node data stored in the model.
Now, that was the easy part of the implementation. The difficult part is how to hook the Kinect to my Mac and consume Kinect depth frames using Flex to detect gestures that will be translated into positive or negative changes to my model hour index property (Remember, I modify that value and the layer reflects that change). Googling around, I came across the OpenKinect project. In the Wrappers section, I was delighted to find that somebody has already developed an ActionScript implementation and from the looks of it, I thought I was almost there. The AS3Kinect client implementation opens a persistent socket connection from flash to a daemon process written in C that was linked at compile time with the libfreenect library. This daemon process reads the Kinect depth frames as a byte stream from the USB port and forwards that stream of bytes through the open socket to the Flash application. Once on the client side and again taking advantage of the bitmap capabilities, blobs can be detected. A blob is a small region on the bitmap with the same color. See, the Kinect sends depth information as bitmap frames. If you extend your hands in front of you and make your palms face the Kinect, your palms and your body are at a different depth relatively to the Kinect device. By creating a virtual front and back plane, depth data can be filtered and converted to either white or black color encoded bytes on a bitmap. White for the front bytes and black for the back bytes. A continuous patch of white bytes (your palms) can be converted to a blob. A blob movement (single palm) can be translated to gestures like a swipe up, down, left and right. And multiple blob movements (your two palms moving) can be translated to for example a rotation when the blobs are swirling around a point or a scale up or down when the blobs are separated from each other diagonally or brought together diagonally. I wrote a simple program to test the transfer of the Kinect bytes through that daemon proxy to my flex application and it was sluggish and non-responsive despite that the supplied test program rgbdemo (written in pure C and utilizing OpenGL) worked flawless. Now, the AS3Kinet forum said that all should be fine when they tested it on their PC's. It was that last word that prompted me to test it on my Windows machine and on that machine, it worked !!! I did a little bit of investigation and that led me to write this blog post. Summarizing the post; the problem is that there exists a 64K chunking limit on sockets in the Flash player on Mac OS, and I needed to process 2 MBytes chunks (the size of a Kinect depth frame). And that 64K limit, throttled way back the data stream resulting in a slow to respond application :-( BTW, in the post, I did not want to give out too much of what I was working on, as I was preparing a surprise demo for GISWORX'11 plenary session.
I tried to circumvent the chunking problem by using Alchemy and LocalConnection, but that too had it chunking limits, and came to the realization that blob detection and gesture recognition has to occur down in the proxy and passed along as small packets of information to the client. The AS3Kinect had yet another project based on the OpenNI specification that did exactly what I needed, but that implementation was based on the Windows API and I have a Mac. I was very disappointed and started to panic with GISWORX'11 looming so closely. More googling around, I came across another natural interface specification, TUIO. The TUIO home page mentioned a Kinect implementation that runs on Mac OS. In addition, somebody implemented an AS3 interface to the TUIO protocol. The process is the same as with the AS3Kinect, where a TUIO server (TUIOKinect.app) is started. It reads the USB data stream and converts the chunks into frames where each frame is analyzed to detect blobs. All that is happening on the server. The detected blobs and their trajectories are converted into gestures. The gestures are encoded into byte arrays per the TUIO specification and broadcasted as UDP packets. The AS3 TUIO protocol implementation can read the UDP packet, decodes it and dispatch it as AS3 event. To test the implementation, a simple sample application was provided to rotate and translate any display object whose mouseenabled property is set to true. The sample application worked beautifully. Now, it was time to hook the TUIO AS3 implementation into my mapping application.
UDP packets can only be consumed by an AIR application, so first, I had to convert my web application to an AIR application. I used the AIRLanchpad application to generate the base template, and because my web application was based on MVC, the port of the model, the controls and some of the views was simple. The main application had to change from an Application subclass to a WindowedApplication subclass. At the application creation complete event handling, a TUIOClient is instantiated with a UDP connector so is a gesture manager with a stage reference and a rotation gesture listener. The gesture manager having a reference to the stage watches for any added display object with mouse enabled property. These display objects can become gesture listeners. The custom layer being mouse enabled and a child of the stage is a candidate for a listener to gesture rotate events. Now, Kinect is very responsive and TUIOKinect will blast the application with rotation events. To smooth this fast sequence of rotation value that could have pikes in the stream, I implemented a digital low pass filter giving me smooth rotation values as my extended palms are performing rotation gestures. A rotation to the right gives me a positive angle which translated to incrementing my hour index value in my model which through binding automagically refreshed the layer to show the flood level values at each node at that time instance. A rotation to the left, does the opposite. Works like a charm, and this was a huge success at the GISWORX'11 plenary. Modest, ain't I ?
If you have a Kinect and want to try it on your mac, download the AIR application from here. Like usual, the source is available for you to check out what I have done. Just hold the right key on the date label of the running application and it will give you the option to view and download the source code.
Happy Kinecting.

Tuesday, December 28, 2010

AS3 Socket Issues With Large Data on MacOS

So... I was writing an MXML/AS3 application that uses a Socket class instance to consume large amounts of data from a Java socket server program. The server is supposed to write very rapidly 1MB data chucks to a connected AS3 client. Now the funny part is that when the packet size is less that 64K, the server would write these packets very quickly, but when it was writing 1MB chucks, it would "stall" between writes while the client was reading the data in 64KB chuncks. So, I start pulling my old TCP tuning trick back from my 'C' days to tune the socket server. But no difference. I can only tune the server side as the client AS3 socket class does not offer any tuning properties and I'm assuming that the folks at Adobe would implement sockets correctly. It is this last statement that kept nagging me. "How often have I said to you that when you have eliminated the impossible, whatever remains, however improbable, must be the truth?" (Sherlock Holmes). So I wrote a simple Java socket client to test my server and guess what...no stall, A-Ha ! So there _is_ an issue with AS3 Sockets...but still...could not believe it, I mean...my MacBook Pro is used for development, God knows how many libraries I've installed and I have two VPN clients and again, God only knows what they setup in the kernel to make the tunnel. So, I took my Java server jar and my AS3 AIR application and installed them on a "clean" MacBook. Started the server and then the AIR application, and guess what....same result. The server stalls between writes as the AS3 Socket client is reading in 64K chucks the data. Now this is messed up. Dusted my old Dell with XP, installed the latest updates (that took forever) and then dropped the java server jar and AIR application. Started the server and then the AIR application, and guess what ? NO STALL. No way....my trusty Flash Player implementation on MacOS has issues. Just to make sure, started the server on XP and AIR on MacOS; stall. Started the server on MacOS and AIR on XP; No Stall.
I'm writing this to share my experience, the binaries and the source code hoping that somebody out there tells me that I've done wrong or if there is indeed an issue.
Please test it yourself. You need to have Java and AIR installed. The AIR package is here and the server jar is here. The java source code is here and the FlashBuilder project is here.
From a command line, start the java server as follows:
$ java -jar SocketServer.jar
As to the client, just double click on the installed application. I'm printing to the console the number on packets that have been sent. On my Mac, I see a print statement every one second. On my XP, all is done in one second.
Thanks Y'all - in the meantime will do my development off my XP. Happy New Year.

Thursday, November 4, 2010

How to use Esri Flex API on Android and iPhone

Update (Jun 2011) : For more updated info, check out my ADC article here.
At MAX2010 (Awesome BTW) Adobe introduced Flex SDK Hero and Flash Builder Burrito which enables you to build and deploy Flex mobile applications on Android by default. In addition, using the revitalized Packager for iPhone, you can postprocess the swf into an ipa that you can deploy on an iPhone using iTunes.

In this post, I will share with you the steps that I took to use the Flex API for ArcGIS to build a mobile mapping application.

First and foremost - RTFM - here are some links that u _need_ to read specially for iPhone provisioning:

http://opensource.adobe.com/wiki/display/flexsdk/Hero
http://labs.adobe.com/technologies/flashbuilder_burrito/
http://labs.adobe.com/technologies/packagerforiphone/

The cool part of this whole process is now you have one code base to build upon and deploy on Android and iPhone and in the future whatever mobile platform Adobe decides to support.
You can download the source code of the sample application from here.
This simple application queries the states demographic layer in arcgis.com and displays the result as a list. By taking advantage of the new state syntax in Flex 4, if the user rotates the phone to view the info in landscape mode, the list is replaced with a map showing the selected states. Cool ?
There is no new Flex API for ArcGIS to learn. I'm using the same old Query, QueryTask, Map, ArcGISTiledLayer, GraphicLayer and SimpleFillSymbol classes from the released Flex API.
Now, to compile the application using Flash Builder Burrito, make sure to include in the libs project folder the flexapi swc and make sure to copy from the Flex sdks folder (under the burrito application folder) the mx.swc and the sparkskins.swc files. For the next release of our swc will not require the last two swc, just add them for now. Your package explorer in Flash Builder should look like this:

Now you can compile, deploy and run your swf on the USB attached Android. Make sure that you have the latest AIR runtime on your phone. If not, then delete AIR using the Settings view and redeploy the application, the latest runtime engine will be automagically installed.

Now to the iPhone. Currently, Burrito does not have a built-in wizard to postprocess the swf into and an ipa. This must be done via command line tools. So, download and install the latest iphone packager for your platform (windows or mac). In my case, I had to re-compile the source code to reproduce the swf. Here is the content of my bash shell script:

FLEX_HOME="/Applications/Adobe Flash Builder Burrito/sdks/4.5.0"
"${FLEX_HOME}/bin/mxmlc"\
-load-config "${FLEX_HOME}/frameworks/airmobile-config.xml"\
-compiler.include-libraries+=libs\
-sp src\
-o bin-debug/MyMobileApp.swf src/MyMobileApp.mxml


Next is to convert the swf to an ipa. Here is the content of my shell script:

~/packagerforiphone_v2_mac_101110/bin/pfi\
-package\
-target ipa-test\
-provisioning-profile ~/YourProfile.mobileprovision\
-storetype pkcs12\
-keystore ~/YourFile.p12\
-storepass YourPassword\
MyMobileApp.ipa\
bin-debug/MyMobileApp-ios.xml\
bin-debug/MyMobileApp.swf\
bin-debug/assets/Default.png\
bin-debug/assets/Icon29.png\
bin-debug/assets/Icon57.png\
bin-debug/assets/Icon512.png


Here is the content of MyMobileApp-ios.xml:

<?xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://ns.adobe.com/air/application/2.0">
<id>ThunderHead</id>
<filename>MyMobileApp</filename>
<name>MyMobileApp</name>
<version>v1</version>
<initialWindow>
<renderMode>gpu</renderMode>
<content>bin-debug/MyMobileApp.swf</content>
<fullScreen>true</fullScreen>
<aspectRatio>portrait</aspectRatio>
<autoOrients>true</autoOrients>
</initialWindow>
<supportedProfiles>mobileDevice</supportedProfiles>
<icon>
<image29x29>bin-debug/assets/Icon29.png</image29x29>
<image57x57>bin-debug/assets/Icon57.png</image57x57>
<image512x512>bin-debug/assets/Icon512.png</image512x512>
</icon>
<iPhone>
<InfoAdditions><![CDATA[
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleBlackOpaque</string>
<key>UIRequiresPersistentWiFi</key>
<string>NO</string>
]]></InfoAdditions>
</iPhone>
</application>


Again - if you want to know what all the above options mean - you _must_ read the packager documentation. The pfi command will run for a long time - do not worry - it will eventually finish - again, this is still in its early stages, and I hope that Adobe will make this easier and faster in the future.
Now drag the ipa file onto iTunes and sync your iPhone. you should in theory have the app on your iPhone.
I hope this works for you and tell me what you think.

Friday, September 24, 2010

Dynamic Legend Generation From An Image Map Services

You can see the national weather warnings that NOAA publishes here. If you look at the page, you will notice that _all_ the legend swatches and text are presented under the map and you are left to your own means of locating the associated colors between the map and the legend grid to figure out what is on the map.
It would be nice if the legend grid could be dynamically generated to list only the swatch colors and their descriptions based on what is on the map. This is what this post tries to solve.
So NOAA publishes the national weather service maps as Esri ArcGIS REST endpoints. Using an instance of an ArcGISDynamicMapServiceLayer subclass, I can intercept the reponse image. Once I have the image bitmap data, I can get a histogram of the color distribution. Now using NOAA color map, I can associate a color with a description and populate a legend UI component. Check out the application in action here. The legend located on the top right corner is not fully transparent, roll the mouse over it to make it fully opaque. And like usual, you can download the source code from here.
Update: Looks like my usage and processing of the histogram does not lead me to a unique set of colors. So I reverted back to good old fashion looping through the pixels and creating a unique bucket of colors. Works pretty fast and more importantly correctly :-) A colleague at Esri was wondering if you can click on the map and popup an info window containing the label of the weather at that location, so I updated the code to handle this request - Thanks Mehul.

Monday, August 16, 2010

Image Flare Symbol For Clustered Graphics

This is a long overdue post following the clustering post where I wanted each flare element in a cluster symbol to flare to a different image symbol when the flare expands out. In addition, the default flare symbol expands upon a rollover mouse event, by me giving you the source code, you can customize it to expand on click, double click, shift click, whatever you want - you have the source code. The same applies to the flare elements. The ImageFlareSymbol has the same properties as the basic FlareSymbol but has two additional properties (backgroundWeights, backgroundColors) to color code the clusters based on their weight value. Each cluster is composed of one or more Graphic instance. In this implementation, each graphic must be symbolized with an instance of ImageFlareElementSymbol. The latter has a property ‘href’ that reference a bitmap url that will be displayed as a flare element. Here is a sample application to show the image flare in action. And like usual, here is the source code.

Thursday, August 5, 2010

Weighted Map Feature Clustering With Attributes

Was asked if the WeightedClusterer can cluster features not just by proximity but by proximity and attribute property value. The idea is that there should be at least one cluster per unique attribute property value. Let me explain further:

The above snapshot is a clustering of cities based on proximity and country - note that despite the proximity of Belgium and The Netherlands, two distinct clusters have been created one for BE and the other for NL - now for France - there is a cluster containing one feature over Paris, however due to the distance from Paris (at that scale) a cluster was created based on 3 cities in the south of France. Make sense ?
In the implementation of the AttrClusterer class that extends the ESRIClusterer class, we override the clusterGraphics function. This function is invoked indirectly by the Flex framework during the update of the display list. In this function, we overlay a virtual grid on the map. This grid acts as a spatial index. Features that are in the same cell will be initially clustered together. Next a process of searching and merging will be executed till no cluster overlaps another cluster. Let me explain this process; for each cluster, search the immediately adjacent cell for any overlapping cluster (that is why we need that spatial index grid :-). If a neighboring cluster is found, then the two cluster merge into one cluster and the location of the new cluster is based on the weight of each original cluster. the new cluster is spatially indexed and the original two clusters are removed. BTW, this process is guaranteed to converge to a steady state solution, so there is no need for a terminal condition like a counter. Now something of importance here is the index used to locate neighbors. The spatial index is implemented as a hash map, the cluster key is a combination of the cluster position relative to the center of the map and the cluster attribute - remember - that what started this whole implementation. You can see the application in action here. I’ve loaded the top 1000 cities by population from geonames. And like usual, you can find the source code here.