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.