<apidoc:module name="KML" subcategory="KML" bucket="XQuery Library Modules" category="Geospatial Supporting Functions" 
  xmlns:apidoc="http://marklogic.com/xdmp/apidoc"
  xmlns="http://www.w3.org/1999/xhtml" lib="kml"
>
<apidoc:summary access="public" subcategory="KML" bucket="XQuery Library Modules" category="Geospatial Supporting Functions">
<p>The KML module provides support for geospatial queries using KML
markup. 
</p>
<p>To use the KML module as part of your own XQuery module, include the
following line in your XQuery prolog:
</p>
<p><code>import module namespace kml = "http://earth.google.com/kml/2.0"
         at "/MarkLogic/geospatial/kml.xqy";</code></p>
<p>The library namespace prefix <code>kml</code> is <em>not</em> predefined
in the server.</p>
</apidoc:summary>

<apidoc:function name="point" type="kml" lib="kml" 
	subcategory="KML" bucket="XQuery Library Modules" category="Geospatial Supporting Functions">
  <apidoc:summary>
  Create a cts:point value from a KML Point or Location element.
  </apidoc:summary>
  <apidoc:params>
    <apidoc:param name="point" type="element()">
    A Point or Location element.
    </apidoc:param>
  </apidoc:params>
  <apidoc:return> cts:point </apidoc:return>
  <apidoc:usage>The KML Point and Location elements include additional
  information that is not retained in the cts:point value.  In particular, the
  elevation part of the point value will be dropped.  Therefore two KML points
  at the same latitude and longitude with different elevations will
  nevertheless have equal cts:point values.</apidoc:usage>
  <apidoc:example><pre xml:space="preserve"><![CDATA[
  xquery version "1.0-ml";
  import module namespace kml = "http://earth.google.com/kml/2.0"
         at "/MarkLogic/geospatial/kml.xqy";

  kml:point(
    <kml:Point>
      <kml:coordinates>-127.24,12.5,10.0</kml:coordinates>
    </kml:Point>)
  ,
  kml:point(
    <kml:Location>
      <kml:latitude>12.5</kml:latitude>
      <kml:longitude>-127.24</kml:longitude>
      <kml:altitude>10.0</kml:altitude>
    </kml:Location>)
  ]]></pre>
  </apidoc:example>
</apidoc:function>

<apidoc:function name="box" type="kml" lib="kml" 
	subcategory="KML" bucket="XQuery Library Modules" category="Geospatial Supporting Functions">
  <apidoc:summary>
  Create a cts:point value from a KML LatLongBox element.
  </apidoc:summary>
  <apidoc:params>
    <apidoc:param name="envelope" type="element(kml:LatLongBox)">
    A LatLongBox element.
    </apidoc:param>
  </apidoc:params>
  <apidoc:return> cts:box </apidoc:return>
  <apidoc:example><pre xml:space="preserve"><![CDATA[
  xquery version "1.0-ml";
  import module namespace kml = "http://earth.google.com/kml/2.0"
         at "/MarkLogic/geospatial/kml.xqy";

  kml:box(
     <kml:LatLongBox>
       <kml:north>30</kml:north>
       <kml:south>12.5</kml:south>
       <kml:east>-122.24</kml:east>
       <kml:west>-127.24</kml:west>
     </kml:LatLongBox>)
  ]]></pre>
  </apidoc:example>
</apidoc:function>

<apidoc:function name="circle" type="kml" lib="kml" 
	subcategory="KML" bucket="XQuery Library Modules" category="Geospatial Supporting Functions">
  <apidoc:summary>
  Create a cts:circle value from a radius and KML Point or Location element.
  </apidoc:summary>
  <apidoc:params>
    <apidoc:param name="radius" type="xs:double">
    The radius of the circle, in miles.
    </apidoc:param>
    <apidoc:param name="center" type="element()">
    A KML Point or Location element representing the center of the circle.
    </apidoc:param>
  </apidoc:params>
  <apidoc:return> cts:circle </apidoc:return>
  <apidoc:example><pre xml:space="preserve"><![CDATA[
  xquery version "1.0-ml";
  import module namespace kml = "http://earth.google.com/kml/2.0"
         at "/MarkLogic/geospatial/kml.xqy";

  kml:circle(47, 
	 <kml:Point>
		 <kml:coordinates>-127.24,12.5</kml:coordinates>
	 </kml:Point>)
  ]]></pre>
  </apidoc:example>
</apidoc:function>

<apidoc:function name="polygon" type="kml" lib="kml" 
	subcategory="KML" bucket="XQuery Library Modules" category="Geospatial Supporting Functions">
  <apidoc:summary>
  Create a cts:polygon value from a KML polygon or a sequence of KML Point or Location elements.
  </apidoc:summary>
  <apidoc:params>
    <apidoc:param name="polygon-or-points" type="element()+">
    A sequence of Point or Location elements representing the vertices of the 
    polygon or a Polygon itself. 
    </apidoc:param>
  </apidoc:params>
  <apidoc:return> cts:polygon </apidoc:return>
  <apidoc:example><pre xml:space="preserve"><![CDATA[
  xquery version "1.0-ml";
  import module namespace kml = "http://earth.google.com/kml/2.0"
         at "/MarkLogic/geospatial/kml.xqy";

  kml:polygon((
    <kml:Point><kml:coordinates>-127.24,12.5</kml:coordinates></kml:Point>,
    <kml:Point><kml:coordinates>-127.8,15.25</kml:coordinates></kml:Point>,
    <kml:Point><kml:coordinates>-126.1,13.45</kml:coordinates></kml:Point>,
    <kml:Point><kml:coordinates>-127.24,12.5</kml:coordinates></kml:Point>
  ))
  ]]></pre>
  </apidoc:example>
</apidoc:function>

<apidoc:function name="polygon" type="kml" lib="kml" 
	subcategory="KML" bucket="XQuery Library Modules" category="Geospatial Supporting Functions">
  <apidoc:summary>
  Create a cts:polygon value from a KML Polygon element. The polygon returned
  represents the exterior polygon.
  </apidoc:summary>
  <apidoc:params>
    <apidoc:param name="polygon-or-points" type="element()+">
    A KML Polygon element representing the polygon.
    </apidoc:param>
  </apidoc:params>
  <apidoc:return> cts:polygon </apidoc:return>
  <apidoc:example><pre xml:space="preserve"><![CDATA[
  xquery version "1.0-ml";
  import module namespace kml = "http://earth.google.com/kml/2.0"
         at "/MarkLogic/geospatial/kml.xqy";

  kml:polygon(
  <kml:Polygon><kml:outerBoundaryIs><kml:LinearRing>
   <kml:coordinates>-127.24,12.5 -127.8,15.25 -126.1,13.45 -127.24,12.5</kml:coordinates>
  </kml:LinearRing></kml:outerBoundaryIs></kml:Polygon>
  )
  ]]></pre>
  </apidoc:example>
</apidoc:function>

<apidoc:function name="interior-polygon" type="kml" lib="kml" 
	subcategory="KML" bucket="XQuery Library Modules" category="Geospatial Supporting Functions">
  <apidoc:summary>
  Create a sequence of cts:polygon values from a KML Polygon element. The 
  returned polygons represent the interior polygons, if any.
  </apidoc:summary>
  <apidoc:params>
    <apidoc:param name="points" type="element(kml:Polygon)">
    A KML Polygon element representing the polygon.
    </apidoc:param>
  </apidoc:params>
  <apidoc:return> cts:polygon* </apidoc:return>
  <apidoc:example><pre xml:space="preserve"><![CDATA[
   xquery version "1.0-ml";
   import module namespace kml = "http://earth.google.com/kml/2.0"
         at "/MarkLogic/geospatial/kml.xqy";

  kml:interior-polygon(
    <kml:Polygon>
      <kml:outerBoundaryIs><kml:LinearRing><kml:coordinates>
      -127.24,12.5 -127.8,15.25 -126.1,13.45 -127.24,12.5
      </kml:coordinates></kml:LinearRing></kml:outerBoundaryIs>
      <kml:innerBoundaryIs><kml:LinearRing><kml:coordinates>
      -127,13 127,-14 126,-14 127,-13
      </kml:coordinates></kml:LinearRing></kml:innerBoundaryIs>
    </kml:Polygon>
  )
  ]]></pre>
  </apidoc:example>
</apidoc:function>

<apidoc:function name="geospatial-query" type="kml" lib="kml" 
	subcategory="KML" bucket="XQuery Library Modules" category="Geospatial Supporting Functions">
  <apidoc:summary>
  Returns a cts:query matching points within given regions.
  </apidoc:summary>
  <apidoc:params>
    <apidoc:param name="regions" type="cts:region*">
    One or more geographic boxes, circles, polygons, or points. Where multiple
    boxes, circles, polygons, or points are specified, the query matches if
    any box, circle, polygon, or
    point matches.
    </apidoc:param>
    <apidoc:param name="options" type="xs:string*" optional="true">
    Options to this query.  The default is ().
    <p>Options include:</p>
      <blockquote>
        <dl>
        <dt>"coordinate-system=wgs84"</dt>
        <dd>Use the WGS84 coordinate system.</dd>
        <!--
        <dt>"unit=miles"</dt>
        <dd>Distance (for circles) is measured in miles.</dd>
        -->
        <dt>"boundaries-included"</dt>
        <dd>Points on boxes' and circles' boundaries are counted as matching.  This is the default.</dd>
        <dt>"boundaries-excluded"</dt>
        <dd>Points on boxes' and circles' boundaries are not counted as matching.</dd>
        <dt>"boundaries-latitude-excluded"</dt>
        <dd>Points on boxes' latitude boundaries are not counted as matching.</dd>
        <dt>"boundaries-longitude-excluded"</dt>
        <dd>Points on boxes' longitude boundaries are not counted as matching.</dd>
        <dt>"boundaries-south-excluded"</dt>
        <dd>Points on the boxes' southern boundaries are not counted as matching.</dd>
        <dt>"boundaries-west-excluded"</dt>
        <dd>Points on the boxes' western boundaries are not counted as matching.</dd>
        <dt>"boundaries-north-excluded"</dt>
        <dd>Points on the boxes' northern boundaries are not counted as matching.</dd>
        <dt>"boundaries-east-excluded"</dt>
        <dd>Points on the boxes' eastern boundaries are not counted as matching.</dd>
        <dt>"boundaries-circle-excluded"</dt>
        <dd>Points on circles' boundary are not counted as matching.</dd>
      </dl></blockquote>
    </apidoc:param>
    <apidoc:param name="weight" type="xs:double?" optional="true">
    A weight for this query.  The default is 1.0.
    </apidoc:param>
  </apidoc:params>
  <apidoc:return> cts:query </apidoc:return>
<apidoc:usage>
<p>The point value is expressed in the content of the element as a pair
of numbers, separated by whitespace and punctuation (excluding decimal points
and sign characters).
</p>
<p>Point values and boundary specifications of boxes are given in degrees
relative to the WGS84 coordinate system.  Southern latitudes and Western 
longitudes take negative values.  Longitudes will be wrapped to the range 
(-180,+180) and latitudes will be clipped to the range (-90,+90).  
</p>
<p>If the northern boundary of a box is south of the southern boundary, no 
points will  match. However, longitudes wrap around the globe, so that if 
the western boundary is east of the eastern boundary,
then the box crosses the anti-meridian.
</p>
<p>Special handling occurs at the poles, as all longitudes exist at latitudes 
+90 and -90.
</p>
</apidoc:usage>
<apidoc:example><pre xml:space="preserve"><![CDATA[
xquery version "1.0-ml";

(: create a document with test data :)
xdmp:document-insert("/points.xml",
<root xmlns:kml="http://earth.google.com/kml/2.0">
  <item><kml:Point><kml:coordinates>30.0,10.5</kml:coordinates></kml:Point></item>
  <item><kml:Point><kml:coordinates>35.34,15.35</kml:coordinates></kml:Point></item>
  <item><kml:Point><kml:coordinates>40.55,5.11</kml:coordinates></kml:Point></item>
</root> );

xquery version "1.0-ml";
import module namespace kml = "http://earth.google.com/kml/2.0"
   at "/MarkLogic/geospatial/kml.xqy";

cts:search(doc("/points.xml")//item, 
  kml:geospatial-query(
    kml:box(
      <kml:LatLongBox>
        <kml:north>20.0</kml:north>
        <kml:south>10.0</kml:south>
        <kml:east>40.0</kml:east>
        <kml:west>35.0</kml:west>
      </kml:LatLongBox>) ))
(:
  returns the following node: 
  <item><kml:Point><kml:coordinates>35.34,15.35</kml:coordinates></kml:Point></item>
:)
,

cts:search(doc("/points.xml")//item, 
  kml:geospatial-query(kml:box(
    <kml:LatLongBox>
      <kml:north>20.0</kml:north>
      <kml:south>10.0</kml:south>
      <kml:east>35.0</kml:east>
      <kml:west>40.0</kml:west>
    </kml:LatLongBox>) ))
(:
  returns the following nodes (wrapping around the Earth):
  <item><kml:Point><kml:coordinates>30.0,10.5</kml:coordinates></kml:Point></item>
:)
 
]]></pre>
  </apidoc:example>
</apidoc:function>

<apidoc:function name="geospatial-query-from-elements" type="kml" lib="kml" 
	subcategory="KML" bucket="XQuery Library Modules" category="Geospatial Supporting Functions">
  <apidoc:summary>
  Returns a cts:query matching points within given regions.
  </apidoc:summary>
  <apidoc:params>
    <apidoc:param name="regions" type="element()*">
    One or more geographic boxes, circles, polygons, or points, represented
    as KML elements. Where multiple
    boxes, circles, polygons, or points are specified, the query matches if
    any box, circle, polygon, or point matches.
    </apidoc:param>
    <apidoc:param name="options" type="xs:string*" optional="true">
    Options to this query.  The default is ().
    <p>Options include:</p>
      <blockquote>
        <dl>
        <dt>"coordinate-system=wgs84"</dt>
        <dd>Use the WGS84 coordinate system.</dd>
        <!--
        <dt>"unit=miles"</dt>
        <dd>Distance (for circles) is measured in miles.</dd>
        -->
        <dt>"boundaries-included"</dt>
        <dd>Points on boxes' and circles' boundaries are counted as matching.  This is the default.</dd>
        <dt>"boundaries-excluded"</dt>
        <dd>Points on boxes' and circles' boundaries are not counted as matching.</dd>
        <dt>"boundaries-latitude-excluded"</dt>
        <dd>Points on boxes' latitude boundaries are not counted as matching.</dd>
        <dt>"boundaries-longitude-excluded"</dt>
        <dd>Points on boxes' longitude boundaries are not counted as matching.</dd>
        <dt>"boundaries-south-excluded"</dt>
        <dd>Points on the boxes' southern boundaries are not counted as matching.</dd>
        <dt>"boundaries-west-excluded"</dt>
        <dd>Points on the boxes' western boundaries are not counted as matching.</dd>
        <dt>"boundaries-north-excluded"</dt>
        <dd>Points on the boxes' northern boundaries are not counted as matching.</dd>
        <dt>"boundaries-east-excluded"</dt>
        <dd>Points on the boxes' eastern boundaries are not counted as matching.</dd>
        <dt>"boundaries-circle-excluded"</dt>
        <dd>Points on circles' boundary are not counted as matching.</dd>
      </dl></blockquote>
    </apidoc:param>
    <apidoc:param name="weight" type="xs:double?" optional="true">
    A weight for this query.  The default is 1.0.
    </apidoc:param>
  </apidoc:params>
  <apidoc:return> cts:query </apidoc:return>
<apidoc:usage>
<p>The point value is expressed in the content of the element as a pair
of numbers, separated by whitespace and punctuation (excluding decimal points
and sign characters).
</p>
<p>Point values and boundary specifications of boxes are given in degrees
relative to the WGS84 coordinate system.  Southern latitudes and Western 
longitudes take negative values.  Longitudes will be wrapped to the range 
(-180,+180) and latitudes will be clipped to the range (-90,+90).  
</p>
<p>If the northern boundary of a box is south of the southern boundary, no 
points will  match. However, longitudes wrap around the globe, so that if 
the western boundary is east of the eastern boundary,
then the box crosses the anti-meridian.
</p>
<p>Special handling occurs at the poles, as all longitudes exist at latitudes 
+90 and -90.
</p>
<p>This function will take into account interior polygons, if any, and properly
construct the query to account for them.
</p>
</apidoc:usage>
<apidoc:example><pre xml:space="preserve"><![CDATA[
xquery version "1.0-ml";

(: create a document with test data :)
xdmp:document-insert("/points.xml",
<root xmlns:kml="http://earth.google.com/kml/2.0">
  <item><kml:Point><kml:coordinates>30.0,10.5</kml:coordinates></kml:Point></item>
  <item><kml:Point><kml:coordinates>35.34,15.35</kml:coordinates></kml:Point></item>
  <item><kml:Point><kml:coordinates>40.55,5.11</kml:coordinates></kml:Point></item>
</root> );

xquery version "1.0-ml";
import module namespace kml = "http://earth.google.com/kml/2.0"
   at "/MarkLogic/geospatial/kml.xqy";

cts:search(doc("/points.xml")//item, 
  kml:geospatial-query-from-elements(
      <kml:LatLongBox>
        <kml:north>20.0</kml:north>
        <kml:south>10.0</kml:south>
        <kml:east>40.0</kml:east>
        <kml:west>35.0</kml:west>
      </kml:LatLongBox>) )
(:
  returns the following node: 
  <item><kml:Point><kml:coordinates>35.34,15.35</kml:coordinates></kml:Point></item>
:)
,

cts:search(doc("/points.xml")//item, 
  kml:geospatial-query-from-elements(
    <kml:LatLongBox>
      <kml:north>20.0</kml:north>
      <kml:south>10.0</kml:south>
      <kml:east>35.0</kml:east>
      <kml:west>40.0</kml:west>
    </kml:LatLongBox>) )
(:
  returns the following nodes (wrapping around the Earth):
  <item><kml:Point><kml:coordinates>30.0,10.5</kml:coordinates></kml:Point></item>
:)
 
]]></pre>
  </apidoc:example>
</apidoc:function>
</apidoc:module>
