|
39 | 39 | #include <iostream>
|
40 | 40 | #include <cstring>
|
41 | 41 | #include <cmath>
|
| 42 | +#include <vector> |
42 | 43 |
|
43 | 44 |
|
44 | 45 | #include <pal/pal.h>
|
@@ -228,7 +229,7 @@ namespace pal
|
228 | 229 |
|
229 | 230 | bool Layer::registerFeature( const char *geom_id, PalGeometry *userGeom, double label_x, double label_y, const char* labelText,
|
230 | 231 | 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 ) |
232 | 233 | {
|
233 | 234 | if ( !geom_id || label_x < 0 || label_y < 0 )
|
234 | 235 | return false;
|
@@ -284,6 +285,74 @@ namespace pal
|
284 | 285 | throw InternalException::UnknownGeometry();
|
285 | 286 | }
|
286 | 287 |
|
| 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 | + |
287 | 356 | while ( simpleGeometries->size() > 0 )
|
288 | 357 | {
|
289 | 358 | const GEOSGeometry* geom = simpleGeometries->pop_front();
|
@@ -320,7 +389,7 @@ namespace pal
|
320 | 389 | continue;
|
321 | 390 | }
|
322 | 391 |
|
323 |
| - if ( mode == LabelPerFeature && ( type == GEOS_POLYGON || type == GEOS_LINESTRING ) ) |
| 392 | + if ( mode == LabelPerFeature && repeatDistance == 0.0 && ( type == GEOS_POLYGON || type == GEOS_LINESTRING ) ) |
324 | 393 | {
|
325 | 394 | if ( type == GEOS_LINESTRING )
|
326 | 395 | GEOSLength( geom, &geom_size );
|
@@ -349,7 +418,7 @@ namespace pal
|
349 | 418 | modMutex->unlock();
|
350 | 419 |
|
351 | 420 | // 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 ) |
353 | 422 | {
|
354 | 423 | addFeaturePart( biggest_part, labelText );
|
355 | 424 | first_feat = false;
|
|
0 commit comments