[GIS] How to convert a CompositeCurve to a NetTopologySuite MultiLineString

gmlnettopologysuite

I would like to use NetTopologySuite to convert a CompositeCurve to a MultiLineString. I would like to find some code which shows how to convert this to a MultiLineString:

  <gml:CompositeCurve srsName="EPSG:4326"
  xmlns:gml="http://www.opengis.net/gml">
    <gml:curveMember>
      <gml:LineString srsName="EPSG:4326">
        <gml:posList srsDimension="2">46.2072145436504 -119.242266357388
        46.2081175005802 -119.239767847285 46.2085501572205
        -119.238573244775</gml:posList>
      </gml:LineString>
    </gml:curveMember>
    <gml:curveMember>
      <gml:Curve srsName="EPSG:4326">
        <gml:segments>
          <gml:Arc interpolation="circularArc3Points">
            <gml:posList srsDimension="2">46.2085501572205 -119.238573244775
            46.2086267189565 -119.238351385025 46.2086927116396
            -119.238126155333</gml:posList>
          </gml:Arc>
        </gml:segments>
      </gml:Curve>
    </gml:curveMember>
    <gml:curveMember>
      <gml:LineString srsName="EPSG:4326">
        <gml:posList srsDimension="2">46.2086927116396 -119.238126155333
        46.2087174795272 -119.238053558363</gml:posList>
      </gml:LineString>
    </gml:curveMember>
  </gml:CompositeCurve>

Here is a draft of my code but "Curve" handling is just a bad guess of how to handle this:

private IGeometry GetGeometry ( XElement shapeNode )
{
    if ( null == shapeNode ) return null;
    var geoType = shapeNode.Name;

    // TODO: not sure what the rule is here...but GML 3.0 introduced the <gml:pos> and <gml:posList>
    // esri wfs 1.1.0 uses gml 3.1.1,
    // see http://home.gdal.org/projects/gml/gml_interop.html
    var geoCoordinates = shapeNode.XPathSelectElement("//gml:coordinates", _nsmgr) ??
                         (shapeNode.XPathSelectElement("//gml:pos", _nsmgr) ??
                          shapeNode.XPathSelectElement("//gml:posList", _nsmgr));

    double[] points;

    if (null != geoCoordinates)
    {
        points =
            geoCoordinates.Value.Split(" ,\r\n\t".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).Select(Double.Parse)
                .ToArray();
    }
    else
    {
        geoCoordinates = shapeNode.XPathSelectElement("//gml:coord", _nsmgr);
        points = new[]
            {
                Double.Parse(geoCoordinates.XPathSelectElement("gml:X", _nsmgr).Value),
                Double.Parse(geoCoordinates.XPathSelectElement("gml:Y", _nsmgr).Value)
            };
    }
    var coordinates =
        points.Where((a, b) => 0 == b%2).Zip(points.Where((a, b) => 1 == b%2), (a, b) => new Coordinate(a, b)).ToArray();

    switch (geoType.LocalName)
    {
        case "Point":
            return new Point(coordinates.First());
        case "Curve":
            {
                var precisionModel = new PrecisionModel(PrecisionModels.Floating);
                var bufParams = new BufferParameters();
                var b = new OffsetCurveBuilder(precisionModel, bufParams);
                return new LineString(b.GetLineCurve(coordinates.ToArray(), 0));
            }
        case "curveMember":
            return shapeNode.Elements ( ).Select ( GetGeometry ).FirstOrDefault();
        case "CompositeCurve":
            {
                var shapes = shapeNode.Elements().Select(GetGeometry);
                var lines = shapes.Select(s => new LineString(s.Coordinates.ToArray()));
                return new MultiLineString(lines.ToArray());
            }
        case "Line":
        case "LineString":
            return new LineString(coordinates.ToArray());
        case "MultiLineString":
            return new LineString(coordinates.ToArray());
        case "MultiSurface":
            return new LineString(coordinates.ToArray());
        case "CompositeSurface":
            return new LineString(coordinates.ToArray());
        case "Box":
            var sw = coordinates.First();
            var ne = coordinates.Skip(1).First();
            var shell = new LinearRing(new[]
                {
                    sw,
                    new Coordinate(ne.X, sw.Y),
                    ne,
                    new Coordinate(sw.X, ne.Y),
                    sw
                });
            return new Polygon(shell);
        case "Polygon":
            shell = new LinearRing(coordinates.ToArray());
            return new Polygon(shell);
        case "MultiPolygon":
            shell = new LinearRing(coordinates.ToArray());
            return new Polygon(shell);
        default:
            throw new ApplicationException(string.Format("Unknown Geometry Type: {0}", geoType));
    }
}

Best Answer

Since NTS supports Simple SQL specification, there isn't native curve handling. Your code looks ok, but you can ask for a better solution in the JTS mailing list (http://sourceforge.net/mailarchive/forum.php?forum_name=jts-topo-suite-user). The code is the same for NTS.

Related Question