Polygon features from XML GML files

GML polygon

This example shows how polygon data can be read and processed from a GML data source. The example reads and processes pand geometries from the BAG.

We advice to put the templates in a separate configuration file.

container pand
{
attribute<string> FileName(File):
   ['9999PND08012016-000001.xml','9999PND008012016-000003.xml'];
attribute<String> XmlData (File)
:   StorageType = "strfiles"
,   StorageName = "%SourceDataDir%/BAG";

container ParsedXML  := parse_xml(XmlData, scheme);
container geoBuilder := ProcessGmlPolygon(ParsedXML/bag_LVC_pand,false);

template scheme
{
  unit<uint32> bag_LVC_pand 
  {
     attribute<string> bag_LVC_identificatie;

     unit<uint32> gml_Polygon 
     {
        unit<uint32> gml_posList
        {
           attribute<string> srsDimension;
           attribute<string> count;
        }
     }
     unit<uint32> gml_Interior 
     {
        unit<uint32> gml_posList
        {
           attribute<string> srsDimension;
           attribute<string> count;
        }
     }
 }
}
// templates for processing polygon geometries
template ProcessGmlPolygon
{
// begin case parameters
unit<uint32>    gmlContext;
parameter<bool> hasMultiplePolygons;
// end case parameters

container impl := ProcessGmlPolygonImpl(gmlContext/gml_Polygon);
parameter<string> geometry_expr:= hasMultiplePolygons
   ?   'templates/optimized_union(
           impl/gmlPolygon
         , gmlContext
         , impl/Polygon/result
         , impl/gmlPolygon/Parent_rel
       )'
   :   'templates/one2one_union(
          impl/gmlPolygon
        , gmlContext
        , impl/Polygon/result
        , impl/gmlPolygon/Parent_rel
       )';
container geometry := = geometry_expr;
attribute<rdc_mm> result (gmlContext, polygon) := geometry/result;
}

template ProcessGmlPolygonImpl
{
// begin case parameters
unit<uint32> gmlPolygon;
// end case parameters

container Exterior := ProcessLinearRing(gmlPolygon, true);
container Interior := ProcessLinearRing(gmlPolygon/gml_Interior, false);
container Polygon  := ProcessPolygon(
   gmlPolygon,              Exterior/geometry_mm, 
   gmlPolygon/gml_Interior, Interior/geometry_mm,
   gmlPolygon/gml_Interior/Parent_rel
   );
}

template ProcessLinearRing
{
// begin case parameters 
unit<uint32> parsedXMLsrc;
parameter<bool> isExt; // exterior
// end case parameters 

container impl 
{
   container posList := ProcessPosList(parsedXMLsrc/gml_posList, isExt);
   container union   := one2one_union(
       parsedXMLsrc/gml_posList
     , parsedXMLsrc
     , posList/result
     , parsedXMLsrc/gml_posList/Parent_rel
     );
 }
 attribute<rdc_mm> geometry_mm(poly,parsedXMLsrc) := impl/union/result;
}

template ProcessPosList
{
// begin case parameters 
unit<uint32> posList;
parameter<bool> isExterior;
// end case parameters 

unit<uint32> impl := posList
{
   attribute<string>  values := _ValuesTable/Values[value_rel];
   attribute<string>  str_sequence := 
      '{'+string(uint32(count) * uint32(srsDimension)) +':'+ values +'}'
   ,  IntegrityCheck = "srsDimension == '2' || srsDimension == '3'";
   attribute<Float64> f64_sequence(poly) := Float64Seq(str_sequence);

   unit<uint32> posListunit := range(uint32, 0, #posList)
   {
      attribute<uint32> nrCoordPerPoint := 
         union_data(posListunit, uint32(srsDimension));
   }
   unit<uint32> coordinates := 
      sequence2points(union_data(posListunit, f64_sequence));

   unit<uint32> p := 
      select_with_org_rel(
               coordinates/ordinal 
             % posListunit/nrCoordPerPoint[coordinates/SequenceNr] == 0
            )
   {
      attribute<float64>      x    := coordinates/point[org_rel];
      attribute<float64>      y    := coordinates/point[org_rel + 1];
      attribute<rdc_mm>       p_mm := 
         point(Round(y * 1000.0), Round(x * 1000.0), rdc_mm);
      attribute<posListunit>  s    := 
         coordinates/SequenceNr[org_rel];
      attribute<uint32>       fo   := 
           coordinates/ordinal[org_rel]
         / posListunit/nrCoordPerPoint[s];
      attribute<uint32>       ro   := 
         pcount(s)[s]- fo - 1;
   }
   attribute<rdc_mm> geometry_mm (poly) := 
      union_data(
                  posList
                , points2sequence_pso(
                      p/p_mm, p/s
                    , isExterior 
                      ?   p/ro 
                      :   p/fo
                  )
                );
}
attribute<rdc_mm> result (posList, poly) := impl/geometry_mm[rdc_mm];
}

template ProcessPolygon
{
// begin case parameters 
unit<uint32>        Exterior;
attribute<rdc_mm>   ExtGeometry(Exterior, poly);
unit<uint32>        Interior;
attribute<rdc_mm>   IntGeometry(Interior, poly);
attribute<Exterior> Parent_rel(Interior);
// end case parameters
container impl
{
   container IntUnion := optimized_union(
      Interior, Exterior, IntGeometry, Parent_rel
      );
   attribute<uint32> count(Exterior) := pcount(parent_rel);

   unit<uint32> ExtCopy := range(Exterior, 0, #Exterior)
   {
      attribute<uint32> count2 := union_data(., count);
   }
   unit<uint32> nonTrivialExterior := select_with_org_rel(ExtCopy/count2 > 0)
   {
      attribute<Exterior> Exterior_rel := 
         value(org_rel, Exterior);
      attribute<rdc_mm>   diff(poly)   := 
        ExtGeometry[Exterior_rel]- IntUnion/result[Exterior_rel];
      attribute<rdc_mm> result(poly,Exterior) := 
         impl/nonTrivialExterior/diff[
            invert(impl/nonTrivialExterior/Exterior_rel)
         ];
   }
attribute<rdc_mm> result(poly,Exterior) := impl/count == 0 
   ? ExtGeometry 
   : impl/result;
attribute<int32>  area  (Exterior)      := area(result, Int32);
}

template union 
{
// begin case parameters 
unit<uint32> child;
unit<uint32> parent;
attribute<rdc_mm> geometry(child, poly);
attribute<parent> parent_rel(child);
// end case parameters 

attribute<rdc_mm> result(poly,parent) := 
   partitioned_union_polygon(geometry, parent_rel);
}

template optimized_union
{
// begin case parameters 
unit<uint32> child;
unit<uint32> parent;
attribute<rdc_mm> geometry(child, poly);
attribute<parent> parent_rel(child);
// end case parameters 

container impl 
{
   attribute<uint32> count(parent) := pcount(parent_rel);
   unit<uint32> childCopy := range(child, 0, #child);

   unit<uint32> nonTrivialChild := 
      select_with_org_rel((count != 1)[union_data(childCopy, parent_rel)])
   {
      attribute<child> child_rel := value(org_rel, child);
      attribute<rdc_mm> union(poly,parent) := 
         partitioned_union_polygon(
              geometry[child_rel]
            , parent_rel[child_rel]
         );
   }
}
attribute<rdc_mm> result (poly,parent) := impl/count <= 1 
   ? geometry[invert(parent_rel)] 
   : impl/nonTrivialChild/union;
attribute<Int32>  area   (parent)      := area(result, Int32);
}

template one2one_union 
{
// begin case parameters 
unit<uint32> child;
unit<uint32> parent;
attribute<rdc_mm> geometry(child, poly);
attribute<parent> parent_rel(child);
// end case parameters 

container impl 
{
   parameter<bool> Check := 
      (#child == #parent) && all(parent_rel == ID(child));
}
attribute<rdc_mm> result(poly,parent) := union_data(parent, geometry)
, IntegrityCheck = "impl/Check";
}