Skip to content

Commit af63e95

Browse files
committed
Fix approximate_circular_arc_by_line_segments
1 parent 6ea89b0 commit af63e95

File tree

2 files changed

+42
-9
lines changed

2 files changed

+42
-9
lines changed

src/irregular/shape.cpp

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,8 @@ std::string ShapeElement::to_string() const
161161
} case ShapeElementType::CircularArc: {
162162
return "CircularArc start " + start.to_string()
163163
+ " end " + end.to_string()
164-
+ " center " + center.to_string();
164+
+ " center " + center.to_string()
165+
+ ((anticlockwise)? " anticlockwise": " clockwise");
165166
}
166167
}
167168
return "";
@@ -268,21 +269,28 @@ std::vector<ShapeElement> irregular::approximate_circular_arc_by_line_segments(
268269
"number_of_line_segments: " + std::to_string(number_of_line_segments) + ".");
269270
}
270271

271-
Angle angle = angle_radian(
272+
Angle angle = (circular_arc.anticlockwise)?
273+
angle_radian(
272274
circular_arc.start - circular_arc.center,
273-
circular_arc.end - circular_arc.center);
274-
if (outer) {
275+
circular_arc.end - circular_arc.center):
276+
angle_radian(
277+
circular_arc.end - circular_arc.center,
278+
circular_arc.start - circular_arc.center);
279+
if ((outer && circular_arc.anticlockwise)
280+
|| (!outer && !circular_arc.anticlockwise)) {
275281
if (angle < M_PI && number_of_line_segments < 2) {
276282
throw std::runtime_error(
277283
"packingsolver::irregular::circular_arc_to_line_segments: "
278-
"at least 2 line segments are needed to outer approximate a circular arc with an angle <= PI; "
284+
"at least 2 line segments are needed to approximate the circular arc; "
285+
"circular_arc: " + circular_arc.to_string() + "; "
279286
"outer: " + std::to_string(outer) + "; "
280287
"angle: " + std::to_string(angle) + "; "
281288
"number_of_line_segments: " + std::to_string(number_of_line_segments) + ".");
282289
} else if (angle >= M_PI && number_of_line_segments < 3) {
283290
throw std::runtime_error(
284291
"packingsolver::irregular::circular_arc_to_line_segments: "
285-
"at least 3 line segments are needed to outer approximate a circular arc with an angle >= PI; "
292+
"at least 3 line segments are needed to approximate the circular arc; "
293+
"circular_arc: " + circular_arc.to_string() + "; "
286294
"outer: " + std::to_string(outer) + "; "
287295
"angle: " + std::to_string(angle) + "; "
288296
"number_of_line_segments: " + std::to_string(number_of_line_segments) + ".");
@@ -297,11 +305,17 @@ std::vector<ShapeElement> irregular::approximate_circular_arc_by_line_segments(
297305
line_segment_id < number_of_line_segments - 1;
298306
++line_segment_id) {
299307
Angle angle_cur = (angle * (line_segment_id + 1)) / (number_of_line_segments - 1);
308+
if (!circular_arc.anticlockwise)
309+
angle_cur *= -1;
300310
Point point_circle;
301-
point_circle.x = circular_arc.center.x + radius * std::cos(angle_cur);
302-
point_circle.y = circular_arc.center.y + radius * std::sin(angle_cur);
311+
point_circle.x = circular_arc.center.x
312+
+ std::cos(angle_cur) * (circular_arc.start.x - circular_arc.center.x)
313+
- std::sin(angle_cur) * (circular_arc.start.y - circular_arc.center.y);
314+
point_circle.y = circular_arc.center.y
315+
+ std::sin(angle_cur) * (circular_arc.start.x - circular_arc.center.x)
316+
+ std::cos(angle_cur) * (circular_arc.start.y - circular_arc.center.y);
303317
Point point_cur;
304-
if (!outer) {
318+
if ((outer && !circular_arc.anticlockwise) || (!outer && circular_arc.anticlockwise)) {
305319
point_cur = point_circle;
306320
} else {
307321
// https://en.wikipedia.org/wiki/Tangent_lines_to_circles#Cartesian_equation
@@ -696,9 +710,13 @@ Shape packingsolver::irregular::build_shape(
696710
element.type = type;
697711
element.start = point_prev;
698712
element.end = {points[pos].x, points[pos].y};
713+
element.center = center;
714+
element.anticlockwise = anticlockwise;
699715
if (!path || pos > 0)
700716
shape.elements.push_back(element);
701717
point_prev = element.end;
718+
anticlockwise = true;
719+
center = {0, 0};
702720
type = ShapeElementType::LineSegment;
703721
} else {
704722
anticlockwise = (point.type == 1);

test/irregular/shape_test.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,29 @@ INSTANTIATE_TEST_SUITE_P(
7979
1,
8080
false,
8181
build_shape({{1, 0}, {0, 1}}, true).elements
82+
}, {
83+
build_shape({{1, 0}, {1, 1, -1}, {0, 1}}, true).elements.front(),
84+
1,
85+
true,
86+
build_shape({{1, 0}, {0, 1}}, true).elements
8287
}, {
8388
build_shape({{1, 0}, {0, 0, 1}, {0, 1}}, true).elements.front(),
8489
2,
8590
true,
8691
build_shape({{1, 0}, {1, 1}, {0, 1}}, true).elements
92+
}, {
93+
build_shape({{1, 0}, {1, 1, -1}, {0, 1}}, true).elements.front(),
94+
2,
95+
false,
96+
build_shape({{1, 0}, {0, 0}, {0, 1}}, true).elements
8797
}, {
8898
build_shape({{1, 0}, {0, 0, 1}, {0, 1}}, true).elements.front(),
8999
3,
90100
true,
91101
build_shape({{1, 0}, {1, 0.414213562373095}, {0.414213562373095, 1}, {0, 1}}, true).elements
102+
}, {
103+
build_shape({{1, 0}, {1, 1, -1}, {0, 1}}, true).elements.front(),
104+
3,
105+
false,
106+
build_shape({{1, 0}, {0.585786437626905, 0}, {0, 0.585786437626905}, {0, 1}}, true).elements
92107
}}));

0 commit comments

Comments
 (0)