This document is archived and information here might be outdated.  Recommended version.


How to efficiently create valid Polygons (ArcObjects .NET 10.5 SDK)

How to efficiently create valid Polygons


 The following code demonstrates how to create valid polygons efficiently. Each of the functions uses a different interface in the creation:
  1. createMultipartPolygonRingSegmentCollection: Create a multipart polygon using rings via ISegmentCollection.
  2. createMultipartPolygonRingPointCollection: Create a multipart polygon using rings via IPointCollection.
  3. createSinglepartPolygonPointCollection: Create a single part polygon via IPointCollection.
  4. createSinglepartPolygonSegmentCollection: Create a single part polygon via ISegmentCollection.
  5. createRectanglePolygonFromEnvelope: Convert an envelope to a polygon via ISegmentCollection.

How to use

  1. Add the functions to your project.
[VCPP]
//************************************************************************************************
//* GEOMETRY TYPE : POLYGON
//* NOTE :In the following samples the geometries are simple without having to use ITopologicalOpeartor::Simplify.
//*       However if the data creation process cannot insure simple geometries
//*       the geometries have to be simplified before storing or using those in geometry operations.
//************************************************************************************************

//*************************************************************************
//* NAME : createMultipartPolygonRingSegmentCollection
//* DESCRIPTION: Create a multipart polygon using rings via ISegmentCollection.
//* This function is demonstrating it by creating 1001
//* concentric square rings and add those to a polygon.
//* NOTE : This is the approach to use if non-linear segments (Circular Arc, Elliptical Arc and Bezier Curve) have to be created.
//*************************************************************************
HRESULT createMultipartPolygonRingSegmentCollection()
{
  IGeometryCollectionPtr ipGonColl(CLSID_Polygon);

  //*********************************************************
  //THE SPATIAL REFERENCE SHOULD BE SET HERE ON THE POLYGON
  //Here the spatial reference is created in memory but could also come from various sources:
  //IMap, IGeodataset, IGeometry etc...
  ISpatialReferencePtr ipspref(CLSID_UnknownCoordinateSystem);
  ipspref->SetFalseOriginAndUnits( - 10000,  - 10000, 100000); 
    // Set the false origin and units.
  // The XYUnits value is equivalent to the precision specified when creating a feature class
  IGeometryPtr ipGeoSpRef(ipGonColl);
  ipGeoSpRef->putref_SpatialReference(ipspref);
  // *********************************************************
  // Initialize offset values
  double d0X0=0, d0Y0=0, d0X1=0, d0Y1=0, d0X2=0, d0Y2=0, d0X3=0,
    d0Y3=0;
  double d1X0=10000, d1Y0=10000, d1X1=10000, d1Y1=10000, d1X2=10000,
    d1Y2=10000, d1X3=10000, d1Y3=10000;
  int i, j;
  // Initialize the points
  IPointPtr ipPointsRing0[4];
  IPointPtr ipPointsRing1[4];
  for (i=0; i < 4; ++i)
  {
    ipPointsRing0[i].CreateInstance(CLSID_Point);
    ipPointsRing1[i].CreateInstance(CLSID_Point);
  }
  // Loop to change the coordinates of the points
  ISegmentCollectionPtr ipRingColl[2];
  ILinePtr ipLine0[4];
  ILinePtr ipLine1[4];
  ISegmentPtr ipSeg0[4];
  ISegmentPtr ipSeg1[4];
  IGeometryPtr ipGeometry[2];
  for (i=0; i < 1001; ++i)
  {
    ipRingColl[0].CreateInstance(CLSID_Ring);
    ipRingColl[1].CreateInstance(CLSID_Ring);
    // Lines are passed by reference to the polygon using ISegmentCollection
    // so a new line has to be instantiated to avoid the polygon to become degenerated
    for (j=0; j < 4; ++j)
    {
      ipLine0[j].CreateInstance(CLSID_Line);
      ipLine1[j].CreateInstance(CLSID_Line);
      // QI (Query interface) to make sure that we have the correct type of geometry
      // when passing these arrays to the addsegments.
      // If passing directly the lines array it will fatal VB. This is a known limit of VB.
      ipSeg0[j]=ipLine0[j];
      ipSeg1[j]=ipLine1[j];
    }
    ipGeometry[0]=ipRingColl[0];
    ipGeometry[1]=ipRingColl[1];
    d0X0 -= 5;
    d0Y0 -= 5;
    d0X1 += 5;
    d0Y1 -= 5;
    d0X2 += 5;
    d0Y2 += 5;
    d0X3 -= 5;
    d0Y3 += 5;
    // Put the coordinates of the points to use in the first ring
    ipPointsRing0[0]->PutCoords(d0X0, d0Y0);
    ipPointsRing0[1]->PutCoords(d0X1, d0Y1);
    ipPointsRing0[2]->PutCoords(d0X2, d0Y2);
    ipPointsRing0[3]->PutCoords(d0X3, d0Y3);

    d1X0 -= 5;
    d1Y0 -= 5;
    d1X1 -= 5;
    d1Y1 += 5;
    d1X2 += 5;
    d1Y2 += 5;
    d1X3 += 5;
    d1Y3 -= 5;
    // Put the coordinates of the points to use in the second ring
    ipPointsRing1[0]->PutCoords(d1X0, d1Y0);
    ipPointsRing1[1]->PutCoords(d1X1, d1Y1);
    ipPointsRing1[2]->PutCoords(d1X2, d1Y2);
    ipPointsRing1[3]->PutCoords(d1X3, d1Y3);
    // Put the coordinates of the lines
    ipLine0[0]->PutCoords(ipPointsRing0[0], ipPointsRing0[1]);
    ipLine0[1]->PutCoords(ipPointsRing0[1], ipPointsRing0[2]);
    ipLine0[2]->PutCoords(ipPointsRing0[2], ipPointsRing0[3]);
    ipLine0[3]->PutCoords(ipPointsRing0[3], ipPointsRing0[0]);

    ipLine1[0]->PutCoords(ipPointsRing1[0], ipPointsRing1[1]);
    ipLine1[1]->PutCoords(ipPointsRing1[1], ipPointsRing1[2]);
    ipLine1[2]->PutCoords(ipPointsRing1[2], ipPointsRing1[3]);
    ipLine1[3]->PutCoords(ipPointsRing1[3], ipPointsRing1[0]);
    // Add the segments to the rings
    for (j=0; j < 4; ++j)
    {
      ipRingColl[0]->AddSegment(ipSeg0[j]);
      ipRingColl[1]->AddSegment(ipSeg1[j]);
    }
    // Add the rings to the polygon
    for (j=0; j < 2; ++j)
    {
      ipGonColl->AddGeometry(ipGeometry[j]);
    }
  }
  // You can draw, store or use the polygon (ipGonColl) in other geometry operations at this point

  return S_OK;
}

//*************************************************************************
//* NAME : createMultipartPolygonRingPointCollection
//* DESCRIPTION : Create a multipart polygon using rings via IPointCollection.
//* This sub is demonstrating it by creating 1001
//* concentric square rings and add those to a polygon.
//*************************************************************************
HRESULT createMultipartPolygonRingPointCollection()
{
  // Create the resulting polygon
  IGeometryCollectionPtr ipGonColl(CLSID_Polygon);
  //*********************************************************
  // THE SPATIAL REFERENCE SHOULD BE SET HERE ON THE POLYGON
  // Here the spatial reference is created in memory but could also come from various sources:
  // IMap, IGeodataset, IGeometry etc...
  ISpatialReferencePtr ipspref(CLSID_UnknownCoordinateSystem);
  ipspref->SetFalseOriginAndUnits( - 10000,  - 10000, 100000); 
    // Set the false origin and units.
  // The XYUnits value is equivalent to the precision specified when creating a feature class
  IGeometryPtr ipGeoSpRef(ipGonColl);
  ipGeoSpRef->putref_SpatialReference(ipspref);
  // *********************************************************
  double d0X0=0, d0Y0=0, d0X1=0, d0Y1=0, d0X2=0, d0Y2=0, d0X3=0,
    d0Y3=0;
  double d1X0=10000, d1Y0=10000, d1X1=10000, d1Y1=10000, d1X2=10000,
    d1Y2=10000, d1X3=10000, d1Y3=10000;
  int i, j;
  IPointCollectionPtr ipRingsColl[2];
  IGeometryPtr ipGeometry[2];
  IPointPtr ipPointsRing0[5];
  IPointPtr ipPointsRing1[5];
  // Loop to change the coordinates of the points
  for (i=0; i < 1001; ++i)
  {
    ipRingsColl[0].CreateInstance(CLSID_Ring);
    ipRingsColl[1].CreateInstance(CLSID_Ring);
    //QI(Query Interface) to make sure that we have the correct type of geometry when passing this array to the addsegments
    ipGeometry[0]=ipRingsColl[0];
    ipGeometry[1]=ipRingsColl[1];
    // Create the new points
    for (j=0; j < 5; ++j)
    {
      ipPointsRing0[j].CreateInstance(CLSID_Point);
      ipPointsRing1[j].CreateInstance(CLSID_Point);
    }
    d0X0 -= 5;
    d0Y0 -= 5;
    d0X1 -= 5;
    d0Y1 += 5;
    d0X2 += 5;
    d0Y2 += 5;
    d0X3 += 5;
    d0Y3 -= 5;
    // Put the coordinates of the points to use in the first ring
    ipPointsRing0[0]->PutCoords(d0X0, d0Y0);
    ipPointsRing0[1]->PutCoords(d0X1, d0Y1);
    ipPointsRing0[2]->PutCoords(d0X2, d0Y2);
    ipPointsRing0[3]->PutCoords(d0X3, d0Y3);
    ipPointsRing0[4]->PutCoords(d0X0, d0Y0);
    // Add the points to the ring
    for (j=0; j < 5; ++j)
    {
      ipRingsColl[0]->AddPoint(ipPointsRing0[j]);
    }
    d1X0 -= 5;
    d1Y0 -= 5;
    d1X1 -= 5;
    d1Y1 += 5;
    d1X2 += 5;
    d1Y2 += 5;
    d1X3 += 5;
    d1Y3 -= 5;
    // Put the coordinates of the points to use in the second ring
    ipPointsRing1[0]->PutCoords(d1X0, d1Y0);
    ipPointsRing1[1]->PutCoords(d1X1, d1Y1);
    ipPointsRing1[2]->PutCoords(d1X2, d1Y2);
    ipPointsRing1[3]->PutCoords(d1X3, d1Y3);
    ipPointsRing1[4]->PutCoords(d1X0, d1Y0);
    // Add the points to the ring
    for (j=0; j < 5; ++j)
    {
      ipRingsColl[1]->AddPoint(ipPointsRing0[j]);
    }
    // Add the rings to the polygon
    for (j=0; j < 2; ++j)
    {
      ipGonColl->AddGeometry(ipGeometry[j]);
    }
  }

  // You can draw, store or use the polygon (ipGonColl) in other geometry operations at this point

  return S_OK;
}


//*************************************************************************
//* NAME : createSinglepartPolygonPointCollection
//* DESCRIPTION : Create a single part polygon via IPointCollection.
//*************************************************************************
HRESULT createSinglepartPolygonPointCollection()
{
  IPointCollectionPtr ipGonColl(CLSID_Polygon);
  ;
  //*********************************************************
  // THE SPATIAL REFERENCE SHOULD BE SET HERE ON THE POLYGON
  // Here the spatial reference is created in memory but could also come from various sources:
  // IMap, IGeodataset, IGeometry etc...
  ISpatialReferencePtr ipspref(CLSID_UnknownCoordinateSystem);
  ipspref->SetFalseOriginAndUnits( - 10000,  - 10000, 100000); 
    // Set the false origin and units.
  // The XYUnits value is equivalent to the precision specified when creating a feature class
  IGeometryPtr ipGeoSpRef(ipGonColl);
  ipGeoSpRef->putref_SpatialReference(ipspref);
  //*********************************************************
  int i;
  // Initialize the points
  IPointPtr ipPoint[5];
  for (i=0; i < 5; ++i)
  {
    ipPoint[i].CreateInstance(CLSID_Point);
  }
  ipPoint[0]->PutCoords(0, 0);
  ipPoint[1]->PutCoords(0, 10);
  ipPoint[2]->PutCoords(10, 10);
  ipPoint[3]->PutCoords(10, 0);
  ipPoint[4]->PutCoords(0, 0);
  // Add the points to the polygon
  for (i=0; i < 5; ++i)
  {
    ipGonColl->AddPoint(ipPoint[i]);
  }

  // You can draw, store or use the polygon (ipGonColl) in other geometry operations at this point

  return S_OK;
}

//*************************************************************************
//* NAME : createSinglepartPolygonSegmentCollection
//* DESCRIPTION : Create a single part polygon via ISegmentCollection.
//*************************************************************************
HRESULT createSinglepartPolygonSegmentCollection()
{
  ISegmentCollectionPtr ipGonColl(CLSID_Polygon);
  //*********************************************************
  // THE SPATIAL REFERENCE SHOULD BE SET HERE ON THE POLYGON
  // Here the spatial reference is created in memory but could also come from various sources:
  // IMap, IGeodataset, IGeometry etc...
  ISpatialReferencePtr ipspref(CLSID_UnknownCoordinateSystem);
  ipspref->SetFalseOriginAndUnits( - 10000,  - 10000, 100000); 
    // Set the false origin and units.
  // The XYUnits value is equivalent to the precision specified when creating a feature class
  IGeometryPtr ipGeoSpRef(ipGonColl);
  ipGeoSpRef->putref_SpatialReference(ipspref);
  //*********************************************************
  // Initialize things
  int i;
  ILinePtr ipLine[4];
  IPointPtr ipPoint[4];
  ISegmentPtr ipSegment[4];
  for (i=0; i < 4; ++i)
  {
    ipLine[i].CreateInstance(CLSID_Line);
    ipPoint[i].CreateInstance(CLSID_Point);
    ipSegment[i]=ipLine[i];
  }
  // Put the coordinates of the points
  ipPoint[0]->PutCoords(0, 0);
  ipPoint[1]->PutCoords(0, 10);
  ipPoint[2]->PutCoords(10, 10);
  ipPoint[3]->PutCoords(10, 0);
  // Put the coordinates of the line
  ipLine[0]->PutCoords(ipPoint[0], ipPoint[1]);
  ipLine[1]->PutCoords(ipPoint[1], ipPoint[2]);
  ipLine[2]->PutCoords(ipPoint[2], ipPoint[3]);
  ipLine[3]->PutCoords(ipPoint[3], ipPoint[0]);
  // Add the segments in the polygon via the ISegmentCollection
  for (i=0; i < 4; ++i)
  {
    ipGonColl->AddSegment(ipSegment[i]);
  }

  // You can draw or store the polygon (ipGonColl)

  return S_OK;
}

//*************************************************************************
//* NAME : CreateRectanglePolygonFromEnvelope
//* DESCRIPTION : Convert an envelope to a polygon via ISegmentCollection
//*************************************************************************
HRESULT CreateRectanglePolygonFromEnvelope()
{
  IEnvelopePtr ipEnvelope(CLSID_Envelope);
  //*********************************************************
  // THE SPATIAL REFERENCE SHOULD BE SET HERE ON THE ENVELOPE
  // Here the spatial reference is created in memory but could also come from various sources:
  // IMap, IGeodataset, IGeometry etc...
  ISpatialReferencePtr ipspref(CLSID_UnknownCoordinateSystem);
  ipspref->SetFalseOriginAndUnits( - 10000,  - 10000, 100000); 
    // Set the false origin and units.
  // The XYUnits value is equivalent to the precision specified when creating a feature class
  ipEnvelope->putref_SpatialReference(ipspref);
  //*********************************************************
  ipEnvelope->PutCoords(0, 0, 100, 100);
  ISegmentCollectionPtr ipSegmentColl(CLSID_Polygon);
  ipSegmentColl->SetRectangle(ipEnvelope); 
    // This is transferring the spatial reference

  //You can draw or store the polygon (ipSegmentColl)

  return S_OK;
}






Development licensing Deployment licensing
Engine Developer Kit Engine