Mercury Geometry and Math Library
リビジョン | 7ff29fb8f53f14a882d75b05af9a84155d2a317b (tree) |
---|---|
日時 | 2022-04-24 05:04:00 |
作者 | Emily Dioxideson <emily@eter...> |
コミッター | Emily Dioxideson |
Use vectors to implement geometry2d
@@ -20,30 +20,116 @@ | ||
20 | 20 | |
21 | 21 | %------------------------------------------------------------------------------% |
22 | 22 | |
23 | -:- type segment ---> | |
24 | - segment(seg_x1::float, seg_y1::float, seg_x2::float, seg_y2::float). | |
23 | +:- type segment ---> segment(seg_p1::vector2, seg_p2::vector2). | |
24 | + | |
25 | +:- func segment(float, float, float, float) = segment. | |
26 | +:- mode segment(in, in, in, in) = (out) is det. | |
27 | +:- mode segment(di, di, di, di) = (uo) is det. | |
28 | +:- mode segment(mdi, mdi, mdi, mdi) = (muo) is det. | |
29 | +:- mode segment(out, out, out, out) = (in) is det. | |
30 | +:- mode segment(uo, uo, uo, uo) = (di) is det. | |
31 | +:- mode segment(muo, muo, muo, muo) = (mdi) is det. | |
32 | +:- mode segment(in, in, in, in) = (in) is semidet. % implied. | |
33 | + | |
34 | +:- func seg_x1(segment) = float. | |
35 | +:- func seg_y1(segment) = float. | |
36 | +:- func seg_x2(segment) = float. | |
37 | +:- func seg_y2(segment) = float. | |
38 | + | |
39 | +:- func 'seg_x1 :='(float, segment) = segment. | |
40 | +:- func 'seg_y1 :='(float, segment) = segment. | |
41 | +:- func 'seg_x2 :='(float, segment) = segment. | |
42 | +:- func 'seg_y2 :='(float, segment) = segment. | |
25 | 43 | |
26 | 44 | %------------------------------------------------------------------------------% |
27 | 45 | |
28 | -:- type rectangle ---> | |
29 | - rectangle(rect_x::float, rect_y::float, rect_w::float, rect_h::float). | |
46 | +:- type rectangle ---> rectangle( | |
47 | + rect_pt::vector2, | |
48 | + rect_w::float, | |
49 | + rect_h::float). | |
50 | + | |
51 | +:- func rectangle(float, float, float, float) = rectangle. | |
52 | +:- mode rectangle(in, in, in, in) = (out) is det. | |
53 | +:- mode rectangle(di, di, di, di) = (uo) is det. | |
54 | +:- mode rectangle(mdi, mdi, mdi, mdi) = (muo) is det. | |
55 | +:- mode rectangle(out, out, out, out) = (in) is det. | |
56 | +:- mode rectangle(uo, uo, uo, uo) = (di) is det. | |
57 | +:- mode rectangle(muo, muo, muo, muo) = (mdi) is det. | |
58 | +:- mode rectangle(in, in, in, in) = (in) is semidet. % implied. | |
59 | + | |
60 | +:- func rect_x(rectangle) = float. | |
61 | +:- func rect_y(rectangle) = float. | |
62 | + | |
63 | +:- func 'rect_x :='(float, rectangle) = rectangle. | |
64 | +:- func 'rect_y :='(float, rectangle) = rectangle. | |
30 | 65 | |
31 | 66 | %------------------------------------------------------------------------------% |
32 | 67 | |
33 | -:- type circle ---> | |
34 | - circle(circle_x::float, circle_y::float, radius::float). | |
68 | +:- type circle ---> circle(circle_center::vector2, radius::float). | |
69 | + | |
70 | +:- func circle(float, float, float) = circle. | |
71 | +:- mode circle(in, in, in) = (out) is det. | |
72 | +:- mode circle(di, di, di) = (uo) is det. | |
73 | +:- mode circle(mdi, mdi, mdi) = (muo) is det. | |
74 | +:- mode circle(out, out, out) = (in) is det. | |
75 | +:- mode circle(uo, uo, uo) = (di) is det. | |
76 | +:- mode circle(muo, muo, muo) = (mdi) is det. | |
77 | +:- mode circle(in, in, in) = (in) is semidet. % implied. | |
78 | + | |
79 | +:- func circle_x(circle) = float. | |
80 | +:- func circle_y(circle) = float. | |
81 | + | |
82 | +:- func 'circle_x :='(float, circle) = circle. | |
83 | +:- func 'circle_y :='(float, circle) = circle. | |
35 | 84 | |
36 | 85 | %------------------------------------------------------------------------------% |
37 | 86 | |
38 | -:- type point ---> | |
39 | - point(x::float, y::float). | |
87 | +:- type point == vector2. | |
88 | + | |
89 | +:- func point(float, float) = point. | |
90 | +:- mode point(in, in) = (out) is det. | |
91 | +:- mode point(di, di) = (uo) is det. | |
92 | +:- mode point(mdi, mdi) = (muo) is det. | |
93 | +:- mode point(out, out) = (in) is det. | |
94 | +:- mode point(uo, uo) = (di) is det. | |
95 | +:- mode point(muo, muo) = (mdi) is det. | |
96 | +:- mode point(in, in) = (in) is semidet. % implied. | |
97 | + | |
98 | +:- func x(point) = float. | |
99 | +:- func y(point) = float. | |
100 | + | |
101 | +:- func 'x :='(float, point) = point. | |
102 | +:- func 'y :='(float, point) = point. | |
40 | 103 | |
41 | 104 | %------------------------------------------------------------------------------% |
42 | 105 | |
43 | -:- type triangle ---> | |
44 | - triangle(tri_x1::float, tri_y1::float, | |
45 | - tri_x2::float, tri_y2::float, | |
46 | - tri_x3::float, tri_y3::float). | |
106 | +:- type triangle ---> triangle( | |
107 | + tri_p1::vector2, | |
108 | + tri_p2::vector2, | |
109 | + tri_p3::vector2). | |
110 | + | |
111 | +:- func triangle(float, float, float, float, float, float) = triangle. | |
112 | +:- mode triangle(in, in, in, in, in, in) = (out) is det. | |
113 | +:- mode triangle(di, di, di, di, di, di) = (uo) is det. | |
114 | +:- mode triangle(mdi, mdi, mdi, mdi, mdi, mdi) = (muo) is det. | |
115 | +:- mode triangle(out, out, out, out, out, out) = (in) is det. | |
116 | +:- mode triangle(uo, uo, uo, uo, uo, uo) = (di) is det. | |
117 | +:- mode triangle(muo, muo, muo, muo, muo, muo) = (mdi) is det. | |
118 | +:- mode triangle(in, in, in, in, in, in) = (in) is semidet. % implied. | |
119 | + | |
120 | +:- func tri_x1(triangle) = float. | |
121 | +:- func tri_y1(triangle) = float. | |
122 | +:- func tri_x2(triangle) = float. | |
123 | +:- func tri_y2(triangle) = float. | |
124 | +:- func tri_x3(triangle) = float. | |
125 | +:- func tri_y3(triangle) = float. | |
126 | + | |
127 | +:- func 'tri_x1 :='(float, triangle) = triangle. | |
128 | +:- func 'tri_y1 :='(float, triangle) = triangle. | |
129 | +:- func 'tri_x2 :='(float, triangle) = triangle. | |
130 | +:- func 'tri_y2 :='(float, triangle) = triangle. | |
131 | +:- func 'tri_x3 :='(float, triangle) = triangle. | |
132 | +:- func 'tri_y3 :='(float, triangle) = triangle. | |
47 | 133 | |
48 | 134 | %------------------------------------------------------------------------------% |
49 | 135 |
@@ -123,22 +209,6 @@ | ||
123 | 209 | |
124 | 210 | %------------------------------------------------------------------------------% |
125 | 211 | |
126 | -:- pred segment_endpoints(segment, point, point). | |
127 | -:- mode segment_endpoints(in, out, out) is det. | |
128 | -:- mode segment_endpoints(di, uo, uo) is det. | |
129 | -:- mode segment_endpoints(out, in, in) is det. | |
130 | -:- mode segment_endpoints(uo, di, di) is det. | |
131 | - | |
132 | -%------------------------------------------------------------------------------% | |
133 | - | |
134 | -:- pred triangle_endpoints(triangle, point, point, point). | |
135 | -:- mode triangle_endpoints(in, out, out, out) is det. | |
136 | -:- mode triangle_endpoints(di, uo, uo, uo) is det. | |
137 | -:- mode triangle_endpoints(out, in, in, in) is det. | |
138 | -:- mode triangle_endpoints(uo, di, di, di) is det. | |
139 | - | |
140 | -%------------------------------------------------------------------------------% | |
141 | - | |
142 | 212 | :- pred triangle_segments(triangle, segment, segment, segment). |
143 | 213 | :- mode triangle_segments(in, out, out, out) is det. |
144 | 214 |
@@ -232,6 +302,76 @@ | ||
232 | 302 | |
233 | 303 | %------------------------------------------------------------------------------% |
234 | 304 | |
305 | +:- pragma inline(segment/4). | |
306 | +segment(X1, Y1, X2, Y2) = segment(vector(X1, Y1), vector(X2, Y2)). | |
307 | + | |
308 | +seg_x1(segment(vector(X, _), _)) = X. | |
309 | +seg_y1(segment(vector(_, Y), _)) = Y. | |
310 | +seg_x2(segment(_, vector(X, _))) = X. | |
311 | +seg_y2(segment(_, vector(_, Y))) = Y. | |
312 | + | |
313 | +'seg_x1 :='(X, segment(vector(_, Y), P2)) = segment(vector(X, Y), P2). | |
314 | +'seg_y1 :='(Y, segment(vector(X, _), P2)) = segment(vector(X, Y), P2). | |
315 | +'seg_x2 :='(X, segment(P1, vector(_, Y))) = segment(P1, vector(X, Y)). | |
316 | +'seg_y2 :='(Y, segment(P1, vector(X, _))) = segment(P1, vector(X, Y)). | |
317 | + | |
318 | +%------------------------------------------------------------------------------% | |
319 | + | |
320 | +:- pragma inline(rectangle/4). | |
321 | +rectangle(X, Y, W, H) = rectangle(vector(X, Y), W, H). | |
322 | + | |
323 | +rect_x(rectangle(vector(X, _), _, _)) = X. | |
324 | +rect_y(rectangle(vector(_, Y), _, _)) = Y. | |
325 | + | |
326 | +'rect_x :='(X, rectangle(vector(_, Y), W, H)) = rectangle(vector(X, Y), W, H). | |
327 | +'rect_y :='(Y, rectangle(vector(X, _), W, H)) = rectangle(vector(X, Y), W, H). | |
328 | + | |
329 | +%------------------------------------------------------------------------------% | |
330 | + | |
331 | +:- pragma inline(circle/3). | |
332 | +circle(X, Y, R) = circle(vector(X, Y), R). | |
333 | + | |
334 | +circle_x(circle(vector(X, _), _)) = X. | |
335 | +circle_y(circle(vector(_, Y), _)) = Y. | |
336 | + | |
337 | +'circle_x :='(X, circle(vector(_, Y), R)) = circle(vector(X, Y), R). | |
338 | +'circle_y :='(Y, circle(vector(X, _), R)) = circle(vector(X, Y), R). | |
339 | + | |
340 | +%------------------------------------------------------------------------------% | |
341 | + | |
342 | +:- pragma inline(point/2). | |
343 | +point(X, Y) = vector(X, Y). | |
344 | + | |
345 | +x(vector(X, _)) = X. | |
346 | +y(vector(_, Y)) = Y. | |
347 | + | |
348 | +'x :='(X, vector(_, Y)) = vector(X, Y). | |
349 | +'y :='(Y, vector(X, _)) = vector(X, Y). | |
350 | + | |
351 | +%------------------------------------------------------------------------------% | |
352 | + | |
353 | +:- pragma inline(triangle/6). | |
354 | +triangle(X1, Y1, X2, Y2, X3, Y3) = triangle( | |
355 | + vector(X1, Y1), | |
356 | + vector(X2, Y2), | |
357 | + vector(X3, Y3)). | |
358 | + | |
359 | +tri_x1(triangle(vector(X, _), _, _)) = X. | |
360 | +tri_y1(triangle(vector(_, Y), _, _)) = Y. | |
361 | +tri_x2(triangle(_, vector(X, _), _)) = X. | |
362 | +tri_y2(triangle(_, vector(_, Y), _)) = Y. | |
363 | +tri_x3(triangle(_, _, vector(X, _))) = X. | |
364 | +tri_y3(triangle(_, _, vector(_, Y))) = Y. | |
365 | + | |
366 | +'tri_x1 :='(X, triangle(vector(_, Y), P2, P3)) = triangle(vector(X, Y), P2, P3). | |
367 | +'tri_y1 :='(Y, triangle(vector(X, _), P2, P3)) = triangle(vector(X, Y), P2, P3). | |
368 | +'tri_x2 :='(X, triangle(P1, vector(_, Y), P3)) = triangle(P1, vector(X, Y), P3). | |
369 | +'tri_y2 :='(Y, triangle(P1, vector(X, _), P3)) = triangle(P1, vector(X, Y), P3). | |
370 | +'tri_x3 :='(X, triangle(P1, P2, vector(_, Y))) = triangle(P1, P2, vector(X, Y)). | |
371 | +'tri_y3 :='(Y, triangle(P1, P2, vector(X, _))) = triangle(P1, P2, vector(X, Y)). | |
372 | + | |
373 | +%------------------------------------------------------------------------------% | |
374 | + | |
235 | 375 | % is_in_range(X, M, N) |
236 | 376 | % Unifies if X is between M and N |
237 | 377 | :- pred is_in_range(float, float, float). |
@@ -331,22 +471,10 @@ rectangle_contains(rectangle(X1, Y1, W1, H1), rectangle(X2, Y2, W2, H2)) :- | ||
331 | 471 | |
332 | 472 | %------------------------------------------------------------------------------% |
333 | 473 | |
334 | -segment_endpoints(segment(X1, Y1, X2, Y2), point(X1, Y1), point(X2, Y2)). | |
335 | - | |
336 | -%------------------------------------------------------------------------------% | |
337 | - | |
338 | -triangle_endpoints(triangle(X1, Y1, X2, Y2, X3, Y3), | |
339 | - point(X1, Y1), | |
340 | - point(X2, Y2), | |
341 | - point(X3, Y3)). | |
342 | - | |
343 | -%------------------------------------------------------------------------------% | |
344 | - | |
345 | -triangle_segments(Triangle, S1, S2, S3) :- | |
346 | - triangle_endpoints(Triangle, P1, P2, P3), | |
347 | - segment_endpoints(S1, P1, P2), | |
348 | - segment_endpoints(S2, P2, P3), | |
349 | - segment_endpoints(S3, P3, P1). | |
474 | +triangle_segments(triangle(P1, P2, P3), S1, S2, S3) :- | |
475 | + S1 = segment(P1, P2), | |
476 | + S2 = segment(P2, P3), | |
477 | + S3 = segment(P3, P1). | |
350 | 478 | |
351 | 479 | %------------------------------------------------------------------------------% |
352 | 480 |
@@ -481,35 +609,29 @@ collide_segments(S1, S2, Point) :- | ||
481 | 609 | |
482 | 610 | %------------------------------------------------------------------------------% |
483 | 611 | |
484 | -collide_segment_circle(Segment, Circle, P) :- | |
485 | - segment_endpoints(Segment, Point1, Point2), | |
612 | +collide_segment_circle(segment(P1, P2), Circle, P) :- | |
486 | 613 | |
487 | 614 | % If neither of the end points are within the circle, then check if the circle's |
488 | 615 | % center is within the radius of the segment |
489 | 616 | ( if |
490 | - point_inside(Circle, Point1) | |
617 | + point_inside(Circle, P1) | |
491 | 618 | then |
492 | - P = Point1 | |
619 | + P = P1 | |
493 | 620 | else if |
494 | - point_inside(Circle, Point2) | |
621 | + point_inside(Circle, P2) | |
495 | 622 | then |
496 | - P = Point2 | |
623 | + P = P2 | |
497 | 624 | else |
498 | 625 | % If we take the dot product of the center of the circle and one of the |
499 | 626 | % endpoints on the segment, this will tell us what the nearest point on |
500 | 627 | % the segment is to the circle. |
501 | 628 | % We can then test this location on the line for being within the radius |
502 | 629 | % of the center of the circle. |
503 | - Point1 = point(X1, Y1), | |
504 | - Vector1 = vector(X1, Y1), | |
505 | - Point2 = point(X2, Y2), | |
506 | - Vector2 = vector(X2, Y2), | |
507 | - | |
508 | - Circle = geometry2d.circle(XC, YC, _), | |
630 | + Circle = geometry2d.circle(Center, _), | |
509 | 631 | |
510 | 632 | % Adjust the center and the segment to start at Point1 |
511 | - SegmentVector = Vector2 - Vector1, | |
512 | - CenterVector = vector(XC, YC) - Vector1, | |
633 | + SegmentVector = P2 - P1, | |
634 | + CenterVector = Center - P1, | |
513 | 635 | |
514 | 636 | % Get the length of the segment, which is our scaling value |
515 | 637 | Length = vector.magnitude(SegmentVector), |
@@ -519,26 +641,26 @@ collide_segment_circle(Segment, Circle, P) :- | ||
519 | 641 | |
520 | 642 | T >= 0.0, T =< 1.0, |
521 | 643 | |
522 | - SegmentVector * T = vector(NearestX, NearestY), | |
523 | - P = geometry2d.point(NearestX + X1, NearestY + Y1), | |
644 | + SegmentVector * T = Nearest, | |
645 | + P = Nearest + P1, | |
524 | 646 | point_inside(Circle, P) |
525 | 647 | ). |
526 | 648 | |
527 | 649 | %------------------------------------------------------------------------------% |
528 | 650 | |
529 | 651 | collide_segment_rectangle(Segment, Rect, P) :- |
530 | - segment_endpoints(Segment, Point1, Point2), | |
652 | + Segment = segment(P1, P2), | |
531 | 653 | |
532 | 654 | % If neither of the end points are within the rectangle, then try to |
533 | 655 | % intersect the segments. |
534 | 656 | ( if |
535 | - point_inside(Rect, Point1) | |
657 | + point_inside(Rect, P1) | |
536 | 658 | then |
537 | - P = Point1 | |
659 | + P = P1 | |
538 | 660 | else if |
539 | - point_inside(Rect, Point2) | |
661 | + point_inside(Rect, P2) | |
540 | 662 | then |
541 | - P = Point2 | |
663 | + P = P2 | |
542 | 664 | else |
543 | 665 | rectangles_intersect(Rect, bounding_box(Segment)), |
544 | 666 | Rect = rectangle(X, Y, W, H), |
@@ -547,23 +669,19 @@ collide_segment_rectangle(Segment, Rect, P) :- | ||
547 | 669 | C3 = point(X + W, Y + H), |
548 | 670 | C4 = point(X, Y + H), |
549 | 671 | ( if |
550 | - segment_endpoints(RectSegment, C1, C2), | |
551 | - collide_segments(RectSegment, Segment, SemiP) | |
672 | + collide_segments(segment(C1, C2), Segment, SemiP) | |
552 | 673 | then |
553 | 674 | P = SemiP |
554 | 675 | else if |
555 | - segment_endpoints(RectSegment, C2, C3), | |
556 | - collide_segments(RectSegment, Segment, SemiP) | |
676 | + collide_segments(segment(C2, C3), Segment, SemiP) | |
557 | 677 | then |
558 | 678 | P = SemiP |
559 | 679 | else if |
560 | - segment_endpoints(RectSegment, C3, C4), | |
561 | - collide_segments(RectSegment, Segment, SemiP) | |
680 | + collide_segments(segment(C3, C4), Segment, SemiP) | |
562 | 681 | then |
563 | 682 | P = SemiP |
564 | 683 | else |
565 | - segment_endpoints(RectSegment, C4, C1), | |
566 | - collide_segments(RectSegment, Segment, P) | |
684 | + collide_segments(segment(C4, C1), Segment, P) | |
567 | 685 | ) |
568 | 686 | ). |
569 | 687 |
@@ -601,8 +719,8 @@ point_to_vector(geometry2d.point(X, Y)) = vector(X, Y). | ||
601 | 719 | H = max(Y1, Y2) - Y), |
602 | 720 | (point_inside(_, _) :- false), |
603 | 721 | (translate(Translate, S1, S2) :- |
604 | - segment_endpoints(S1, S1P1, S1P2), | |
605 | - segment_endpoints(S2, S2P1, S2P2), | |
722 | + S1 = segment(S1P1, S1P2), | |
723 | + S2 = segment(S2P1, S2P2), | |
606 | 724 | translate(Translate, S1P1, S2P1), |
607 | 725 | translate(Translate, S1P2, S2P2)), |
608 | 726 | (convex(segment(X1, Y1, X2, Y2), 0.0, [point(X1, Y1)|[point(X2, Y2)|[]]])), |
@@ -704,21 +822,13 @@ point_to_vector(geometry2d.point(X, Y)) = vector(X, Y). | ||
704 | 822 | Side2 = Side3 |
705 | 823 | ) |
706 | 824 | ), |
707 | - (translate(Point, TriangleIn, TriangleOut) :- | |
708 | - triangle_endpoints(TriangleIn, P1in, P2in, P3in), | |
709 | - triangle_endpoints(TriangleOut, P1out, P2out, P3out), | |
710 | - translate(Point, P1in, P1out), | |
711 | - translate(Point, P2in, P2out), | |
712 | - translate(Point, P3in, P3out) | |
713 | - ), | |
714 | - (convex(Triangle, 0.0, [P1, P2, P3]) :- | |
715 | - triangle_endpoints(Triangle, P1, P2, P3) | |
825 | + (translate(P, triangle(!.P1, !.P2, !.P3), triangle(!:P1, !:P2, !:P3)) :- | |
826 | + translate(P, !P1), | |
827 | + translate(P, !P2), | |
828 | + translate(P, !P3) | |
716 | 829 | ), |
717 | - (scale(X, Y, TriangleIn) = (TriangleOut) :- | |
718 | - triangle_endpoints(TriangleIn, P1, P2, P3), | |
719 | - triangle_endpoints(TriangleOut, | |
720 | - scale(X, Y, P1), | |
721 | - scale(X, Y, P2), | |
722 | - scale(X, Y, P3)) | |
723 | - ) | |
830 | + convex(triangle(P1, P2, P3), 0.0, [P1|[P2|[P3|[]]]]), | |
831 | + (scale(X, Y, triangle(P1, P2, P3)) = triangle(P * P1, P * P2, P * P3) :- | |
832 | + P = vector(X, Y)) | |
833 | + | |
724 | 834 | ]. |