Skip to content

Commit c3d7f0d

Browse files
committedMay 7, 2014
Add line multi-labelling support to pal
1 parent 0575c71 commit c3d7f0d

File tree

3 files changed

+77
-4
lines changed

3 files changed

+77
-4
lines changed
 

‎src/core/pal/layer.cpp

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include <iostream>
4040
#include <cstring>
4141
#include <cmath>
42+
#include <vector>
4243

4344

4445
#include <pal/pal.h>
@@ -228,7 +229,7 @@ namespace pal
228229

229230
bool Layer::registerFeature( const char *geom_id, PalGeometry *userGeom, double label_x, double label_y, const char* labelText,
230231
double labelPosX, double labelPosY, bool fixedPos, double angle, bool fixedAngle,
231-
int xQuadOffset, int yQuadOffset, double xOffset, double yOffset, bool alwaysShow )
232+
int xQuadOffset, int yQuadOffset, double xOffset, double yOffset, bool alwaysShow, double repeatDistance )
232233
{
233234
if ( !geom_id || label_x < 0 || label_y < 0 )
234235
return false;
@@ -284,6 +285,74 @@ namespace pal
284285
throw InternalException::UnknownGeometry();
285286
}
286287

288+
// if multiple labels are requested for lines, split the line in pieces of desired distance
289+
if(repeatDistance > 0) {
290+
int nSimpleGeometries = simpleGeometries->size();
291+
for(int i = 0; i < nSimpleGeometries; ++i) {
292+
const GEOSGeometry* geom = simpleGeometries->pop_front();
293+
if(GEOSGeomTypeId(geom) == GEOS_LINESTRING) {
294+
295+
// get number of points
296+
int n = GEOSGeomGetNumPoints(geom);
297+
298+
// Read points
299+
std::vector<Point> points(n);
300+
for(int i = 0; i < n; ++i) {
301+
GEOSGeometry* p = GEOSGeomGetPointN(geom, i);
302+
GEOSGeomGetX(p, &points[i].x);
303+
GEOSGeomGetY(p, &points[i].y);
304+
GEOSGeom_destroy(p);
305+
}
306+
307+
// Cumulative length vector
308+
std::vector<double> len(n, 0);
309+
for(int i = 1; i < n; ++i) {
310+
double dx = points[i].x - points[i - 1].x;
311+
double dy = points[i].y - points[i - 1].y;
312+
len[i] = len[i - 1] + std::sqrt(dx * dx + dy * dy);
313+
}
314+
315+
// Walk along line
316+
int cur = 0;
317+
double lambda = 0;
318+
std::vector<Point> part;
319+
while(true) {
320+
lambda += repeatDistance;
321+
for(; cur < n && lambda > len[cur]; ++cur) {
322+
part.push_back(points[cur]);
323+
}
324+
if(cur >= n) {
325+
break;
326+
}
327+
double c = (lambda - len[cur - 1]) / (len[cur] - len[cur - 1]);
328+
Point p;
329+
p.x = points[cur - 1].x + c * (points[cur].x - points[cur - 1].x);
330+
p.y = points[cur - 1].y + c * (points[cur].y - points[cur - 1].y);
331+
part.push_back(p);
332+
GEOSCoordSequence* cooSeq = GEOSCoordSeq_create(part.size(), 2);
333+
for(std::size_t i = 0; i < part.size(); ++i) {
334+
GEOSCoordSeq_setX(cooSeq, i, part[i].x);
335+
GEOSCoordSeq_setY(cooSeq, i, part[i].y);
336+
}
337+
338+
simpleGeometries->push_back(GEOSGeom_createLineString(cooSeq));
339+
part.clear();
340+
part.push_back(p);
341+
}
342+
// Create final part
343+
part.push_back(points[n - 1]);
344+
GEOSCoordSequence* cooSeq = GEOSCoordSeq_create(part.size(), 2);
345+
for(std::size_t i = 0; i < part.size(); ++i) {
346+
GEOSCoordSeq_setX(cooSeq, i, part[i].x);
347+
GEOSCoordSeq_setY(cooSeq, i, part[i].y);
348+
}
349+
simpleGeometries->push_back(GEOSGeom_createLineString(cooSeq));
350+
}else{
351+
simpleGeometries->push_back( geom );
352+
}
353+
}
354+
}
355+
287356
while ( simpleGeometries->size() > 0 )
288357
{
289358
const GEOSGeometry* geom = simpleGeometries->pop_front();
@@ -320,7 +389,7 @@ namespace pal
320389
continue;
321390
}
322391

323-
if ( mode == LabelPerFeature && ( type == GEOS_POLYGON || type == GEOS_LINESTRING ) )
392+
if ( mode == LabelPerFeature && repeatDistance == 0.0 && ( type == GEOS_POLYGON || type == GEOS_LINESTRING ) )
324393
{
325394
if ( type == GEOS_LINESTRING )
326395
GEOSLength( geom, &geom_size );
@@ -349,7 +418,7 @@ namespace pal
349418
modMutex->unlock();
350419

351420
// if using only biggest parts...
352-
if (( mode == LabelPerFeature || f->fixedPosition() ) && biggest_part != NULL )
421+
if (( (mode == LabelPerFeature && repeatDistance == 0.0) || f->fixedPosition() ) && biggest_part != NULL )
353422
{
354423
addFeaturePart( biggest_part, labelText );
355424
first_feat = false;

‎src/core/pal/layer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ namespace pal
317317
const char* labelText = NULL, double labelPosX = 0.0, double labelPosY = 0.0,
318318
bool fixedPos = false, double angle = 0.0, bool fixedAngle = false,
319319
int xQuadOffset = 0, int yQuadOffset = 0, double xOffset = 0.0, double yOffset = 0.0,
320-
bool alwaysShow = false );
320+
bool alwaysShow = false, double repeatDistance = 0.0 );
321321

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

‎src/core/pal/util.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ namespace pal
7474
int new_label;
7575
} ElemTrans;
7676

77+
struct Point {
78+
double x, y;
79+
};
80+
7781

7882

7983
#define EPSILON 1e-9

0 commit comments

Comments
 (0)
Please sign in to comment.