Пример #1
0
Polygon::Polygon()
    : m_geom(0)
    , m_prepGeom(0)
    , m_ctx(pdal::GlobalEnvironment::get().geos().ctx)
{
    m_geom = GEOSGeom_createEmptyPolygon_r(m_ctx);
}
Пример #2
0
 void object::test<3>()
 {
     geom1_ = GEOSGeom_createEmptyPolygon_r(handle_);
     ensure(0 != GEOSisEmpty_r(handle_, geom1_));
     ensure_equals(GEOSGeomTypeId_r(handle_, geom1_), GEOS_POLYGON);
     GEOSGeom_destroy(geom1_); geom1_=0;
 }
Пример #3
0
// Will return NULL on error (expect error handler being called by then)
Q_NOWARN_UNREACHABLE_PUSH
static GEOSGeometry *LWGEOM_GEOS_makeValidPolygon( const GEOSGeometry *gin, QString &errorMessage )
{
  GEOSContextHandle_t handle = QgsGeos::getGEOSHandler();

  GEOSGeom gout;
  GEOSGeom geos_bound;
  GEOSGeom geos_cut_edges, geos_area, collapse_points;
  GEOSGeometry *vgeoms[3]; // One for area, one for cut-edges
  unsigned int nvgeoms = 0;

  Q_ASSERT( GEOSGeomTypeId_r( handle, gin ) == GEOS_POLYGON ||
            GEOSGeomTypeId_r( handle, gin ) == GEOS_MULTIPOLYGON );

  geos_bound = GEOSBoundary_r( handle, gin );
  if ( !geos_bound )
    return nullptr;

  // Use noded boundaries as initial "cut" edges

  geos_cut_edges = LWGEOM_GEOS_nodeLines( geos_bound );
  if ( !geos_cut_edges )
  {
    GEOSGeom_destroy_r( handle, geos_bound );
    errorMessage = QStringLiteral( "LWGEOM_GEOS_nodeLines() failed" );
    return nullptr;
  }

  // NOTE: the noding process may drop lines collapsing to points.
  //       We want to retrieve any of those
  {
    GEOSGeometry *pi = nullptr;
    GEOSGeometry *po = nullptr;

    try
    {
      pi = GEOSGeom_extractUniquePoints_r( handle, geos_bound );
    }
    catch ( GEOSException &e )
    {
      GEOSGeom_destroy_r( handle, geos_bound );
      errorMessage = QStringLiteral( "GEOSGeom_extractUniquePoints(): %1" ).arg( e.what() );
      return nullptr;
    }

    try
    {
      po = GEOSGeom_extractUniquePoints_r( handle, geos_cut_edges );
    }
    catch ( GEOSException &e )
    {
      GEOSGeom_destroy_r( handle, geos_bound );
      GEOSGeom_destroy_r( handle, pi );
      errorMessage = QStringLiteral( "GEOSGeom_extractUniquePoints(): %1" ).arg( e.what() );
      return nullptr;
    }

    try
    {
      collapse_points = GEOSDifference_r( handle, pi, po );
    }
    catch ( GEOSException &e )
    {
      GEOSGeom_destroy_r( handle, geos_bound );
      GEOSGeom_destroy_r( handle, pi );
      GEOSGeom_destroy_r( handle, po );
      errorMessage = QStringLiteral( "GEOSDifference(): %1" ).arg( e.what() );
      return nullptr;
    }

    GEOSGeom_destroy_r( handle, pi );
    GEOSGeom_destroy_r( handle, po );
  }
  GEOSGeom_destroy_r( handle, geos_bound );

  // And use an empty geometry as initial "area"
  try
  {
    geos_area = GEOSGeom_createEmptyPolygon_r( handle );
  }
  catch ( GEOSException &e )
  {
    errorMessage = QStringLiteral( "GEOSGeom_createEmptyPolygon(): %1" ).arg( e.what() );
    GEOSGeom_destroy_r( handle, geos_cut_edges );
    return nullptr;
  }

  // See if an area can be build with the remaining edges
  // and if it can, symdifference with the original area.
  // Iterate this until no more polygons can be created
  // with left-over edges.
  while ( GEOSGetNumGeometries_r( handle, geos_cut_edges ) )
  {
    GEOSGeometry *new_area = nullptr;
    GEOSGeometry *new_area_bound = nullptr;
    GEOSGeometry *symdif = nullptr;
    GEOSGeometry *new_cut_edges = nullptr;

    // ASSUMPTION: cut_edges should already be fully noded

    try
    {
      new_area = LWGEOM_GEOS_buildArea( geos_cut_edges, errorMessage );
    }
    catch ( GEOSException &e )
    {
      GEOSGeom_destroy_r( handle, geos_cut_edges );
      GEOSGeom_destroy_r( handle, geos_area );
      errorMessage = QStringLiteral( "LWGEOM_GEOS_buildArea() threw an error: %1" ).arg( e.what() );
      return nullptr;
    }

    if ( GEOSisEmpty_r( handle, new_area ) )
    {
      // no more rings can be build with thes edges
      GEOSGeom_destroy_r( handle, new_area );
      break;
    }

    // We succeeded in building a ring !

    // Save the new ring boundaries first (to compute
    // further cut edges later)
    try
    {
      new_area_bound = GEOSBoundary_r( handle, new_area );
    }
    catch ( GEOSException &e )
    {
      // We did check for empty area already so
      // this must be some other error
      errorMessage = QStringLiteral( "GEOSBoundary() threw an error: %1" ).arg( e.what() );
      GEOSGeom_destroy_r( handle, new_area );
      GEOSGeom_destroy_r( handle, geos_area );
      return nullptr;
    }

    // Now symdiff new and old area
    try
    {
      symdif = GEOSSymDifference_r( handle, geos_area, new_area );
    }
    catch ( GEOSException &e )
    {
      GEOSGeom_destroy_r( handle, geos_cut_edges );
      GEOSGeom_destroy_r( handle, new_area );
      GEOSGeom_destroy_r( handle, new_area_bound );
      GEOSGeom_destroy_r( handle, geos_area );
      errorMessage = QStringLiteral( "GEOSSymDifference() threw an error: %1" ).arg( e.what() );
      return nullptr;
    }

    GEOSGeom_destroy_r( handle, geos_area );
    GEOSGeom_destroy_r( handle, new_area );
    geos_area = symdif;
    symdif = nullptr;

    // Now let's re-set geos_cut_edges with what's left
    // from the original boundary.
    // ASSUMPTION: only the previous cut-edges can be
    //             left, so we don't need to reconsider
    //             the whole original boundaries
    //
    // NOTE: this is an expensive operation.

    try
    {
      new_cut_edges = GEOSDifference_r( handle, geos_cut_edges, new_area_bound );
    }
    catch ( GEOSException &e )
    {
      GEOSGeom_destroy_r( handle, geos_cut_edges );
      GEOSGeom_destroy_r( handle, new_area_bound );
      GEOSGeom_destroy_r( handle, geos_area );
      errorMessage = QStringLiteral( "GEOSDifference() threw an error: %1" ).arg( e.what() );
      return nullptr;
    }
    GEOSGeom_destroy_r( handle, geos_cut_edges );
    GEOSGeom_destroy_r( handle, new_area_bound );
    geos_cut_edges = new_cut_edges;
  }

  if ( !GEOSisEmpty_r( handle, geos_area ) )
  {
    vgeoms[nvgeoms++] = geos_area;
  }
  else
  {
    GEOSGeom_destroy_r( handle, geos_area );
  }

  if ( !GEOSisEmpty_r( handle, geos_cut_edges ) )
  {
    vgeoms[nvgeoms++] = geos_cut_edges;
  }
  else
  {
    GEOSGeom_destroy_r( handle, geos_cut_edges );
  }

  if ( !GEOSisEmpty_r( handle, collapse_points ) )
  {
    vgeoms[nvgeoms++] = collapse_points;
  }
  else
  {
    GEOSGeom_destroy_r( handle, collapse_points );
  }

  if ( 1 == nvgeoms )
  {
    // Return cut edges
    gout = vgeoms[0];
  }
  else
  {
    // Collect areas and lines (if any line)
    try
    {
      gout = GEOSGeom_createCollection_r( handle, GEOS_GEOMETRYCOLLECTION, vgeoms, nvgeoms );
    }
    catch ( GEOSException &e )
    {
      errorMessage = QStringLiteral( "GEOSGeom_createCollection() threw an error: %1" ).arg( e.what() );
      // TODO: cleanup!
      return nullptr;
    }
  }

  return gout;

}