46 : mProvider( provider )
50 , mLabelLayer( toLabel )
51 , mDisplayAll( displayAll )
52 , mCentroidInside( false )
53 , mArrangement( arrangement )
54 , mMergeLines( false )
55 , mUpsidedownLabels( Upright )
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 std::unique_ptr<QLinkedList<const GEOSGeometry *>> simpleGeometries(
Util::unmulti( lf->
geometry() ) );
110 if ( !simpleGeometries )
119 while ( !simpleGeometries->isEmpty() )
121 const GEOSGeometry *geom = simpleGeometries->takeFirst();
124 if ( GEOSisValid_r( geosctxt, geom ) != 1 )
129 const int type = GEOSGeomTypeId_r( geosctxt, geom );
131 if ( type != GEOS_POINT && type != GEOS_LINESTRING && type != GEOS_POLYGON )
136 std::unique_ptr<FeaturePart> fpart = std::make_unique<FeaturePart>( lf, geom );
139 if ( ( type == GEOS_LINESTRING && fpart->nbPoints < 2 ) ||
140 ( type == GEOS_POLYGON && fpart->nbPoints < 3 ) )
152 const bool labelWellDefined = ( lf->
size().width() > 0.0000001 && lf->
size().height() > 0.0000001 );
175 if ( !lf->
labelAllParts() && ( 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 );
207 QgsDebugMsg( QStringLiteral(
"Obstacle geometry passed to PAL labeling engine could not be converted to GEOS! %1" ).arg( ( *it )->asWkt() ) );
212 if ( GEOSisValid_r( geosctxt, geom.get() ) != 1 )
215 QgsDebugMsg( QStringLiteral(
"Obstacle geometry passed to PAL labeling engine is not valid! %1" ).arg( ( *it )->asWkt() ) );
219 const int type = GEOSGeomTypeId_r( geosctxt, geom.get() );
221 if ( type != GEOS_POINT && type != GEOS_LINESTRING && type != GEOS_POLYGON )
226 std::unique_ptr<FeaturePart> fpart = std::make_unique<FeaturePart>( lf, geom.get() );
229 if ( ( type == GEOS_LINESTRING && fpart->nbPoints < 2 ) ||
230 ( type == GEOS_POLYGON && fpart->nbPoints < 3 ) )
285 static FeaturePart *_findConnectedPart(
FeaturePart *partCheck,
const QVector<FeaturePart *> &otherParts )
288 auto it = otherParts.constBegin();
289 while ( it != otherParts.constEnd() )
305 int connectedFeaturesId = 0;
308 QVector<FeaturePart *> partsToMerge = it.value();
314 return a->length() > b->length();
318 while ( partsToMerge.count() > 1 )
320 connectedFeaturesId++;
323 FeaturePart *partToJoinTo = partsToMerge.takeFirst();
327 QVector< FeaturePart *> partsLeftToTryThisRound = partsToMerge;
328 while ( !partsLeftToTryThisRound.empty() )
330 if (
FeaturePart *otherPart = _findConnectedPart( partToJoinTo, partsLeftToTryThisRound ) )
332 partsLeftToTryThisRound.removeOne( otherPart );
338 partsToMerge.removeAll( otherPart );
339 const auto matchingPartIt = std::find_if(
mFeatureParts.begin(),
mFeatureParts.end(), [otherPart](
const std::unique_ptr< FeaturePart> &part ) { return part.get() == otherPart; } );
357 if ( part->feature()->minimumSize() != 0.0 && part->length() < part->feature()->minimumSize() )
362 } ), mFeatureParts.end() );
373 std::deque< std::unique_ptr< FeaturePart > > newFeatureParts;
376 std::unique_ptr< FeaturePart > fpart = std::move(
mFeatureParts.front() );
379 const GEOSGeometry *geom = fpart->geos();
380 double chopInterval = fpart->repeatDistance();
383 bool canChop =
false;
384 double featureLen = 0;
385 if ( chopInterval != 0. && GEOSGeomTypeId_r( geosctxt, geom ) == GEOS_LINESTRING )
387 featureLen = fpart->length();
388 if ( featureLen > chopInterval )
393 bool shouldChop = canChop;
394 int possibleSegments = 0;
398 chopInterval *= std::ceil( fpart->getLabelWidth() / fpart->repeatDistance() );
401 possibleSegments =
static_cast< int >( std::floor( featureLen / chopInterval ) );
413 chopInterval = featureLen / possibleSegments;
415 shouldChop = possibleSegments > 1;
420 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosctxt, geom );
424 GEOSCoordSeq_getSize_r( geosctxt, cs, &n );
427 std::vector<Point> points( n );
428 for (
unsigned int i = 0; i < n; ++i )
430 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
431 GEOSCoordSeq_getXY_r( geosctxt, cs, i, &points[i].x, &points[i].y );
433 GEOSCoordSeq_getX_r( geosctxt, cs, i, &points[i].x );
434 GEOSCoordSeq_getY_r( geosctxt, cs, i, &points[i].y );
439 std::vector<double> len( n, 0 );
440 for (
unsigned int i = 1; i < n; ++i )
442 const double dx = points[i].x - points[i - 1].x;
443 const double dy = points[i].y - points[i - 1].y;
444 len[i] = len[i - 1] + std::sqrt( dx * dx + dy * dy );
448 unsigned int cur = 0;
450 std::vector<Point> part;
452 QList<FeaturePart *> repeatParts;
453 repeatParts.reserve( possibleSegments );
457 lambda += chopInterval;
458 for ( ; cur < n && lambda > len[cur]; ++cur )
460 part.push_back( points[cur] );
465 GEOSCoordSequence *cooSeq = GEOSCoordSeq_create_r( geosctxt,
static_cast< unsigned int >( part.size() ), 2 );
466 for (
unsigned int i = 0; i < part.size(); ++i )
468 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
469 GEOSCoordSeq_setXY_r( geosctxt, cooSeq, i, part[i].x, part[i].y );
471 GEOSCoordSeq_setX_r( geosctxt, cooSeq, i, part[i].x );
472 GEOSCoordSeq_setY_r( geosctxt, cooSeq, i, part[i].y );
475 GEOSGeometry *newgeom = GEOSGeom_createLineString_r( geosctxt, cooSeq );
476 std::unique_ptr< FeaturePart > newfpart = std::make_unique< FeaturePart >( fpart->feature(), newgeom );
477 repeatParts.push_back( newfpart.get() );
478 newFeatureParts.emplace_back( std::move( newfpart ) );
481 const double c = ( lambda - len[cur - 1] ) / ( len[cur] - len[cur - 1] );
483 p.
x = points[cur - 1].x +
c * ( points[cur].x - points[cur - 1].x );
484 p.
y = points[cur - 1].y +
c * ( points[cur].y - points[cur - 1].y );
486 GEOSCoordSequence *cooSeq = GEOSCoordSeq_create_r( geosctxt,
static_cast< unsigned int >( part.size() ), 2 );
487 for ( std::size_t i = 0; i < part.size(); ++i )
489 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8
490 GEOSCoordSeq_setXY_r( geosctxt, cooSeq, i, part[i].x, part[i].y );
492 GEOSCoordSeq_setX_r( geosctxt, cooSeq,
static_cast< unsigned int >( i ), part[i].x );
493 GEOSCoordSeq_setY_r( geosctxt, cooSeq,
static_cast< unsigned int >( i ), part[i].y );
497 GEOSGeometry *newgeom = GEOSGeom_createLineString_r( geosctxt, cooSeq );
498 std::unique_ptr< FeaturePart > newfpart = std::make_unique< FeaturePart >( fpart->feature(), newgeom );
499 repeatParts.push_back( newfpart.get() );
500 newFeatureParts.emplace_back( std::move( newfpart ) );
506 partPtr->setTotalRepeats( repeatParts.count() );
510 newFeatureParts.emplace_back( std::move( fpart ) );
The QgsAbstractLabelProvider class is an interface class.
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 geos::unique_ptr asGeos(const QgsGeometry &geometry, double precision=0)
Returns a geos geometry - caller takes ownership of the object (should be deleted with GEOSGeom_destr...
static GEOSContextHandle_t getGEOSHandler()
The QgsLabelFeature class 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.
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.
GEOSGeometry * geometry() const
Gets access to the associated geometry.
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.
Placement
Placement modes which determine how label candidates are generated for a feature.
Main class to handle 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.
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
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.
Layer(QgsAbstractLabelProvider *provider, const QString &name, QgsPalLayerSettings::Placement arrangement, double defaultPriority, bool active, bool toLabel, Pal *pal, bool displayAll=false)
Create a new layer.
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
QLineF segment(int index, QRectF rect, double radius)