/// <summary> /// handles the attributes while adding a shape /// </summary> /// <param name="shape"></param> /// <returns>A data row, but only if attributes are populated</returns> private DataRow AddAttributes(Shape shape) { // Handle attributes if the array is not null. Assumes compatible schema. if (shape.Attributes != null) { DataColumn[] columns = GetColumns(); Dictionary<string, object> rowContent = new Dictionary<string, object>(); object[] fixedContent = new object[columns.Length]; DataRow addedRow; if (shape.Attributes.Length != columns.Length) { throw new ArgumentException("Attribute column count mismatch."); } for (int iField = 0; iField < columns.Length; iField++) { object value = shape.Attributes[iField]; if (value != null) { if (columns[iField].DataType != value.GetType()) { // this may throw an exception if the type casting fails value = Convert.ChangeType(value, columns[iField].DataType); } } fixedContent[iField] = value; rowContent.Add(columns[iField].ColumnName, value); } if (AttributesPopulated) { // just add a new datarow addedRow = _dataTable.NewRow(); addedRow.ItemArray = fixedContent; return addedRow; } // Insert a new row in the source AddRow(rowContent); } return null; }
/// <summary> /// Gets a shape at the specified shape index. If the featureset is in /// indexmode, this returns a copy of the shape. If not, it will create /// a new shape based on the specified feature. /// </summary> /// <param name="index">The zero based integer index of the shape.</param> /// <param name="getAttributes">If getAttributes is true, then this also try to get attributes for that shape. /// If attributes are loaded, then it will use the existing datarow. Otherwise, it will read the attributes /// from the file. (This second option is not recommended for large repeats. In such a case, the attributes /// can be set manually from a larger bulk query of the source attributes.)</param> /// <returns>The Shape object</returns> public virtual Shape GetShape(int index, bool getAttributes) { if (InternalDataSet != null) { return InternalDataSet.GetShape(index, getAttributes); } if (_indexMode == false) return new Shape(Features[index]); Shape result = new Shape(FeatureType); // This will also deep copy the parts, attributes and vertices ShapeRange range = ShapeIndices[index]; result.Range = range.Copy(); int start = range.StartIndex; int numPoints = range.NumPoints; double[] vertices = new double[numPoints * 2]; double[] m = new double[numPoints]; Array.Copy(_vertices, start*2, vertices, 0, numPoints * 2); if (_z != null && (_z.Length - start) >= numPoints) { result.Z = new double[numPoints]; Array.Copy(_z, start, result.Z, 0, numPoints); } if(_m != null && (_m.Length - start) >= numPoints) { result.M = new double[numPoints]; Array.Copy(_m, start, result.M, 0, numPoints); } result.Vertices = vertices; // There is presumed to be only a single shape in the output array. result.Range.StartIndex = 0; if(AttributesPopulated) { if (getAttributes) result.Attributes = DataTable.Rows[index].ItemArray; } else { DataTable dt = GetAttributes(index, 1); if(dt != null && dt.Rows.Count > 0) { result.Attributes = dt.Rows[0].ItemArray; } } return result; }
public void FinishShape(object sender, EventArgs e) { Feature f = null; if (_featureSet.FeatureType == FeatureTypes.MultiPoint) { f = new Feature(new MultiPoint(_coordinates)); } if (_featureSet.FeatureType == FeatureTypes.Line || _featureSet.FeatureType == FeatureTypes.Polygon) { FinishPart(sender, e); Shape shp = new Shape(_featureSet.FeatureType); foreach (List<Coordinate> part in _parts) { shp.AddPart(part, _featureSet.CoordinateType); } f = new Feature(shp); } if (f != null) { _featureSet.Features.Add(f); _featureSet.UpdateEnvelopes(); } _featureSet.InvalidateVertices(); _coordinates = new List<Coordinate>(); _parts = new List<List<Coordinate>>(); }
/// <summary> /// If this featureset is in index mode, this will append the vertices and shapeindex of the shape. /// Otherwise, this will add a new feature based on this shape. If the attributes of the shape are not null, /// this will attempt to append a new datarow It is up to the developer /// to ensure that the object array of attributes matches the this featureset. If the Attributes of this feature are loaded, /// this will add the attributes in ram only. Otherwise, this will attempt to insert the attributes as a /// new record using the "AddRow" method. The schema of the object array should match this featureset's column schema. /// </summary> /// <param name="shape">The shape to add to this featureset.</param> public void AddShape(Shape shape) { if(InternalDataSet != null) { InternalDataSet.AddShape(shape); return; } IFeature addedFeature = null; // This first section controls the indices which need to happen regardless // because drawing uses indices even if editors like working with features. int count = (_vertices != null) ? _vertices.Length / 2 : 0; // Original number of points int totalCount = shape.Range.NumPoints + count; int start = shape.Range.StartIndex; int num = shape.Range.NumPoints; double[] vertices = new double[totalCount*2]; if (_vertices != null) Array.Copy(_vertices, 0, vertices, 0, _vertices.Length); if(shape.Vertices != null) Array.Copy(shape.Vertices, start * 2, vertices, count * 2, num * 2); if(_m != null || shape.M != null) { double[] m = new double[totalCount]; if (_m != null) Array.Copy(_m, 0, m, 0, _m.Length); if (shape.M != null) Array.Copy(shape.Vertices, start, m, count, num); _m = m; } if(_z != null || shape.Z != null) { double[] z = new double[totalCount]; if (_z != null) Array.Copy(_z, 0, z, 0, _z.Length); if (shape.Z != null) Array.Copy(shape.Vertices, start, z, count, num); _z = z; } shape.Range.StartIndex = count; ShapeIndices.Add(shape.Range); Vertex = vertices; shape.Vertices = vertices; if (Extent == null) Extent = new Extent(); Extent.ExpandToInclude(shape.Range.Extent); Envelope = Extent.ToEnvelope(); if(!_indexMode) { // Just add a new feature addedFeature = new Feature(shape); Features.Add(addedFeature); addedFeature.DataRow = AddAttributes(shape); if(Extent == null)Extent = new Extent(); if (!shape.Range.Extent.IsEmpty()) Extent.ExpandToInclude(new Extent(addedFeature.Envelope)); Envelope = Extent.ToEnvelope(); } }
private static Shape ReadMultiPolygon(Stream data) { Shape result = new Shape(FeatureTypes.Polygon); int numPolygons = ReadInt32(data); List<double[]> rings = new List<double[]>(); int partOffset = 0; for (int iPoly = 0; iPoly < numPolygons; iPoly++) { data.Seek(5, SeekOrigin.Current); // endian and geometry type int numRings = ReadInt32(data); for (int iRing = 0; iRing < numRings; iRing++) { int numPoints = ReadInt32(data); // ring structures are like a linestring without the final point. double[] coords = ReadDouble(data, 2 * numPoints); if (iRing == 0) { // By shapefile standard, the shell should be clockwise if (IsCounterClockwise(coords)) ReverseCoords(coords); } else { // By shapefile standard, the holes should be counter clockwise. if (!IsCounterClockwise(coords)) ReverseCoords(coords); } PartRange lPrt = new PartRange(FeatureTypes.Polygon); lPrt.PartOffset = partOffset; lPrt.NumVertices = numPoints; result.Range.Parts.Add(lPrt); partOffset += coords.Length / 2; rings.Add(coords); } } double[] allVertices = new double[partOffset * 2]; int offset = 0; foreach (double[] ring in rings) { Array.Copy(ring, 0, allVertices, offset, ring.Length); offset += ring.Length; } result.Vertices = allVertices; return result; }
private static Shape ReadMultiLineString(Stream data) { Shape result = new Shape(FeatureTypes.Line); int numLineStrings = ReadInt32(data); List<double[]> strings = new List<double[]>(); int partOffset = 0; for (int iString = 0; iString < numLineStrings; iString++) { // Each of these needs to read a full WKBLineString data.Seek(5, SeekOrigin.Current); //ignore header int numPoints = ReadInt32(data); double[] coords = ReadDouble(data, 2 * numPoints); PartRange lPrt = new PartRange(FeatureTypes.Line); lPrt.PartOffset = partOffset; lPrt.NumVertices = numPoints; result.Range.Parts.Add(lPrt); partOffset += coords.Length / 2; strings.Add(coords); } double[] allVertices = new double[partOffset * 2]; int offset = 0; foreach (double[] ring in strings) { Array.Copy(ring, 0, allVertices, offset, ring.Length); offset += ring.Length; } result.Vertices = allVertices; return result; }
private static Shape ReadLineString(Stream data) { Shape result = new Shape(FeatureTypes.Line); int count = ReadInt32(data); double[] coords = ReadDouble(data, 2 * count); PartRange lPrt = new PartRange(FeatureTypes.Line); lPrt.NumVertices = count; result.Range.Parts.Add(lPrt); result.Vertices = coords; return result; }
/// <summary> /// Reads one multipoint shape from a data stream. /// (this assumes that the two bytes (endian and type) have already been read. /// </summary> /// <param name="data"></param> /// <returns></returns> private static Shape ReadMultiPoint(Stream data) { Shape result = new Shape(FeatureTypes.MultiPoint); int count = ReadInt32(data); PartRange prt = new PartRange(FeatureTypes.MultiPoint); prt.NumVertices = count; result.Range.Parts.Add(prt); double[] vertices = new double[count * 2]; for (int iPoint = 0; iPoint < count; iPoint++) { data.ReadByte(); // ignore endian ReadInt32(data); // ignore geometry type double[] coord = ReadDouble(data, 2); Array.Copy(coord, 0, vertices, iPoint * 2, 2); } result.Vertices = vertices; return result; }
/// <summary> /// This assumes that the byte order and shapetype have already been read. /// </summary> /// <param name="data"></param> public static Shape ReadPoint(Stream data) { Shape result = new Shape(); result.Range = new ShapeRange(FeatureTypes.Point); PartRange prt = new PartRange(FeatureTypes.Point); prt.NumVertices = 1; result.Range.Parts.Add(prt); result.Vertices = ReadDouble(data, 2); return result; }