ArcIMS to GE script
Categories: Mapdex GE Mapdex Dev
For those of you curious about the logic behind the ArcIMS to Google Earth script (GE_KML.cfm), I have posted the code from that program. The conversion script is written in ColdFusion. It should be fairly straight forward to convert it to another server-side language.
As you will see, I need to add a bit more error checking.
Let me know if you have any quesitons.
Jeremy
<cfsetting ENABLECFOUTPUTONLY="Yes" showdebugoutput="false">
<!---<cfcontent type = "application/keyhole" >--->
<cfcontent type = "text/plain">
<cfsilent>
<cfset tickBegin = GetTickCount()>
<!---Parse mapserver and mapservice name from url--->
<cfset servername = "#url.servername#">
<cfset mapservice = "#url.mapservice#">
<cfif isdefined('url.bbox')>
<!---If bbox is defined then GE is requesting a particular lat-long envelope--->
<cfset coords = #ListToArray(url.bbox, ",")#>
<cfelse>
<!---If there is no url parameter bbox, then request the default mapservice lat-long envelope--->
<cfoutput>
<!---Get Mapservice default view in Lat-Long--->
<!--- Save arcxml for getserviceinfo to be sent to mapserver in a variable.
This returns the defualt enevelope, defined projection, and layer id's--->
<cfsavecontent variable = "arcxml">
<ARCXML version="1.1">
<REQUEST>
<GET_SERVICE_INFO fields="false" envelope="true" renderer="false" extensions="false" />
</REQUEST>
</ARCXML>
</cfsavecontent>
<cfset curl ='http://' & #servername# & '/servlet/com.esri.esrimap.Esrimap?ServiceName=#mapservice#&ClientVersion=4.0.1'>
<!---Submit arcxml request to the remote server--->
<cfhttp method="post"
url="#curl#"
timeout = "30">
<cfhttpparam encoded="no" type="body" name="ArcXMLRequest" value="#arcxml#">
</cfhttp>
<!---Parse getserviceinfo response from remote ArcIMS server--->
<CFSET sResponse = #cfhttp.FileContent#>
<cfset out_responseaxl = #trim(sResponse)#>
<cfset response_axl = #xmlparse(out_responseaxl)#>
<!---get envelope from xml document--->
<cftry>
<cfset orig_minx = #response_axl.arcxml.response.serviceinfo.properties.envelope.xmlattributes.minx#>
<cfset orig_miny = #response_axl.arcxml.response.serviceinfo.properties.envelope.xmlattributes.miny#>
<cfset orig_maxx = #response_axl.arcxml.response.serviceinfo.properties.envelope.xmlattributes.maxx#>
<cfset orig_maxy = #response_axl.arcxml.response.serviceinfo.properties.envelope.xmlattributes.maxy#>
<cfcatch type="any">
<cfdump var="#response_axl#"><cfabort>
</cfcatch>
</cftry>
<!---Get either custom projection string or id from xml document. If neither are defined or not empty, then
abort request--->
<cfif isdefined('response_axl.arcxml.response.serviceinfo.properties.featurecoordsys.xmlattributes.id')>
<cfset current_coordsys_id = "#response_axl.arcxml.response.serviceinfo.properties.featurecoordsys.xmlattributes.id#">
<cfset current_coordsys_string = "">
<cfelseif isdefined('response_axl.arcxml.response.serviceinfo.properties.featurecoordsys.xmlattributes.string')>
<cfset current_coordsys_id = "">
<cfset current_coordsys_string = "#response_axl.arcxml.response.serviceinfo.properties.featurecoordsys.xmlattributes.string#">
<cfelse>
ERROR. No Coordinate System Defined. <cfabort>
</cfif>
<!---Call coord_conversion service to reproject mapservice coordinates from default projection coordinates to
latitude and longitude coordinates--->
<cfinvoke component="coord_conversion" method="coord_conversion" returnVariable="coord_out">
<cfinvokeargument name="minx" value="#orig_minx#">
<cfinvokeargument name="miny" value="#orig_miny#">
<cfinvokeargument name="maxx" value="#orig_maxx#">
<cfinvokeargument name="maxy" value="#orig_maxy#">
<cfinvokeargument name="current_coordsys_id" value="#current_coordsys_id#">
<cfinvokeargument name="current_coordsys_string" value="#current_coordsys_string#">
<cfinvokeargument name="output_coordsys" value="4326">
</cfinvoke>
<cfset coords = #ListToArray(coord_out, ",")#>
</cfoutput>
</cfif>
<!---For clarity, place each coordinate into a clearly marked bottom_left or top_right variable--->
<cfset long_min = coords[1]>
<cfset lat_min = coords[2]>
<cfset long_max = coords[3]>
<cfset lat_max = coords[4]>
<!---with a default image width of 800, compute a height value that respects the envelopes ratio--->
<cfset width = 800>
<cfset ratio1 = (long_max - long_min)>
<cfset ratio2 = abs(lat_min - lat_max)>
<cfset ratio = (ratio1 / ratio2)>
<cfset height = int(width / ratio)>
<!---center of image in lat-long--->
<cfset userlon = ((coords[3] - coords[1])/2) + coords[1]>
<cfset userlat = ((coords[4] - coords[2])/2) + coords[2]>
<!---If request has a layer_id list as a url parameter, then request layer ids from remote mapservice.--->
<!---Note this should be done only if the above request was not done. Maybe results should be stored for
a client session? This needs a bit of work.--->
<cfif isdefined('url.layer_id')>
<cfoutput>
<cfsavecontent variable = "arcxml">
<ARCXML version="1.1">
<REQUEST>
<GET_SERVICE_INFO fields="false" envelope="true" renderer="false" extensions="false" />
</REQUEST>
</ARCXML>
</cfsavecontent>
<cfset curl ='http://' & #servername# & '/servlet/com.esri.esrimap.Esrimap?ServiceName=#mapservice#&ClientVersion=4.0.1'>
<cfhttp method="post"
url="#curl#"
timeout = "30">
<cfhttpparam encoded="no" type="body" name="ArcXMLRequest" value="#arcxml#">
</cfhttp>
<CFSET sResponse = #cfhttp.FileContent#>
<cfset out_responseaxl = #trim(sResponse)#>
<cfset response_axl = #xmlparse(out_responseaxl)#>
<cftry>
<cfset layerinfo_length = #arraylen(response_axl.arcxml.response.serviceinfo.layerinfo)#>
<cfset layernamelist = "#response_axl.arcxml.response.serviceinfo.layerinfo[1].xmlattributes.id#">
<cfloop from="2" to="#layerinfo_length#" index="i">
<cfset layernamelist = layernamelist & "," & #response_axl.arcxml.response.serviceinfo.layerinfo[i].xmlattributes.id#>
</cfloop>
<cfcatch type="any">
<cfdump var="#response_axl#"><cfabort>
</cfcatch>
</cftry>
</cfoutput>
</cfif>
<cfoutput>
<!---Save arcims request to generate map--->
<cfsavecontent variable = "arcxml">
<ARCXML version="1.1">
<REQUEST>
<GET_IMAGE autoresize ="true">
<PROPERTIES>
<BACKGROUND color="255,255,255" transcolor="255,255,255"/>
<!---Lat Long envelope from above--->
<ENVELOPE minx="#long_min#" miny="#lat_min#" maxx="#long_max#" maxy="#lat_max#" />
<!---projection of WGS84--->
<FEATURECOORDSYS id="4326" />
<FILTERCOORDSYS id="4326" />
<!---image width and height from above--->
<IMAGESIZE height="#height#" width="#width#" />
<OUTPUT type="png8" />
<!---If layer id is set, then only draw layers that are in the layer_id list. If not then draw the default layers that are turned on.--->
<cfif isdefined('url.layer_id')>
<LAYERLIST order="false">
<cfloop list="#layernamelist#" index="layer_ID">
<cfif listfindnocase(url.layer_id,layer_ID, ',') eq 0>
<LAYERDEF id="#layer_ID#" visible="false"/>
<cfelse>
<LAYERDEF id="#layer_ID#" visible="true"/>
</cfif>
</cfloop>
</LAYERLIST>
</cfif>
</PROPERTIES>
<!---Add source text at the top right of the requested image--->
<LAYER type="acetate" name="test" visible="true" id="9999">
<OBJECT units="database">
<COORDSYS id="4326" />
<TEXT coords="#(long_min + (0.05 * ratio1))# #(lat_max - (0.05 * ratio2))#" label="#mapservice# MapService from #servername#">
<TEXTMARKERSYMBOL fontstyle="normal" fontsize="8" font="Arial" fontcolor="0,0,0" outline="255,255,255" antialiasing="true" glowing="200,200,200" />
</TEXT>
</OBJECT>
</LAYER>
</GET_IMAGE>
</REQUEST>
</ARCXML>
</cfsavecontent>
<!---Submit arcxml request to the remote server--->
<cfset curl ='http://' & #servername# & '/servlet/com.esri.esrimap.Esrimap?ServiceName=#mapservice#&ClientVersion=4.0.1'>
<cfhttp method="post"
url='#curl#'
timeout = "30">
<cfhttpparam encoded="no" type="body" name="ArcXMLRequest" value="#arcxml#">
</cfhttp>
<!---Parse response--->
<CFSET sResponse = #replace(cfhttp.FileContent,'<?xml version="1.0"?>',"")#>
<cfset in_requestaxl = #arcxml#>
<cfset out_responseaxl = #trim(sResponse)#>
<cfset response_axl = #xmlparse(out_responseaxl)#>
<cfset OUT_IMAGEURL="#response_axl.arcxml.response.image.output.xmlattributes.url#">
<!---If response envelope has an nls_lang type of ',.' (European--commas as decimals) then replace commas with decimals--->
<cfif (IsNumeric(response_axl.arcxml.response.image.envelope.xmlattributes.minx) eq "NO") or (IsNumeric(response_axl.arcxml.response.image.envelope.xmlattributes.miny) eq "NO")>
<cfset OUT_MinX="#replace(response_axl.arcxml.response.image.envelope.xmlattributes.minx,",",".","ALL")#">
<cfset OUT_MinY="#replace(response_axl.arcxml.response.image.envelope.xmlattributes.miny,",",".","ALL")#">
<cfset OUT_MaxX="#replace(response_axl.arcxml.response.image.envelope.xmlattributes.maxx,",",".","ALL")#">
<cfset OUT_MaxY="#replace(response_axl.arcxml.response.image.envelope.xmlattributes.maxy,",",".","ALL")#">
<cfelse>
<cfset OUT_MinX="#response_axl.arcxml.response.image.envelope.xmlattributes.minx#">
<cfset OUT_MinY="#response_axl.arcxml.response.image.envelope.xmlattributes.miny#">
<cfset OUT_MaxX="#response_axl.arcxml.response.image.envelope.xmlattributes.maxx#">
<cfset OUT_MaxY="#response_axl.arcxml.response.image.envelope.xmlattributes.maxy#">
</cfif>
</cfoutput>
<!---compute how long Arcims request took from remote server--->
<cfset tickEnd = GetTickCount()>
<cfset RequestTime = tickEnd - tickBegin>
<!---Generate KML out of the remote ArcIMS server response--->
</cfsilent>
<cfoutput><?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.0">
<Folder>
<description>Please contact #servername# for more information</description>
<name>ArcIMS Live Feed</name>
<GroundOverlay>
<name>#mapservice# MapService from #servername#</name>
<visibility>1</visibility>
<Icon>
<href>#OUT_IMAGEURL#</href>
</Icon>
<LatLonBox>
<north>#OUT_MaxY#</north>
<south>#OUT_MinY#</south>
<east>#OUT_MaxX#</east>
<west>#OUT_MinX#</west>
<rotation>0</rotation>
</LatLonBox>
</GroundOverlay>
<Placemark>
<name>ArcIMS Map returned in #RequestTime# milliseconds</name>
<Point>
<coordinates>#userlon#,#userlat#,10</coordinates>
</Point>
</Placemark>
</Folder>
</kml>
</cfoutput>
As you will see, I need to add a bit more error checking.
Let me know if you have any quesitons.
Jeremy
<cfsetting ENABLECFOUTPUTONLY="Yes" showdebugoutput="false">
<!---<cfcontent type = "application/keyhole" >--->
<cfcontent type = "text/plain">
<cfsilent>
<cfset tickBegin = GetTickCount()>
<!---Parse mapserver and mapservice name from url--->
<cfset servername = "#url.servername#">
<cfset mapservice = "#url.mapservice#">
<cfif isdefined('url.bbox')>
<!---If bbox is defined then GE is requesting a particular lat-long envelope--->
<cfset coords = #ListToArray(url.bbox, ",")#>
<cfelse>
<!---If there is no url parameter bbox, then request the default mapservice lat-long envelope--->
<cfoutput>
<!---Get Mapservice default view in Lat-Long--->
<!--- Save arcxml for getserviceinfo to be sent to mapserver in a variable.
This returns the defualt enevelope, defined projection, and layer id's--->
<cfsavecontent variable = "arcxml">
<ARCXML version="1.1">
<REQUEST>
<GET_SERVICE_INFO fields="false" envelope="true" renderer="false" extensions="false" />
</REQUEST>
</ARCXML>
</cfsavecontent>
<cfset curl ='http://' & #servername# & '/servlet/com.esri.esrimap.Esrimap?ServiceName=#mapservice#&ClientVersion=4.0.1'>
<!---Submit arcxml request to the remote server--->
<cfhttp method="post"
url="#curl#"
timeout = "30">
<cfhttpparam encoded="no" type="body" name="ArcXMLRequest" value="#arcxml#">
</cfhttp>
<!---Parse getserviceinfo response from remote ArcIMS server--->
<CFSET sResponse = #cfhttp.FileContent#>
<cfset out_responseaxl = #trim(sResponse)#>
<cfset response_axl = #xmlparse(out_responseaxl)#>
<!---get envelope from xml document--->
<cftry>
<cfset orig_minx = #response_axl.arcxml.response.serviceinfo.properties.envelope.xmlattributes.minx#>
<cfset orig_miny = #response_axl.arcxml.response.serviceinfo.properties.envelope.xmlattributes.miny#>
<cfset orig_maxx = #response_axl.arcxml.response.serviceinfo.properties.envelope.xmlattributes.maxx#>
<cfset orig_maxy = #response_axl.arcxml.response.serviceinfo.properties.envelope.xmlattributes.maxy#>
<cfcatch type="any">
<cfdump var="#response_axl#"><cfabort>
</cfcatch>
</cftry>
<!---Get either custom projection string or id from xml document. If neither are defined or not empty, then
abort request--->
<cfif isdefined('response_axl.arcxml.response.serviceinfo.properties.featurecoordsys.xmlattributes.id')>
<cfset current_coordsys_id = "#response_axl.arcxml.response.serviceinfo.properties.featurecoordsys.xmlattributes.id#">
<cfset current_coordsys_string = "">
<cfelseif isdefined('response_axl.arcxml.response.serviceinfo.properties.featurecoordsys.xmlattributes.string')>
<cfset current_coordsys_id = "">
<cfset current_coordsys_string = "#response_axl.arcxml.response.serviceinfo.properties.featurecoordsys.xmlattributes.string#">
<cfelse>
ERROR. No Coordinate System Defined. <cfabort>
</cfif>
<!---Call coord_conversion service to reproject mapservice coordinates from default projection coordinates to
latitude and longitude coordinates--->
<cfinvoke component="coord_conversion" method="coord_conversion" returnVariable="coord_out">
<cfinvokeargument name="minx" value="#orig_minx#">
<cfinvokeargument name="miny" value="#orig_miny#">
<cfinvokeargument name="maxx" value="#orig_maxx#">
<cfinvokeargument name="maxy" value="#orig_maxy#">
<cfinvokeargument name="current_coordsys_id" value="#current_coordsys_id#">
<cfinvokeargument name="current_coordsys_string" value="#current_coordsys_string#">
<cfinvokeargument name="output_coordsys" value="4326">
</cfinvoke>
<cfset coords = #ListToArray(coord_out, ",")#>
</cfoutput>
</cfif>
<!---For clarity, place each coordinate into a clearly marked bottom_left or top_right variable--->
<cfset long_min = coords[1]>
<cfset lat_min = coords[2]>
<cfset long_max = coords[3]>
<cfset lat_max = coords[4]>
<!---with a default image width of 800, compute a height value that respects the envelopes ratio--->
<cfset width = 800>
<cfset ratio1 = (long_max - long_min)>
<cfset ratio2 = abs(lat_min - lat_max)>
<cfset ratio = (ratio1 / ratio2)>
<cfset height = int(width / ratio)>
<!---center of image in lat-long--->
<cfset userlon = ((coords[3] - coords[1])/2) + coords[1]>
<cfset userlat = ((coords[4] - coords[2])/2) + coords[2]>
<!---If request has a layer_id list as a url parameter, then request layer ids from remote mapservice.--->
<!---Note this should be done only if the above request was not done. Maybe results should be stored for
a client session? This needs a bit of work.--->
<cfif isdefined('url.layer_id')>
<cfoutput>
<cfsavecontent variable = "arcxml">
<ARCXML version="1.1">
<REQUEST>
<GET_SERVICE_INFO fields="false" envelope="true" renderer="false" extensions="false" />
</REQUEST>
</ARCXML>
</cfsavecontent>
<cfset curl ='http://' & #servername# & '/servlet/com.esri.esrimap.Esrimap?ServiceName=#mapservice#&ClientVersion=4.0.1'>
<cfhttp method="post"
url="#curl#"
timeout = "30">
<cfhttpparam encoded="no" type="body" name="ArcXMLRequest" value="#arcxml#">
</cfhttp>
<CFSET sResponse = #cfhttp.FileContent#>
<cfset out_responseaxl = #trim(sResponse)#>
<cfset response_axl = #xmlparse(out_responseaxl)#>
<cftry>
<cfset layerinfo_length = #arraylen(response_axl.arcxml.response.serviceinfo.layerinfo)#>
<cfset layernamelist = "#response_axl.arcxml.response.serviceinfo.layerinfo[1].xmlattributes.id#">
<cfloop from="2" to="#layerinfo_length#" index="i">
<cfset layernamelist = layernamelist & "," & #response_axl.arcxml.response.serviceinfo.layerinfo[i].xmlattributes.id#>
</cfloop>
<cfcatch type="any">
<cfdump var="#response_axl#"><cfabort>
</cfcatch>
</cftry>
</cfoutput>
</cfif>
<cfoutput>
<!---Save arcims request to generate map--->
<cfsavecontent variable = "arcxml">
<ARCXML version="1.1">
<REQUEST>
<GET_IMAGE autoresize ="true">
<PROPERTIES>
<BACKGROUND color="255,255,255" transcolor="255,255,255"/>
<!---Lat Long envelope from above--->
<ENVELOPE minx="#long_min#" miny="#lat_min#" maxx="#long_max#" maxy="#lat_max#" />
<!---projection of WGS84--->
<FEATURECOORDSYS id="4326" />
<FILTERCOORDSYS id="4326" />
<!---image width and height from above--->
<IMAGESIZE height="#height#" width="#width#" />
<OUTPUT type="png8" />
<!---If layer id is set, then only draw layers that are in the layer_id list. If not then draw the default layers that are turned on.--->
<cfif isdefined('url.layer_id')>
<LAYERLIST order="false">
<cfloop list="#layernamelist#" index="layer_ID">
<cfif listfindnocase(url.layer_id,layer_ID, ',') eq 0>
<LAYERDEF id="#layer_ID#" visible="false"/>
<cfelse>
<LAYERDEF id="#layer_ID#" visible="true"/>
</cfif>
</cfloop>
</LAYERLIST>
</cfif>
</PROPERTIES>
<!---Add source text at the top right of the requested image--->
<LAYER type="acetate" name="test" visible="true" id="9999">
<OBJECT units="database">
<COORDSYS id="4326" />
<TEXT coords="#(long_min + (0.05 * ratio1))# #(lat_max - (0.05 * ratio2))#" label="#mapservice# MapService from #servername#">
<TEXTMARKERSYMBOL fontstyle="normal" fontsize="8" font="Arial" fontcolor="0,0,0" outline="255,255,255" antialiasing="true" glowing="200,200,200" />
</TEXT>
</OBJECT>
</LAYER>
</GET_IMAGE>
</REQUEST>
</ARCXML>
</cfsavecontent>
<!---Submit arcxml request to the remote server--->
<cfset curl ='http://' & #servername# & '/servlet/com.esri.esrimap.Esrimap?ServiceName=#mapservice#&ClientVersion=4.0.1'>
<cfhttp method="post"
url='#curl#'
timeout = "30">
<cfhttpparam encoded="no" type="body" name="ArcXMLRequest" value="#arcxml#">
</cfhttp>
<!---Parse response--->
<CFSET sResponse = #replace(cfhttp.FileContent,'<?xml version="1.0"?>',"")#>
<cfset in_requestaxl = #arcxml#>
<cfset out_responseaxl = #trim(sResponse)#>
<cfset response_axl = #xmlparse(out_responseaxl)#>
<cfset OUT_IMAGEURL="#response_axl.arcxml.response.image.output.xmlattributes.url#">
<!---If response envelope has an nls_lang type of ',.' (European--commas as decimals) then replace commas with decimals--->
<cfif (IsNumeric(response_axl.arcxml.response.image.envelope.xmlattributes.minx) eq "NO") or (IsNumeric(response_axl.arcxml.response.image.envelope.xmlattributes.miny) eq "NO")>
<cfset OUT_MinX="#replace(response_axl.arcxml.response.image.envelope.xmlattributes.minx,",",".","ALL")#">
<cfset OUT_MinY="#replace(response_axl.arcxml.response.image.envelope.xmlattributes.miny,",",".","ALL")#">
<cfset OUT_MaxX="#replace(response_axl.arcxml.response.image.envelope.xmlattributes.maxx,",",".","ALL")#">
<cfset OUT_MaxY="#replace(response_axl.arcxml.response.image.envelope.xmlattributes.maxy,",",".","ALL")#">
<cfelse>
<cfset OUT_MinX="#response_axl.arcxml.response.image.envelope.xmlattributes.minx#">
<cfset OUT_MinY="#response_axl.arcxml.response.image.envelope.xmlattributes.miny#">
<cfset OUT_MaxX="#response_axl.arcxml.response.image.envelope.xmlattributes.maxx#">
<cfset OUT_MaxY="#response_axl.arcxml.response.image.envelope.xmlattributes.maxy#">
</cfif>
</cfoutput>
<!---compute how long Arcims request took from remote server--->
<cfset tickEnd = GetTickCount()>
<cfset RequestTime = tickEnd - tickBegin>
<!---Generate KML out of the remote ArcIMS server response--->
</cfsilent>
<cfoutput><?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.0">
<Folder>
<description>Please contact #servername# for more information</description>
<name>ArcIMS Live Feed</name>
<GroundOverlay>
<name>#mapservice# MapService from #servername#</name>
<visibility>1</visibility>
<Icon>
<href>#OUT_IMAGEURL#</href>
</Icon>
<LatLonBox>
<north>#OUT_MaxY#</north>
<south>#OUT_MinY#</south>
<east>#OUT_MaxX#</east>
<west>#OUT_MinX#</west>
<rotation>0</rotation>
</LatLonBox>
</GroundOverlay>
<Placemark>
<name>ArcIMS Map returned in #RequestTime# milliseconds</name>
<Point>
<coordinates>#userlon#,#userlat#,10</coordinates>
</Point>
</Placemark>
</Folder>
</kml>
</cfoutput>
Posted by jbartley at 11:34 AM | Link | 0 comments
Subscription Options
You are not logged in, so your subscription status for this entry is unknown. You can login or register here.
No comments found.
Commenting has been disabled for this entry.