BillW Posted May 6, 2016 Share Posted May 6, 2016 Banging my head against the wall on this one. I am testing a polygon. If I have 3 vertices, "start point", "test point", "to point" - I can test the angle between the 3 points using the logic of the developer example PROCEDURE Example; VAR pt1, pt2, pt3, pt4 :VECTOR; ang :REAL; BEGIN GetPt(pt1.x, pt1.y); {start point} GetPtL(pt1.x, pt1.y, pt2.x, pt2.y); {test point} GetPtL(pt2.x, pt2.y, pt3.x, pt3.y); {to point} MoveTo(pt1.x, pt1.y); LineTo(pt2.x, pt2.y); LineTo(pt3.x, pt3.y); pt4 := (pt1 + pt3) / 2; {Find the angle between the vectors.} ang := Rad2Deg(ArcCos(DotProduct(UnitVec(pt1-pt2), UnitVec(pt3-pt2)))); TextOrigin(pt4.x, pt4.y); CreateText(Concat(ang)); END; RUN(Example); This always returns a positive angle. What I need to find out is if the "to point" is to the left (-ive) or right (+ive) of a vector "start point" to "test point" I tried comp(p2-p1,p3-p1,v3,v4) with v4 orthogonal to p2-p1 I thought I could test v4.y for +ive or -ive sense but cant seem to get it to work. TIA Bill Wood Quote Link to comment
MullinRJ Posted May 6, 2016 Share Posted May 6, 2016 Bill, You can test CW / CCW 'ness with the CrossProduct() function. If the CrossProduct's Z component is positive, the angle turns one way. If it is negative it turns the other way. If it is 0, the lines are collinear. The sign of the Z component is determined by the Right-Hand-Rule, which is well documented online. The magnitude of the CrossProduct's Z component is not important in this test, just its sign. If your lines always have a left/right angle between them the following code will test for CW/CCW: This should be easy to follow: function isCCW(P1, P2, P3 :Vector) :Boolean; { Return TRUE if the angle at P2 is CCW, FALSE if it is CW (or straight). } Var V1, V2, CP :Vector; Begin V1 := P2 - P1; { first line } V2 := P3 - P2; { second line } CP := CrossProduct(V1, V2); isCCW := CP.z > 0; End; { isCCW } If you are interested in more compact code (like me), then here's the same routine squished: function isCCW(P1, P2, P3 :Vector) :Boolean; { Return TRUE if the angle at P2 is CCW, FALSE if it is CW (or straight). } Var CP :Vector; Begin CP := CrossProduct(P2-P1, P3-P2); isCCW := CP.z > 0 ; End; { isCCW } HTH, Raymond 1 Quote Link to comment
BillW Posted May 13, 2016 Author Share Posted May 13, 2016 Raymond Thanks for the code, much simpler. In the desperate need to finish the code, I didn't see/manage to pick up your code in time. I did it a slightly different way which seems to work fine - see below Thanks anyway. Bill Wood procedure getpolydef(polyH : HANDLE; vertnum : INTEGER); Var j : INTEGER; p1,p2,p3 : VECTOR; v1,v2 : VECTOR; ang,testang : REAL; ang1,ang2 : REAL; begin for j := 1 to vertnum do begin GetPolyPt(polyH ,j,p2.x,p2.y); {test vertex} if (j = numvert) then GetPolyPt(polyH,1,p3.x,p3.y) {next vertex} else GetPolyPt(objH,j+1,p3.x,p3.y); if (j=1) then GetPolyPt(objH,numvert,p1.x,p1.y) {previous vertex} else GetPolyPt(objH,j-1,p1.x,p1.y); pathdef[j].x := p2.x; pathdef[j].y := p2.y; ang := Rad2Deg(ArcCos(DotProduct(UnitVec(p1-p2), UnitVec(p3-p2)))); {angle between 3 points always positive} v1.x := p2.x-p1.x; v1.y := p2.y-p1.y; v2.x := p3.x-p1.x; v2.y := p3.y-p1.y; ang1 := vec2ang(v1); ang2 := vec2ang(v2); testang := ang1-ang2; {work out angle direction from test point to to point} if testang >= 180 then pathdef[j].angle := -ang else if testang >= 0 then pathdef[j].angle := ang else if testang < -180 then pathdef[j].angle := ang else pathdef[j].angle := -ang; end; end; {getpolydef} Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.