53 if ( defaultPriority < 0.0001 )
55 else if ( defaultPriority > 1.0 )
82 if ( lf->
size().width() < 0 || lf->
size().height() < 0 )
85 QMutexLocker locker( &
mMutex );
99 bool addedFeature =
false;
101 double geom_size = -1, biggest_size = -1;
102 std::unique_ptr<FeaturePart> biggestPart;
105 std::unique_ptr<QLinkedList<const GEOSGeometry *>> simpleGeometries(
Util::unmulti( lf->
geometry() ) );
106 if ( !simpleGeometries )
115 while ( !simpleGeometries->isEmpty() )
117 const GEOSGeometry *geom = simpleGeometries->takeFirst();
120 if ( GEOSisValid_r( geosctxt, geom ) != 1 )
125 const int type = GEOSGeomTypeId_r( geosctxt, geom );
127 if ( type != GEOS_POINT && type != GEOS_LINESTRING && type != GEOS_POLYGON )
132 auto fpart = std::make_unique<FeaturePart>( lf, geom );
135 if ( ( type == GEOS_LINESTRING && fpart->nbPoints < 2 ) ||
136 ( type == GEOS_POLYGON && fpart->nbPoints < 3 ) )
148 const bool labelWellDefined = ( lf->
size().width() > 0.0000001 && lf->
size().height() > 0.0000001 );
171 if ( !lf->
labelAllParts() && ( type == GEOS_POLYGON || type == GEOS_LINESTRING ) )
173 if ( type == GEOS_LINESTRING )
174 geom_size = fpart->length();
175 else if ( type == GEOS_POLYGON )
176 geom_size = fpart->area();
178 if ( geom_size > biggest_size )
180 biggest_size = geom_size;
181 biggestPart = std::move( fpart );
203 QgsDebugError( QStringLiteral(
"Obstacle geometry passed to PAL labeling engine could not be converted to GEOS! %1" ).arg( ( *it )->asWkt() ) );
208 if ( GEOSisValid_r( geosctxt, geom.get() ) != 1 )
211 QgsDebugError( QStringLiteral(
"Obstacle geometry passed to PAL labeling engine is not valid! %1" ).arg( ( *it )->asWkt() ) );
215 const int type = GEOSGeomTypeId_r( geosctxt, geom.get() );
217 if ( type != GEOS_POINT && type != GEOS_LINESTRING && type != GEOS_POLYGON )
222 auto fpart = std::make_unique<FeaturePart>( lf, geom.get() );
225 if ( ( type == GEOS_LINESTRING && fpart->nbPoints < 2 ) ||
226 ( type == GEOS_POLYGON && fpart->nbPoints < 3 ) )
284 auto it = otherParts.constBegin();
285 while ( it != otherParts.constEnd() )
301 int connectedFeaturesId = 0;
304 QVector<FeaturePart *> partsToMerge = it.value();
310 return a->length() > b->length();
314 while ( partsToMerge.count() > 1 )
316 connectedFeaturesId++;
319 FeaturePart *partToJoinTo = partsToMerge.takeFirst();
323 QVector< FeaturePart *> partsLeftToTryThisRound = partsToMerge;
324 while ( !partsLeftToTryThisRound.empty() )
326 if (
FeaturePart *otherPart = _findConnectedPart( partToJoinTo, partsLeftToTryThisRound ) )
328 partsLeftToTryThisRound.removeOne( otherPart );
334 partsToMerge.removeAll( otherPart );
335 const auto matchingPartIt = std::find_if(
mFeatureParts.begin(),
mFeatureParts.end(), [otherPart](
const std::unique_ptr< FeaturePart> &part ) { return part.get() == otherPart; } );
353 if ( part->feature()->minimumSize() != 0.0 && part->length() < part->feature()->minimumSize() )
358 } ), mFeatureParts.end() );
369 std::deque< std::unique_ptr< FeaturePart > > newFeatureParts;
372 std::unique_ptr< FeaturePart > fpart = std::move(
mFeatureParts.front() );
376 double chopInterval = fpart->repeatDistance();
379 bool canChop =
false;
380 double featureLen = 0;
381 if ( chopInterval != 0. && GEOSGeomTypeId_r( geosctxt, geom ) == GEOS_LINESTRING )
383 featureLen = fpart->length();
384 if ( featureLen > chopInterval )
389 bool shouldChop = canChop;
390 int possibleSegments = 0;
394 chopInterval *= std::ceil( fpart->getLabelWidth() / fpart->repeatDistance() );
397 possibleSegments =
static_cast< int >( std::floor( featureLen / chopInterval ) );
409 chopInterval = featureLen / possibleSegments;
411 shouldChop = possibleSegments > 1;
416 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosctxt, geom );
420 GEOSCoordSeq_getSize_r( geosctxt, cs, &n );
423 std::vector<Point> points( n );
424 for (
unsigned int i = 0; i < n; ++i )
426 GEOSCoordSeq_getXY_r( geosctxt, cs, i, &points[i].x, &points[i].y );
430 std::vector<double> len( n, 0 );
431 for (
unsigned int i = 1; i < n; ++i )
433 const double dx = points[i].x - points[i - 1].x;
434 const double dy = points[i].y - points[i - 1].y;
435 len[i] = len[i - 1] + std::sqrt( dx * dx + dy * dy );
439 unsigned int cur = 0;
441 std::vector<Point> part;
443 QList<FeaturePart *> repeatParts;
444 repeatParts.reserve( possibleSegments );
448 lambda += chopInterval;
449 for ( ; cur < n && lambda > len[cur]; ++cur )
451 part.push_back( points[cur] );
456 GEOSCoordSequence *cooSeq = GEOSCoordSeq_create_r( geosctxt,
static_cast< unsigned int >( part.size() ), 2 );
457 for (
unsigned int i = 0; i < part.size(); ++i )
459 GEOSCoordSeq_setXY_r( geosctxt, cooSeq, i, part[i].x, part[i].y );
461 GEOSGeometry *newgeom = GEOSGeom_createLineString_r( geosctxt, cooSeq );
462 auto newfpart = std::make_unique< FeaturePart >( fpart->feature(), newgeom );
463 repeatParts.push_back( newfpart.get() );
464 newFeatureParts.emplace_back( std::move( newfpart ) );
467 const double c = ( lambda - len[cur - 1] ) / ( len[cur] - len[cur - 1] );
469 p.
x = points[cur - 1].x +
c * ( points[cur].x - points[cur - 1].x );
470 p.
y = points[cur - 1].y +
c * ( points[cur].y - points[cur - 1].y );
472 GEOSCoordSequence *cooSeq = GEOSCoordSeq_create_r( geosctxt,
static_cast< unsigned int >( part.size() ), 2 );
473 for ( std::size_t i = 0; i < part.size(); ++i )
475 GEOSCoordSeq_setXY_r( geosctxt, cooSeq, i, part[i].x, part[i].y );
478 GEOSGeometry *newgeom = GEOSGeom_createLineString_r( geosctxt, cooSeq );
479 auto newfpart = std::make_unique< FeaturePart >( fpart->feature(), newgeom );
480 repeatParts.push_back( newfpart.get() );
481 newFeatureParts.emplace_back( std::move( newfpart ) );
490 partPtr->setTotalRepeats( repeatParts.count() );
495 newFeatureParts.emplace_back( std::move( fpart ) );
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.
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.
bool labelAllParts() const
Returns true if all parts of the feature should be labeled.
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.
QHash< QgsFeatureId, QgsLabelFeature * > mHashtable
Lookup table of label features (owned by the label feature provider that created them).
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.
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 QLinkedList< 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