45 : mProvider( provider )
49 , mLabelLayer( toLabel )
50 , mArrangement( arrangement )
52 if ( defaultPriority < 0.0001 )
54 else if ( defaultPriority > 1.0 )
81 if ( lf->
size().width() < 0 || lf->
size().height() < 0 )
84 QMutexLocker locker( &
mMutex );
98 bool addedFeature =
false;
100 double geom_size = -1, biggest_size = -1;
101 std::unique_ptr<FeaturePart> biggestPart;
104 std::unique_ptr<QLinkedList<const GEOSGeometry *>> simpleGeometries(
Util::unmulti( lf->
geometry() ) );
105 if ( !simpleGeometries )
114 while ( !simpleGeometries->isEmpty() )
116 const GEOSGeometry *geom = simpleGeometries->takeFirst();
119 if ( GEOSisValid_r( geosctxt, geom ) != 1 )
124 const int type = GEOSGeomTypeId_r( geosctxt, geom );
126 if ( type != GEOS_POINT && type != GEOS_LINESTRING && type != GEOS_POLYGON )
131 std::unique_ptr<FeaturePart> fpart = std::make_unique<FeaturePart>( lf, geom );
134 if ( ( type == GEOS_LINESTRING && fpart->nbPoints < 2 ) ||
135 ( type == GEOS_POLYGON && fpart->nbPoints < 3 ) )
147 const bool labelWellDefined = ( lf->
size().width() > 0.0000001 && lf->
size().height() > 0.0000001 );
170 if ( !lf->
labelAllParts() && ( type == GEOS_POLYGON || type == GEOS_LINESTRING ) )
172 if ( type == GEOS_LINESTRING )
173 geom_size = fpart->length();
174 else if ( type == GEOS_POLYGON )
175 geom_size = fpart->area();
177 if ( geom_size > biggest_size )
179 biggest_size = geom_size;
180 biggestPart = std::move( fpart );
202 QgsDebugError( QStringLiteral(
"Obstacle geometry passed to PAL labeling engine could not be converted to GEOS! %1" ).arg( ( *it )->asWkt() ) );
207 if ( GEOSisValid_r( geosctxt, geom.get() ) != 1 )
210 QgsDebugError( QStringLiteral(
"Obstacle geometry passed to PAL labeling engine is not valid! %1" ).arg( ( *it )->asWkt() ) );
214 const int type = GEOSGeomTypeId_r( geosctxt, geom.get() );
216 if ( type != GEOS_POINT && type != GEOS_LINESTRING && type != GEOS_POLYGON )
221 std::unique_ptr<FeaturePart> fpart = std::make_unique<FeaturePart>( lf, geom.get() );
224 if ( ( type == GEOS_LINESTRING && fpart->nbPoints < 2 ) ||
225 ( type == GEOS_POLYGON && fpart->nbPoints < 3 ) )
283 auto it = otherParts.constBegin();
284 while ( it != otherParts.constEnd() )
300 int connectedFeaturesId = 0;
303 QVector<FeaturePart *> partsToMerge = it.value();
309 return a->length() > b->length();
313 while ( partsToMerge.count() > 1 )
315 connectedFeaturesId++;
318 FeaturePart *partToJoinTo = partsToMerge.takeFirst();
322 QVector< FeaturePart *> partsLeftToTryThisRound = partsToMerge;
323 while ( !partsLeftToTryThisRound.empty() )
325 if (
FeaturePart *otherPart = _findConnectedPart( partToJoinTo, partsLeftToTryThisRound ) )
327 partsLeftToTryThisRound.removeOne( otherPart );
333 partsToMerge.removeAll( otherPart );
334 const auto matchingPartIt = std::find_if(
mFeatureParts.begin(),
mFeatureParts.end(), [otherPart](
const std::unique_ptr< FeaturePart> &part ) { return part.get() == otherPart; } );
352 if ( part->feature()->minimumSize() != 0.0 && part->length() < part->feature()->minimumSize() )
357 } ), mFeatureParts.end() );
368 std::deque< std::unique_ptr< FeaturePart > > newFeatureParts;
371 std::unique_ptr< FeaturePart > fpart = std::move(
mFeatureParts.front() );
375 double chopInterval = fpart->repeatDistance();
378 bool canChop =
false;
379 double featureLen = 0;
380 if ( chopInterval != 0. && GEOSGeomTypeId_r( geosctxt, geom ) == GEOS_LINESTRING )
382 featureLen = fpart->length();
383 if ( featureLen > chopInterval )
388 bool shouldChop = canChop;
389 int possibleSegments = 0;
393 chopInterval *= std::ceil( fpart->getLabelWidth() / fpart->repeatDistance() );
396 possibleSegments =
static_cast< int >( std::floor( featureLen / chopInterval ) );
408 chopInterval = featureLen / possibleSegments;
410 shouldChop = possibleSegments > 1;
415 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosctxt, geom );
419 GEOSCoordSeq_getSize_r( geosctxt, cs, &n );
422 std::vector<Point> points( n );
423 for (
unsigned int i = 0; i < n; ++i )
425 GEOSCoordSeq_getXY_r( geosctxt, cs, i, &points[i].x, &points[i].y );
429 std::vector<double> len( n, 0 );
430 for (
unsigned int i = 1; i < n; ++i )
432 const double dx = points[i].x - points[i - 1].x;
433 const double dy = points[i].y - points[i - 1].y;
434 len[i] = len[i - 1] + std::sqrt( dx * dx + dy * dy );
438 unsigned int cur = 0;
440 std::vector<Point> part;
442 QList<FeaturePart *> repeatParts;
443 repeatParts.reserve( possibleSegments );
447 lambda += chopInterval;
448 for ( ; cur < n && lambda > len[cur]; ++cur )
450 part.push_back( points[cur] );
455 GEOSCoordSequence *cooSeq = GEOSCoordSeq_create_r( geosctxt,
static_cast< unsigned int >( part.size() ), 2 );
456 for (
unsigned int i = 0; i < part.size(); ++i )
458 GEOSCoordSeq_setXY_r( geosctxt, cooSeq, i, part[i].x, part[i].y );
460 GEOSGeometry *newgeom = GEOSGeom_createLineString_r( geosctxt, cooSeq );
461 std::unique_ptr< FeaturePart > newfpart = std::make_unique< FeaturePart >( fpart->feature(), newgeom );
462 repeatParts.push_back( newfpart.get() );
463 newFeatureParts.emplace_back( std::move( newfpart ) );
466 const double c = ( lambda - len[cur - 1] ) / ( len[cur] - len[cur - 1] );
468 p.
x = points[cur - 1].x +
c * ( points[cur].x - points[cur - 1].x );
469 p.
y = points[cur - 1].y +
c * ( points[cur].y - points[cur - 1].y );
471 GEOSCoordSequence *cooSeq = GEOSCoordSeq_create_r( geosctxt,
static_cast< unsigned int >( part.size() ), 2 );
472 for ( std::size_t i = 0; i < part.size(); ++i )
474 GEOSCoordSeq_setXY_r( geosctxt, cooSeq, i, part[i].x, part[i].y );
477 GEOSGeometry *newgeom = GEOSGeom_createLineString_r( geosctxt, cooSeq );
478 std::unique_ptr< FeaturePart > newfpart = std::make_unique< FeaturePart >( fpart->feature(), newgeom );
479 repeatParts.push_back( newfpart.get() );
480 newFeatureParts.emplace_back( std::move( newfpart ) );
489 partPtr->setTotalRepeats( repeatParts.count() );
494 newFeatureParts.emplace_back( std::move( fpart ) );
LabelPlacement
Placement modes which determine how label candidates are generated for a feature.
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 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...
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.
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.
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.
int connectedFeatureId(QgsFeatureId featureId) const
Returns the connected feature ID for a label feature ID, which is unique for all features which have ...
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.
double priority() const
Returns the layer's priority, between 0 and 1.
static QLinkedList< const GEOSGeometry * > * unmulti(const GEOSGeometry *the_geom)
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