Mercury Geometry and Math Library
リビジョン | d803d6f195accd635e33c76a2ad3eb7e027cd016 (tree) |
---|---|
日時 | 2022-03-27 05:18:10 |
作者 | AlaskanEmily <emily@alas...> |
コミッター | AlaskanEmily |
Fix point_inside for triangles, add 2D cross-product to vector2
@@ -43,7 +43,7 @@ | ||
43 | 43 | |
44 | 44 | %------------------------------------------------------------------------------% |
45 | 45 | |
46 | -:- type side ---> left ; right ; collinear. | |
46 | +:- type side ---> left ; right ; colinear. | |
47 | 47 | |
48 | 48 | %------------------------------------------------------------------------------% |
49 | 49 |
@@ -82,6 +82,7 @@ | ||
82 | 82 | %==============================================================================% |
83 | 83 | |
84 | 84 | :- import_module float. |
85 | +:- import_module vector.vector2. | |
85 | 86 | |
86 | 87 | %------------------------------------------------------------------------------% |
87 | 88 |
@@ -101,7 +102,20 @@ as_tuple(S, {S ^ p1, S ^ p2}). | ||
101 | 102 | |
102 | 103 | %------------------------------------------------------------------------------% |
103 | 104 | % TODO! |
104 | -side(_, _) = collinear. | |
105 | + | |
106 | +side(segment(A, B), C) = Side :- | |
107 | + Cross = vector.vector2.cross(B - A, C - A), | |
108 | + ( if | |
109 | + Cross > float.epsilon | |
110 | + then | |
111 | + Side = left | |
112 | + else if | |
113 | + Cross < -float.epsilon | |
114 | + then | |
115 | + Side = right | |
116 | + else | |
117 | + Side = colinear | |
118 | + ). | |
105 | 119 | |
106 | 120 | %------------------------------------------------------------------------------% |
107 | 121 |
@@ -224,6 +224,8 @@ | ||
224 | 224 | :- use_module math. |
225 | 225 | :- import_module float. |
226 | 226 | |
227 | +:- use_module geometry. | |
228 | +:- use_module geometry.segment. | |
227 | 229 | :- use_module multi_math. |
228 | 230 | :- import_module vector.vector2. |
229 | 231 |
@@ -674,32 +676,31 @@ point_to_vector(geometry2d.point(X, Y)) = vector.vector2.vector(X, Y). | ||
674 | 676 | Y = min(min(Y1, Y2), Y3), |
675 | 677 | W = max(max(X1, X2), X3) - X, |
676 | 678 | H = max(max(Y1, Y2), Y3) - Y), |
677 | - (point_inside(Triangle, point(PX, PY)) :- | |
678 | - triangle_segments(Triangle, S1, S2, S3), | |
679 | + (point_inside(triangle(X1, Y1, X2, Y2, X3, Y3), point(PX, PY)) :- | |
680 | + % Find the side of the point for each segment | |
681 | + Pos = vector.vector2.vector(PX, PY), | |
682 | + Vector1 = vector.vector2.vector(X1, Y1), | |
683 | + Vector2 = vector.vector2.vector(X2, Y2), | |
684 | + Vector3 = vector.vector2.vector(X3, Y3), | |
685 | + Segment1 = geometry.segment.segment(Vector1, Vector2), | |
686 | + Segment2 = geometry.segment.segment(Vector2, Vector3), | |
687 | + Segment3 = geometry.segment.segment(Vector3, Vector1), | |
679 | 688 | |
680 | - bounding_box(Triangle) = Bounds, | |
681 | - segment(Bounds ^ rect_x - 1.0, PY, PX, PY) = TestSegment, | |
689 | + Side1 = geometry.segment.side(Segment1, Pos), | |
690 | + Side2 = geometry.segment.side(Segment2, Pos), | |
691 | + Side3 = geometry.segment.side(Segment3, Pos), | |
682 | 692 | |
683 | - % I tried my best to use existential term instantiation to express an | |
684 | - % exclusive-or disjunction. It didn't work. | |
685 | - % So I'm sorry. I should have done more. | |
686 | - ( collide_segments(TestSegment, S1, _) <=> not ( | |
687 | - collide_segments(TestSegment, S2, _) | |
688 | - ; | |
689 | - collide_segments(TestSegment, S3, _) | |
690 | - ) | |
691 | - ), | |
692 | - ( collide_segments(TestSegment, S2, _) <=> not ( | |
693 | - collide_segments(TestSegment, S1, _) | |
694 | - ; | |
695 | - collide_segments(TestSegment, S3, _) | |
696 | - ) | |
697 | - ), | |
698 | - ( collide_segments(TestSegment, S3, _) <=> not ( | |
699 | - collide_segments(TestSegment, S1, _) | |
700 | - ; | |
701 | - collide_segments(TestSegment, S2, _) | |
702 | - ) | |
693 | + % Either the point must be colinear, or we must be on the same side of | |
694 | + % all three segments. | |
695 | + ( | |
696 | + Side1 = geometry.segment.colinear | |
697 | + ; | |
698 | + Side2 = geometry.segment.colinear | |
699 | + ; | |
700 | + Side3 = geometry.segment.colinear | |
701 | + ; | |
702 | + Side1 = Side2, | |
703 | + Side2 = Side3 | |
703 | 704 | ) |
704 | 705 | ), |
705 | 706 | (translate(Point, TriangleIn, TriangleOut) :- |
@@ -26,6 +26,10 @@ | ||
26 | 26 | |
27 | 27 | %------------------------------------------------------------------------------% |
28 | 28 | |
29 | +:- func cross(vector2, vector2) = float. | |
30 | + | |
31 | +%------------------------------------------------------------------------------% | |
32 | + | |
29 | 33 | :- func (vector2::in) + (vector2::in) = (vector2::uo) is det. |
30 | 34 | :- func (vector2::in) - (vector2::in) = (vector2::uo) is det. |
31 | 35 | :- func (vector2::in) * (vector2::in) = (vector2::uo) is det. |
@@ -117,6 +121,10 @@ get_y(V) = V ^ y. | ||
117 | 121 | |
118 | 122 | %------------------------------------------------------------------------------% |
119 | 123 | |
124 | +cross(vector(X1, Y1), vector(X2, Y2)) = (X1 * Y2) - (Y1 * X2). | |
125 | + | |
126 | +%------------------------------------------------------------------------------% | |
127 | + | |
120 | 128 | (vector(X1, Y1)) + (vector(X2, Y2)) = (vector(X1+X2, Y1+Y2)). |
121 | 129 | (vector(X1, Y1)) - (vector(X2, Y2)) = (vector(X1-X2, Y1-Y2)). |
122 | 130 | (vector(X1, Y1)) * (vector(X2, Y2)) = (vector(X1*X2, Y1*Y2)). |