47 : nbPoints( nbPoints )
48 , type( GEOS_POLYGON )
103 bool needClose =
false;
109 GEOSCoordSequence *coord =
nullptr;
110#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 )
114 coord = GEOSCoordSeq_copyFromArrays_r( geosctxt,
x.data(),
y.data(),
nullptr,
nullptr,
nbPoints );
123 coord = GEOSCoordSeq_create_r( geosctxt,
nbPoints + ( needClose ? 1 : 0 ), 2 );
124 for (
int i = 0; i <
nbPoints; ++i )
126 GEOSCoordSeq_setXY_r( geosctxt, coord, i,
x[i],
y[i] );
132 GEOSCoordSeq_setXY_r( geosctxt, coord,
nbPoints,
x[0],
y[0] );
139 mGeos = GEOSGeom_createPolygon_r( geosctxt, GEOSGeom_createLinearRing_r( geosctxt, coord ),
nullptr, 0 );
142 case GEOS_LINESTRING:
143 mGeos = GEOSGeom_createLineString_r( geosctxt, coord );
147 mGeos = GEOSGeom_createPoint_r( geosctxt, coord );
159 if ( !mPreparedGeom )
163 return mPreparedGeom;
170 GEOSGeom_destroy_r( geosctxt,
mGeos );
176 GEOSPreparedGeom_destroy_r( geosctxt, mPreparedGeom );
177 mPreparedGeom =
nullptr;
180 if ( mGeosPreparedBoundary )
182 GEOSPreparedGeom_destroy_r( geosctxt, mGeosPreparedBoundary );
183 mGeosPreparedBoundary =
nullptr;
186 if ( mMultipartPreparedGeos )
188 GEOSPreparedGeom_destroy_r( geosctxt, mMultipartPreparedGeos );
189 mMultipartPreparedGeos =
nullptr;
191 if ( mMultipartGeos )
193 GEOSGeom_destroy_r( geosctxt, mMultipartGeos );
194 mMultipartGeos =
nullptr;
207 GEOSGeom_destroy_r( geosctxt,
mGeos );
210 GEOSPreparedGeom_destroy_r( geosctxt, mPreparedGeom );
212 if ( mGeosPreparedBoundary )
214 GEOSPreparedGeom_destroy_r( geosctxt, mGeosPreparedBoundary );
215 mGeosPreparedBoundary =
nullptr;
218 if ( mMultipartPreparedGeos )
220 GEOSPreparedGeom_destroy_r( geosctxt, mMultipartPreparedGeos );
221 mMultipartPreparedGeos =
nullptr;
223 if ( mMultipartGeos )
225 GEOSGeom_destroy_r( geosctxt, mMultipartGeos );
226 mMultipartGeos =
nullptr;
238std::unique_ptr<PointSet>
PointSet::extractShape(
int nbPtSh,
int imin,
int imax,
int fps,
int fpe,
double fptx,
double fpty )
242 std::unique_ptr<PointSet> newShape = std::make_unique< PointSet >();
243 newShape->type = GEOS_POLYGON;
244 newShape->nbPoints = nbPtSh;
245 newShape->x.resize( newShape->nbPoints );
246 newShape->y.resize( newShape->nbPoints );
249 for ( j = 0, i = imin; i != ( imax + 1 ) %
nbPoints; i = ( i + 1 ) %
nbPoints, j++ )
251 newShape->x[j] =
x[i];
252 newShape->y[j] =
y[i];
258 newShape->x[j] = fptx;
259 newShape->y[j] = fpty;
267 return std::unique_ptr< PointSet>(
new PointSet( *
this ) );
276 const bool result = ( GEOSPreparedContainsProperly_r( geosctxt,
preparedGeom(), point.get() ) == 1 );
280 catch ( GEOSException &e )
282 qWarning(
"GEOS exception: %s", e.what() );
307 const double labelArea = labelWidth * labelHeight;
309 QLinkedList<PointSet *> inputShapes;
310 inputShapes.push_back( inputShape );
311 QLinkedList<PointSet *> outputShapes;
313 while ( !inputShapes.isEmpty() )
315 PointSet *shape = inputShapes.takeFirst();
317 const std::vector< double > &
x = shape->
x;
318 const std::vector< double > &
y = shape->
y;
320 std::vector< int > pts( nbp );
321 for (
int i = 0; i < nbp; i++ )
333 for ( std::size_t ihs = 0; ihs < shape->
convexHull.size(); ihs++ )
336 const std::size_t ihn = ( ihs + 1 ) % shape->
convexHull.size();
339 const int ipn = ( ips + 1 ) % nbp;
345 for (
int i = ips; i != shape->
convexHull[ihn]; i = ( i + 1 ) % nbp )
369 const double s = ( base + b +
c ) / 2;
370 double area = s * ( s - base ) * ( s - b ) * ( s -
c );
392 bestArea = std::sqrt( bestArea );
393 double cx, cy, dx, dy, ex, ey, fx, fy, seg_length, ptx = 0, pty = 0, fptx = 0, fpty = 0;
394 int ps = -1, pe = -1, fps = -1, fpe = -1;
395 if ( retainedPt >= 0 && bestArea > labelArea )
397 double c = std::numeric_limits<double>::max();
402 for (
int i = ( shape->
convexHull[holeE] + 1 ) % nbp; i != ( shape->
convexHull[holeS] - 1 + nbp ) % nbp; i = j )
410 cx = (
x[i] +
x[j] ) / 2.0;
411 cy = (
y[i] +
y[j] ) / 2.0;
449 double pointX, pointY;
472 if ( isValid && b <
c )
483 const int imin = retainedPt;
484 int imax = ( ( ( fps < retainedPt && fpe < retainedPt ) || ( fps > retainedPt && fpe > retainedPt ) ) ? std::min( fps, fpe ) : std::max( fps, fpe ) );
486 int nbPtSh1, nbPtSh2;
488 nbPtSh1 = imax - imin + 1 + ( fpe != fps );
490 nbPtSh1 = imax + nbp - imin + 1 + ( fpe != fps );
492 if ( ( imax == fps ? fpe : fps ) < imin )
493 nbPtSh2 = imin - ( imax == fps ? fpe : fps ) + 1 + ( fpe != fps );
495 nbPtSh2 = imin + nbp - ( imax == fps ? fpe : fps ) + 1 + ( fpe != fps );
497 if ( retainedPt == -1 || fps == -1 || fpe == -1 )
503 else if ( imax == imin || nbPtSh1 <= 2 || nbPtSh2 <= 2 || nbPtSh1 == nbp || nbPtSh2 == nbp )
505 outputShapes.append( shape );
510 PointSet *newShape = shape->
extractShape( nbPtSh1, imin, imax, fps, fpe, fptx, fpty ).release();
517 inputShapes.append( newShape );
524 newShape = shape->
extractShape( nbPtSh2, imax, imin, fps, fpe, fptx, fpty ).release();
531 inputShapes.append( newShape );
539 outputShapes.append( shape );
557 newGeos.reset( GEOSOffsetCurve_r( geosctxt,
mGeos, distance, 0, GEOSBUF_JOIN_MITRE, 2 ) );
562 if ( GEOSGeomTypeId_r( geosctxt, newGeos.get() ) == GEOS_MULTILINESTRING )
565 const int nParts = GEOSGetNumGeometries_r( geosctxt, newGeos.get() );
566 double maximumLength = -1;
567 const GEOSGeometry *longestPart =
nullptr;
568 for (
int i = 0; i < nParts; ++i )
570 const GEOSGeometry *part = GEOSGetGeometryN_r( geosctxt, newGeos.get(), i );
571 double partLength = -1;
572 if ( GEOSLength_r( geosctxt, part, &partLength ) == 1 )
574 if ( partLength > maximumLength )
576 maximumLength = partLength;
588 geos::unique_ptr longestPartClone( GEOSGeom_clone_r( geosctxt, longestPart ) );
589 newGeos = std::move( longestPartClone );
599 newGeos = std::move( reversed );
602 const int newNbPoints = GEOSGeomGetNumPoints_r( geosctxt, newGeos.get() );
603 const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosctxt, newGeos.get() );
604 std::vector< double > newX;
605 std::vector< double > newY;
606 newX.resize( newNbPoints );
607 newY.resize( newNbPoints );
608 for (
int i = 0; i < newNbPoints; i++ )
610 GEOSCoordSeq_getX_r( geosctxt, coordSeq, i, &newX[i] );
611 GEOSCoordSeq_getY_r( geosctxt, coordSeq, i, &newY[i] );
617 catch ( GEOSException &e )
619 qWarning(
"GEOS exception: %s", e.what() );
625 mGeos = newGeos.release();
636 if ( startDistance > 0 )
642 double distanceConsumed = 0;
645 for (
int i = 1; i <
nbPoints; ++i )
647 const double thisX =
x[i];
648 const double thisY =
y[i];
649 const double thisSegmentLength = std::sqrt( ( thisX - lastX ) * ( thisX - lastX ) + ( thisY - lastY ) * ( thisY - lastY ) );
650 distanceConsumed += thisSegmentLength;
651 if ( distanceConsumed >= smoothDistance )
653 const double c = ( distanceConsumed - smoothDistance ) / thisSegmentLength;
654 x1 = lastX +
c * ( thisX - lastX );
655 y1 = lastY +
c * ( thisY - lastY );
662 const double distance = std::sqrt( ( x1 - x0 ) * ( x1 - x0 ) + ( y1 - y0 ) * ( y1 - y0 ) );
663 const double extensionFactor = ( startDistance + distance ) / distance;
670 if ( endDistance > 0 )
678 double distanceConsumed = 0;
681 for (
int i =
nbPoints - 2; i >= 0; --i )
683 const double thisX =
x[i];
684 const double thisY =
y[i];
685 const double thisSegmentLength = std::sqrt( ( thisX - lastX ) * ( thisX - lastX ) + ( thisY - lastY ) * ( thisY - lastY ) );
686 distanceConsumed += thisSegmentLength;
687 if ( distanceConsumed >= smoothDistance )
689 const double c = ( distanceConsumed - smoothDistance ) / thisSegmentLength;
690 xend1 = lastX +
c * ( thisX - lastX );
691 yend1 = lastY +
c * ( thisY - lastY );
698 const double distance = std::sqrt( ( xend1 - xend0 ) * ( xend1 - xend0 ) + ( yend1 - yend0 ) * ( yend1 - yend0 ) );
699 const double extensionFactor = ( endDistance + distance ) / distance;
701 x.emplace_back( newEnd.
x() );
702 y.emplace_back( newEnd.
y() );
706 if ( startDistance > 0 )
708 x.insert(
x.begin(), x0 );
709 y.insert(
y.begin(), y0 );
730 double best_area = std::numeric_limits<double>::max();
731 double best_alpha = -1;
733 double best_length = 0;
734 double best_width = 0;
737 bbox[0] = std::numeric_limits<double>::max();
738 bbox[1] = std::numeric_limits<double>::max();
739 bbox[2] = std::numeric_limits<double>::lowest();
740 bbox[3] = std::numeric_limits<double>::lowest();
742 for ( std::size_t i = 0; i <
convexHull.size(); i++ )
759 const double dref = bbox[2] - bbox[0];
766 for ( alpha_d = 0; alpha_d < 90; alpha_d++ )
768 alpha = alpha_d * M_PI / 180.0;
769 d1 = std::cos( alpha ) * dref;
770 d2 = std::sin( alpha ) * dref;
791 bb[14] = bb[12] + d2;
792 bb[15] = bb[13] - d1;
795 for (
int i = 0; i < 16; i += 4 )
798 alpha_seg = ( ( i / 4 > 0 ? ( i / 4 ) - 1 : 3 ) ) * M_PI_2 + alpha;
800 double best_cp = std::numeric_limits<double>::max();
802 for ( std::size_t j = 0; j <
convexHull.size(); j++ )
811 const double distNearestPoint = best_cp / dref;
813 d1 = std::cos( alpha_seg ) * distNearestPoint;
814 d2 = std::sin( alpha_seg ) * distNearestPoint;
838 memcpy( best_bb, bb,
sizeof(
double ) * 16 );
843 for (
int i = 0; i < 16; i = i + 4 )
846 best_bb[( i + 4 ) % 16], best_bb[( i + 5 ) % 16], best_bb[( i + 6 ) % 16], best_bb[( i + 7 ) % 16],
847 &finalBb.
x[int ( i / 4 )], &finalBb.
y[int ( i / 4 )] );
850 finalBb.
alpha = best_alpha;
851 finalBb.
width = best_width;
852 finalBb.
length = best_length;
869 geos::unique_ptr geosPt( GEOSGeom_createPointFromXY_r( geosctxt, px, py ) );
870 const int type = GEOSGeomTypeId_r( geosctxt,
mGeos );
871 const GEOSGeometry *extRing =
nullptr;
872 const GEOSPreparedGeometry *preparedExtRing =
nullptr;
874 if (
type != GEOS_POLYGON )
882 extRing = GEOSGetExteriorRing_r( geosctxt,
mGeos );
883 if ( ! mGeosPreparedBoundary )
885 mGeosPreparedBoundary = GEOSPrepare_r( geosctxt, extRing );
887 preparedExtRing = mGeosPreparedBoundary;
893 unsigned int nPoints = 0;
894 GEOSCoordSeq_getSize_r( geosctxt, nearestCoord.get(), &nPoints );
898 ( void )GEOSCoordSeq_getXY_r( geosctxt, nearestCoord.get(), 0, &nx, &ny );
907 catch ( GEOSException &e )
909 qWarning(
"GEOS exception: %s", e.what() );
929 const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosctxt, centroidGeom.get() );
930 unsigned int nPoints = 0;
931 GEOSCoordSeq_getSize_r( geosctxt, coordSeq, &nPoints );
934 GEOSCoordSeq_getXY_r( geosctxt, coordSeq, 0, &px, &py );
944 const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosctxt, pointGeom.get() );
945 unsigned int nPoints = 0;
946 GEOSCoordSeq_getSize_r( geosctxt, coordSeq, &nPoints );
950 GEOSCoordSeq_getXY_r( geosctxt, coordSeq, 0, &px, &py );
954 catch ( GEOSException &e )
956 qWarning(
"GEOS exception: %s", e.what() );
982 while ( i <
nbPoints && ad[i] <= dl ) i++;
992 di = std::sqrt( dx * dx + dy * dy );
996 dx =
x[i + 1] -
x[i];
997 dy =
y[i + 1] -
y[i];
1002 *px =
x[i] + dx * distr / di;
1003 *py =
y[i] + dy * distr / di;
1014 const GEOSGeometry *thisGeos =
geos();
1023 catch ( GEOSException &e )
1025 qWarning(
"GEOS exception: %s", e.what() );
1032 const GEOSGeometry *thisGeos =
geos();
1036 double distance = -1;
1041 catch ( GEOSException &e )
1043 qWarning(
"GEOS exception: %s", e.what() );
1076 catch ( GEOSException &e )
1078 qWarning(
"GEOS exception: %s", e.what() );
1099 ( void )GEOSArea_r( geosctxt,
mGeos, &
mArea );
1103 catch ( GEOSException &e )
1105 qWarning(
"GEOS exception: %s", e.what() );
1125 GEOSWKTWriter *writer = GEOSWKTWriter_create_r( geosctxt );
1127 char *wkt = GEOSWKTWriter_write_r( geosctxt, writer,
mGeos );
1128 const QString res( wkt );
1130 GEOSFree_r( geosctxt, wkt );
1132 GEOSWKTWriter_destroy_r( geosctxt, writer );
1137 catch ( GEOSException &e )
1139 qWarning(
"GEOS exception: %s", e.what() );
1147 std::vector< double > distances(
nbPoints );
1148 double totalDistance = 0;
1149 double oldX = -1.0, oldY = -1.0;
1150 for (
int i = 0; i <
nbPoints; i++ )
1155 distances[i] = std::sqrt( std::pow( oldX -
x[i], 2 ) + std::pow( oldY -
y[i], 2 ) );
1159 totalDistance += distances[i];
1161 return std::make_tuple( std::move( distances ), totalDistance );
static QgsPointXY interpolatePointOnLine(double x1, double y1, double x2, double y2, double fraction) SIP_HOLDGIL
Interpolates the position of a point a fraction of the way along the line from (x1,...
static GEOSContextHandle_t getGEOSHandler()
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
A class to represent a 2D point.
static double dist_euc2d(double x1, double y1, double x2, double y2)
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 double dist_euc2d_sq(double x1, double y1, double x2, double y2)
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.
The underlying raw pal geometry class.
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.
OrientedConvexHullBoundingBox computeConvexHullOrientedBoundingBox(bool &ok)
Computes an oriented bounding box for the shape's convex hull.
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.
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
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.
static QLinkedList< PointSet * > splitPolygons(PointSet *inputShape, double labelWidth, double labelHeight)
Split a polygon using some random logic into some other polygons.
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.