52 , reversed( isReversed )
54 , quadrant( quadrant )
56 , mHasObstacleConflict( false )
57 , mUpsideDownCharCount( 0 )
65 while ( this->alpha > 2 * M_PI )
66 this->alpha -= 2 * M_PI;
68 while ( this->alpha < 0 )
69 this->alpha += 2 * M_PI;
71 double beta = this->alpha + M_PI_2;
73 double dx1, dx2, dy1, dy2;
75 dx1 = std::cos( this->alpha ) *
w;
76 dy1 = std::sin( this->alpha ) *
w;
78 dx2 = std::cos( beta ) *
h;
79 dy2 = std::sin( beta ) *
h;
87 x[2] = x1 + dx1 + dx2;
88 y[2] = y1 + dy1 + dy2;
95 this->alpha > M_PI_2 && this->alpha <= 3 * M_PI_2 )
120 if ( this->alpha < M_PI )
131 for (
int i = 0; i <
nbPoints; ++i )
153 if ( other.mNextPart )
154 mNextPart = std::make_unique< LabelPosition >( *other.mNextPart );
160 mHasObstacleConflict = other.mHasObstacleConflict;
161 mUpsideDownCharCount = other.mUpsideDownCharCount;
168 for ( i = 0; i < 4; i++ )
170 if (
x[i] >= bbox[0] &&
x[i] <= bbox[2] &&
171 y[i] >= bbox[1] &&
y[i] <= bbox[3] )
176 return mNextPart->isIn( bbox );
185 for ( i = 0; i < 4; i++ )
187 if (
x[i] >= bbox[0] &&
x[i] <= bbox[2] &&
188 y[i] >= bbox[1] &&
y[i] <= bbox[3] )
193 return mNextPart->isIntersect( bbox );
209 else if ( mNextPart )
211 return mNextPart->intersects( geometry );
214 catch ( GEOSException &e )
216 qWarning(
"GEOS exception: %s", e.what() );
235 else if ( mNextPart )
237 return mNextPart->within( geometry );
240 catch ( GEOSException &e )
242 qWarning(
"GEOS exception: %s", e.what() );
252 for (
int i = 0; i < 4; i++ )
254 if ( !(
x[i] >= bbox[0] &&
x[i] <= bbox[2] &&
255 y[i] >= bbox[1] &&
y[i] <= bbox[3] ) )
260 return mNextPart->isInside( bbox );
279 return isInConflictMultiPart( lp );
282 bool LabelPosition::isInConflictMultiPart(
const LabelPosition *lp )
const
284 if ( !mMultipartGeos )
285 createMultiPartGeosGeom();
287 if ( !lp->mMultipartGeos )
288 lp->createMultiPartGeosGeom();
293 bool result = ( GEOSPreparedIntersects_r( geosctxt,
preparedMultiPartGeom(), lp->mMultipartGeos ) == 1 );
296 catch ( GEOSException &e )
298 qWarning(
"GEOS exception: %s", e.what() );
306 int LabelPosition::partCount()
const
309 return mNextPart->partCount() + 1;
316 for (
int i = 0; i < 4; i++ )
323 mNextPart->offsetPosition( xOffset, yOffset );
335 return ( i >= 0 && i < 4 ?
x[i] : -1 );
340 return ( i >= 0 && i < 4 ?
y[i] : -1 );
352 mCost -= int ( mCost );
365 mNextPart->getBoundingBox( amin, amax );
369 amin[0] = std::numeric_limits<double>::max();
370 amax[0] = std::numeric_limits<double>::lowest();
371 amin[1] = std::numeric_limits<double>::max();
372 amax[1] = std::numeric_limits<double>::lowest();
374 for (
int c = 0;
c < 4;
c++ )
376 if (
x[
c] < amin[0] )
378 if (
x[
c] > amax[0] )
380 if (
y[
c] < amin[1] )
382 if (
y[
c] > amax[1] )
389 mHasObstacleConflict = conflicts;
391 mNextPart->setConflictsWithObstacle( conflicts );
396 mHasHardConflict = conflicts;
398 mNextPart->setHasHardObstacleConflict( conflicts );
418 void LabelPosition::createMultiPartGeosGeom()
const
422 std::vector< const GEOSGeometry * > geometries;
426 const GEOSGeometry *partGeos = tmp1->
geos();
427 if ( !GEOSisEmpty_r( geosctxt, partGeos ) )
428 geometries.emplace_back( partGeos );
432 const std::size_t partCount = geometries.size();
433 GEOSGeometry **geomarr =
new GEOSGeometry*[ partCount ];
434 for ( std::size_t i = 0; i < partCount; ++i )
436 geomarr[i ] = GEOSGeom_clone_r( geosctxt, geometries[i] );
439 mMultipartGeos = GEOSGeom_createCollection_r( geosctxt, GEOS_MULTIPOLYGON, geomarr, partCount );
445 if ( !mMultipartGeos )
446 createMultiPartGeosGeom();
448 if ( !mMultipartPreparedGeos )
452 return mMultipartPreparedGeos;
458 bool contains =
false;
462 contains =
x[0] <= xp &&
x[1] >= xp &&
y[0] <= yp &&
y[2] >= yp;
469 double distance = -1;
474 const double dx = std::max( std::max(
x[0] - xp, 0.0 ), xp -
x[1] );
475 const double dy = std::max( std::max(
y[0] - yp, 0.0 ), yp -
y[2] );
476 distance = std::sqrt( dx * dx + dy * dy );
484 if ( mNextPart && distance > 0 )
485 return std::min( distance, mNextPart->getDistanceToPoint( xp, yp ) );
505 else if ( mNextPart )
507 return mNextPart->crossesLine( line );
510 catch ( GEOSException &e )
512 qWarning(
"GEOS exception: %s", e.what() );
525 if ( !polygon->
mGeos )
536 else if ( mNextPart )
538 return mNextPart->crossesBoundary( polygon );
541 catch ( GEOSException &e )
543 qWarning(
"GEOS exception: %s", e.what() );
554 double totalCost = polygonIntersectionCostForParts( polygon );
556 return std::ceil( totalCost / n );
564 if ( !polygon->
mGeos )
575 catch ( GEOSException &e )
577 qWarning(
"GEOS exception: %s", e.what() );
583 return mNextPart->intersectsWithPolygon( polygon );
591 double LabelPosition::polygonIntersectionCostForParts(
PointSet *polygon )
const
596 if ( !polygon->
mGeos )
611 for (
int i = 0; i < 4; ++i )
616 for (
int a = 0; a < 2; ++a )
620 px = (
x[i] +
x[( i + 1 ) % 4] ) / 2.0;
621 py = (
y[i] +
y[( i + 1 ) % 4] ) / 2.0;
625 px = (
x[0] +
x[2] ) / 2.0;
626 py = (
y[0] +
y[2] ) / 2.0;
633 catch ( GEOSException &e )
635 qWarning(
"GEOS exception: %s", e.what() );
644 cost += mNextPart->polygonIntersectionCostForParts( polygon );
652 double angleDiff = 0.0, angleLast = 0.0, diff;
653 double sinAvg = 0, cosAvg = 0;
659 diff = std::fabs( tmp->
getAlpha() - angleLast );
660 if ( diff > 2 * M_PI ) diff -= 2 * M_PI;
661 diff = std::min( diff, 2 * M_PI - diff );
665 sinAvg += std::sin( tmp->
getAlpha() );
666 cosAvg += std::cos( tmp->
getAlpha() );
A rtree spatial index for use in the pal labeling engine.
void insert(T *data, const QgsRectangle &bounds)
Inserts new data into the spatial index, with the specified bounds.
void remove(T *data, const QgsRectangle &bounds)
Removes existing data from the spatial index, with the specified bounds.
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 rectangle specified with double values.
Main class to handle feature.
bool onlyShowUprightLabels() const
Returns true if feature's label must be displayed upright.
Layer * layer()
Returns the layer that feature belongs to.
LabelPosition is a candidate feature label position.
bool intersectsWithPolygon(PointSet *polygon) const
Returns true if any intersection between polygon and position exists.
bool isInConflict(const LabelPosition *ls) const
Check whether or not this overlap with another labelPosition.
bool isIntersect(double *bbox)
Is the labelposition intersect the bounding-box ?
double getAlpha() const
Returns the angle to rotate text (in rad).
Quadrant
Position of label candidate relative to feature.
LabelPosition::Quadrant quadrant
double angleDifferential()
Returns the angle differential of all LabelPosition parts.
void removeFromIndex(PalRtree< LabelPosition > &index)
Removes the label position from the specified index.
bool isInside(double *bbox)
Is the labelposition inside the bounding-box ?
bool crossesLine(PointSet *line) const
Returns true if this label crosses the specified line.
int getId() const
Returns the id.
void validateCost()
Make sure the cost is less than 1.
bool isIn(double *bbox)
Is the labelposition in the bounding-box ? (intersect or inside????)
double cost() const
Returns the candidate label position's geographical cost.
void setConflictsWithObstacle(bool conflicts)
Sets whether the position is marked as conflicting with an obstacle feature.
bool intersects(const GEOSPreparedGeometry *geometry)
Returns true if the label position intersects a geometry.
void setHasHardObstacleConflict(bool conflicts)
Sets whether the position is marked as having a hard conflict with an obstacle feature.
bool crossesBoundary(PointSet *polygon) const
Returns true if this label crosses the boundary of the specified polygon.
LabelPosition * nextPart() const
Returns the next part of this label position (i.e.
void offsetPosition(double xOffset, double yOffset)
Shift the label by specified offset.
double getDistanceToPoint(double xp, double yp) const
Gets distance from this label to a point. If point lies inside, returns negative number.
FeaturePart * getFeaturePart() const
Returns the feature corresponding to this labelposition.
const GEOSPreparedGeometry * preparedMultiPartGeom() const
Returns a prepared GEOS representation of all label parts as a multipolygon.
double getX(int i=0) const
Returns the down-left x coordinate.
void getBoundingBox(double amin[2], double amax[2]) const
Returns bounding box - amin: xmin,ymin - amax: xmax,ymax.
double getY(int i=0) const
Returns the down-left y coordinate.
bool within(const GEOSPreparedGeometry *geometry)
Returns true if the label position is within a geometry.
void insertIntoIndex(PalRtree< LabelPosition > &index)
Inserts the label position into the specified index.
int polygonIntersectionCost(PointSet *polygon) const
Returns cost of position intersection with polygon (testing area of intersection and center).
bool isCurved() const
Returns true if the layer has curved labels.
The underlying raw pal geometry class.
friend class LabelPosition
void createGeosGeom() const
bool boundingBoxIntersects(const PointSet *other) const
Returns true if the bounding box of this pointset intersects the bounding box of another pointset.
const GEOSPreparedGeometry * preparedGeom() const
const GEOSGeometry * geos() const
Returns the point set's GEOS geometry.
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,...
bool containsPoint(double x, double y) const
Tests whether point set contains a specified point.
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)