Skip to content

Commit 1d0976d

Browse files
authored
fix(UI): Disallow the planet label from jumping around at different zooms (#7342)
1 parent 56b0a26 commit 1d0976d

File tree

3 files changed

+64
-30
lines changed

3 files changed

+64
-30
lines changed

source/PlanetLabel.cpp

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -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

source/Preferences.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,20 @@ bool Preferences::ZoomViewOut()
191191

192192

193193

194+
double Preferences::MinViewZoom()
195+
{
196+
return ZOOMS[0];
197+
}
198+
199+
200+
201+
double Preferences::MaxViewZoom()
202+
{
203+
return ZOOMS[ZOOMS.size() - 1];
204+
}
205+
206+
207+
194208
void Preferences::ToggleScreenMode()
195209
{
196210
GameWindow::ToggleFullscreen();

source/Preferences.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ class Preferences {
4949
static double ViewZoom();
5050
static bool ZoomViewIn();
5151
static bool ZoomViewOut();
52+
static double MinViewZoom();
53+
static double MaxViewZoom();
5254

5355
static void ToggleScreenMode();
5456
static const std::string &ScreenModeSetting();

0 commit comments

Comments
 (0)