/// <summary> /// This function lets the user set up whether the shape should be regular, type M or type Z. /// This will not interfere with existing shapes in the geometry, but will simply /// add the specified geometry to the end of the existing information. Sending a null shape /// will create a new shape of the appropriate kind. /// </summary> /// <param name="geom">A Geometries.Geometry specifying what to append to the shape. /// Simply returns mwShape unchanged if geom is null.</param> /// <param name="mwShape">An existing shape with a shapetype already specified.</param> public static void AppendGeometryToShape(IGeometry geom, ref MapWinGIS.Shape mwShape) { // we don't need to throw an error if geom is null, there is simply nothing to add. if (geom == null) { return; } // If we have to set up a new shape object, we will also have to specify a shape type. bool SpecifyShapeType = false; if (mwShape == null) { mwShape = new MapWinGIS.Shape(); SpecifyShapeType = true; } MapWinGIS.Point mwPoint; int rfPt = mwShape.numPoints; // Flexible Point Index int rfPrt = mwShape.NumParts; // Flexible Part Index if (rfPt > 0 && rfPrt == 0) { //Change single part to a multipart shapefile mwShape.InsertPart(0, ref rfPrt); rfPrt++; } #region -------------------------- POINT ------------------------------------------- if (geom.GetType() == typeof(Point)) { if (SpecifyShapeType == true) { mwShape.ShapeType = MapWinGIS.ShpfileType.SHP_POINT; } // Only allow appending to a point shape type if there isn't a point defined yet. if ((mwShape.ShapeType == MapWinGIS.ShpfileType.SHP_MULTIPOINT || mwShape.ShapeType == MapWinGIS.ShpfileType.SHP_MULTIPOINTM || mwShape.ShapeType == MapWinGIS.ShpfileType.SHP_MULTIPOINTZ) || ((mwShape.ShapeType == MapWinGIS.ShpfileType.SHP_POINT || mwShape.ShapeType == MapWinGIS.ShpfileType.SHP_POINTM || mwShape.ShapeType == MapWinGIS.ShpfileType.SHP_POINTZ) && rfPt == 0)) { Point newPoint = geom as Point; mwPoint = new MapWinGIS.Point(); mwPoint.x = newPoint.X; mwPoint.y = newPoint.Y; mwShape.InsertPoint(mwPoint, ref rfPt); return; } else { if ((mwShape.ShapeType == MapWinGIS.ShpfileType.SHP_POINT || mwShape.ShapeType == MapWinGIS.ShpfileType.SHP_POINTM || mwShape.ShapeType == MapWinGIS.ShpfileType.SHP_POINTZ)) { throw new ArgumentException("The Shape type of mwShape must be MultiPoint, MultiPointM, or MultiPointZ in order to Append a Point Geometry to a shape that already contains a point."); } else { throw new ArgumentException("mwShape had a shape type that did not correspond to Point or MultiPoint. Point geometry not added."); } } } #endregion #region -------------------------- MULTI POINT-------------------------------------- if (geom.GetType() == typeof(MultiPoint)) { if (SpecifyShapeType == true) { mwShape.ShapeType = MapWinGIS.ShpfileType.SHP_MULTIPOINT; } if (mwShape.ShapeType == MapWinGIS.ShpfileType.SHP_MULTIPOINT || mwShape.ShapeType == MapWinGIS.ShpfileType.SHP_MULTIPOINTM || mwShape.ShapeType == MapWinGIS.ShpfileType.SHP_MULTIPOINTZ) { MultiPoint newPoints = geom as MultiPoint; for (int iPoint = 0; iPoint < newPoints.Count; iPoint++) { Point CurPoint = newPoints.Geometries[iPoint] as Point; mwPoint = new MapWinGIS.Point(); mwPoint.x = CurPoint.X; mwPoint.y = CurPoint.Y; mwShape.InsertPoint(mwPoint, ref rfPt); rfPt++; // I don't think we can have multi-parts in a multipoint shape } return; } else { throw new ArgumentException("The shape type must be one of the multipoint types to add a multipoint geometry."); } } #endregion #region -------------------------- LINE STRING ------------------------------------- if (geom.GetType() == typeof(LineString) || geom.GetType() == typeof(LinearRing)) { if (SpecifyShapeType == true) { mwShape.ShapeType = MapWinGIS.ShpfileType.SHP_POLYLINE; } if (mwShape.ShapeType == MapWinGIS.ShpfileType.SHP_POLYLINE || mwShape.ShapeType == MapWinGIS.ShpfileType.SHP_POLYLINEM || mwShape.ShapeType == MapWinGIS.ShpfileType.SHP_POLYLINEZ) { LineString newPoints = geom as LineString; // Polymorphism should allow linear rings to be line strings for (int iPoint = 0; iPoint < newPoints.Count; iPoint++) { ICoordinate CurPoint = newPoints.Coordinates[iPoint]; mwPoint = new MapWinGIS.Point(); mwPoint.x = CurPoint.X; mwPoint.y = CurPoint.Y; mwShape.InsertPoint(mwPoint, ref rfPt); rfPt++; // I don't think we can have multi-parts in a multipoint shape } return; } else { throw new ArgumentException("The shape type must be one of the polyline types to add a LineString geometry."); } } #endregion #region -------------------------- MULTI LINESTRING -------------------------------- if (geom.GetType() == typeof(MultiLineString)) { if (SpecifyShapeType == true) { mwShape.ShapeType = MapWinGIS.ShpfileType.SHP_POLYLINE; } MultiLineString MLS = geom as MultiLineString; if (mwShape.ShapeType == MapWinGIS.ShpfileType.SHP_POLYLINE || mwShape.ShapeType == MapWinGIS.ShpfileType.SHP_POLYLINEM || mwShape.ShapeType == MapWinGIS.ShpfileType.SHP_POLYLINEZ) { for (int iGeom = 0; iGeom < MLS.NumGeometries; iGeom++) { LineString LS = MLS.Geometries[iGeom] as LineString; AppendGeometryToShape(LS, ref mwShape); // prevents a lot of code duplication } return; } else { throw new ArgumentException("Cannot append a MultiLineString geometry to a " + mwShape.ShapeType.ToString() + " shape."); } } #endregion #region -------------------------- POLYGON ----------------------------------------- if (geom.GetType() == typeof(Polygon)) { Polygon newPolygon = geom as Polygon; if (SpecifyShapeType == true) { mwShape.ShapeType = MapWinGIS.ShpfileType.SHP_POLYGON; } if (mwShape.ShapeType == MapWinGIS.ShpfileType.SHP_POLYGON || mwShape.ShapeType == MapWinGIS.ShpfileType.SHP_POLYGONM || mwShape.ShapeType == MapWinGIS.ShpfileType.SHP_POLYGONZ) { mwShape.InsertPart(rfPt, ref rfPrt); rfPrt++; ILinearRing Shell = newPolygon.Shell; for (int iPoint = 0; iPoint < Shell.NumPoints; iPoint++) { ICoordinate Coord = Shell.Coordinates[iPoint]; mwPoint = new MapWinGIS.Point(); mwPoint.x = Coord.X; mwPoint.y = Coord.Y; mwShape.InsertPoint(mwPoint, ref rfPt); rfPt++; } // The same hole may appear multiple times in overlapping polygons. // Create a list of holes in order to test clockwise. if (newPolygon.NumInteriorRings > 0) { List <ILinearRing> UniqueHoles = new List <ILinearRing>(); List <ILinearRing> Holes = GetHoles(mwShape); //holes in the existing shape for (int iHole = 0; iHole < newPolygon.NumInteriorRings; iHole++) { if (Holes.Count > 0) { for (int jHole = 0; jHole < Holes.Count; jHole++) { if (newPolygon.Holes[iHole] == Holes[jHole]) { continue; } // if we get here, the new hole is unique and should be added UniqueHoles.Add(newPolygon.Holes[iHole]); // Also add it to the list to compare against other future holes Holes.Add(newPolygon.Holes[iHole]); // Holes.Count is re-evaluated each time so this should be ok } } //else //{ // //make sure holes are added to a shape with no holes // UniqueHoles.Add(newPolygon.Holes[iHole]); // Holes.Add(newPolygon.Holes[iHole]); //} } for (int iHole = 0; iHole < UniqueHoles.Count; iHole++) { mwShape.InsertPart(rfPt, ref rfPrt); rfPrt++; ICoordinate[] Hole; if (IsClockwise(UniqueHoles[iHole].Coordinates)) { // Holes should be counter clockwise Hole = UniqueHoles[iHole].Reverse().Coordinates; } else { Hole = UniqueHoles[iHole].Coordinates; } int Count = Hole.GetUpperBound(0) + 1; for (int iPoint = 0; iPoint < Count; iPoint++) { ICoordinate Coord = Hole[iPoint]; mwPoint = new MapWinGIS.Point(); mwPoint.x = Coord.X; mwPoint.y = Coord.Y; mwShape.InsertPoint(mwPoint, ref rfPt); rfPt++; } } } } } #endregion #region -------------------------- MULTI POLYGON------------------------------------ // The reason not to just Call Add Polygon recursively with this is that we only // want to test for unique holes once. Doing so each and every time we add a polygon // would be a major inefficiency, plus the overhead from converting back and forth // to a shape object. if (geom.GetType() == typeof(MultiPolygon)) { MultiPolygon MPG = geom as MultiPolygon; if (SpecifyShapeType == true) { mwShape.ShapeType = MapWinGIS.ShpfileType.SHP_POLYGON; } if (mwShape.ShapeType == MapWinGIS.ShpfileType.SHP_POLYGON || mwShape.ShapeType == MapWinGIS.ShpfileType.SHP_POLYGONM || mwShape.ShapeType == MapWinGIS.ShpfileType.SHP_POLYGONZ) { // By doing this one time up here, we prevent a lot of duplication List <ILinearRing> Holes = Holes = GetHoles(mwShape); for (int iPolygon = 0; iPolygon < MPG.NumGeometries; iPolygon++) { Polygon newPolygon = MPG.Geometries[iPolygon] as Polygon; mwShape.InsertPart(rfPt, ref rfPrt); rfPrt++; ILinearRing Shell = newPolygon.Shell; for (int iPoint = 0; iPoint < Shell.NumPoints; iPoint++) { ICoordinate Coord = Shell.Coordinates[iPoint]; mwPoint = new MapWinGIS.Point(); mwPoint.x = Coord.X; mwPoint.y = Coord.Y; mwShape.InsertPoint(mwPoint, ref rfPt); rfPt++; } // The same hole may appear multiple times in overlapping polygons. // Create a list of holes in order to test clockwise. if (newPolygon.NumInteriorRings > 0) { List <ILinearRing> UniqueHoles = new List <ILinearRing>(); for (int iHole = 0; iHole < newPolygon.NumInteriorRings; iHole++) { for (int jHole = 0; jHole < Holes.Count; jHole++) { if (newPolygon.Holes[iHole] == Holes[jHole]) { continue; } // if we get here, the new hole is unique and should be added UniqueHoles.Add(newPolygon.Holes[iHole]); // Also add it to the list to compare against other future holes Holes.Add(newPolygon.Holes[iHole]); // Holes.Count is re-evaluated each time so this should be ok } } for (int iHole = 0; iHole < UniqueHoles.Count; iHole++) { mwShape.InsertPart(rfPt, ref rfPrt); rfPrt++; ICoordinate[] Hole; if (IsClockwise(UniqueHoles[iHole].Coordinates)) { // Holes should be counter clockwise Hole = UniqueHoles[iHole].Reverse().Coordinates; } else { Hole = UniqueHoles[iHole].Coordinates; } int Count = Hole.GetUpperBound(0) + 1; for (int iPoint = 0; iPoint < Count; iPoint++) { ICoordinate Coord = Hole[iPoint]; mwPoint = new MapWinGIS.Point(); mwPoint.x = Coord.X; mwPoint.y = Coord.Y; mwShape.InsertPoint(mwPoint, ref rfPt); rfPt++; } } } } } } #endregion }