45using namespace Qt::StringLiterals;
57 if ( defaultPriority < 0.0001 )
59 else if ( defaultPriority > 1.0 )
86 if ( lf->
size().width() < 0 || lf->
size().height() < 0 )
89 QMutexLocker locker( &
mMutex );
103 bool addedFeature =
false;
105 double geom_size = -1, biggest_size = -1;
106 std::unique_ptr<FeaturePart> biggestPart;
109 const std::optional<QVector<const GEOSGeometry *>> simpleGeometries =
Util::unmulti( lf->
geometry() );
110 if ( !simpleGeometries.has_value() )
119 for (
const GEOSGeometry *geom : simpleGeometries.value() )
122 if ( GEOSisValid_r( geosctxt, geom ) != 1 )
127 const int type = GEOSGeomTypeId_r( geosctxt, geom );
129 if ( type != GEOS_POINT && type != GEOS_LINESTRING && type != GEOS_POLYGON )
134 auto fpart = std::make_unique<FeaturePart>( lf, geom );
137 if ( ( type == GEOS_LINESTRING && fpart->nbPoints < 2 ) || ( type == GEOS_POLYGON && fpart->nbPoints < 3 ) )
149 const bool labelWellDefined = ( lf->
size().width() > 0.0000001 && lf->
size().height() > 0.0000001 );
175 if ( type == GEOS_POLYGON || type == GEOS_LINESTRING )
177 if ( type == GEOS_LINESTRING )
178 geom_size = fpart->length();
179 else if ( type == GEOS_POLYGON )
180 geom_size = fpart->area();
182 if ( geom_size > biggest_size )
184 biggest_size = geom_size;
185 biggestPart = std::move( fpart );
214 QgsDebugError( u
"Obstacle geometry passed to PAL labeling engine could not be converted to GEOS! %1"_s.arg( ( *it )->asWkt() ) );
219 if ( GEOSisValid_r( geosctxt, geom.get() ) != 1 )
222 QgsDebugError( u
"Obstacle geometry passed to PAL labeling engine is not valid! %1"_s.arg( ( *it )->asWkt() ) );
226 const int type = GEOSGeomTypeId_r( geosctxt, geom.get() );
228 if ( type != GEOS_POINT && type != GEOS_LINESTRING && type != GEOS_POLYGON )
233 auto fpart = std::make_unique<FeaturePart>( lf, geom.get() );
236 if ( ( type == GEOS_LINESTRING && fpart->nbPoints < 2 ) || ( type == GEOS_POLYGON && fpart->nbPoints < 3 ) )
294 auto it = otherParts.constBegin();
295 while ( it != otherParts.constEnd() )
311 int connectedFeaturesId = 0;
314 QVector<FeaturePart *> partsToMerge = it.value();
318 std::sort( partsToMerge.begin(), partsToMerge.end(), [](
FeaturePart *a,
FeaturePart *b ) { return a->length() > b->length(); } );
321 while ( partsToMerge.count() > 1 )
323 connectedFeaturesId++;
326 FeaturePart *partToJoinTo = partsToMerge.takeFirst();
330 QVector< FeaturePart *> partsLeftToTryThisRound = partsToMerge;
331 while ( !partsLeftToTryThisRound.empty() )
333 if (
FeaturePart *otherPart = _findConnectedPart( partToJoinTo, partsLeftToTryThisRound ) )
335 partsLeftToTryThisRound.removeOne( otherPart );
341 partsToMerge.removeAll( otherPart );
342 const auto matchingPartIt = std::find_if(
mFeatureParts.begin(),
mFeatureParts.end(), [otherPart](
const std::unique_ptr< FeaturePart> &part ) { return part.get() == otherPart; } );
362 [](
const std::unique_ptr< FeaturePart > &part ) {
363 if ( part->feature()->minimumSize() != 0.0 && part->length() < part->feature()->minimumSize() )
382 std::deque< std::unique_ptr< FeaturePart > > newFeatureParts;
385 std::unique_ptr< FeaturePart > fpart = std::move(
mFeatureParts.front() );
389 double chopInterval = fpart->repeatDistance();
392 bool canChop =
false;
393 double featureLen = 0;
394 if ( chopInterval != 0. && GEOSGeomTypeId_r( geosctxt, geom ) == GEOS_LINESTRING )
396 featureLen = fpart->length();
397 if ( featureLen > chopInterval )
402 bool shouldChop = canChop;
403 int possibleSegments = 0;
407 chopInterval *= std::ceil( fpart->getLabelWidth() / fpart->repeatDistance() );
410 possibleSegments =
static_cast< int >( std::floor( featureLen / chopInterval ) );
422 chopInterval = featureLen / possibleSegments;
424 shouldChop = possibleSegments > 1;
429 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosctxt, geom );
433 GEOSCoordSeq_getSize_r( geosctxt, cs, &n );
436 std::vector<Point> points( n );
437 for (
unsigned int i = 0; i < n; ++i )
439 GEOSCoordSeq_getXY_r( geosctxt, cs, i, &points[i].x, &points[i].y );
443 std::vector<double> len( n, 0 );
444 for (
unsigned int i = 1; i < n; ++i )
446 const double dx = points[i].x - points[i - 1].x;
447 const double dy = points[i].y - points[i - 1].y;
448 len[i] = len[i - 1] + std::sqrt( dx * dx + dy * dy );
452 unsigned int cur = 0;
454 std::vector<Point> part;
456 QList<FeaturePart *> repeatParts;
457 repeatParts.reserve( possibleSegments );
461 lambda += chopInterval;
462 for ( ; cur < n && lambda > len[cur]; ++cur )
464 part.push_back( points[cur] );
469 GEOSCoordSequence *cooSeq = GEOSCoordSeq_create_r( geosctxt,
static_cast< unsigned int >( part.size() ), 2 );
470 for (
unsigned int i = 0; i < part.size(); ++i )
472 GEOSCoordSeq_setXY_r( geosctxt, cooSeq, i, part[i].x, part[i].y );
474 GEOSGeometry *newgeom = GEOSGeom_createLineString_r( geosctxt, cooSeq );
475 auto newfpart = std::make_unique< FeaturePart >( fpart->feature(), newgeom );
476 repeatParts.push_back( newfpart.get() );
477 newFeatureParts.emplace_back( std::move( newfpart ) );
480 const double c = ( lambda - len[cur - 1] ) / ( len[cur] - len[cur - 1] );
482 p.
x = points[cur - 1].x +
c * ( points[cur].x - points[cur - 1].x );
483 p.
y = points[cur - 1].y +
c * ( points[cur].y - points[cur - 1].y );
485 GEOSCoordSequence *cooSeq = GEOSCoordSeq_create_r( geosctxt,
static_cast< unsigned int >( part.size() ), 2 );
486 for ( std::size_t i = 0; i < part.size(); ++i )
488 GEOSCoordSeq_setXY_r( geosctxt, cooSeq, i, part[i].x, part[i].y );
491 GEOSGeometry *newgeom = GEOSGeom_createLineString_r( geosctxt, cooSeq );
492 auto newfpart = std::make_unique< FeaturePart >( fpart->feature(), newgeom );
493 repeatParts.push_back( newfpart.get() );
494 newFeatureParts.emplace_back( std::move( newfpart ) );
503 partPtr->setTotalRepeats( repeatParts.count() );
508 newFeatureParts.emplace_back( std::move( fpart ) );
@ LabelLargestPartOnly
Place a label only on the largest part from the geometry.
@ SplitLabelTextLinesOverParts
Splits the label text over the parts of the geometry, such that each consecutive part is labeled with...
@ LabelEveryPartWithEntireLabel
Place the (same) entire label over every part from the geometry.
LabelPlacement
Placement modes which determine how label candidates are generated for a feature.
An abstract interface class for label providers.
A generic rtree spatial index based on a libspatialindex backend.
A geometry is the spatial representation of a feature.
QgsAbstractGeometry::const_part_iterator const_parts_begin() const
Returns STL-style const iterator pointing to the first part of the geometry.
QgsAbstractGeometry::const_part_iterator const_parts_end() const
Returns STL-style iterator pointing to the imaginary part after the last part of the geometry.
static GEOSContextHandle_t get()
Returns a thread local instance of a GEOS context, safe for use in the current thread.
static geos::unique_ptr asGeos(const QgsGeometry &geometry, double precision=0, Qgis::GeosCreationFlags flags=Qgis::GeosCreationFlags())
Returns a geos geometry - caller takes ownership of the object (should be deleted with GEOSGeom_destr...
Describes a feature that should be used within the labeling engine.
Qgis::MultiPartLabelingBehavior multiPartBehavior() const
Returns the multipart labeling behavior.
const QgsLabelObstacleSettings & obstacleSettings() const
Returns the label's obstacle settings.
QSizeF size(double angle=0.0) const
Size of the label (in map units).
void setLayer(pal::Layer *layer)
Assign PAL layer to the label feature. Should be only used internally in PAL.
GEOSGeometry * geometry() const
Gets access to the associated geometry.
QgsFeatureId id() const
Identifier of the label (unique within the parent label provider).
bool hasFixedPosition() const
Whether the label should use a fixed position instead of being automatically placed.
QString labelText() const
Text of the label.
int subPartId() const
Sub part identifier (for features which register multiple labels).
bool isObstacle() const
Returns true if the features are obstacles to labels of other layers.
QgsGeometry obstacleGeometry() const
Returns the label's obstacle geometry, if different to the feature geometry.
Represents a part of a label feature.
QgsFeatureId featureId() const
Returns the unique ID of the feature.
bool mergeWithFeaturePart(FeaturePart *other)
Merge other (connected) part with this one and save the result in this part (other is unchanged).
bool isConnected(FeaturePart *p2)
Check whether this part is connected with some other part.
static bool reorderPolygon(std::vector< double > &x, std::vector< double > &y)
Reorder points to have cross prod ((x,y)[i], (x,y)[i+1), point) > 0 when point is outside.
Thrown when a geometry type is not like expected.
QHash< QString, QVector< FeaturePart * > > mConnectedHashtable
std::deque< std::unique_ptr< FeaturePart > > mFeatureParts
List of feature parts.
QList< FeaturePart * > mObstacleParts
List of obstacle parts.
bool registerFeature(QgsLabelFeature *label)
Register a feature in the layer.
QString name() const
Returns the layer's name.
QgsAbstractLabelProvider * provider() const
Returns pointer to the associated provider.
bool active() const
Returns whether the layer is currently active.
QgsAbstractLabelProvider * mProvider
int connectedFeatureId(QgsFeatureId featureId) const
Returns the connected feature ID for a label feature ID, which is unique for all features which have ...
Qgis::LabelPlacement arrangement() const
Returns the layer's arrangement policy.
void addFeaturePart(std::unique_ptr< FeaturePart > fpart, const QString &labelText=QString())
Add newly created feature part into r tree and to the list.
QHash< QgsFeatureId, int > mConnectedFeaturesIds
Layer(QgsAbstractLabelProvider *provider, const QString &name, Qgis::LabelPlacement arrangement, double defaultPriority, bool active, bool toLabel, Pal *pal)
Create a new layer.
void joinConnectedFeatures()
Join connected features with the same label text.
void chopFeaturesAtRepeatDistance()
Chop layer features at the repeat distance.
std::vector< geos::unique_ptr > mGeosObstacleGeometries
void addObstaclePart(FeaturePart *fpart)
Add newly created obstacle part into r tree and to the list.
QHash< QPair< QgsFeatureId, int >, QgsLabelFeature * > mHashtable
Lookup table of label features (owned by the label feature provider that created them).
void setPriority(double priority)
Sets the layer's priority.
Qgis::LabelPlacement mArrangement
Optional flags used for some placement methods.
double priority() const
Returns the layer's priority, between 0 and 1.
static std::optional< QVector< const GEOSGeometry * > > unmulti(const GEOSGeometry *the_geom)
std::unique_ptr< GEOSGeometry, GeosDeleter > unique_ptr
Scoped GEOS 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
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
#define QgsDebugError(str)
QLineF segment(int index, QRectF rect, double radius)
struct GEOSGeom_t GEOSGeometry