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

<apidoc:function name="point" type="geo" lib="geo" 
	subcategory="GEO" bucket="XQuery Library Modules" category="Geospatial Supporting Functions">
  <apidoc:summary>
  Create a cts:point value from an element representing a point in one of
  the supported markup vocabularies.
  </apidoc:summary>
  <apidoc:params>
    <apidoc:param name="point" type="element()">
    An element representing a point.
    </apidoc:param>
  </apidoc:params>
  <apidoc:return> cts:point </apidoc:return>
  <apidoc:example><pre xml:space="preserve"><![CDATA[
  xquery version "1.0-ml";
  import module namespace geo = "http://marklogic.com/geospatial"
         at "/MarkLogic/geospatial/geospatial.xqy";
  declare namespace gml= "http://www.opengis.net/gml";

  geo:point(<gml:Point><gml:pos>12.5 -127.24</gml:pos></gml:Point>)
  ]]></pre>
  </apidoc:example>
</apidoc:function>

<apidoc:function name="box" type="geo" lib="geo" 
	subcategory="GEO" bucket="XQuery Library Modules" category="Geospatial Supporting Functions">
  <apidoc:summary>
  Create a cts:point value from an element representing a box in one of the
  supported markup vocabularies.
  </apidoc:summary>
  <apidoc:params>
    <apidoc:param name="box" type="element()">
    An element representing a box.
    </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 geo = "http://marklogic.com/geospatial"
         at "/MarkLogic/geospatial/geospatial.xqy";
  declare namespace kml= "http://earth.google.com/kml/2.0";

  geo: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="geo" lib="geo" 
	subcategory="GEO" bucket="XQuery Library Modules" category="Geospatial Supporting Functions">
  <apidoc:summary>
  Create a cts:circle value from a radius and an element representing a point
  in one of the supported markup vocabularies.
  </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()">
    An element representing the point at 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 geo = "http://marklogic.com/geospatial"
         at "/MarkLogic/geospatial/geospatial.xqy";

  geo:circle(47, <Dot Latitude="12.5" Longitude="-127.24"/>)
  ]]></pre>
  </apidoc:example>
</apidoc:function>

<apidoc:function name="polygon" type="geo" lib="geo" 
	subcategory="GEO" bucket="XQuery Library Modules" category="Geospatial Supporting Functions">
  <apidoc:summary>
  Create a cts:polygon value from a sequence of point elements
  in one of the supported markup vocabularies.
  </apidoc:summary>
  <apidoc:params>
    <apidoc:param name="polygon-or-points" type="element()+">
    A sequence of elements, each representing a vertex (point) of the polygon, or a polygon element. A polygon element from one of the supported markup vocabularies represents the exterior polygon for those vocabularies that include both exterior and interior polygons in their representation.
    </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 geo = "http://marklogic.com/geospatial"
         at "/MarkLogic/geospatial/geospatial.xqy";

  geo:polygon(( <Dot Latitude="12.5" Longitude="-127.24"/>,
                <Dot Latitude="15.25" Longitude="-127.8"/>,
                <Dot Latitude="13.45" Longitude="-126.1"/>,
                <Dot Latitude="12.5" Longitude="-127.24"/>
             ))
  ]]></pre>
  </apidoc:example>
</apidoc:function>

<apidoc:function name="interior-polygon" type="geo" lib="geo" 
	subcategory="GEO" bucket="XQuery Library Modules" category="Geospatial Supporting Functions">
  <apidoc:summary>
  Create a sequence of cts:polygon values from a polygon element
  in one of the supported markup vocabularies. These polygons represent the
  interior polygons, if any.
  </apidoc:summary>
  <apidoc:params>
    <apidoc:param name="polygon" type="element()">
    An elements 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 geo = "http://marklogic.com/geospatial"
      at "/MarkLogic/geospatial/geospatial.xqy";
  declare namespace georss= "http://www.georss.org/georss";

  (: Returns empty; no interior polygon in this format :)
  geo:interior-polygon( 
    <georss:polygon>
      12.5,-127.24 15.25,-127.8 13.45,-126.1 12.5,-127.24
    </georss:polygon>
  ) 
  ]]></pre>
  </apidoc:example>
</apidoc:function>

<apidoc:function name="geospatial-query" type="geo" lib="geo" 
	subcategory="GEO" 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>
<p>The query constructed will examine points in all the supported geospatial
markup vocabularies.  If not all these vocabularies will be in use, it may
be more efficient to use the query constructors for just the vocabulary or 
vocabularies that are in actual use.
</p>
</apidoc:usage>
<apidoc:example><pre xml:space="preserve"><![CDATA[
xquery version "1.0-ml";
(: create a document with test data :)
declare namespace gml= "http://www.opengis.net/gml";
declare namespace georss= "http://www.georss.org/georss";

xdmp:document-insert("/points.xml",
<root xmlns:geo="http://marklogic.com/geospatial">
  <item><gml:Point><gml:pos>10.5 30.0</gml:pos></gml:Point></item>
  <item><georss:point>15.35 35.34</georss:point></item>
  <item><Dot Latitude="5.11" Longitude="40.55"/></item>
</root> );

xquery version "1.0-ml";
import module namespace geo = "http://marklogic.com/geospatial"
   at "/MarkLogic/geospatial/geospatial.xqy";
declare namespace gml= "http://www.opengis.net/gml";
declare namespace georss= "http://www.georss.org/georss";
declare namespace kml= "http://earth.google.com/kml/2.0";

cts:search(doc("/points.xml")//item, 
  geo:geospatial-query(
    geo:box(
      <gml:Envelope>
        <gml:lowerCorner>10.0 35.0</gml:lowerCorner>
        <gml:upperCorner>20.0 40.0</gml:upperCorner>
      </gml:Envelope>)
  ))
(:
  returns the following node: 
  <item><georss:point>15.35 35.34</georss:point></item>
:)
,

cts:search(doc("/points.xml")//item, 
  geo:geospatial-query(geo: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><gml:Point><gml:pos>10.5 30.0</gml:pos></gml:Point></item>
:)
,

cts:search(doc("/points.xml")//item, 
  geo:geospatial-query(
    cts:box(10.0, 35.0, 20.0, 40.0)))
(:
  returns the following node:
  <item><georss:point>15.35 35.34</georss:point></item>
:)
 
]]></pre>
  </apidoc:example>
</apidoc:function>

<apidoc:function name="geospatial-query-from-elements" type="geo" lib="geo" 
	subcategory="GEO" 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
    by elements in one of the supported vocabularies.
    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>The query constructed will examine points in all the supported geospatial
markup vocabularies.  If not all these vocabularies will be in use, it may
be more efficient to use the query constructors for just the vocabulary or 
vocabularies that are in actual use.
</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 :)
declare namespace gml= "http://www.opengis.net/gml";
declare namespace georss= "http://www.georss.org/georss";

xdmp:document-insert("/points.xml",
<root xmlns:geo="http://marklogic.com/geospatial">
  <item><gml:Point><gml:pos>10.5 30.0</gml:pos></gml:Point></item>
  <item><georss:point>15.35 35.34</georss:point></item>
  <item><Dot Latitude="5.11" Longitude="40.55"/></item>
</root> );

xquery version "1.0-ml";
import module namespace geo = "http://marklogic.com/geospatial"
   at "/MarkLogic/geospatial/geospatial.xqy";
declare namespace gml= "http://www.opengis.net/gml";
declare namespace georss= "http://www.georss.org/georss";
declare namespace kml= "http://earth.google.com/kml/2.0";

cts:search(doc("/points.xml")//item, 
  geo:geospatial-query-from-elements(
    <gml:Envelope>
      <gml:lowerCorner>10.0 35.0</gml:lowerCorner>
      <gml:upperCorner>20.0 40.0</gml:upperCorner>
    </gml:Envelope>
  ) )
(:
  returns the following node: 
  <item><georss:point>15.35 35.34</georss:point></item>
:)
,

cts:search(doc("/points.xml")//item, 
  geo: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><georss:point>15.35 35.34</georss:point></item>
  <item><gml:Point><gml:pos>10.5 30.0</gml:pos></gml:Point></item>
:)

]]></pre>
  </apidoc:example>
</apidoc:function>
</apidoc:module>
