public void TestMultipatchConversionWithMultipleRings()
        {
            Rectangular[] positions = new Rectangular[] {
                new Rectangular(0.0, 5.0),
                new Rectangular(5.0, 10.0),
                new Rectangular(10.0, 5.0),
                new Rectangular(5.0, 0.0),
                new Rectangular(0.0, 5.0),

                new Rectangular(2.0, 5.0),
                new Rectangular(5.0, 2.0),
                new Rectangular(8.0, 5.0),
                new Rectangular(5.0, 8.0),
                new Rectangular(2.0, 5.0),
            };

            CartographicExtent extent = new CartographicExtent(0.0, 0.0, 10.0, 10.0);

            int[] parts = new int[] { 0, 5 };
            MultiPatchPartType[] partTypes = new MultiPatchPartType[] { MultiPatchPartType.Ring, MultiPatchPartType.Ring };

            double[] zValues  = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
            double[] measures = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };

            MultiPatchShape multipatch = new MultiPatchShape(0, m_metadata, extent, parts, partTypes, positions, 0.0, 0.0, zValues, 0.0, 0.0, measures);
            MultiPatch      patch      = new MultiPatch(multipatch, m_document, Color.Blue);

            patch.Write();
            string result         = m_stringWriter.ToString();
            Regex  polygonPattern = new Regex(m_polygonPattern);

            Assert.AreEqual(2, polygonPattern.Matches(result).Count);
        }
        public void TestMultipatchConversionWithTriangleStrip()
        {
            Rectangular[] positions = new Rectangular[] {
                new Rectangular(0.0, 0.0),
                new Rectangular(0.0, 1.0),
                new Rectangular(1.0, 0.0),
                new Rectangular(1.0, 1.0),
                new Rectangular(2.0, 0.0),
                new Rectangular(2.0, 1.0),
                new Rectangular(3.0, 0.0)
            };

            CartographicExtent extent = new CartographicExtent(0.0, 0.0, 3.0, 1.0);

            int[] parts = new int[] { 0 };
            MultiPatchPartType[] partTypes = new MultiPatchPartType[] { MultiPatchPartType.TriangleStrip };

            double[] zValues  = new double[] { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 };
            double[] measures = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };

            MultiPatchShape multipatch = new MultiPatchShape(0, m_metadata, extent, parts, partTypes, positions, 0.0, 0.0, zValues, 0.0, 0.0, measures);
            MultiPatch      patch      = new MultiPatch(multipatch, m_document, Color.Blue);

            patch.Write();
            string result          = m_stringWriter.ToString();
            Regex  trianglePattern = new Regex(m_trianglePattern);

            Assert.AreEqual(5, trianglePattern.Matches(result).Count);
        }
        public void TestMultipatchConversionWithInnerAndOuterRings()
        {
            Rectangular[] positions = new Rectangular[] {
                new Rectangular(0.0, 5.0),
                new Rectangular(5.0, 10.0),
                new Rectangular(10.0, 5.0),
                new Rectangular(5.0, 0.0),
                new Rectangular(0.0, 5.0),

                new Rectangular(2.0, 5.0),
                new Rectangular(5.0, 2.0),
                new Rectangular(8.0, 5.0),
                new Rectangular(5.0, 8.0),
                new Rectangular(2.0, 5.0),
            };

            CartographicExtent extent = new CartographicExtent(0.0, 0.0, 10.0, 10.0);

            int[] parts = new int[] { 0, 5 };
            MultiPatchPartType[] partTypes = new MultiPatchPartType[] { MultiPatchPartType.OuterRing, MultiPatchPartType.InnerRing };

            double[] zValues  = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
            double[] measures = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };

            MultiPatchShape multipatch = new MultiPatchShape(0, m_metadata, extent, parts, partTypes, positions, 0.0, 0.0, zValues, 0.0, 0.0, measures);
            MultiPatch      patch      = new MultiPatch(multipatch, m_document, Color.Blue);

            patch.Write();
            string result = m_stringWriter.ToString();

            Assert.IsTrue(System.Text.RegularExpressions.Regex.IsMatch(result, m_polygonPattern));
        }
Esempio n. 4
0
        /// <summary>
        /// Writes the MultiPatch shape to its <see cref="CzmlDocument"/> as a series of polygon packets.
        /// </summary>
        public override void Write()
        {
            MultiPatchShape multipatch = (MultiPatchShape)m_shape;
            List <Polygon>  polygons   = new List <Polygon>();

            StringDictionary metadata = new StringDictionary();
            var fields = multipatch.GetMetadataFields();

            foreach (String field in fields)
            {
                metadata.Add(field, multipatch.GetMetadataValue(field));
            }

            for (int i = 0; i < multipatch.Count; i++)
            {
                List <ShapePart> polygonParts = new List <ShapePart>();
                PolygonShape     temp;

                switch (multipatch.GetPartType(i))
                {
                case MultiPatchPartType.TriangleFan:
                case MultiPatchPartType.TriangleStrip:
                    for (int j = 2; j < multipatch[i].Count; j++)
                    {
                        int            firstIndex = (multipatch.GetPartType(i) == MultiPatchPartType.TriangleFan) ? 0 : j - 2;
                        Cartographic[] vertices   = new Cartographic[] { multipatch[i][firstIndex], multipatch[i][j - 1], multipatch[i][j] };
                        ShapePart      triangle   = new ShapePart(vertices, 0, vertices.Length);
                        PolygonShape   p          = new PolygonShape(multipatch.RecordNumber, metadata, multipatch.Extent, new ShapePart[] { triangle });
                        (new Polygon(p, m_document, m_color)).Write();
                    }
                    break;

                case MultiPatchPartType.Ring:
                    while (i < multipatch.Count && multipatch.GetPartType(i) == MultiPatchPartType.Ring)
                    {
                        temp = new PolygonShape(multipatch.RecordNumber, metadata, multipatch.Extent, new ShapePart[] { multipatch[i] });
                        (new Polygon(temp, m_document, m_color)).Write();
                        i++;
                    }
                    i--;
                    break;

                case MultiPatchPartType.OuterRing:
                case MultiPatchPartType.FirstRing:
                    polygonParts.Add(multipatch[i]);
                    MultiPatchPartType comparisonType = (multipatch.GetPartType(i) == MultiPatchPartType.OuterRing) ? MultiPatchPartType.InnerRing : MultiPatchPartType.Ring;
                    while (++i < multipatch.Count && multipatch.GetPartType(i) == comparisonType)
                    {
                        polygonParts.Add(multipatch[i]);
                    }
                    temp = new PolygonShape(multipatch.RecordNumber, metadata, multipatch.Extent, polygonParts.ToArray());
                    (new Polygon(temp, m_document, m_color)).Write();
                    i--;
                    break;
                }
            }
        }
Esempio n. 5
0
        public MultiPatchShape(
            int recordNumber,
            StringDictionary metadata,
            CartographicExtent extent,
            int[] parts,
            MultiPatchPartType[] partTypes,
            Rectangular[] positions,
            double minimumZ,
            double maximumZ,
            double[] zValues,
            double minimumMeasure,
            double maximumMeasure,
            double[] measures,
            ShapeType shapeType = ShapeType.MultiPatch)
            : base(recordNumber, metadata, shapeType)
        {
            _extent = new CartographicExtent(
               extent.WestLongitude * Constants.RadiansPerDegree,
               extent.SouthLatitude * Constants.RadiansPerDegree,
               extent.EastLongitude * Constants.RadiansPerDegree,
               extent.NorthLatitude * Constants.RadiansPerDegree);

            _minimumZ = minimumZ;
            _maximumZ = maximumZ;
            _minimumMeasure = minimumMeasure;
            _maximumMeasure = maximumMeasure;
            _measures = (double[])measures.Clone();

            for (int i = 0; i < positions.Length; i++)
            {
                positions[i] = new Rectangular(positions[i].X * Constants.RadiansPerDegree, positions[i].Y * Constants.RadiansPerDegree);
            }

            _parts = new ShapePart[parts.Length];
            for (int i = 0; i < parts.Length; ++i)
            {
                int count = ((i == parts.Length - 1) ?
                    positions.Length : parts[i + 1]) - parts[i];

                _parts[i] = new ShapePart(positions, zValues, parts[i], count);
            }

            _partTypes = (MultiPatchPartType[])partTypes.Clone();
        }
Esempio n. 6
0
        public ShapefileReader(string filename)
        {
            // ESRI Shapefile Technical Description:
            //    http://www.esri.com/library/whitepapers/pdfs/shapefile.pdf
            using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
            {
                // File Header:
                //
                // Position  Field         Value        Type     Byte Order
                // --------  -----         -----        ----     ----------
                // Byte 0    File Code     9994         Integer  Big
                // Byte 4    Unused        0            Integer  Big
                // Byte 8    Unused        0            Integer  Big
                // Byte 12   Unused        0            Integer  Big
                // Byte 16   Unused        0            Integer  Big
                // Byte 20   Unused        0            Integer  Big
                // Byte 24   File Length   File Length  Integer  Big
                // Byte 28   Version       1000         Integer  Little
                // Byte 32   Shape Type    Shape Type   Integer  Little
                // Byte 36   Bounding Box  Xmin         Double   Little
                // Byte 44   Bounding Box  Ymin         Double   Little
                // Byte 52   Bounding Box  Xmax         Double   Little
                // Byte 60   Bounding Box  Ymax         Double   Little
                // Byte 68*  Bounding Box  Zmin         Double   Little
                // Byte 76*  Bounding Box  Zmax         Double   Little
                // Byte 84*  Bounding Box  Mmin         Double   Little
                // Byte 92*  Bounding Box  Mmax         Double   Little
                //
                // * Unused, with value 0.0, if not Measured or Z type

                byte[] fileHeader = Read(fs, _fileHeaderLength);
                if (fileHeader == null)
                {
                    throw new InvalidDataException("Could not read shapefile header.");
                }

                _byteOrder = BitConverter.IsLittleEndian ? ByteOrder.LittleEndian : ByteOrder.BigEndian;
                int fileCode = ToInteger(fileHeader, 0, ByteOrder.BigEndian);;

                if (fileCode != _fileCode)
                {
                    throw new InvalidDataException("Could not read shapefile file code.  Is this a valid shapefile?");
                }

                int fileLengthInBytes = ToInteger(fileHeader, 24, ByteOrder.BigEndian) * 2;

                int version = ToInteger(fileHeader, 28, ByteOrder.LittleEndian);
                if (version != _version)
                {
                    throw new InvalidDataException("Shapefile version " + version + " is not supported.  Only version " + _version + " is supported.");
                }

                // If a .prj file exists, check to see if the projection is supported.
                string prjFilepath = Path.ChangeExtension(filename, "prj");
                if (File.Exists(prjFilepath))
                {
                    string prj        = System.IO.File.ReadAllText(prjFilepath);
                    string projection = @"PROJECTION";
                    string unit       = @"Degree";
                    if (Regex.IsMatch(prj, projection))
                    {
                        throw new InvalidDataException("Shapefile projection not supported.");
                    }
                    else if (!(Regex.IsMatch(prj, unit)))
                    {
                        throw new InvalidDataException("Shapefile units not supported. Only degrees is supported.");
                    }
                }

                _shapeType = (ShapeType)ToInteger(fileHeader, 32, ByteOrder.LittleEndian);

                double xMin = ToDouble(fileHeader, 36, ByteOrder.LittleEndian);
                double yMin = ToDouble(fileHeader, 44, ByteOrder.LittleEndian);
                double xMax = ToDouble(fileHeader, 52, ByteOrder.LittleEndian);
                double yMax = ToDouble(fileHeader, 60, ByteOrder.LittleEndian);

                if (fileLengthInBytes == _fileHeaderLength)
                {
                    // If the shapefile is empty (that is, has no records),
                    // the values for xMin, yMin, xMax, and yMax are unspecified.
                    //
                    // I like zero better.

                    xMin = 0.0;
                    yMin = 0.0;
                    xMax = 0.0;
                    yMax = 0.0;
                }

                _extent = new CartographicExtent(xMin, yMin, xMax, yMax);

                // Read each header...

                // Record Header:
                //
                // Position  Field           Value           Type     Byte Order
                // --------  -----           -----           ----     ----------
                // Byte 0    Record Number   Record Number   Integer  Big
                // Byte 4    Content Length  Content Length  Integer  Big

                _shapes = new List <Shape>();
                byte[] recordHeader;

                string    dBaseFilepath = Path.ChangeExtension(filename, "dbf");
                DataTable metadataTable = ParseDBF.ReadDBF(dBaseFilepath);

                while ((recordHeader = Read(fs, _recordHeaderLength)) != null)
                {
                    int    recordNumber         = ToInteger(recordHeader, 0, ByteOrder.BigEndian);
                    int    contextLengthInBytes = ToInteger(recordHeader, 4, ByteOrder.BigEndian) * 2;
                    byte[] record = Read(fs, contextLengthInBytes);
                    int    mOffset, zOffset;

                    StringDictionary metadata = new StringDictionary();
                    foreach (DataColumn column in metadataTable.Columns)
                    {
                        metadata.Add(column.ColumnName, Convert.ToString(metadataTable.Rows[recordNumber - 1][column]).Trim());
                    }

                    ShapeType recordShapeType = (ShapeType)ToInteger(record, 0, ByteOrder.LittleEndian);
                    switch (recordShapeType)
                    {
                    case ShapeType.NullShape:
                        // Filter out null shapes.  Otherwise, every client
                        // would have to deal with them.
                        break;

                    case ShapeType.Point:
                        double       x        = ToDouble(record, 4, ByteOrder.LittleEndian);
                        double       y        = ToDouble(record, 12, ByteOrder.LittleEndian);
                        Cartographic position = new Cartographic(x, y, 0.0);
                        _shapes.Add(new PointShape(recordNumber, metadata, position));
                        break;

                    case ShapeType.PointM:
                        x        = ToDouble(record, 4, ByteOrder.LittleEndian);
                        y        = ToDouble(record, 12, ByteOrder.LittleEndian);
                        position = new Cartographic(x, y, 0.0);
                        double measure = ToDouble(record, 20, ByteOrder.LittleEndian);
                        _shapes.Add(new PointMShape(recordNumber, metadata, position, measure));
                        break;

                    case ShapeType.PointZ:
                        x = ToDouble(record, 4, ByteOrder.LittleEndian);
                        y = ToDouble(record, 12, ByteOrder.LittleEndian);
                        double z = ToDouble(record, 20, ByteOrder.LittleEndian);
                        position = new Cartographic(x, y, z);
                        measure  = ToDouble(record, 28, ByteOrder.LittleEndian);
                        _shapes.Add(new PointZShape(recordNumber, metadata, position, measure));
                        break;

                    case ShapeType.MultiPoint:
                    case ShapeType.MultiPointM:
                    case ShapeType.MultiPointZ:
                        CartographicExtent extent = new CartographicExtent(
                            ToDouble(record, 4, ByteOrder.LittleEndian),
                            ToDouble(record, 12, ByteOrder.LittleEndian),
                            ToDouble(record, 20, ByteOrder.LittleEndian),
                            ToDouble(record, 28, ByteOrder.LittleEndian));

                        int            numberOfPoints = ToInteger(record, 36, ByteOrder.LittleEndian);
                        Cartographic[] points         = new Cartographic[numberOfPoints];
                        for (int i = 0; i < numberOfPoints; ++i)
                        {
                            points[i] = new Cartographic(
                                ToDouble(record, 40 + (16 * i), ByteOrder.LittleEndian),
                                ToDouble(record, 40 + (16 * i) + 8, ByteOrder.LittleEndian),
                                0.0);
                        }

                        if (recordShapeType == ShapeType.MultiPoint)
                        {
                            _shapes.Add(new MultiPointShape(recordNumber, metadata, extent, points));
                        }
                        else
                        {
                            mOffset = 40 + (16 * numberOfPoints);
                            zOffset = 40 + (16 * numberOfPoints);
                            if (recordShapeType == ShapeType.MultiPointZ)
                            {
                                mOffset = zOffset + 16 + (8 * numberOfPoints);
                            }

                            double   mMin     = ToDouble(record, mOffset, ByteOrder.LittleEndian);
                            double   mMax     = ToDouble(record, mOffset + 8, ByteOrder.LittleEndian);
                            double[] measures = new double[numberOfPoints];
                            for (int i = 0; i < numberOfPoints; i++)
                            {
                                measures[i] = ToDouble(record, mOffset + 16 + (8 * i), ByteOrder.LittleEndian);
                            }

                            if (recordShapeType == ShapeType.MultiPointM)
                            {
                                _shapes.Add(new MultiPointMShape(recordNumber, metadata, extent, points, mMin, mMax, measures));
                            }
                            else
                            {
                                double   zMin    = ToDouble(record, zOffset, ByteOrder.LittleEndian);
                                double   zMax    = ToDouble(record, zOffset + 8, ByteOrder.LittleEndian);
                                double[] zValues = new double[numberOfPoints];
                                for (int i = 0; i < numberOfPoints; i++)
                                {
                                    x         = points[i].Longitude;
                                    y         = points[i].Latitude;
                                    z         = ToDouble(record, zOffset + 16 + (8 * i), ByteOrder.LittleEndian);
                                    points[i] = new Cartographic(x, y, z);
                                }
                                _shapes.Add(new MultiPointZShape(recordNumber, metadata, extent, points, zMin, zMax, mMin, mMax, measures));
                            }
                        }

                        break;

                    case ShapeType.Polyline:
                    case ShapeType.PolylineM:
                    case ShapeType.PolylineZ:
                    case ShapeType.Polygon:
                    case ShapeType.PolygonM:
                    case ShapeType.PolygonZ:
                    case ShapeType.MultiPatch:
                        extent = new CartographicExtent(
                            ToDouble(record, 4, ByteOrder.LittleEndian),
                            ToDouble(record, 12, ByteOrder.LittleEndian),
                            ToDouble(record, 20, ByteOrder.LittleEndian),
                            ToDouble(record, 28, ByteOrder.LittleEndian));
                        int numberOfParts = ToInteger(record, 36, ByteOrder.LittleEndian);
                        numberOfPoints = ToInteger(record, 40, ByteOrder.LittleEndian);

                        int[]         parts     = new int[numberOfParts];
                        Rectangular[] positions = new Rectangular[numberOfPoints];

                        // These two loops can be optimized if the machine is little endian.
                        for (int i = 0; i < numberOfParts; ++i)
                        {
                            parts[i] = ToInteger(record, 44 + (4 * i), ByteOrder.LittleEndian);
                        }

                        int pointOffset    = 44 + (4 * numberOfParts);
                        int partTypeOffset = 44 + (4 * numberOfParts);
                        if (recordShapeType == ShapeType.MultiPatch)
                        {
                            pointOffset = partTypeOffset + (4 * numberOfParts);
                        }

                        for (int i = 0; i < numberOfPoints; ++i)
                        {
                            positions[i] = new Rectangular(
                                ToDouble(record, pointOffset + (16 * i), ByteOrder.LittleEndian),
                                ToDouble(record, pointOffset + (16 * i) + 8, ByteOrder.LittleEndian));
                        }

                        if (recordShapeType == ShapeType.Polyline)
                        {
                            _shapes.Add(new PolylineShape(recordNumber, metadata, extent, parts, positions));
                        }
                        else if (recordShapeType == ShapeType.Polygon)
                        {
                            _shapes.Add(new PolygonShape(recordNumber, metadata, extent, parts, positions));
                        }
                        else
                        {
                            mOffset = pointOffset + (16 * numberOfPoints);
                            zOffset = pointOffset + (16 * numberOfPoints);
                            if (recordShapeType == ShapeType.PolylineZ || recordShapeType == ShapeType.PolygonZ || recordShapeType == ShapeType.MultiPatch)
                            {
                                mOffset = zOffset + 16 + (8 * numberOfPoints);
                            }

                            double   mMin     = ToDouble(record, mOffset, ByteOrder.LittleEndian);
                            double   mMax     = ToDouble(record, mOffset + 8, ByteOrder.LittleEndian);
                            double[] measures = new double[numberOfPoints];
                            for (int i = 0; i < numberOfPoints; i++)
                            {
                                measures[i] = ToDouble(record, mOffset + 16 + (8 * i), ByteOrder.LittleEndian);
                            }

                            if (recordShapeType == ShapeType.PolylineM)
                            {
                                _shapes.Add(new PolylineMShape(recordNumber, metadata, extent, parts, positions, mMin, mMax, measures));
                            }
                            else if (recordShapeType == ShapeType.PolygonM)
                            {
                                _shapes.Add(new PolygonMShape(recordNumber, metadata, extent, parts, positions, mMin, mMax, measures));
                            }
                            else
                            {
                                double   zMin    = ToDouble(record, zOffset, ByteOrder.LittleEndian);
                                double   zMax    = ToDouble(record, zOffset + 8, ByteOrder.LittleEndian);
                                double[] zValues = new double[numberOfPoints];
                                for (int i = 0; i < numberOfPoints; i++)
                                {
                                    zValues[i] = ToDouble(record, zOffset + 16 + (8 * i), ByteOrder.LittleEndian);
                                }

                                if (recordShapeType == ShapeType.PolylineZ)
                                {
                                    _shapes.Add(new PolylineZShape(recordNumber, metadata, extent, parts, positions, zMin, zMax, zValues, mMin, mMax, measures));
                                }
                                else if (recordShapeType == ShapeType.PolygonZ)
                                {
                                    _shapes.Add(new PolygonZShape(recordNumber, metadata, extent, parts, positions, zMin, zMax, zValues, mMin, mMax, measures));
                                }
                                else
                                {
                                    MultiPatchPartType[] partTypes = new MultiPatchPartType[numberOfParts];
                                    for (int i = 0; i < numberOfParts; i++)
                                    {
                                        partTypes[i] = (MultiPatchPartType)ToInteger(record, partTypeOffset + (4 * i), ByteOrder.LittleEndian);
                                    }
                                    _shapes.Add(new MultiPatchShape(recordNumber, metadata, extent, parts, partTypes, positions, zMin, zMax, zValues, mMin, mMax, measures));
                                }
                            }
                        }

                        break;

                    default:
                        throw new NotImplementedException("The shapefile type is not supported.  Only null, point, polyline, and polygon are supported.");
                    }
                }
            }
        }
        public void TestMultipatchConversionWithTriangleStrip()
        {
            Rectangular[] positions = new Rectangular[] {
                new Rectangular(0.0, 0.0),
                new Rectangular(0.0, 1.0),
                new Rectangular(1.0, 0.0),
                new Rectangular(1.0, 1.0),
                new Rectangular(2.0, 0.0),
                new Rectangular(2.0, 1.0),
                new Rectangular(3.0, 0.0)
            };

            CartographicExtent extent = new CartographicExtent(0.0, 0.0, 3.0, 1.0);
            int[] parts = new int[] { 0 };
            MultiPatchPartType[] partTypes = new MultiPatchPartType[] { MultiPatchPartType.TriangleStrip };

            double[] zValues = new double[] { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 };
            double[] measures = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };

            MultiPatchShape multipatch = new MultiPatchShape(0, m_metadata, extent, parts, partTypes, positions, 0.0, 0.0, zValues, 0.0, 0.0, measures);
            MultiPatch patch = new MultiPatch(multipatch, m_document, Color.Blue);
            patch.Write();
            string result = m_stringWriter.ToString();
            Regex trianglePattern = new Regex(m_trianglePattern);
            Assert.AreEqual(5, trianglePattern.Matches(result).Count);
        }
        public void TestMultipatchConversionWithMultipleRings()
        {
            Rectangular[] positions = new Rectangular[] {
                new Rectangular(0.0, 5.0),
                new Rectangular(5.0, 10.0),
                new Rectangular(10.0, 5.0),
                new Rectangular(5.0, 0.0),
                new Rectangular(0.0, 5.0),

                new Rectangular(2.0, 5.0),
                new Rectangular(5.0, 2.0),
                new Rectangular(8.0, 5.0),
                new Rectangular(5.0, 8.0),
                new Rectangular(2.0, 5.0),
            };

            CartographicExtent extent = new CartographicExtent(0.0, 0.0, 10.0, 10.0);
            int[] parts = new int[] { 0, 5 };
            MultiPatchPartType[] partTypes = new MultiPatchPartType[] { MultiPatchPartType.Ring, MultiPatchPartType.Ring };

            double[] zValues = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
            double[] measures = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };

            MultiPatchShape multipatch = new MultiPatchShape(0, m_metadata, extent, parts, partTypes, positions, 0.0, 0.0, zValues, 0.0, 0.0, measures);
            MultiPatch patch = new MultiPatch(multipatch, m_document, Color.Blue);
            patch.Write();
            string result = m_stringWriter.ToString();
            Regex polygonPattern = new Regex(m_polygonPattern);
            Assert.AreEqual(2, polygonPattern.Matches(result).Count);
        }
        public void TestMultipatchConversionWithInnerAndOuterRings()
        {
            Rectangular[] positions = new Rectangular[] {
                new Rectangular(0.0, 5.0),
                new Rectangular(5.0, 10.0),
                new Rectangular(10.0, 5.0),
                new Rectangular(5.0, 0.0),
                new Rectangular(0.0, 5.0),

                new Rectangular(2.0, 5.0),
                new Rectangular(5.0, 2.0),
                new Rectangular(8.0, 5.0),
                new Rectangular(5.0, 8.0),
                new Rectangular(2.0, 5.0),
            };

            CartographicExtent extent = new CartographicExtent(0.0, 0.0, 10.0, 10.0);
            int[] parts = new int[] { 0, 5 };
            MultiPatchPartType[] partTypes = new MultiPatchPartType[] { MultiPatchPartType.OuterRing, MultiPatchPartType.InnerRing} ;

            double[] zValues = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
            double[] measures = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };

            MultiPatchShape multipatch = new MultiPatchShape(0, m_metadata, extent, parts, partTypes, positions, 0.0, 0.0, zValues, 0.0, 0.0, measures);
            MultiPatch patch = new MultiPatch(multipatch, m_document, Color.Blue);
            patch.Write();
            string result = m_stringWriter.ToString();
            Assert.IsTrue(System.Text.RegularExpressions.Regex.IsMatch(result, m_polygonPattern));
        }