PS: If you have a 10 server - there is a REST way to get all the layers published in a map server that could be used to create swatches from the rendering information.
Monday, July 26, 2010
Merging Table Of Content and Legend Info
Initially, while working on Gulf Of Mexico Response Map, the legend and table-of-content were two separate windows. That took too much real-estate, and a TOC layer was hard to correlate with the legend swatch by name only. So I set upon merging the legend window and the table-of-content into one window. There is plenty of TOC code as a visual tree component, but it is the legend UI that causes us trouble as there is no REST endpoint to get the layer swatch information. Well with the advent of FeatureLayer somebody can argue that this could be done. But you still have to go back and forth for each layer and get the rendering information. BTW, this will be remedied in 10.1, as a new REST endpoint will be introduced to get _all_ rendering information of a map service. In the meantime, I had to do something. As you can imagine the project map services were very dynamic and the layer content was changing constantly, so having a static legend is out of the question. There were attempts to create an ArcObject proxy, where the client application connects to that proxy who issues a SOAP request to an ArcGIS server for the legend info. The SOAP result is converted to JSON and forwarded back to the client for decoding and rendering. The code was written in .Net and have a Java based server. I wanted to be platform independent and have a two tier architecture (at least from a 10,000 feet perspective) and the introduction of a proxy was out of the question. So....I have to issue SOAP calls directly from the client to ArcGIS server. This is where the advent of FlashBuilder with its data connectivity option was a blessing. FlashBuilder can generate correctly stub code for ArcGIS SOAP methods based on a map service WSDL. This was impossible in FlexBuilder. Yes, it does bloat the code base a bit, but it is a small price to pay for such a dynamic system. The TOC code is based on the FlexViewer TOC code. I modified the item renderer to be of variable height to accommodate the renderer swatches as child elements. You can see the application in action here. And like usual, you can download the source code from here. Small note: First time through, it take a few seconds to get the swatches, so if you open the tree, it will look “plain” and somehow AGS returns blank swatches for tiled map services. not sure why ! have to ask the core team about that. Oh one more thing, in addition to adding the Flex API for AGS swc, make sure to include the Adobe provided fiber swcs. Until 10.1 (hopefully soon) hope this can help.
Thursday, July 22, 2010
Pixel Bender For Map Projection
A customer came up to me at the User Conference and asked me if I can apply the same overlay method that I used in my OverlaySymbol application to position a geographic referenced image on a web mercator tiled base map; since esri is migrating most of its published maps on arcgis.com to web mercator. After talking it over with my friend Kerry (who is the final authority when it comes to map projections), he recommended that this should be a pixel by pixel operation due to the exponential latitude elongation nature of web mercator. So basically the algorithm is; for each output mercator pixel, convert it back to geographic, find out in the geographic image source what is the pixel color at that geographic location and assign that color to the output mercator pixel. Straight forward, I mean the web mercator transform is well known. I just have to do it a million time, and... that is when I started panicking. A million time loop in AS3 - that will take forever (well actually half a second) in user space. Then I remembered PixelBender. That is what it does for living very well - massively process pixels at the GPU level. So I downloaded the toolkit, went over the tutorials (all awesome) and I started writing my own filter. PixelBender can operate in a filter, blender or filler mode. It is the last mode that I'm interested in, as it enables me to fill any region in a display object based on a set of parameters. So I approached this overlay method differently than my previous experiment. I created a layer rather than an symbol to overlay the geographic image. The source of the image will be a property of the layer. The layer will load the compiled PixelBender filter code and on an extent change, PixelBender will be invoked to fill the layer graphics context based on the image source and extent as parameters. And it is fast :-). The following is a snippet of the mercator filter source code:
So the evaluatePixel() function is invoked by Pixel Bender on each pixel in the target image. the built-in outCoord() function return the coordinated in the target image that is currently being processed. In the next two lines, I convert the pixel values into mercator values - this is a linear transformation. Then I convert the mercator values into geographic value. If the values are 'outside' the geographic boundaries are return a fully transparent pixel value. Otherwise I linearly convert it to a pixel coordinate based on the image source width and height and I invoke the built-in sampleNearest() function to get me the pixel color value and return that value to pixel bender who will paint the target pixel location with that value. Cool, eh ?
You can see the application in action here. It shows precipitation image data from NOAA. And like usual you can download the source code from here. BTW, this requires the new Flex API for ArcGIS Server.
void evaluatePixel()
{
float2 pt = outCoord();
pt.x = pt.x * targetWidthFact + targetXMin;
pt.y = (targetPixelHeight - pt.y) * targetHeightFact + targetYMin;
pt.x = degrees(pt.x / 6378137.0);
pt.y = degrees(2.0*atan(1.0) - (2.0 * atan(exp(-1.0 * pt.y / 6378137.0))));
if( pt.x < -180.0 || pt.x > 180.0 || pt.y < -90.0 || pt.y > 90.0)
{
dst = float4(0.0,0.0,0.0,0.0);
}
else
{
pt.x = (pt.x - sourceXMin) * sourceWidthFact;
pt.y = (sourceYMax - pt.y) * sourceHeightFact;
dst = sampleNearest(src,pt);
}
}
So the evaluatePixel() function is invoked by Pixel Bender on each pixel in the target image. the built-in outCoord() function return the coordinated in the target image that is currently being processed. In the next two lines, I convert the pixel values into mercator values - this is a linear transformation. Then I convert the mercator values into geographic value. If the values are 'outside' the geographic boundaries are return a fully transparent pixel value. Otherwise I linearly convert it to a pixel coordinate based on the image source width and height and I invoke the built-in sampleNearest() function to get me the pixel color value and return that value to pixel bender who will paint the target pixel location with that value. Cool, eh ?
You can see the application in action here. It shows precipitation image data from NOAA. And like usual you can download the source code from here. BTW, this requires the new Flex API for ArcGIS Server.
Labels:
Flex,
PixelBender
Tuesday, March 9, 2010
Augmented Reality, iPhone and ArcGIS Server
I am a HUGE fan of Augmented Reality, and one of my favorite applications on the iPhone is Layar. In this post, I will "walk you" through how to setup a simple ArcGIS Layar Point Of Interests (POI) layer and how to expose it through the iPhone application. In addition, I created a small Flex application that will enable you to add POIs to that feature class through a python geo-processor task.
BTW - this is heavily geared to using ESRI desktop and server tools and I'm assuming that you are familiar with these tools.
First, request a developer key from http://dev.layar.com/. This might take a couple of hours to get to you.
So, in the meantime, let's get started. Using ArcCatalog, create a new point feature class called 'Layar' in a geodatabase with the following fields: Title (text), Line2 (Text), Line3 (Text), Line4 (Text), Attribution (Text), Type (Integer), ImageUrl (Text:512).

Import that layer into a map document using ArcMap. Save and publish the MXD as a Map Service. Just to be on the safe side, clear your REST endpoint service directory cache and list the available services. You should now see the new map service and you can now query using REST the newly created 'Layar' layer.
Next, we need to populate this 'Layar' layer. With the Advent of ArcGIS 10, this could easily be achieved using the new FeatureTask endpoint. However, I'm still using a 9.3.X server and I will have to rely on a geoprocessing task to add point features to the Layar feature class. For the sake of simplicity and quick deployment, I decided to implement this GP task using python. So, using ArcCatalog, create a new GP Toolbox and add to the toolbox a new python script. You can download the script from here. Again, I'm assuming that you are familiar with all these tools. This script will have two parameters. The first input parameter should be named 'featureSet' of type 'FeatureSet' and its schema should reference the Layar feature class. The second parameter should be named 'objectID'. It has an output direction and is of type LONG. Basically what the script does; it expects a feature set with one feature. That feature is read using a cursor and placed in memory. Next an insert cursor is created on the Layar feature class and populated with the in memory information and executed. Upon a successful execution, the OBJECTID of the last inserted feature is retrieved and returned back as a parameter. The whole script is surrounded by a try: except: in case of an exception, where a -1 as an OBJECTID value is returned back. Simple but not simplistic :-) Publish this Toolbox, clear the cache and now you should have new GPService task.
To use this GP task interactively, I created a Flex based web application.
This application consists of a side-by-side map and form component enabling the user by zooming and panning to click and define POI coordinates and to populate that POI attributes. By clicking the Save button, the above publish GP task is invoked and upon a successful completion, the map is refreshed to show the newly added POI. The Flex application source code can be downloaded from here.
Now that we have created and authored this Layar information, we need to publish and consume it on the iPhone Layar application. The Layar folks have described in detail the JSON publishing format - http://layar.pbworks.com/GetPointsOfInterest. So what we need now, is a middleware that accepts an HTTP request from an iPhone, convert the input parameters to an ArcGIS REST query, invoke a query task whose URL is the Layar layer URL in the above publish map service, read the ArcGIS JSON response and convert to a Layar JSON response. Easy, eh ? That is why we have computers :-) I accomplished all this using Java Web Application - you can download the source code from here. This web application is basically a servlet that relies on the Apache HTTPClient library for http communication and the Jackson JSON processor library for fast consumption and JSON production. You might wonder why I decided to write this in Java versus say python. well...First, I'm a Java nut. Two, I can whip this up fairly quickly, Three, wanted to experiment with Google Java App Engine so I can be "in the cloud man !" - LOL, last one is just an artifact of the first two - but it is cool ! When the iPhone Layar application requests POI, it does so on a predefined URL (more on this later) with the following HTTP GET parameters, lat: your current latitude location, lon: your current longitude location, radius: the search radius in meters plus other parameters. In this application I'm just decoding lat, lon and radius.
Now that you have an in-the-cloud POI Layar endpoint and assuming that you have gotten your Layar developer key, you can sign in to http://dev.layar.com/ and create your own layer. The form will request a POI URL, enter your in-the-cloud poi servlet endpoint. All of the above was leading this point. I highly recommend that you test your layer using the Layar test page http://dev.layar.com/api20test/layarTestPage/.
To test this on your iPhone, go to "Settings" add add your developer ID and key to the Layar application settings. Launch the Layar application, and you should see your newly published layer.
This is just the tip of the iceberg. There is so much more that you can do, adjust and customize. I just wanted to share this "little" experience with you. Hope you found it useful and tell me what you think.
Friday, February 26, 2010
Heat Map Layer Revisited
Following this post, Glenn G. found an "issue" when panning the map. I revisited the project and indeed there was a bug. Thanks Glenn. I updated the project and here is the result. In this project, I downloaded from geonames all cities with population over 15000 and plotted them on the map. The clustering of the cities (over 21,000) generated a cool heat map. Check it out and tell me what you think. And like usual, you can download the source code from here.
Wednesday, February 10, 2010
How Oracle Can Improve Java
Found this great article "15 Ways Oracle Can Make Java Better (and Improve Its Stance with Developers)" - here is my "in the weed" take:So....what do you think ?
- Keep JavaONE - with heavy focus on developers.
- Embrace OSGi down in the core VM.
- Kill JavaFx - Work closer with Adobe on Flex / BlazeDS / LCDS.
- Improve Dynamic Language Support - groovy / scala / JRuby / Jython /etc...
- Talk to Google about ME (seriously?) / Android
- Kill NetBeans - Eclipse may be King, but IntelliJ is God !
- Introduce new language primitives XML / Function / JSON.
- Improve language - set/get bean, native String ( switch myString {case "foo": ...}) as for casting.
- LINQ for Java - LCDS can help here.
- Talk to the Spring folks - there-is-only-one-framework-zuul :-)
- No "Effing" store !
Labels:
java
Sunday, December 20, 2009
Street View Within Flex API for AGS
There is this great sample in our code gallery where a Google Streetview is integrated with a map based on the Flex API for AGS. However, what I wanted is to have the street view to be part of the map, not an HTML sibling element. Found this project (flex-iframe) on google code, where you can display an HTML page inside a flex application. So I went ahead and merged the two projects. One of the requirements is to modify the template html file that is generated by Flex Builder with additional javascript code that enables the bridging between the flash and javascript world. I was not thrilled with fooling around with generated code, then I remembered the JavaScript flex tag by Abdul Qabiz. This flex element enables you to put javascript code _in_ a flex application, and on initialization it will be "evaled" and injected into the parent document DOM. So I merged all three projects together and this is you get. Check out it and tell me what you think. And like usual, the source code is here. There are some gems in there, like a custom symbol and I've adjusted the JavaScript flex tag. I've tried the app on my mac using safari, firefox and chrome, and it worked fine. However, I had issues with firefox on vista. IE worked for me.
Labels:
StreetView
Sunday, November 22, 2009
Yet Another Resizable TitleWindow
Was kinda ticked that TitleWindow did not have a resizable property :-( Found this reference when I googled "ResizableTitleWindow" - but was way too heavy. I just needed a _simple_ resizable title window, where I can grab the lower right corner and drag it to resize the window. Then I remembered that flexlib has a MDI package and I was always impressed with the code quality :-) Found the most excellent code for the MDIWindow component with resizable behaviour and additional features that I did not need. Here is my yet simplified derived version. And like usual, you can down the source code from here. BTW, I leave it as an "exercise" to the reader to add a visual element to the title window to indicate that it is resizable.
Labels:
resizable,
titlewindow
Subscribe to:
Posts (Atom)


