Hi Mapscript Developers...<div><br></div><div>We have been stuck on Mapscript 4.6 or so for quite some time because we generated all of our aircraft, airport, data block and flight track lines by explicitly building them up with SWIG from points, lines, shapes, etc, and kludging to show the aircraft's heading in a way that Mapscript 5 broke.</div>
<div><br></div><div>So I learned over time I kind of did it the wrong way, but I needed a data source besides static file types and databases. So recognizing that only by generating geometry and attributes as rows are we going to get to the latest stuff plus get access to the parameterizable elements that you can't get to directly, and possessed of some custom memory-resident databases for stuff for which real databases are just too slow, I set out to write a loadable layer plugin built around Tcl and succeeded with that.</div>
<div><br></div><div>I'm gonna paste the README below and we're going to be open sourcing it.</div><div><br></div><div>One of the touches in our FlightAware maps is that we indicate the aircraft altitude, roughly, with a drop shadow. Issue now is that you can't bind attributes for shadowsize. It looks like it would be pretty simple to add. Are you guys OK with something like this?</div>
<div><br></div><div>Karl</div><div><br></div><div>---------------------------------------- snip -----------------------------------------------</div><div><div>TclPlug is a mapserver layer database plugin.</div><div><br></div>
<div>You define one or more layers in your map file as connection type PLUGIN and add a PLUGIN line.</div><div><br></div><div> CONNECTIONTYPE plugin</div><div> PLUGIN "/home/karl/src/mapscript-svn/mapserver/maptclplug.so"</div>
<div><br></div><div>The first time a plugin layer is rendered, a full-powered Tcl interpreter is created and a file called tclplug.tcl is loaded. It is retained and used for all layers using the plugin connection type and referencing/loading the tclplug shared library.</div>
<div><br></div><div>It evaluates the connection string as Tcl source, so you can source in a file there or do a package require.</div><div><br></div><div>Your package/file must define some procs:</div><div><br></div><div>
geo_query</div><div> get_geometry</div><div> get_attributes</div><div><br></div><div>GEO_QUERY</div><div><br></div><div>When any tclplug layer is being rendered, geo_query is called to perform the query.</div><div>
<br></div><div>It is passed one argument, which is a list of named attributes that the mapscript library is expecting due to what's been defined as bound attributes in the layer.</div><div><br></div><div>For instance, say the map layer is:</div>
<div><br></div><div> LAYER</div><div> NAME "plugin" </div><div> PROJECTION "+proj=latlong +ellps=GRS80" END</div><div> STATUS on</div><div> DEBUG 10</div><div> </div>
<div> CONNECTIONTYPE plugin</div><div> PLUGIN "/home/karl/src/mapscript-svn/mapserver/maptclplug.so"</div><div> CONNECTION "package require mytclplug" </div><div> DATA "search -originOrDestination {KJFK KTEB KLGA KEWR}""</div>
<div> TYPE LINE</div><div> FILTER "CFCC LIKE 'A5%' OR CFCC LIKE 'A6%' OR CFCC LIKE 'A0%'"</div><div> </div><div> LABELITEM myDataBlock</div><div> TRANSPARENCY 50</div>
<div> TOLERANCE 10</div><div> CLASS</div><div> TEMPLATE roads.html</div><div> LABEL</div><div> ANGLE [myAngle]</div><div> TYPE TRUETYPE</div><div> ANTIALIAS TRUE</div>
<div> COLOR [myColor]</div><div> #COLOR 195 195 255</div><div> #OUTLINECOLOR 96 96 96</div><div> MINDISTANCE 200</div><div> #MINFEATURESIZE auto</div>
<div> MINFEATURESIZE 10</div><div> POSITION UC</div><div> SIZE 8</div><div> OFFSET 0 2</div><div> FONT "chalkboard"</div><div> END</div>
<div> STYLE</div><div> COLOR 96 96 96</div><div> SYMBOL 1</div><div> SIZE 5</div><div> END</div><div> STYLE</div><div> COLOR 200 225 255</div>
<div> SYMBOL 1</div><div> SIZE 3 </div><div> END</div><div> END</div><div> END</div><div><br></div><div><br></div><div>This then causes the layer to be rendered by drawing the map or something. geo_query will be called with {myDataBlock myAngle myColor} as its argument.</div>
<div><br></div><div>geo_query is expected to perform its search or whatever, and return the number of rows resulting from the query.</div><div><br></div><div>What the query is is entirely up to you, but your geo_query must return a number of rows.</div>
<div><br></div><div>LAYER ARRAY</div><div><br></div><div>A global array named layer is created with several elements in it. For the above map payer, when geo_query is called, the layer array would contain:</div><div><br>
</div><div>layer(connection) = here's my connection info</div><div>layer(data) = here's my data</div><div>layer(name) = plugin</div><div>layer(plugin_library) = /home/karl/src/mapscript-svn/mapserver/maptclplug.so</div>
<div>layer(rectange) = -114.560132712 8.33658444212 -65.4398672878 41.2751764447</div><div>layer(type) = line</div><div><br></div><div>Type can be "line", "point", "polygon", "chart", "annotation", or "query".</div>
<div>No testing has been done with chart, annotation or query.</div><div><br></div><div><br></div><div>Note that you can use rectangle to constrain the geometry of your search.</div><div><br></div><div>STARTUP</div><div><br>
</div><div>The contents of the connection string are evaluated. This should be a source command or a package require or something that causes three procs to be created in a namespace that matches layer name.</div><div><br>
</div><div>ROW PROCESSING</div><div><br></div><div>GEOMETRY</div><div><br></div><div>Now as the layer is rendered, for each row that you said you have, get_geometry is called with the corresponding row number.</div><div><br>
</div><div>For instance if your geo_query returned 8, get_geometry will be called eight times with its argument starting at 0 and going through 7.</div><div><br></div><div>Your get_geometry returns geometry.</div><div><br>
</div><div>It returns a list of lists of x, y coordinate pairs.</div><div><br></div><div>If the layer type is points, each point in every list is inserted into the layer as a point.</div><div><br></div><div>If the layer type is line, each list of points is inserted into the layer as a line.</div>
<div><br></div><div>If the layer type is polygon, each list of points is inserted into the layer as a polygon.</div><div><br></div><div>If for some reason for a certain row you do not wish to emit geometry, no problem, just return an empty list and no geometry will be emitted.</div>
<div><br></div><div>ATTRIBUTES</div><div><br></div><div>If geometry was emitted, TclPlug will come back and request the needed attributes' values to complete processing the row.</div><div><br></div><div>get_attributes is called with the corresponding row number that get_geometry was called with. get_geometry should return a list of values corresponding positionally to the element names passed to geo_qery.</div>
<div><br></div><div>For the example layer, the list should be the values for myDataBlock, myAngle, and myColor.</div><div><br></div></div>