static POINTARRAY * ptarray_set_effective_area(POINTARRAY *inpts,int avoid_collaps,int set_area, double trshld) { LWDEBUG(2, "Entered ptarray_set_effective_area"); int p; POINT4D pt; EFFECTIVE_AREAS *ea; POINTARRAY *opts; int set_m; if(set_area) set_m=1; else set_m=FLAGS_GET_M(inpts->flags); ea=initiate_effectivearea(inpts); opts = ptarray_construct_empty(FLAGS_GET_Z(inpts->flags), set_m, inpts->npoints); ptarray_calc_areas(ea,avoid_collaps,set_area,trshld); if(set_area) { /*Only return points with an effective area above the threashold*/ for (p=0;p<ea->inpts->npoints;p++) { if(ea->res_arealist[p]>=trshld) { pt=getPoint4d(ea->inpts, p); pt.m=ea->res_arealist[p]; ptarray_append_point(opts, &pt, LW_TRUE); } } } else { /*Only return points with an effective area above the threashold*/ for (p=0;p<ea->inpts->npoints;p++) { if(ea->res_arealist[p]>=trshld) { pt=getPoint4d(ea->inpts, p); ptarray_append_point(opts, &pt, LW_TRUE); } } } destroy_effectivearea(ea); return opts; }
static void do_test_lwgeom_effectivearea(POINTARRAY *pa,double *the_areas,int avoid_collaps) { int i; EFFECTIVE_AREAS *ea; ea=initiate_effectivearea(pa); ptarray_calc_areas(ea,avoid_collaps,1,0); for (i=0;i<pa->npoints;i++) { CU_ASSERT_EQUAL(ea->res_arealist[i],the_areas[i]); } destroy_effectivearea(ea); }
//! Simplify the WKB-geometry using the specified tolerance QgsGeometry QgsMapToPixelSimplifier::simplifyGeometry( int simplifyFlags, SimplifyAlgorithm simplifyAlgorithm, QgsWkbTypes::Type wkbType, const QgsAbstractGeometry& geometry, const QgsRectangle &envelope, double map2pixelTol, bool isaLinearRing ) { bool isGeneralizable = true; // Can replace the geometry by its BBOX ? if (( simplifyFlags & QgsMapToPixelSimplifier::SimplifyEnvelope ) && isGeneralizableByMapBoundingBox( envelope, map2pixelTol ) ) { return generalizeWkbGeometryByBoundingBox( wkbType, geometry, envelope ); } if ( !( simplifyFlags & QgsMapToPixelSimplifier::SimplifyGeometry ) ) isGeneralizable = false; const QgsWkbTypes::Type flatType = QgsWkbTypes::flatType( wkbType ); // Write the geometry if ( flatType == QgsWkbTypes::LineString || flatType == QgsWkbTypes::CircularString ) { const QgsCurve& srcCurve = dynamic_cast<const QgsCurve&>( geometry ); QScopedPointer<QgsCurve> output( createEmptySameTypeGeom( srcCurve ) ); double x = 0.0, y = 0.0, lastX = 0.0, lastY = 0.0; QgsRectangle r; r.setMinimal(); const int numPoints = srcCurve.numPoints(); if ( numPoints <= ( isaLinearRing ? 4 : 2 ) ) isGeneralizable = false; bool isLongSegment; bool hasLongSegments = false; //-> To avoid replace the simplified geometry by its BBOX when there are 'long' segments. // Check whether the LinearRing is really closed. if ( isaLinearRing ) { isaLinearRing = qgsDoubleNear( srcCurve.xAt( 0 ), srcCurve.xAt( numPoints - 1 ) ) && qgsDoubleNear( srcCurve.yAt( 0 ), srcCurve.yAt( numPoints - 1 ) ); } // Process each vertex... switch ( simplifyAlgorithm ) { case SnapToGrid: { double gridOriginX = envelope.xMinimum(); double gridOriginY = envelope.yMinimum(); // Use a factor for the maximum displacement distance for simplification, similar as GeoServer does float gridInverseSizeXY = map2pixelTol != 0 ? ( float )( 1.0f / ( 0.8 * map2pixelTol ) ) : 0.0f; for ( int i = 0; i < numPoints; ++i ) { x = srcCurve.xAt( i ); y = srcCurve.yAt( i ); if ( i == 0 || !isGeneralizable || !equalSnapToGrid( x, y, lastX, lastY, gridOriginX, gridOriginY, gridInverseSizeXY ) || ( !isaLinearRing && ( i == 1 || i >= numPoints - 2 ) ) ) { output->insertVertex( QgsVertexId( 0, 0, output->numPoints() ), QgsPointV2( x, y ) ); lastX = x; lastY = y; } r.combineExtentWith( x, y ); } break; } case Visvalingam: { map2pixelTol *= map2pixelTol; //-> Use mappixelTol for 'Area' calculations. EFFECTIVE_AREAS ea( srcCurve ); int set_area = 0; ptarray_calc_areas( &ea, isaLinearRing ? 4 : 2, set_area, map2pixelTol ); for ( int i = 0; i < numPoints; ++i ) { if ( ea.res_arealist[ i ] > map2pixelTol ) { output->insertVertex( QgsVertexId( 0, 0, output->numPoints() ), ea.inpts.at( i ) ); } } break; } case Distance: { map2pixelTol *= map2pixelTol; //-> Use mappixelTol for 'LengthSquare' calculations. for ( int i = 0; i < numPoints; ++i ) { x = srcCurve.xAt( i ); y = srcCurve.yAt( i ); isLongSegment = false; if ( i == 0 || !isGeneralizable || ( isLongSegment = ( calculateLengthSquared2D( x, y, lastX, lastY ) > map2pixelTol ) ) || ( !isaLinearRing && ( i == 1 || i >= numPoints - 2 ) ) ) { output->insertVertex( QgsVertexId( 0, 0, output->numPoints() ), QgsPointV2( x, y ) ); lastX = x; lastY = y; hasLongSegments |= isLongSegment; } r.combineExtentWith( x, y ); } } } if ( output->numPoints() < ( isaLinearRing ? 4 : 2 ) ) { // we simplified the geometry too much! if ( !hasLongSegments ) { // approximate the geometry's shape by its bounding box // (rect for linear ring / one segment for line string) return generalizeWkbGeometryByBoundingBox( wkbType, geometry, r ); } else { // Bad luck! The simplified geometry is invalid and approximation by bounding box // would create artifacts due to long segments. // We will return the original geometry return QgsGeometry( geometry.clone() ); } } if ( isaLinearRing ) { // make sure we keep the linear ring closed if ( !qgsDoubleNear( lastX, output->xAt( 0 ) ) || !qgsDoubleNear( lastY, output->yAt( 0 ) ) ) { output->insertVertex( QgsVertexId( 0, 0, output->numPoints() ), QgsPointV2( output->xAt( 0 ), output->yAt( 0 ) ) ); } } return QgsGeometry( output.take() ); } else if ( flatType == QgsWkbTypes::Polygon ) { const QgsPolygonV2& srcPolygon = dynamic_cast<const QgsPolygonV2&>( geometry ); QScopedPointer<QgsPolygonV2> polygon( new QgsPolygonV2() ); polygon->setExteriorRing( dynamic_cast<QgsCurve*>( simplifyGeometry( simplifyFlags, simplifyAlgorithm, srcPolygon.exteriorRing()->wkbType(), *srcPolygon.exteriorRing(), envelope, map2pixelTol, true ).geometry()->clone() ) ); for ( int i = 0; i < srcPolygon.numInteriorRings(); ++i ) { const QgsCurve* sub = srcPolygon.interiorRing( i ); polygon->addInteriorRing( dynamic_cast<QgsCurve*>( simplifyGeometry( simplifyFlags, simplifyAlgorithm, sub->wkbType(), *sub, envelope, map2pixelTol, true ).geometry()->clone() ) ); } return QgsGeometry( polygon.take() ); } else if ( QgsWkbTypes::isMultiType( flatType ) ) { const QgsGeometryCollection& srcCollection = dynamic_cast<const QgsGeometryCollection&>( geometry ); QScopedPointer<QgsGeometryCollection> collection( createEmptySameTypeGeom( srcCollection ) ); const int numGeoms = srcCollection.numGeometries(); for ( int i = 0; i < numGeoms; ++i ) { const QgsAbstractGeometry* sub = srcCollection.geometryN( i ); collection->addGeometry( simplifyGeometry( simplifyFlags, simplifyAlgorithm, sub->wkbType(), *sub, envelope, map2pixelTol, false ).geometry()->clone() ); } return QgsGeometry( collection.take() ); } return QgsGeometry( geometry.clone() ); }