@@ -23,6 +23,7 @@ this program. If not, see <https://www.gnu.org/licenses/>.
2323#include " pi.h"
2424#include " Planet.h"
2525#include " PointerShader.h"
26+ #include " Preferences.h"
2627#include " RingShader.h"
2728#include " StellarObject.h"
2829#include " System.h"
@@ -39,6 +40,41 @@ namespace {
3940 const double LINE_GAP = 1.7 ;
4041 const double GAP = 6 .;
4142 const double MIN_DISTANCE = 30 .;
43+
44+ // Check if the given label for the given stellar object and direction overlaps with any other stellar object in the system.
45+ bool Overlaps (const System &system, const StellarObject &object, double zoom, double width, int direction)
46+ {
47+ Point start = zoom * (object.Position () +
48+ (object.Radius () + INNER_SPACE + LINE_GAP + LINE_LENGTH) * Angle (LINE_ANGLE[direction]).Unit ());
49+ // Offset the label correctly depending on its location relative to the stellar object.
50+ Point unit (LINE_ANGLE[direction] > 180 . ? -1 . : 1 ., 0 .);
51+ Point end = start + unit * width;
52+
53+ for (const StellarObject &other : system.Objects ())
54+ {
55+ if (&other == &object)
56+ continue ;
57+
58+ double minDistance = (other.Radius () + MIN_DISTANCE) * zoom;
59+
60+ Point otherPos = other.Position () * zoom;
61+ double startDistance = otherPos.Distance (start);
62+ double endDistance = otherPos.Distance (end);
63+ if (startDistance < minDistance || endDistance < minDistance)
64+ return true ;
65+
66+ // Check overlap with the middle of the label, when the end and/or start might not overlap.
67+ double projection = (otherPos - start).Dot (unit);
68+ if (projection > 0 . && projection < width)
69+ {
70+ double distance = sqrt (startDistance * startDistance - projection * projection);
71+ if (distance < minDistance)
72+ return true ;
73+ }
74+ }
75+
76+ return false ;
77+ }
4278}
4379
4480
@@ -71,42 +107,24 @@ PlanetLabel::PlanetLabel(const Point &position, const StellarObject &object, con
71107
72108 // Figure out how big the label has to be.
73109 double width = max (FontSet::Get (18 ).Width (name), FontSet::Get (14 ).Width (government)) + 8 .;
74- for (int d = 0 ; d < 4 ; ++d)
75- {
76- bool overlaps = false ;
77-
78- Point start = object.Position () * zoom +
79- (radius + INNER_SPACE + LINE_GAP + LINE_LENGTH) * Angle (LINE_ANGLE[d]).Unit ();
80- Point unit (LINE_ANGLE[d] > 180 . ? -1 . : 1 ., 0 .);
81- Point end = start + unit * width;
82110
83- for (const StellarObject &other : system->Objects ())
111+ // Try to find a label direction that not overlapping under any zoom.
112+ for (int d = 0 ; d < 4 ; ++d)
113+ if (!Overlaps (*system, object, Preferences::MinViewZoom (), width, d)
114+ && !Overlaps (*system, object, Preferences::MaxViewZoom (), width, d))
84115 {
85- if (&other == &object)
86- continue ;
87-
88- double minDistance = (other.Radius () + MIN_DISTANCE) * zoom;
89-
90- Point otherPos = other.Position () * zoom;
91- double startDistance = otherPos.Distance (start);
92- double endDistance = otherPos.Distance (end);
93- overlaps |= (startDistance < minDistance || endDistance < minDistance);
94- double projection = (otherPos - start).Dot (unit);
95-
96- if (projection > 0 . && projection < width)
97- {
98- double distance = sqrt (startDistance * startDistance - projection * projection);
99- overlaps |= (distance < minDistance);
100- }
101- if (overlaps)
102- break ;
116+ direction = d;
117+ return ;
103118 }
104- if (!overlaps)
119+
120+ // If we can't find a suitable direction, then try to find a direction under the current
121+ // zoom that is not overlapping.
122+ for (int d = 0 ; d < 4 ; ++d)
123+ if (!Overlaps (*system, object, zoom, width, d))
105124 {
106125 direction = d;
107- break ;
126+ return ;
108127 }
109- }
110128}
111129
112130
0 commit comments