Skip to content

Commit

Permalink
Merge pull request #1395 from manisandro/line_multi_labeling_improved
Browse files Browse the repository at this point in the history
Line multi labeling improved
  • Loading branch information
mhugent committed Jun 27, 2014
2 parents ae9b306 + 00692c7 commit abd6a69
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 126 deletions.
4 changes: 2 additions & 2 deletions src/app/qgslabelinggui.cpp
Expand Up @@ -1290,12 +1290,12 @@ void QgsLabelingGui::updatePlacementWidgets()
}

mPlacementLineFrame->setVisible( showLineFrame );
mPlacmentCentroidFrame->setVisible( showCentroidFrame );
mPlacementCentroidFrame->setVisible( showCentroidFrame );
mPlacementQuadrantFrame->setVisible( showQuadrantFrame );
mPlacementOffsetFrame->setVisible( showOffsetFrame );
mPlacementDistanceFrame->setVisible( showDistanceFrame );
mPlacementRotationFrame->setVisible( showRotationFrame );
mPlacmentRepeatDistanceFrame->setVisible( curWdgt == pageLine );
mPlacementRepeatDistanceFrame->setVisible( curWdgt == pageLine || ( curWdgt == pagePolygon && radPolygonPerimeter->isChecked() ) );
mPlacementMaxCharAngleFrame->setVisible( showMaxCharAngleFrame );

mMultiLinesFrame->setEnabled( enableMultiLinesFrame );
Expand Down
12 changes: 12 additions & 0 deletions src/core/pal/feature.h
Expand Up @@ -228,6 +228,18 @@ namespace pal
*/
//int getId();

/**
* \brief return the feature
* \return the feature
*/
Feature* getFeature() { return f; }

/**
* \brief return the geometry
* \return the geometry
*/
const GEOSGeometry* getGeometry() const { return the_geom; }

/**
* \brief return the layer that feature belongs to
* \return the layer of the feature
Expand Down
182 changes: 99 additions & 83 deletions src/core/pal/layer.cpp
Expand Up @@ -229,7 +229,7 @@ namespace pal

bool Layer::registerFeature( const char *geom_id, PalGeometry *userGeom, double label_x, double label_y, const char* labelText,
double labelPosX, double labelPosY, bool fixedPos, double angle, bool fixedAngle,
int xQuadOffset, int yQuadOffset, double xOffset, double yOffset, bool alwaysShow, double repeatDistance )
int xQuadOffset, int yQuadOffset, double xOffset, double yOffset, bool alwaysShow )
{
if ( !geom_id || label_x < 0 || label_y < 0 )
return false;
Expand Down Expand Up @@ -285,86 +285,6 @@ namespace pal
throw InternalException::UnknownGeometry();
}

// if multiple labels are requested for lines, split the line in pieces of desired distance
if ( repeatDistance > 0 )
{
int nSimpleGeometries = simpleGeometries->size();
for ( int i = 0; i < nSimpleGeometries; ++i )
{
const GEOSGeometry* geom = simpleGeometries->pop_front();
if ( GEOSGeomTypeId( geom ) == GEOS_LINESTRING )
{
const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq( geom );

// get number of points
unsigned int n;
GEOSCoordSeq_getSize( cs, &n );

// Read points
std::vector<Point> points( n );
for ( unsigned int i = 0; i < n; ++i )
{
GEOSCoordSeq_getX( cs, i, &points[i].x );
GEOSCoordSeq_getY( cs, i, &points[i].y );
}

// Cumulative length vector
std::vector<double> len( n, 0 );
for ( unsigned int i = 1; i < n; ++i )
{
double dx = points[i].x - points[i - 1].x;
double dy = points[i].y - points[i - 1].y;
len[i] = len[i - 1] + std::sqrt( dx * dx + dy * dy );
}

// Walk along line
unsigned int cur = 0;
double lambda = 0;
std::vector<Point> part;
for ( ;; )
{
lambda += repeatDistance;
for ( ; cur < n && lambda > len[cur]; ++cur )
{
part.push_back( points[cur] );
}
if ( cur >= n )
{
break;
}
double c = ( lambda - len[cur - 1] ) / ( len[cur] - len[cur - 1] );
Point p;
p.x = points[cur - 1].x + c * ( points[cur].x - points[cur - 1].x );
p.y = points[cur - 1].y + c * ( points[cur].y - points[cur - 1].y );
part.push_back( p );
GEOSCoordSequence* cooSeq = GEOSCoordSeq_create( part.size(), 2 );
for ( std::size_t i = 0; i < part.size(); ++i )
{
GEOSCoordSeq_setX( cooSeq, i, part[i].x );
GEOSCoordSeq_setY( cooSeq, i, part[i].y );
}

simpleGeometries->push_back( GEOSGeom_createLineString( cooSeq ) );
part.clear();
part.push_back( p );
}
// Create final part
part.push_back( points[n - 1] );
GEOSCoordSequence* cooSeq = GEOSCoordSeq_create( part.size(), 2 );
for ( std::size_t i = 0; i < part.size(); ++i )
{
GEOSCoordSeq_setX( cooSeq, i, part[i].x );
GEOSCoordSeq_setY( cooSeq, i, part[i].y );
}
simpleGeometries->push_back( GEOSGeom_createLineString( cooSeq ) );
}
else
{
simpleGeometries->push_back( geom );
}
}
}

while ( simpleGeometries->size() > 0 )
{
const GEOSGeometry* geom = simpleGeometries->pop_front();
Expand Down Expand Up @@ -401,7 +321,7 @@ namespace pal
continue;
}

if ( mode == LabelPerFeature && repeatDistance == 0.0 && ( type == GEOS_POLYGON || type == GEOS_LINESTRING ) )
if ( mode == LabelPerFeature && ( type == GEOS_POLYGON || type == GEOS_LINESTRING ) )
{
if ( type == GEOS_LINESTRING )
GEOSLength( geom, &geom_size );
Expand Down Expand Up @@ -430,7 +350,7 @@ namespace pal
modMutex->unlock();

// if using only biggest parts...
if ((( mode == LabelPerFeature && repeatDistance == 0.0 ) || f->fixedPosition() ) && biggest_part != NULL )
if (( mode == LabelPerFeature || f->fixedPosition() ) && biggest_part != NULL )
{
addFeaturePart( biggest_part, labelText );
first_feat = false;
Expand Down Expand Up @@ -569,6 +489,102 @@ namespace pal
connectedTexts = NULL;
}

void Layer::chopFeatures( double chopInterval )
{
LinkedList<FeaturePart*> * newFeatureParts = new LinkedList<FeaturePart*>( ptrFeaturePartCompare );
while ( FeaturePart* fpart = featureParts->pop_front() )
{
const GEOSGeometry* geom = fpart->getGeometry();
if ( GEOSGeomTypeId( geom ) == GEOS_LINESTRING )
{

double bmin[2], bmax[2];
fpart->getBoundingBox( bmin, bmax );
rtree->Remove( bmin, bmax, fpart );

const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq( geom );

// get number of points
unsigned int n;
GEOSCoordSeq_getSize( cs, &n );

// Read points
std::vector<Point> points( n );
for ( unsigned int i = 0; i < n; ++i )
{
GEOSCoordSeq_getX( cs, i, &points[i].x );
GEOSCoordSeq_getY( cs, i, &points[i].y );
}

// Cumulative length vector
std::vector<double> len( n, 0 );
for ( unsigned int i = 1; i < n; ++i )
{
double dx = points[i].x - points[i - 1].x;
double dy = points[i].y - points[i - 1].y;
len[i] = len[i - 1] + std::sqrt( dx * dx + dy * dy );
}

// Walk along line
unsigned int cur = 0;
double lambda = 0;
std::vector<Point> part;
for ( ;; )
{
lambda += chopInterval;
for ( ; cur < n && lambda > len[cur]; ++cur )
{
part.push_back( points[cur] );
}
if ( cur >= n )
{
break;
}
double c = ( lambda - len[cur - 1] ) / ( len[cur] - len[cur - 1] );
Point p;
p.x = points[cur - 1].x + c * ( points[cur].x - points[cur - 1].x );
p.y = points[cur - 1].y + c * ( points[cur].y - points[cur - 1].y );
part.push_back( p );
GEOSCoordSequence* cooSeq = GEOSCoordSeq_create( part.size(), 2 );
for ( std::size_t i = 0; i < part.size(); ++i )
{
GEOSCoordSeq_setX( cooSeq, i, part[i].x );
GEOSCoordSeq_setY( cooSeq, i, part[i].y );
}

GEOSGeometry* newgeom = GEOSGeom_createLineString( cooSeq );
FeaturePart* newfpart = new FeaturePart( fpart->getFeature(), newgeom );
newFeatureParts->push_back( newfpart );
newfpart->getBoundingBox( bmin, bmax );
rtree->Insert( bmin, bmax, newfpart );
part.clear();
part.push_back( p );
}
// Create final part
part.push_back( points[n - 1] );
GEOSCoordSequence* cooSeq = GEOSCoordSeq_create( part.size(), 2 );
for ( std::size_t i = 0; i < part.size(); ++i )
{
GEOSCoordSeq_setX( cooSeq, i, part[i].x );
GEOSCoordSeq_setY( cooSeq, i, part[i].y );
}

GEOSGeometry* newgeom = GEOSGeom_createLineString( cooSeq );
FeaturePart* newfpart = new FeaturePart( fpart->getFeature(), newgeom );
newFeatureParts->push_back( newfpart );
newfpart->getBoundingBox( bmin, bmax );
rtree->Insert( bmin, bmax, newfpart );
}
else
{
newFeatureParts->push_back( fpart );
}
}

delete featureParts;
featureParts = newFeatureParts;
}



} // end namespace
Expand Down
8 changes: 7 additions & 1 deletion src/core/pal/layer.h
Expand Up @@ -113,6 +113,7 @@ namespace pal
unsigned long arrangementFlags;
LabelMode mode;
bool mergeLines;
double repeatDistance;

UpsideDownLabels upsidedownLabels;

Expand Down Expand Up @@ -289,6 +290,9 @@ namespace pal
void setMergeConnectedLines( bool m ) { mergeLines = m; }
bool getMergeConnectedLines() const { return mergeLines; }

void setRepeatDistance( double distance ) { repeatDistance = distance; }
double getRepeatDistance() const { return repeatDistance; }

void setUpsidedownLabels( UpsideDownLabels ud ) { upsidedownLabels = ud; }
UpsideDownLabels getUpsidedownLabels() const { return upsidedownLabels; }

Expand Down Expand Up @@ -321,14 +325,16 @@ namespace pal
const char* labelText = NULL, double labelPosX = 0.0, double labelPosY = 0.0,
bool fixedPos = false, double angle = 0.0, bool fixedAngle = false,
int xQuadOffset = 0, int yQuadOffset = 0, double xOffset = 0.0, double yOffset = 0.0,
bool alwaysShow = false, double repeatDistance = 0.0 );
bool alwaysShow = false );

/** return pointer to feature or NULL if doesn't exist */
Feature* getFeature( const char* geom_id );

/** join connected features with the same label text */
void joinConnectedFeatures();

void chopFeatures(double chopInterval );

};

} // end namespace pal
Expand Down
3 changes: 3 additions & 0 deletions src/core/pal/pal.cpp
Expand Up @@ -429,6 +429,9 @@ namespace pal
if ( layer->getMergeConnectedLines() )
layer->joinConnectedFeatures();

if ( layer->getRepeatDistance() > 0 )
layer->chopFeatures( layer->getRepeatDistance() );

context->layer = layer;
context->priority = layersFactor[i];
// lookup for feature (and generates candidates list)
Expand Down

0 comments on commit abd6a69

Please sign in to comment.