51 ,
type( GEOS_POLYGON )
96 mGeos = GEOSGeom_clone_r( QgsGeosContext::get(), ps.mGeos );
105 bool needClose =
false;
111 GEOSCoordSequence *coord =
nullptr;
112#if GEOS_VERSION_MAJOR > 3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR >= 10 )
116 coord = GEOSCoordSeq_copyFromArrays_r( geosctxt,
x.data(),
y.data(),
nullptr,
nullptr,
nbPoints );
125 coord = GEOSCoordSeq_create_r( geosctxt,
nbPoints + ( needClose ? 1 : 0 ), 2 );
126 for (
int i = 0; i <
nbPoints; ++i )
128 GEOSCoordSeq_setXY_r( geosctxt, coord, i,
x[i],
y[i] );
134 GEOSCoordSeq_setXY_r( geosctxt, coord,
nbPoints,
x[0],
y[0] );
141 mGeos = GEOSGeom_createPolygon_r( geosctxt, GEOSGeom_createLinearRing_r( geosctxt, coord ),
nullptr, 0 );
144 case GEOS_LINESTRING:
145 mGeos = GEOSGeom_createLineString_r( geosctxt, coord );
149 mGeos = GEOSGeom_createPoint_r( geosctxt, coord );
161 if ( !mPreparedGeom )
165 return mPreparedGeom;
172 GEOSGeom_destroy_r( geosctxt,
mGeos );
178 GEOSPreparedGeom_destroy_r( geosctxt, mPreparedGeom );
179 mPreparedGeom =
nullptr;
182 if ( mGeosPreparedBoundary )
184 GEOSPreparedGeom_destroy_r( geosctxt, mGeosPreparedBoundary );
185 mGeosPreparedBoundary =
nullptr;
188 if ( mMultipartPreparedGeos )
190 GEOSPreparedGeom_destroy_r( geosctxt, mMultipartPreparedGeos );
191 mMultipartPreparedGeos =
nullptr;
193 if ( mMultipartGeos )
195 GEOSGeom_destroy_r( geosctxt, mMultipartGeos );
196 mMultipartGeos =
nullptr;
209 GEOSGeom_destroy_r( geosctxt,
mGeos );
212 GEOSPreparedGeom_destroy_r( geosctxt, mPreparedGeom );
214 if ( mGeosPreparedBoundary )
216 GEOSPreparedGeom_destroy_r( geosctxt, mGeosPreparedBoundary );
217 mGeosPreparedBoundary =
nullptr;
220 if ( mMultipartPreparedGeos )
222 GEOSPreparedGeom_destroy_r( geosctxt, mMultipartPreparedGeos );
223 mMultipartPreparedGeos =
nullptr;
225 if ( mMultipartGeos )
227 GEOSGeom_destroy_r( geosctxt, mMultipartGeos );
228 mMultipartGeos =
nullptr;
240std::unique_ptr<PointSet>
PointSet::extractShape(
int nbPtSh,
int imin,
int imax,
int fps,
int fpe,
double fptx,
double fpty )
244 auto newShape = std::make_unique< PointSet >();
245 newShape->type = GEOS_POLYGON;
246 newShape->nbPoints = nbPtSh;
247 newShape->x.resize( newShape->nbPoints );
248 newShape->y.resize( newShape->nbPoints );
251 for ( j = 0, i = imin; i != ( imax + 1 ) %
nbPoints; i = ( i + 1 ) %
nbPoints, j++ )
253 newShape->x[j] =
x[i];
254 newShape->y[j] =
y[i];
260 newShape->x[j] = fptx;
261 newShape->y[j] = fpty;
269 return std::unique_ptr< PointSet>(
new PointSet( *
this ) );
278 const bool result = ( GEOSPreparedContainsProperly_r( geosctxt,
preparedGeom(), point.get() ) == 1 );
282 catch ( QgsGeosException &e )
284 qWarning(
"GEOS exception: %s", e.what() );
308 const double labelArea = labelWidth * labelHeight;
310 QVector<PointSet *> inputShapes;
311 inputShapes.push_back( inputShape );
312 QVector<PointSet *> outputShapes;
314 while ( !inputShapes.isEmpty() )
316 PointSet *shape = inputShapes.takeFirst();
318 const std::vector< double > &
x = shape->
x;
319 const std::vector< double > &
y = shape->
y;
321 std::vector< int > pts( nbp );
322 for (
int i = 0; i < nbp; i++ )
334 for ( std::size_t ihs = 0; ihs < shape->
convexHull.size(); ihs++ )
337 const std::size_t ihn = ( ihs + 1 ) % shape->
convexHull.size();
340 const int ipn = ( ips + 1 ) % nbp;
346 for (
int i = ips; i != shape->
convexHull[ihn]; i = ( i + 1 ) % nbp )
365 const double s = ( base + b +
c ) / 2;
366 double area = s * ( s - base ) * ( s - b ) * ( s -
c );
388 bestArea = std::sqrt( bestArea );
389 double cx, cy, dx, dy, ex, ey, fx, fy, seg_length, ptx = 0, pty = 0, fptx = 0, fpty = 0;
390 int ps = -1, pe = -1, fps = -1, fpe = -1;
391 if ( retainedPt >= 0 && bestArea > labelArea )
393 double c = std::numeric_limits<double>::max();
398 for (
int i = ( shape->
convexHull[holeE] + 1 ) % nbp; i != ( shape->
convexHull[holeS] - 1 + nbp ) % nbp; i = j )
406 cx = (
x[i] +
x[j] ) / 2.0;
407 cy = (
y[i] +
y[j] ) / 2.0;
446 double pointX, pointY;
469 if ( isValid && b <
c )
480 const int imin = retainedPt;
481 int imax = ( ( ( fps < retainedPt && fpe < retainedPt ) || ( fps > retainedPt && fpe > retainedPt ) ) ? std::min( fps, fpe ) : std::max( fps, fpe ) );
483 int nbPtSh1, nbPtSh2;
485 nbPtSh1 = imax - imin + 1 + ( fpe != fps );
487 nbPtSh1 = imax + nbp - imin + 1 + ( fpe != fps );
489 if ( ( imax == fps ? fpe : fps ) < imin )
490 nbPtSh2 = imin - ( imax == fps ? fpe : fps ) + 1 + ( fpe != fps );
492 nbPtSh2 = imin + nbp - ( imax == fps ? fpe : fps ) + 1 + ( fpe != fps );
494 if ( retainedPt == -1 || fps == -1 || fpe == -1 )
500 else if ( imax == imin || nbPtSh1 <= 2 || nbPtSh2 <= 2 || nbPtSh1 == nbp || nbPtSh2 == nbp )
502 outputShapes.append( shape );
506 PointSet *newShape = shape->
extractShape( nbPtSh1, imin, imax, fps, fpe, fptx, fpty ).release();
513 inputShapes.append( newShape );
520 newShape = shape->
extractShape( nbPtSh2, imax, imin, fps, fpe, fptx, fpty ).release();
527 inputShapes.append( newShape );
535 outputShapes.append( shape );
553 newGeos.reset( GEOSOffsetCurve_r( geosctxt,
mGeos, distance, 0, GEOSBUF_JOIN_MITRE, 2 ) );
558 if ( GEOSGeomTypeId_r( geosctxt, newGeos.get() ) == GEOS_MULTILINESTRING )
561 const int nParts = GEOSGetNumGeometries_r( geosctxt, newGeos.get() );
562 double maximumLength = -1;
564 for (
int i = 0; i < nParts; ++i )
566 const GEOSGeometry *part = GEOSGetGeometryN_r( geosctxt, newGeos.get(), i );
567 double partLength = -1;
568 if ( GEOSLength_r( geosctxt, part, &partLength ) == 1 )
570 if ( partLength > maximumLength )
572 maximumLength = partLength;
584 geos::unique_ptr longestPartClone( GEOSGeom_clone_r( geosctxt, longestPart ) );
585 newGeos = std::move( longestPartClone );
588#if GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR < 11
596 newGeos = std::move( reversed );
600 const int newNbPoints = GEOSGeomGetNumPoints_r( geosctxt, newGeos.get() );
601 const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosctxt, newGeos.get() );
602 std::vector< double > newX;
603 std::vector< double > newY;
604 newX.resize( newNbPoints );
605 newY.resize( newNbPoints );
606 for (
int i = 0; i < newNbPoints; i++ )
608 GEOSCoordSeq_getX_r( geosctxt, coordSeq, i, &newX[i] );
609 GEOSCoordSeq_getY_r( geosctxt, coordSeq, i, &newY[i] );
612 x = std::move( newX );
613 y = std::move( newY );
615 catch ( QgsGeosException &e )
617 qWarning(
"GEOS exception: %s", e.what() );
623 mGeos = newGeos.release();
634 if ( startDistance > 0 )
640 double distanceConsumed = 0;
643 for (
int i = 1; i <
nbPoints; ++i )
645 const double thisX =
x[i];
646 const double thisY =
y[i];
648 distanceConsumed += thisSegmentLength;
649 if ( distanceConsumed >= smoothDistance )
651 const double c = ( distanceConsumed - smoothDistance ) / thisSegmentLength;
652 x1 = lastX +
c * ( thisX - lastX );
653 y1 = lastY +
c * ( thisY - lastY );
661 const double extensionFactor = ( startDistance + distance ) / distance;
668 if ( endDistance > 0 )
676 double distanceConsumed = 0;
679 for (
int i =
nbPoints - 2; i >= 0; --i )
681 const double thisX =
x[i];
682 const double thisY =
y[i];
684 distanceConsumed += thisSegmentLength;
685 if ( distanceConsumed >= smoothDistance )
687 const double c = ( distanceConsumed - smoothDistance ) / thisSegmentLength;
688 xend1 = lastX +
c * ( thisX - lastX );
689 yend1 = lastY +
c * ( thisY - lastY );
697 const double extensionFactor = ( endDistance + distance ) / distance;
699 x.emplace_back( newEnd.
x() );
700 y.emplace_back( newEnd.
y() );
704 if ( startDistance > 0 )
706 x.insert(
x.begin(), x0 );
707 y.insert(
y.begin(), y0 );
728 double best_area = std::numeric_limits<double>::max();
729 double best_alpha = -1;
731 double best_length = 0;
732 double best_width = 0;
735 bbox[0] = std::numeric_limits<double>::max();
736 bbox[1] = std::numeric_limits<double>::max();
737 bbox[2] = std::numeric_limits<double>::lowest();
738 bbox[3] = std::numeric_limits<double>::lowest();
740 for ( std::size_t i = 0; i <
convexHull.size(); i++ )
757 const double dref = bbox[2] - bbox[0];
764 for ( alpha_d = 0; alpha_d < 90; alpha_d++ )
766 alpha = alpha_d * M_PI / 180.0;
767 d1 = std::cos( alpha ) * dref;
768 d2 = std::sin( alpha ) * dref;
789 bb[14] = bb[12] + d2;
790 bb[15] = bb[13] - d1;
793 for (
int i = 0; i < 16; i += 4 )
795 alpha_seg = ( ( i / 4 > 0 ? ( i / 4 ) - 1 : 3 ) ) * M_PI_2 + alpha;
797 double best_cp = std::numeric_limits<double>::max();
799 for ( std::size_t j = 0; j <
convexHull.size(); j++ )
808 const double distNearestPoint = best_cp / dref;
810 d1 = std::cos( alpha_seg ) * distNearestPoint;
811 d2 = std::sin( alpha_seg ) * distNearestPoint;
835 memcpy( best_bb, bb,
sizeof(
double ) * 16 );
840 for (
int i = 0; i < 16; i = i + 4 )
847 best_bb[( i + 4 ) % 16],
848 best_bb[( i + 5 ) % 16],
849 best_bb[( i + 6 ) % 16],
850 best_bb[( i + 7 ) % 16],
851 &finalBb.
x[
int( i / 4 )],
852 &finalBb.
y[
int( i / 4 )]
856 finalBb.
alpha = best_alpha;
857 finalBb.
width = best_width;
858 finalBb.
length = best_length;
875 geos::unique_ptr geosPt( GEOSGeom_createPointFromXY_r( geosctxt, px, py ) );
876 const int type = GEOSGeomTypeId_r( geosctxt,
mGeos );
878 const GEOSPreparedGeometry *preparedExtRing =
nullptr;
880 if (
type != GEOS_POLYGON )
888 extRing = GEOSGetExteriorRing_r( geosctxt,
mGeos );
889 if ( !mGeosPreparedBoundary )
891 mGeosPreparedBoundary = GEOSPrepare_r( geosctxt, extRing );
893 preparedExtRing = mGeosPreparedBoundary;
899 unsigned int nPoints = 0;
900 GEOSCoordSeq_getSize_r( geosctxt, nearestCoord.get(), &nPoints );
904 ( void ) GEOSCoordSeq_getXY_r( geosctxt, nearestCoord.get(), 0, &nx, &ny );
913 catch ( QgsGeosException &e )
915 qWarning(
"GEOS exception: %s", e.what() );
935 const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosctxt, centroidGeom.get() );
936 unsigned int nPoints = 0;
937 GEOSCoordSeq_getSize_r( geosctxt, coordSeq, &nPoints );
940 GEOSCoordSeq_getXY_r( geosctxt, coordSeq, 0, &px, &py );
950 const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosctxt, pointGeom.get() );
951 unsigned int nPoints = 0;
952 GEOSCoordSeq_getSize_r( geosctxt, coordSeq, &nPoints );
956 GEOSCoordSeq_getXY_r( geosctxt, coordSeq, 0, &px, &py );
960 catch ( QgsGeosException &e )
962 qWarning(
"GEOS exception: %s", e.what() );
988 while ( i <
nbPoints && ad[i] <= dl )
999 di = std::sqrt( dx * dx + dy * dy );
1003 dx =
x[i + 1] -
x[i];
1004 dy =
y[i + 1] -
y[i];
1009 *px =
x[i] + dx * distr / di;
1010 *py =
y[i] + dy * distr / di;
1030 catch ( QgsGeosException &e )
1032 qWarning(
"GEOS exception: %s", e.what() );
1043 double distance = -1;
1048 catch ( QgsGeosException &e )
1050 qWarning(
"GEOS exception: %s", e.what() );
1083 catch ( QgsGeosException &e )
1085 qWarning(
"GEOS exception: %s", e.what() );
1106 ( void ) GEOSArea_r( geosctxt,
mGeos, &
mArea );
1110 catch ( QgsGeosException &e )
1112 qWarning(
"GEOS exception: %s", e.what() );
1132 GEOSWKTWriter *writer = GEOSWKTWriter_create_r( geosctxt );
1134 char *wkt = GEOSWKTWriter_write_r( geosctxt, writer,
mGeos );
1135 const QString res( wkt );
1137 GEOSFree_r( geosctxt, wkt );
1139 GEOSWKTWriter_destroy_r( geosctxt, writer );
1144 catch ( QgsGeosException &e )
1146 qWarning(
"GEOS exception: %s", e.what() );
1154 std::vector< double > distances(
nbPoints );
1155 double totalDistance = 0;
1156 double oldX = -1.0, oldY = -1.0;
1157 for (
int i = 0; i <
nbPoints; i++ )
1162 distances[i] = std::sqrt( std::pow( oldX -
x[i], 2 ) + std::pow( oldY -
y[i], 2 ) );
1166 totalDistance += distances[i];
1168 return std::make_tuple( std::move( distances ), totalDistance );
static double sqrDistance2D(double x1, double y1, double x2, double y2)
Returns the squared 2D distance between (x1, y1) and (x2, y2).
static double distance2D(double x1, double y1, double x2, double y2)
Returns the 2D distance between (x1, y1) and (x2, y2).
static QgsPointXY interpolatePointOnLine(double x1, double y1, double x2, double y2, double fraction)
Interpolates the position of a point a fraction of the way along the line from (x1,...
static GEOSContextHandle_t get()
Returns a thread local instance of a GEOS context, safe for use in the current thread.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
static std::vector< int > convexHullId(std::vector< int > &id, const std::vector< double > &x, const std::vector< double > &y)
Compute the convex hull in O(n·log(n)).
static bool computeLineIntersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double *x, double *y)
Compute the point where two lines intersect.
static bool isSegIntersects(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
Returns true if the two segments intersect.
static double cross_product(double x1, double y1, double x2, double y2, double x3, double y3)
static bool containsCandidate(const GEOSPreparedGeometry *geom, double x, double y, double width, double height, double alpha)
Returns true if a GEOS prepared geometry totally contains a label candidate.
geos::unique_ptr interpolatePoint(double distance) const
Returns a GEOS geometry representing the point interpolated on the shape by distance.
std::unique_ptr< PointSet > clone() const
Returns a copy of the point set.
bool containsLabelCandidate(double x, double y, double width, double height, double alpha=0) const
Tests whether a possible label candidate will fit completely within the shape.
double lineLocatePoint(const GEOSGeometry *point) const
Returns the distance along the geometry closest to the specified GEOS point.
double length() const
Returns length of line geometry.
void extendLineByDistance(double startDistance, double endDistance, double smoothDistance)
Extends linestrings by the specified amount at the start and end of the line, by extending the existi...
double area() const
Returns area of polygon geometry.
bool isClosed() const
Returns true if pointset is closed.
static QVector< PointSet * > splitPolygons(PointSet *inputShape, double labelWidth, double labelHeight)
Split a polygon using some random logic into some other polygons.
void createGeosGeom() const
void getPointByDistance(double *d, double *ad, double dl, double *px, double *py) const
Gets a point a set distance along a line geometry.
bool boundingBoxIntersects(const PointSet *other) const
Returns true if the bounding box of this pointset intersects the bounding box of another pointset.
void getCentroid(double &px, double &py, bool forceInside=false) const
OrientedConvexHullBoundingBox computeConvexHullOrientedBoundingBox(bool &ok) const
Computes an oriented bounding box for the shape's convex hull.
void offsetCurveByDistance(double distance)
Offsets linestrings by the specified distance.
std::vector< int > convexHull
const GEOSPreparedGeometry * preparedGeom() const
QString toWkt() const
Returns a WKT representation of the point set.
const GEOSGeometry * geos() const
Returns the point set's GEOS geometry.
void invalidateGeos() const
double minDistanceToPoint(double px, double py, double *rx=nullptr, double *ry=nullptr) const
Returns the squared minimum distance between the point set geometry and the point (px,...
std::unique_ptr< PointSet > extractShape(int nbPtSh, int imin, int imax, int fps, int fpe, double fptx, double fpty)
Does... something completely inscrutable.
bool containsPoint(double x, double y) const
Tests whether point set contains a specified point.
std::tuple< std::vector< double >, double > edgeDistances() const
Returns a vector of edge distances as well as its total length.
std::unique_ptr< GEOSGeometry, GeosDeleter > unique_ptr
Scoped GEOS pointer.
std::unique_ptr< GEOSCoordSequence, GeosDeleter > coord_sequence_unique_ptr
Scoped GEOS coordinate sequence pointer.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Represents the minimum area, oriented bounding box surrounding a convex hull.
struct GEOSGeom_t GEOSGeometry