Advertisement
Guest User

Untitled

a guest
Mar 9th, 2012
38
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 26.54 KB | None | 0 0
  1. // ********************************************************************************************************
  2. // Product Name: DotSpatial.Data.dll
  3. // Description:  The data access libraries for the DotSpatial project.
  4. // ********************************************************************************************************
  5. // The contents of this file are subject to the MIT License (MIT)
  6. // you may not use this file except in compliance with the License. You may obtain a copy of the License at
  7. // http://dotspatial.codeplex.com/license
  8. //
  9. // Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
  10. // ANY KIND, either expressed or implied. See the License for the specific language governing rights and
  11. // limitations under the License.
  12. //
  13. // The Original Code is from MapWindow.dll version 6.0
  14. //
  15. // The Initial Developer of this Original Code is Ted Dunsford. Created 3/6/2010 11:28:53 AM
  16. //
  17. // Contributor(s): (Open source contributors should list themselves and their modifications here).
  18. //
  19. // ********************************************************************************************************
  20.  
  21. using System;
  22. using System.Collections.Generic;
  23. using System.Linq;
  24. using DotSpatial.Topology;
  25. using DotSpatial.Topology.Algorithm;
  26.  
  27. namespace DotSpatial.Data
  28. {
  29.     /// <summary>
  30.     /// The shape caries information about the raw vertices as well as a shapeRange.
  31.     /// It is effectively away to move around a single shape.
  32.     /// </summary>
  33.     public class Shape : ICloneable
  34.     {
  35.         #region Private Variables
  36.  
  37.         private object[] _attributes;
  38.         private double[] _m;
  39.         private ShapeRange _shapeRange;
  40.         private double[] _vertices;
  41.         private double[] _z;
  42.  
  43.         #endregion
  44.  
  45.         #region Constructors
  46.  
  47.         /// <summary>
  48.         /// Creates a new instance of Shape
  49.         /// </summary>
  50.         public Shape()
  51.         {
  52.         }
  53.  
  54.         /// <summary>
  55.         /// Creates a new shape type where the shaperange exists and has a type specified
  56.         /// </summary>
  57.         /// <param name="type"></param>
  58.         public Shape(FeatureType type)
  59.         {
  60.             _shapeRange = new ShapeRange(type);
  61.         }
  62.  
  63.         /// <summary>
  64.         /// Creates a shape based on the specified feature.  This shape will be standing alone,
  65.         /// all by itself.  The fieldnames and field types will be null.
  66.         /// </summary>
  67.         /// <param name="feature"></param>
  68.         public Shape(IFeature feature)
  69.         {
  70.             if(Equals(feature, null))
  71.                 throw new ArgumentNullException("feature");
  72.  
  73.             _attributes = feature.DataRow.ItemArray;
  74.             IList<Coordinate> coords = feature.Coordinates;
  75.             _vertices = new double[feature.NumPoints * 2];
  76.             _z = new double[feature.NumPoints];
  77.             _m = new double[feature.NumPoints];
  78.             for (int i = 0; i < coords.Count; i++)
  79.             {
  80.                 Coordinate c = coords[i];
  81.                 _vertices[i * 2] = c.X;
  82.                 _vertices[i * 2 + 1] = c.Y;
  83.                 _z[i] = c.Z;
  84.                 _m[i] = c.M;
  85.             }
  86.             _shapeRange = ShapeRangeFromFeature(feature, _vertices);
  87.         }
  88.  
  89.         /// <summary>
  90.         /// Creates a shape based on the specified geometry.  This shape will be standing alone,
  91.         /// all by itself.  The attributes will be null.
  92.         /// </summary>
  93.         /// <param name="geometry">The geometry to create a shape from.</param>
  94.         public Shape(IGeometry geometry)
  95.         {
  96.             if(Equals(geometry, null))
  97.                 throw new ArgumentNullException("geometry");
  98.  
  99.             IList<Coordinate> coords = geometry.Coordinates;
  100.             _vertices = new double[geometry.NumPoints * 2];
  101.             _z = new double[geometry.NumPoints];
  102.             _m = new double[geometry.NumPoints];
  103.             for (int i = 0; i < coords.Count; i++)
  104.             {
  105.                 Coordinate c = coords[i];
  106.                 _vertices[i * 2] = c.X;
  107.                 _vertices[i * 2 + 1] = c.Y;
  108.                 _z[i] = c.Z;
  109.                 _m[i] = c.M;
  110.             }
  111.             _shapeRange = ShapeRangeFromGeometry(geometry, _vertices, 0);
  112.         }
  113.  
  114.         /// <summary>
  115.         /// Creates a point shape from a coordinate
  116.         /// </summary>
  117.         /// <param name="coord"></param>
  118.         public Shape(Coordinate coord)
  119.         {
  120.             if(Equals(coord, null))
  121.                 throw new ArgumentNullException("coord");
  122.  
  123.             _shapeRange = new ShapeRange(FeatureType.Point);
  124.             _vertices = new double[2];
  125.             _vertices[0] = coord.X;
  126.             _vertices[1] = coord.Y;
  127.             if (!double.IsNaN(coord.Z))
  128.             {
  129.                 _z = new double[1];
  130.                 _z[0] = coord.Z;
  131.             }
  132.             if (!double.IsNaN(coord.M))
  133.             {
  134.                 _z = new double[1];
  135.                 _m[0] = coord.M;
  136.             }
  137.             const int offset = 0;
  138.             PartRange part = new PartRange(_vertices, 0, offset, FeatureType.Point);
  139.             part.NumVertices = 1;
  140.             _shapeRange.Parts.Add(part);
  141.             _shapeRange.Extent = new Extent(coord.X, coord.Y, coord.X, coord.Y);
  142.         }
  143.  
  144.         /// <summary>
  145.         /// Creates a point shape from a vertex
  146.         /// </summary>
  147.         /// <param name="coord"></param>
  148.         public Shape(Vertex coord)
  149.         {
  150.             _shapeRange = new ShapeRange(FeatureType.Point);
  151.             _vertices = new double[2];
  152.             _vertices[0] = coord.X;
  153.             _vertices[1] = coord.Y;
  154.             const int offset = 0;
  155.             PartRange part = new PartRange(_vertices, 0, offset, FeatureType.Point);
  156.             part.NumVertices = 1;
  157.             _shapeRange.Parts.Add(part);
  158.             _shapeRange.Extent = new Extent(coord.X, coord.Y, coord.X, coord.Y);
  159.         }
  160.  
  161.         /// <summary>
  162.         /// Creates a clockwise polygon shape from an extent
  163.         /// </summary>
  164.         /// <param name="extent"></param>
  165.         public Shape(Extent extent)
  166.         {
  167.             if(Equals(extent, null))
  168.                 throw new ArgumentNullException("extent");
  169.  
  170.             _shapeRange = new ShapeRange(FeatureType.Polygon);
  171.             _vertices = new double[8];
  172.             double xMin = extent.MinX;
  173.             double yMin = extent.MinY;
  174.             double xMax = extent.MaxX;
  175.             double yMax = extent.MaxY;
  176.             _vertices[0] = xMin;
  177.             _vertices[1] = yMax;
  178.             _vertices[2] = xMax;
  179.             _vertices[3] = yMax;
  180.             _vertices[4] = xMax;
  181.             _vertices[5] = yMin;
  182.             _vertices[6] = xMin;
  183.             _vertices[7] = yMin;
  184.             const int offset = 0;
  185.             PartRange part = new PartRange(_vertices, 0, offset, FeatureType.Polygon);
  186.             part.NumVertices = 4;
  187.             _shapeRange.Parts.Add(part);
  188.         }
  189.  
  190.         /// <summary>
  191.         /// Creates a clockwise polygon shape from an envelope
  192.         /// </summary>
  193.         /// <param name="envelope"></param>
  194.         public Shape(IEnvelope envelope)
  195.         {
  196.             if(Equals(envelope, null))
  197.                 throw new ArgumentNullException("envelope");
  198.  
  199.             _shapeRange = new ShapeRange(FeatureType.Polygon);
  200.             _vertices = new double[8];
  201.             double xMin = envelope.Minimum.X;
  202.             double yMin = envelope.Minimum.Y;
  203.             double xMax = envelope.Maximum.X;
  204.             double yMax = envelope.Maximum.Y;
  205.             _vertices[0] = xMin;
  206.             _vertices[1] = yMax;
  207.             _vertices[2] = xMax;
  208.             _vertices[3] = yMax;
  209.             _vertices[4] = xMax;
  210.             _vertices[5] = yMin;
  211.             _vertices[6] = xMin;
  212.             _vertices[7] = yMin;
  213.             const int offset = 0;
  214.             PartRange part = new PartRange(_vertices, 0, offset, FeatureType.Polygon);
  215.             part.NumVertices = 4;
  216.             _shapeRange.Parts.Add(part);
  217.         }
  218.  
  219.         #endregion
  220.  
  221.         #region Methods
  222.  
  223.         /// <summary>
  224.         /// Converts this shape into a Geometry using the default factory.
  225.         /// </summary>
  226.         /// <returns>The geometry version of this shape.</returns>
  227.         public IGeometry ToGeometry()
  228.         {
  229.             return ToGeometry(Geometry.DefaultFactory);
  230.         }
  231.  
  232.         /// <summary>
  233.         /// Converts this shape into a Geometry.
  234.         /// </summary>
  235.         /// <returns>The geometry version of this shape.</returns>
  236.         public IGeometry ToGeometry(IGeometryFactory factory)
  237.         {
  238.             if (_shapeRange.FeatureType == FeatureType.Polygon)
  239.             {
  240.                 return FromPolygon(factory);
  241.             }
  242.             if (_shapeRange.FeatureType == FeatureType.Line)
  243.             {
  244.                 return FromLine(factory);
  245.             }
  246.             if (_shapeRange.FeatureType == FeatureType.MultiPoint)
  247.             {
  248.                 return FromMultiPoint(factory);
  249.             }
  250.             if (_shapeRange.FeatureType == FeatureType.Point)
  251.             {
  252.                 return FromPoint(factory);
  253.             }
  254.             return null;
  255.         }
  256.  
  257.         /// <summary>
  258.         /// Get the point for this shape if this is a point shape.
  259.         /// </summary>
  260.         /// <param name="factory"></param>
  261.         /// <returns></returns>
  262.         protected IGeometry FromPoint(IGeometryFactory factory)
  263.         {
  264.             if (factory == null) factory = Geometry.DefaultFactory;
  265.             foreach (PartRange part in _shapeRange.Parts)
  266.             {
  267.                 foreach (Vertex vertex in part)
  268.                 {
  269.                     Coordinate c = new Coordinate(vertex.X, vertex.Y);
  270.                     return factory.CreatePoint(c);
  271.                 }
  272.             }
  273.             return null;
  274.         }
  275.  
  276.         /// <summary>
  277.         /// Creates a new MultiPoint geometry from a MultiPoint shape
  278.         /// </summary>
  279.         /// <param name="factory">The IGeometryFactory to use to create the new shape.</param>
  280.         /// <returns></returns>
  281.         protected IGeometry FromMultiPoint(IGeometryFactory factory)
  282.         {
  283.             if (factory == null) factory = Geometry.DefaultFactory;
  284.             List<Coordinate> coords = new List<Coordinate>();
  285.             foreach (PartRange part in _shapeRange.Parts)
  286.             {
  287.                 int i = part.StartIndex;
  288.                 foreach (Vertex vertex in part)
  289.                 {
  290.                     Coordinate c = new Coordinate(vertex.X, vertex.Y);
  291.                     coords.Add(c);
  292.                     if (M != null && M.Length != 0) c.M = M[i];
  293.                     if (Z != null && Z.Length != 0) c.Z = Z[i];
  294.                     i++;
  295.                 }
  296.             }
  297.             return factory.CreateMultiPoint(coords);
  298.         }
  299.  
  300.         /// <summary>
  301.         /// Gets the line for the specified index
  302.         /// </summary>
  303.         /// <returns>A LineString or MultiLineString geometry created from this shape.</returns>
  304.         protected IGeometry FromLine(IGeometryFactory factory)
  305.         {
  306.             if (factory == null) factory = Geometry.DefaultFactory;
  307.             List<IBasicLineString> lines = new List<IBasicLineString>();
  308.             foreach (PartRange part in _shapeRange.Parts)
  309.             {
  310.                 int i = part.StartIndex;
  311.                 List<Coordinate> coords = new List<Coordinate>();
  312.                 foreach (Vertex d in part)
  313.                 {
  314.                     Coordinate c = new Coordinate(d.X, d.Y);
  315.                     coords.Add(c);
  316.                     if (M != null && M.Length > 0) c.M = M[i];
  317.                     if (Z != null && Z.Length > 0) c.Z = Z[i];
  318.                     i++;
  319.                 }
  320.                 lines.Add(factory.CreateLineString(coords));
  321.             }
  322.             if (lines.Count == 1) return (IGeometry)lines[0];
  323.             return factory.CreateMultiLineString(lines.ToArray());
  324.         }
  325.  
  326.         /// <summary>
  327.         /// Creates a Polygon or MultiPolygon from this Polygon shape.
  328.         /// </summary>
  329.         /// <param name="factory">The IGeometryFactory to use to create the new IGeometry.</param>
  330.         /// <returns>The IPolygon or IMultiPolygon created from this shape.</returns>
  331.         protected IGeometry FromPolygon(IGeometryFactory factory)
  332.         {
  333.             if (factory == null) factory = Geometry.DefaultFactory;
  334.             List<ILinearRing> shells = new List<ILinearRing>();
  335.             List<ILinearRing> holes = new List<ILinearRing>();
  336.             foreach (PartRange part in _shapeRange.Parts)
  337.             {
  338.                 List<Coordinate> coords = new List<Coordinate>();
  339.                 int i = part.StartIndex;
  340.                 foreach (Vertex d in part)
  341.                 {
  342.                     Coordinate c = new Coordinate(d.X, d.Y);
  343.                     if (M != null && M.Length > 0) c.M = M[i];
  344.                     if (Z != null && Z.Length > 0) c.Z = Z[i];
  345.                     i++;
  346.                     coords.Add(c);
  347.                 }
  348.                 ILinearRing ring = factory.CreateLinearRing(coords);
  349.                 if (_shapeRange.Parts.Count == 1)
  350.                 {
  351.                     shells.Add(ring);
  352.                 }
  353.                 else
  354.                 {
  355.                     if (CgAlgorithms.IsCounterClockwise(ring.Coordinates))
  356.                     {
  357.                         holes.Add(ring);
  358.                     }
  359.                     else
  360.                     {
  361.                         shells.Add(ring);
  362.                     }
  363.                 }
  364.             }
  365.             //// Now we have a list of all shells and all holes
  366.             List<ILinearRing>[] holesForShells = new List<ILinearRing>[shells.Count];
  367.             for (int i = 0; i < shells.Count; i++)
  368.             {
  369.                 holesForShells[i] = new List<ILinearRing>();
  370.             }
  371.  
  372.             // Find holes
  373.             foreach (ILinearRing t in holes)
  374.             {
  375.                 ILinearRing testRing = t;
  376.                 ILinearRing minShell = null;
  377.                 IEnvelope minEnv = null;
  378.                 IEnvelope testEnv = testRing.EnvelopeInternal;
  379.                 Coordinate testPt = testRing.Coordinates[0];
  380.                 ILinearRing tryRing;
  381.                 for (int j = 0; j < shells.Count; j++)
  382.                 {
  383.                     tryRing = shells[j];
  384.                     IEnvelope tryEnv = tryRing.EnvelopeInternal;
  385.                     if (minShell != null)
  386.                         minEnv = minShell.EnvelopeInternal;
  387.                     bool isContained = false;
  388.  
  389.                     if (tryEnv.Contains(testEnv)
  390.                         && (CgAlgorithms.IsPointInRing(testPt, tryRing.Coordinates)
  391.                             || (PointInList(testPt, tryRing.Coordinates))))
  392.                     {
  393.                         isContained = true;
  394.                     }
  395.  
  396.                     // Check if this new containing ring is smaller than the current minimum ring
  397.                     if (isContained)
  398.                     {
  399.                         if (minShell == null || minEnv.Contains(tryEnv))
  400.                         {
  401.                             minShell = tryRing;
  402.                         }
  403.                         holesForShells[j].Add(t);
  404.                     }
  405.                 }
  406.             }
  407.  
  408.             IPolygon[] polygons = new Polygon[shells.Count];
  409.             for (int i = 0; i < shells.Count; i++)
  410.             {
  411.                 polygons[i] = factory.CreatePolygon(shells[i], holesForShells[i].ToArray());
  412.             }
  413.  
  414.             if (polygons.Length == 1)
  415.             {
  416.                 return polygons[0];
  417.             }
  418.             // It's a multi part
  419.             return factory.CreateMultiPolygon(polygons);
  420.         }
  421.  
  422.         /// <summary>
  423.         /// Test if a point is in a list of coordinates.
  424.         /// </summary>
  425.         /// <param name="testPoint">TestPoint the point to test for.</param>
  426.         /// <param name="pointList">PointList the list of points to look through.</param>
  427.         /// <returns>true if testPoint is a point in the pointList list.</returns>
  428.         private static bool PointInList(Coordinate testPoint, IEnumerable<Coordinate> pointList)
  429.         {
  430.             return pointList.Any(p => p.Equals2D(testPoint));
  431.         }
  432.  
  433.         /// <summary>
  434.         /// Copies the field names and types from the parent feature set if they are currently null.
  435.         /// Attempts to copy the members of the feature's datarow.  This assumes the features have been
  436.         /// loaded into memory and are available on the feature's DataRow property.
  437.         /// </summary>
  438.         /// <param name="feature">An IFeature to copy the attributes from.  If the schema is null, this will try to use the parent featureset schema.</param>
  439.         public void CopyAttributes(IFeature feature)
  440.         {
  441.             object[] dr = feature.DataRow.ItemArray;
  442.             _attributes = new object[dr.Length];
  443.             Array.Copy(dr, _attributes, dr.Length);
  444.         }
  445.  
  446.         /// <summary>
  447.         /// In cases where the attributes are not in ram yet, this can obtain only the attributes for the
  448.         /// specified shape.
  449.         /// </summary>
  450.         /// <param name="source"></param>
  451.         /// <param name="index"></param>
  452.         public void CopyAttributes(IFeatureSet source, int index)
  453.         {
  454.         }
  455.  
  456.         /// <summary>
  457.         /// Create a ShapeRange from a Geometry to use in constructing a Shape
  458.         /// </summary>
  459.         /// <param name="geometry"></param>
  460.         /// <param name="vertices"></param>
  461.         /// <param name="offset">offset into vertices array where this feature starts</param>
  462.         /// <returns></returns>
  463.         public static ShapeRange ShapeRangeFromGeometry(IBasicGeometry geometry, double[] vertices, int offset)
  464.         {
  465.             var featureType = geometry.FeatureType;
  466.             ShapeRange shx = new ShapeRange(featureType) { Extent = new Extent(geometry.Envelope) };
  467.             int vIndex = offset / 2;
  468.             shx.Parts = new List<PartRange>();
  469.             int shapeStart = vIndex;
  470.             for (int part = 0; part < geometry.NumGeometries; part++)
  471.             {
  472.                 PartRange prtx = new PartRange(vertices, shapeStart, vIndex - shapeStart, featureType);
  473.                 IBasicPolygon bp = geometry.GetBasicGeometryN(part) as IBasicPolygon;
  474.                 if (bp != null)
  475.                 {
  476.                     // Account for the Shell
  477.                     prtx.NumVertices = bp.Shell.NumPoints;
  478.  
  479.                     vIndex += bp.Shell.NumPoints;
  480.  
  481.                     // The part range should be adjusted to no longer include the holes
  482.                     foreach (var hole in bp.Holes)
  483.                     {
  484.                         PartRange holex = new PartRange(vertices, shapeStart, vIndex - shapeStart, featureType)
  485.                                               {
  486.                                                   NumVertices = hole.NumPoints
  487.                                               };
  488.                         shx.Parts.Add(holex);
  489.                         vIndex += hole.NumPoints;
  490.                     }
  491.                 }
  492.                 else
  493.                 {
  494.                     int numPoints = geometry.GetBasicGeometryN(part).NumPoints;
  495.  
  496.                     // This is not a polygon, so just add the number of points.
  497.                     vIndex += numPoints;
  498.                     prtx.NumVertices = numPoints;
  499.                 }
  500.  
  501.                 shx.Parts.Add(prtx);
  502.             }
  503.             return shx;
  504.         }
  505.  
  506.         /// <summary>
  507.         /// Create a ShapeRange from a Feature to use in constructing a Shape
  508.         /// </summary>
  509.         /// <param name="feature"></param>
  510.         /// <param name="vertices"></param>
  511.         /// <param name="offset">offset into vertices array where this feature starts</param>
  512.         /// <returns></returns>
  513.         public static ShapeRange ShapeRangeFromFeature(IFeature feature, double[] vertices, int offset)
  514.         {
  515.             return ShapeRangeFromGeometry(feature.BasicGeometry, vertices, offset);
  516.         }
  517.  
  518.         /// <summary>
  519.         /// Create a ShapeRange from a Feature to use in constructing a Shape
  520.         /// </summary>
  521.         /// <param name="feature"></param>
  522.         /// <param name="vertices"></param>
  523.         /// <returns></returns>
  524.         public static ShapeRange ShapeRangeFromFeature(IFeature feature, double[] vertices)
  525.         {
  526.             return ShapeRangeFromFeature(feature, vertices, 0);
  527.         }
  528.  
  529.         #endregion
  530.  
  531.         #region Properties
  532.  
  533.         /// <summary>
  534.         /// Gets or sets the minimum M
  535.         /// </summary>
  536.         public double MinM { get; set; }
  537.  
  538.         /// <summary>
  539.         ///  Gets or sets the maximum M
  540.         /// </summary>
  541.         public double MaxM { get; set; }
  542.  
  543.         /// <summary>
  544.         ///  Gets or sets the minimum Z
  545.         /// </summary>
  546.         public double MinZ { get; set; }
  547.  
  548.         /// <summary>
  549.         ///  Gets or sets the maximum Z
  550.         /// </summary>
  551.         public double MaxZ { get; set; }
  552.  
  553.         /// <summary>
  554.         /// Gives a way to cycle through the vertices of this shape.
  555.         /// </summary>
  556.         public ShapeRange Range
  557.         {
  558.             get { return _shapeRange; }
  559.             set { _shapeRange = value; }
  560.         }
  561.  
  562.         /// <summary>
  563.         /// The double vertices in X1, Y1, X2, Y2, ..., Xn, Yn order.
  564.         /// </summary>
  565.         public double[] Vertices
  566.         {
  567.             get { return _vertices; }
  568.             set
  569.             {
  570.                 _vertices = value;
  571.                 foreach (PartRange part in _shapeRange.Parts)
  572.                 {
  573.                     part.Vertices = value;
  574.                 }
  575.             }
  576.         }
  577.  
  578.         /// <summary>
  579.         /// The Z values if any
  580.         /// </summary>
  581.         public double[] Z
  582.         {
  583.             get { return _z; }
  584.             set { _z = value; }
  585.         }
  586.  
  587.         /// <summary>
  588.         /// The M values if any, organized in order.
  589.         /// </summary>
  590.         public double[] M
  591.         {
  592.             get { return _m; }
  593.             set { _m = value; }
  594.         }
  595.  
  596.         /// <summary>
  597.         /// Gets or sets the attributes.  Since the most likely use is to copy values from one source to
  598.         /// another, this should be an independant array in each shape and be deep-copied.
  599.         /// </summary>
  600.         public object[] Attributes
  601.         {
  602.             get { return _attributes; }
  603.             set { _attributes = value; }
  604.         }
  605.  
  606.         /// <summary>
  607.         /// Without changing the feature type or anything else, simply update the local coordinates
  608.         /// to include the new coordinates.  All the new coordinates will be considered one part.
  609.         /// Since point and multi-point shapes don't have parts, they will just be appended to the
  610.         /// original part.
  611.         /// </summary>
  612.         public void AddPart(IEnumerable<Coordinate> coordinates, CoordinateType coordType)
  613.         {
  614.             bool hasM = (coordType == CoordinateType.M || coordType == CoordinateType.Z);
  615.             bool hasZ = (coordType == CoordinateType.Z);
  616.             List<double> vertices = new List<double>();
  617.             List<double> z = new List<double>();
  618.             List<double> m = new List<double>();
  619.             int numPoints = 0;
  620.             int oldNumPoints = (_vertices != null) ? _vertices.Length / 2 : 0;
  621.             foreach (Coordinate coordinate in coordinates)
  622.             {
  623.                 if (_shapeRange.Extent == null) _shapeRange.Extent = new Extent();
  624.                 _shapeRange.Extent.ExpandToInclude(coordinate.X, coordinate.Y);
  625.                 vertices.Add(coordinate.X);
  626.                 vertices.Add(coordinate.Y);
  627.                 if (hasM) m.Add(coordinate.M);
  628.                 if (hasZ) z.Add(coordinate.Z);
  629.                 numPoints++;
  630.             }
  631.             // Using public accessor also updates individual part references
  632.             Vertices = (_vertices != null) ? _vertices.Concat(vertices).ToArray() : vertices.ToArray();
  633.             if (hasZ) _z = (_z != null) ? _z.Concat(z).ToArray() : z.ToArray();
  634.             if (hasM) _m = (_m != null) ? _m.Concat(m).ToArray() : m.ToArray();
  635.  
  636.             if (_shapeRange.FeatureType == FeatureType.MultiPoint || _shapeRange.FeatureType == FeatureType.Point)
  637.             {
  638.                 // Only one part exists
  639.                 _shapeRange.Parts[0].NumVertices += numPoints;
  640.             }
  641.             else
  642.             {
  643.                 PartRange part = new PartRange(_vertices, _shapeRange.StartIndex, oldNumPoints, _shapeRange.FeatureType);
  644.                 part.NumVertices = numPoints;
  645.                 _shapeRange.Parts.Add(part);
  646.             }
  647.         }
  648.  
  649.         #endregion
  650.  
  651.         #region ICloneable Members
  652.  
  653.         /// <summary>
  654.         /// This creates a duplicate shape, also copying the vertex array to
  655.         /// a new array containing just this shape, as well as duplicating the attribute array.
  656.         /// The FieldNames and FieldTypes are a shallow copy since this shouldn't change.
  657.         /// </summary>
  658.         /// <returns></returns>
  659.         public object Clone()
  660.         {
  661.             if (_shapeRange == null) return new Shape();
  662.  
  663.             Shape copy = (Shape)MemberwiseClone();
  664.             int numPoints = _shapeRange.NumPoints;
  665.             int start = _shapeRange.StartIndex;
  666.  
  667.             copy.Range = _shapeRange.Copy();
  668.             // Be sure to set vertex array AFTER the shape range to update part indices correctly.
  669.             double[] verts = new double[numPoints * 2];
  670.             Array.Copy(_vertices, start, verts, 0, numPoints * 2);
  671.             copy.Vertices = verts;
  672.             if (_z != null && (_z.Length - start) >= numPoints)
  673.             {
  674.                 copy.Z = new double[numPoints];
  675.                 Array.Copy(_z, start, copy._z, 0, numPoints);
  676.             }
  677.             if (_m != null && (_m.Length - start) >= numPoints)
  678.             {
  679.                 copy.M = new double[numPoints];
  680.                 Array.Copy(_m, start, copy._m, 0, numPoints);
  681.             }
  682.             // Update the start-range to work like a stand-alone shape.
  683.             copy.Range.StartIndex = 0;
  684.  
  685.             // Copy the attributes (handling the null case)
  686.             if (null == _attributes)
  687.                 copy.Attributes = null;
  688.             else
  689.             {
  690.                 copy.Attributes = new object[_attributes.Length];
  691.                 Array.Copy(_attributes, 0, copy._attributes, 0, _attributes.Length);
  692.             }
  693.             return copy;
  694.         }
  695.  
  696.         #endregion
  697.     }
  698. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement