Skip to content

Commit

Permalink
Chop lines after merging connected features
Browse files Browse the repository at this point in the history
  • Loading branch information
manisandro committed Jun 21, 2014
1 parent 7e4600f commit 00692c7
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 121 deletions.
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
78 changes: 41 additions & 37 deletions src/core/qgspallabeling.cpp
Expand Up @@ -2264,48 +2264,12 @@ void QgsPalLayerSettings::registerFeature( QgsFeature& f, const QgsRenderContext
#endif
lbl->setDefinedFont( labelFont );

// data defined repeat distance?
double repeatDist = repeatDistance;
if ( dataDefinedEvaluate( QgsPalLayerSettings::RepeatDistance, exprVal ) )
{
bool ok;
double distD = exprVal.toDouble( &ok );
if ( ok )
{
repeatDist = distD;
}
}

// data defined label-repeat distance units?
bool repeatdistinmapunit = repeatDistanceUnit == MapUnits;
if ( dataDefinedEvaluate( QgsPalLayerSettings::RepeatDistanceUnit, exprVal ) )
{
QString units = exprVal.toString().trimmed();
QgsDebugMsgLevel( QString( "exprVal RepeatDistanceUnits:%1" ).arg( units ), 4 );
if ( !units.isEmpty() )
{
repeatdistinmapunit = ( _decodeUnits( units ) == QgsPalLayerSettings::MapUnits );
}
}

if ( repeatDist != 0 )
{
if ( !repeatdistinmapunit ) //convert distance from mm/map units to pixels
{
repeatDist *= repeatDistanceMapUnitScale.computeMapUnitsPerPixel( context ) * context.scaleFactor();
}
else //mm
{
repeatDist *= vectorScaleFactor;
}
}

// feature to the layer
try
{
if ( !palLayer->registerFeature( lbl->strId(), lbl, labelX, labelY, labelText.toUtf8().constData(),
xPos, yPos, dataDefinedPosition, angle, dataDefinedRotation,
quadOffsetX, quadOffsetY, offsetX, offsetY, alwaysShow, repeatDist ) )
quadOffsetX, quadOffsetY, offsetX, offsetY, alwaysShow ) )
return;
}
catch ( std::exception &e )
Expand Down Expand Up @@ -3422,9 +3386,49 @@ int QgsPalLabeling::prepareLayer( QgsVectorLayer* layer, QStringList& attrNames,
// set whether adjacent lines should be merged
l->setMergeConnectedLines( lyr.mergeLines );


// set whether location of centroid must be inside of polygons
l->setCentroidInside( lyr.centroidInside );

// set repeat distance
// data defined repeat distance?
QVariant exprVal;
double repeatDist = lyr.repeatDistance;
if ( lyr.dataDefinedEvaluate( QgsPalLayerSettings::RepeatDistance, exprVal ) )
{
bool ok;
double distD = exprVal.toDouble( &ok );
if ( ok )
{
repeatDist = distD;
}
}

// data defined label-repeat distance units?
bool repeatdistinmapunit = lyr.repeatDistanceUnit == QgsPalLayerSettings::MapUnits;
if ( lyr.dataDefinedEvaluate( QgsPalLayerSettings::RepeatDistanceUnit, exprVal ) )
{
QString units = exprVal.toString().trimmed();
QgsDebugMsgLevel( QString( "exprVal RepeatDistanceUnits:%1" ).arg( units ), 4 );
if ( !units.isEmpty() )
{
repeatdistinmapunit = ( _decodeUnits( units ) == QgsPalLayerSettings::MapUnits );
}
}

if ( repeatDist != 0 )
{
if ( !repeatdistinmapunit ) //convert distance from mm/map units to pixels
{
repeatDist *= lyr.repeatDistanceMapUnitScale.computeMapUnitsPerPixel( ctx ) * ctx.scaleFactor();
}
else //mm
{
repeatDist *= lyr.vectorScaleFactor;
}
}
l->setRepeatDistance( repeatDist );

// set how to show upside-down labels
Layer::UpsideDownLabels upsdnlabels;
switch ( lyr.upsidedownLabels )
Expand Down

0 comments on commit 00692c7

Please sign in to comment.