@@ -70,6 +70,7 @@ namespace pal
70
70
71
71
label_x = -1 ;
72
72
label_y = -1 ;
73
+ labelInfo = NULL ;
73
74
74
75
xmin = feat->minmax [0 ];
75
76
xmax = feat->minmax [2 ];
@@ -532,6 +533,242 @@ namespace pal
532
533
}
533
534
534
535
536
+ StraightLabelPosition* Feature::curvedPlacementAtOffset ( PointSet* path_positions, double * path_distances, int orientation, int index, double distance )
537
+ {
538
+ // Check that the given distance is on the given index and find the correct index and distance if not
539
+ while (distance < 0 && index > 1 )
540
+ {
541
+ index --;
542
+ distance += path_distances[index ];
543
+ }
544
+
545
+ if (index <= 1 && distance < 0 ) // We've gone off the start, fail out
546
+ {
547
+ std::cerr << " err1" << std::endl;
548
+ return NULL ;
549
+ }
550
+
551
+ // Same thing, checking if we go off the end
552
+ while (index < path_positions->nbPoints && distance > path_distances[index ])
553
+ {
554
+ distance -= path_distances[index ];
555
+ index += 1 ;
556
+ }
557
+ if (index >= path_positions->nbPoints )
558
+ {
559
+ std::cerr << " err2" << std::endl;
560
+ return NULL ;
561
+ }
562
+
563
+ // Keep track of the initial index,distance incase we need to re-call get_placement_offset
564
+ int initial_index = index ;
565
+ double initial_distance = distance;
566
+
567
+ double string_height = labelInfo->label_height ;
568
+ double old_x = path_positions->x [index -1 ];
569
+ double old_y = path_positions->y [index -1 ];
570
+
571
+ double new_x = path_positions->x [index ];
572
+ double new_y = path_positions->y [index ];
573
+
574
+ double dx = new_x - old_x;
575
+ double dy = new_y - old_y;
576
+
577
+ double segment_length = path_distances[index ];
578
+ if (segment_length == 0 )
579
+ {
580
+ // Not allowed to place across on 0 length segments or discontinuities
581
+ std::cerr << " err3" << std::endl;
582
+ return NULL ;
583
+ }
584
+
585
+ StraightLabelPosition* slp = NULL ;
586
+ StraightLabelPosition* slp_tmp = NULL ;
587
+ // current_placement = placement_result()
588
+ double xBase = old_x + dx*distance/segment_length;
589
+ double yBase = old_y + dy*distance/segment_length;
590
+ double angle = atan2 (-dy, dx);
591
+
592
+ bool orientation_forced = (orientation != 0 ); // Whether the orientation was set by the caller
593
+ if (!orientation_forced)
594
+ orientation = (angle > 0.55 *M_PI || angle < -0.45 *M_PI ? -1 : 1 );
595
+
596
+ int upside_down_char_count = 0 ; // Count of characters that are placed upside down.
597
+
598
+ for (int i = 0 ; i < labelInfo->char_num ; i++)
599
+ {
600
+ double last_character_angle = angle;
601
+
602
+ // grab the next character according to the orientation
603
+ LabelInfo::CharacterInfo& ci = (orientation > 0 ? labelInfo->char_info [i] : labelInfo->char_info [labelInfo->char_num -i-1 ]);
604
+
605
+ // Coordinates this character will start at
606
+ if (segment_length == 0 )
607
+ {
608
+ // Not allowed to place across on 0 length segments or discontinuities
609
+ std::cerr << " err4" << std::endl;
610
+ return NULL ;
611
+ }
612
+
613
+ double start_x = old_x + dx*distance/segment_length;
614
+ double start_y = old_y + dy*distance/segment_length;
615
+ // Coordinates this character ends at, calculated below
616
+ double end_x = 0 ;
617
+ double end_y = 0 ;
618
+
619
+ std::cerr << " segment len " << segment_length << " distance " << distance << std::endl;
620
+ if (segment_length - distance >= ci.width )
621
+ {
622
+ // if the distance remaining in this segment is enough, we just go further along the segment
623
+ distance += ci.width ;
624
+ end_x = old_x + dx*distance/segment_length;
625
+ end_y = old_y + dy*distance/segment_length;
626
+ }
627
+ else
628
+ {
629
+ // If there isn't enough distance left on this segment
630
+ // then we need to search until we find the line segment that ends further than ci.width away
631
+ do
632
+ {
633
+ old_x = new_x;
634
+ old_y = new_y;
635
+ index ++;
636
+ if (index >= path_positions->nbPoints ) // Bail out if we run off the end of the shape
637
+ {
638
+ std::cerr << " err5" << std::endl;
639
+ return NULL ;
640
+ }
641
+ new_x = path_positions->x [index ];
642
+ new_y = path_positions->y [index ];
643
+ dx = new_x - old_x;
644
+ dy = new_y - old_y;
645
+ segment_length = path_distances[index ];
646
+
647
+ std::cerr << " -> " << sqrt (pow (start_x - new_x,2 ) + pow (start_y - new_y,2 )) << " vs " << ci.width << std::endl;
648
+
649
+ } while (sqrt (pow (start_x - new_x,2 ) + pow (start_y - new_y,2 )) < ci.width ); // Distance from start_ to new_
650
+
651
+ // Calculate the position to place the end of the character on
652
+ findLineCircleIntersection ( start_x, start_y, ci.width , old_x, old_y, new_x, new_y, end_x, end_y);
653
+
654
+ // Need to calculate distance on the new segment
655
+ distance = sqrt (pow (old_x - end_x,2 ) + pow (old_y - end_y,2 ));
656
+ }
657
+
658
+ // Calculate angle from the start of the character to the end based on start_/end_ position
659
+ angle = atan2 (start_y-end_y, end_x-start_x);
660
+ // angle = atan2(end_y-start_y, end_x-start_x);
661
+
662
+ // Test last_character_angle vs angle
663
+ // since our rendering angle has changed then check against our
664
+ // max allowable angle change.
665
+ double angle_delta = last_character_angle - angle;
666
+ // normalise between -180 and 180
667
+ while (angle_delta > M_PI) angle_delta -= 2 *M_PI;
668
+ while (angle_delta < -M_PI) angle_delta += 2 *M_PI;
669
+ if (labelInfo->max_char_angle_delta > 0 && fabs (angle_delta) > labelInfo->max_char_angle_delta *(M_PI/180 ))
670
+ {
671
+ std::cerr << " err6" << std::endl;
672
+ return NULL ;
673
+ }
674
+
675
+ double render_angle = angle;
676
+
677
+ double render_x = start_x;
678
+ double render_y = start_y;
679
+
680
+ // Center the text on the line
681
+ // render_x -= ((string_height/2.0) - 1.0)*math.cos(render_angle+math.pi/2)
682
+ // render_y += ((string_height/2.0) - 1.0)*math.sin(render_angle+math.pi/2)
683
+
684
+ if (orientation < 0 )
685
+ {
686
+ // rotate in place
687
+ render_x += ci.width *cos (render_angle); // - (string_height-2)*sin(render_angle);
688
+ render_y -= ci.width *sin (render_angle); // + (string_height-2)*cos(render_angle);
689
+ render_angle += M_PI;
690
+ }
691
+
692
+ std::cerr << " adding part: " << render_x << " " << render_y << std::endl;
693
+ StraightLabelPosition* tmp = new StraightLabelPosition (0 , render_x /* - xBase*/ , render_y /* - yBase*/ , ci.width , string_height, -render_angle, 0.0001 , this );
694
+ tmp->setPartId ( orientation > 0 ? i : labelInfo->char_num -i-1 );
695
+ if (slp == NULL )
696
+ slp = tmp;
697
+ else
698
+ slp_tmp->setNextPart (tmp);
699
+ slp_tmp = tmp;
700
+
701
+ // current_placement.add_node(ci.character,render_x, -render_y, render_angle);
702
+ // current_placement.add_node(ci.character,render_x - current_placement.starting_x, render_y - current_placement.starting_y, render_angle)
703
+
704
+ // Normalise to 0 <= angle < 2PI
705
+ while (render_angle >= 2 *M_PI) render_angle -= 2 *M_PI;
706
+ while (render_angle < 0 ) render_angle += 2 *M_PI;
707
+
708
+ if (render_angle > M_PI/2 && render_angle < 1.5 *M_PI)
709
+ upside_down_char_count++;
710
+ }
711
+ // END FOR
712
+
713
+ // If we placed too many characters upside down
714
+ if (upside_down_char_count >= labelInfo->char_num /2.0 )
715
+ {
716
+ // if we auto-detected the orientation then retry with the opposite orientation
717
+ if (!orientation_forced)
718
+ {
719
+ orientation = -orientation;
720
+ slp = curvedPlacementAtOffset (path_positions, path_distances, orientation, initial_index, initial_distance);
721
+ }
722
+ else
723
+ {
724
+ // Otherwise we have failed to find a placement
725
+ std::cerr << " err7" << std::endl;
726
+ return NULL ;
727
+ }
728
+ }
729
+
730
+ return slp;
731
+ }
732
+
733
+ int Feature::setPositionForLineCurved ( LabelPosition ***lPos, PointSet* mapShape )
734
+ {
735
+ // label info must be present
736
+ if (labelInfo == NULL || labelInfo->char_num == 0 )
737
+ return 0 ;
738
+
739
+ // distance calculation
740
+ double * path_distances = new double [mapShape->nbPoints ];
741
+ double old_x, old_y, new_x, new_y;
742
+ for (int i = 0 ; i < mapShape->nbPoints ; i++)
743
+ {
744
+ if (i == 0 )
745
+ path_distances[i] = 0 ;
746
+ else
747
+ path_distances[i] = sqrt ( pow (old_x - mapShape->x [i], 2 ) + pow (old_y - mapShape->y [i],2 ) );
748
+ old_x = mapShape->x [i];
749
+ old_y = mapShape->y [i];
750
+ }
751
+
752
+ // TODO: generate more labels
753
+
754
+ // generate curved label
755
+ StraightLabelPosition* slp = curvedPlacementAtOffset (mapShape, path_distances, 0 , 1 , 0.0 );
756
+
757
+ if (!slp)
758
+ return 0 ;
759
+
760
+ // TODO: evaluate cost
761
+
762
+ int nbp = 1 ;
763
+ ( *lPos ) = new LabelPosition*[nbp];
764
+ (*lPos)[0 ] = slp;
765
+
766
+ return nbp;
767
+ }
768
+
769
+
770
+
771
+
535
772
/*
536
773
* seg 2
537
774
* pt3 ____________pt2
@@ -843,7 +1080,10 @@ namespace pal
843
1080
releaseCoordinates ();
844
1081
break ;
845
1082
case GEOS_LINESTRING:
846
- nbp = setPositionForLine ( scale, lPos, mapShape, delta );
1083
+ if ( layer->getArrangement () == P_CURVED )
1084
+ nbp = setPositionForLineCurved ( lPos, mapShape );
1085
+ else
1086
+ nbp = setPositionForLine ( scale, lPos, mapShape, delta );
847
1087
break ;
848
1088
849
1089
case GEOS_POLYGON:
0 commit comments