Skip to content

Commit f935a4a

Browse files
authored
Merge pull request #4475 from Goober5000/fix_erroneous_angle_modification
fix erroneous position/angle modification
2 parents a009dc1 + 601addd commit f935a4a

File tree

2 files changed

+65
-21
lines changed

2 files changed

+65
-21
lines changed

fred2/orienteditor.cpp

Lines changed: 58 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
static char THIS_FILE[] = __FILE__;
2222
#endif
2323

24-
const float input_threshold = 0.01f; // smallest increment of input box
24+
constexpr auto INPUT_THRESHOLD = 0.01f; // smallest increment of input box
25+
constexpr auto INPUT_FORMAT = "%.01f";
2526

2627
/////////////////////////////////////////////////////////////////////////////
2728
// orient_editor dialog
@@ -45,15 +46,15 @@ orient_editor::orient_editor(CWnd* pParent /*=NULL*/)
4546

4647
Assert(query_valid_object());
4748
auto pos = &Objects[cur_object_index].pos;
48-
m_position_x.Format("%.01f", pos->xyz.x);
49-
m_position_y.Format("%.01f", pos->xyz.y);
50-
m_position_z.Format("%.01f", pos->xyz.z);
49+
m_position_x.Format(INPUT_FORMAT, pos->xyz.x);
50+
m_position_y.Format(INPUT_FORMAT, pos->xyz.y);
51+
m_position_z.Format(INPUT_FORMAT, pos->xyz.z);
5152

5253
angles ang;
5354
vm_extract_angles_matrix(&ang, &Objects[cur_object_index].orient);
54-
m_orientation_p.Format("%.01f", to_degrees(ang.p));
55-
m_orientation_b.Format("%.01f", to_degrees(ang.b));
56-
m_orientation_h.Format("%.01f", to_degrees(ang.h));
55+
m_orientation_p.Format(INPUT_FORMAT, to_degrees(ang.p));
56+
m_orientation_b.Format(INPUT_FORMAT, to_degrees(ang.b));
57+
m_orientation_h.Format(INPUT_FORMAT, to_degrees(ang.h));
5758
}
5859

5960
void orient_editor::DoDataExchange(CDataExchange* pDX)
@@ -182,29 +183,47 @@ BOOL orient_editor::OnInitDialog()
182183
return TRUE;
183184
}
184185

185-
bool orient_editor::close(float val, const CString &str)
186+
/**
187+
* Checks whether the position value is close enough to the input string value that we can assume the input has not changed.
188+
*/
189+
bool orient_editor::is_close(float val, const CString &input_str) const
186190
{
187-
float diff = val - convert(str);
188-
return diff > -input_threshold && diff < input_threshold;
191+
val = perform_input_rounding(val);
192+
float input_val = convert(input_str);
193+
194+
float diff = val - input_val;
195+
return abs(diff) < INPUT_THRESHOLD;
196+
}
197+
198+
/**
199+
* Checks whether the angle value is close enough to the input string value that we can assume the input has not changed.
200+
*/
201+
bool orient_editor::is_angle_close(float rad, const CString &input_str) const
202+
{
203+
float deg = perform_input_rounding(to_degrees(rad));
204+
float input_deg = normalize_degrees(convert(input_str));
205+
206+
float diff = deg - input_deg;
207+
return abs(diff) < INPUT_THRESHOLD;
189208
}
190209

191210
bool orient_editor::query_modified()
192211
{
193-
if (!close(Objects[cur_object_index].pos.xyz.x, m_position_x))
212+
if (!is_close(Objects[cur_object_index].pos.xyz.x, m_position_x))
194213
return true;
195-
if (!close(Objects[cur_object_index].pos.xyz.y, m_position_y))
214+
if (!is_close(Objects[cur_object_index].pos.xyz.y, m_position_y))
196215
return true;
197-
if (!close(Objects[cur_object_index].pos.xyz.z, m_position_z))
216+
if (!is_close(Objects[cur_object_index].pos.xyz.z, m_position_z))
198217
return true;
199218

200219
angles ang;
201220
vm_extract_angles_matrix(&ang, &Objects[cur_object_index].orient);
202221

203-
if (!close(to_degrees(ang.p), m_orientation_p))
222+
if (!is_angle_close(ang.p, m_orientation_p))
204223
return true;
205-
if (!close(to_degrees(ang.b), m_orientation_b))
224+
if (!is_angle_close(ang.b, m_orientation_b))
206225
return true;
207-
if (!close(to_degrees(ang.h), m_orientation_h))
226+
if (!is_angle_close(ang.h, m_orientation_h))
208227
return true;
209228

210229
if (((CButton *) GetDlgItem(IDC_POINT_TO_CHECKBOX))->GetCheck() == TRUE)
@@ -224,7 +243,7 @@ void orient_editor::OnOK()
224243

225244
// there's enough difference in our position that we're changing it
226245
cur_pos = &Objects[cur_object_index].pos;
227-
if (!close(cur_pos->xyz.x, m_position_x) || !close(cur_pos->xyz.y, m_position_y) || !close(cur_pos->xyz.z, m_position_z))
246+
if (!is_close(cur_pos->xyz.x, m_position_x) || !is_close(cur_pos->xyz.y, m_position_y) || !is_close(cur_pos->xyz.z, m_position_z))
228247
{
229248
vec3d pos;
230249
pos.xyz.x = convert(m_position_x);
@@ -237,7 +256,7 @@ void orient_editor::OnOK()
237256

238257
// there's enough difference in our orientation that we're changing it
239258
vm_extract_angles_matrix(&ang, &Objects[cur_object_index].orient);
240-
if (!close(to_degrees(ang.p), m_orientation_p) || !close(to_degrees(ang.b), m_orientation_b) || !close(to_degrees(ang.h), m_orientation_h))
259+
if (!is_angle_close(ang.p, m_orientation_p) || !is_angle_close(ang.b, m_orientation_b) || !is_angle_close(ang.h, m_orientation_h))
241260
{
242261
ang.p = fl_radians(convert(m_orientation_p));
243262
ang.b = fl_radians(convert(m_orientation_b));
@@ -354,6 +373,11 @@ void orient_editor::actually_point_object(object *ptr)
354373
float orient_editor::to_degrees(float rad)
355374
{
356375
float deg = fl_degrees(rad);
376+
return normalize_degrees(deg);
377+
}
378+
379+
float orient_editor::normalize_degrees(float deg)
380+
{
357381
while (deg < -180.0f)
358382
deg += 180.0f;
359383
while (deg > 180.0f)
@@ -364,7 +388,10 @@ float orient_editor::to_degrees(float rad)
364388
return deg;
365389
}
366390

367-
float orient_editor::convert(const CString &str)
391+
/**
392+
* Extract a float from the CString, being mindful of any comma separators.
393+
*/
394+
float orient_editor::convert(const CString &str) const
368395
{
369396
char buf[256];
370397
size_t i, j, len;
@@ -379,6 +406,18 @@ float orient_editor::convert(const CString &str)
379406
return (float) atof(buf);
380407
}
381408

409+
/**
410+
* Perform rounding of the float value by loading it into the input box format string and parsing it again.
411+
* This accounts for not only decimal rounding to the precision of the input box, but also floating point rounding due to inexact fractions such as 1/10.
412+
* See also GitHub PR #4475.
413+
*/
414+
float orient_editor::perform_input_rounding(float val) const
415+
{
416+
CString str;
417+
str.Format(INPUT_FORMAT, val);
418+
return convert(str);
419+
}
420+
382421
void orient_editor::OnPointTo()
383422
{
384423
UpdateData(TRUE);

fred2/orienteditor.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class orient_editor : public CDialog
2424
orient_editor(CWnd* pParent = NULL); // standard constructor
2525

2626
static float to_degrees(float radians);
27+
static float normalize_degrees(float degrees);
2728

2829
// Dialog Data
2930
//{{AFX_DATA(orient_editor)
@@ -69,8 +70,12 @@ class orient_editor : public CDialog
6970
DECLARE_MESSAGE_MAP()
7071

7172
private:
72-
float convert(const CString &str);
73-
bool close(float val, const CString &str);
73+
float convert(const CString &str) const;
74+
float perform_input_rounding(float val) const;
75+
76+
bool is_close(float val, const CString &input_str) const;
77+
bool is_angle_close(float rad, const CString &input_str) const;
78+
7479
int total;
7580
int index[MAX_OBJECTS];
7681
void actually_point_object(object *ptr);

0 commit comments

Comments
 (0)