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