Post by tsh73 on Aug 27, 2023 11:18:54 GMT
That is, given a line and rectangle, get part of the line *in* rectangle.
using the Cohen-Sutherland Algorithm,
en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm
converted from C# (source link in code)
The only gripes is very Very VERY long list of arguments I got...
Run it, then click-n-drag to draw a line.
Part inside rectangle will be overdrawn with red.
using the Cohen-Sutherland Algorithm,
en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm
converted from C# (source link in code)
The only gripes is very Very VERY long list of arguments I got...
Run it, then click-n-drag to draw a line.
Part inside rectangle will be overdrawn with red.
'Clipping Lines to a Rectangle using the Cohen-Sutherland Algorithm
'traslation to LB from C#
'http://www.richardssoftware.net/2014/07/clipping-lines-to-rectangle-using-cohen.html
'tsh73 Aug 2023
global OutCode.Inside, OutCode.Left, OutCode.Right, OutCode.Bottom, OutCode.Top
OutCode.Inside = 0
OutCode.Left = 1
OutCode.Right = 2
OutCode.Bottom = 4
OutCode.Top = 8
'open GUI
open "Line clipping" for graphics_nsb_nf as #gr
#gr "home; down; posxy cx cy"
#gr "trapclose [quit]"
'register mid rectangle
r.Left=2*cx/3
r.Right=2*cx/3*2
r.Top=2*cy/3
r.Bottom=2*cy/3*2
print "Rectangle (left right top bottom)"
print, r.Left,r.Right,r.Top,r.Bottom
#gr "place ";r.Left;" ";r.Top
#gr "box ";r.Right;" ";r.Bottom
#gr "when leftButtonDown [down]"
#gr "when leftButtonUp [up]"
wait
'then mouseDown startDraw
[down]
p1.X=MouseX
p1.Y=MouseY
wait
'then mouseUp draw line
[up]
p2.X=MouseX
p2.Y=MouseY
print "Line "
print p1.X,p1.Y,p2.X,p2.Y
#gr "color black"
#gr "line ";p1.X;" ";p1.Y; " ";p2.X;" ";p2.Y
call ClipSegment r.Left,r.Right,r.Top,r.Bottom, p1.X,p1.Y, p2.X,p2.Y, _
accept, pOut1.X, pOut1.Y, pOut2.X, pOut2.Y
if accept=0 then
print ,"No intersect"
else
print ,"Clipped segment"
print pOut1.X,pOut1.Y,pOut2.X,pOut2.Y
#gr "color red"
#gr "line ";pOut1.X;" ";pOut1.Y; " ";pOut2.X;" ";pOut2.Y
end if
wait
[quit]
timer 0
close #gr
end
'=======================================================================
' functions for line clipping
'top level is
'sub ClipSegment r.Left,r.Right,r.Top,r.Bottom, p1.X,p1.Y, p2.X,p2.Y, byRef accept, byRef pOut1.X, byRef pOut1.Y, byRef pOut2.X, byRef pOut2.Y
function ComputeOutCode(x, y, r.Left, r.Right, r.Top, r.Bottom)
code = OutCode.Inside
if (x < r.Left) then code = code OR OutCode.Left
if (x > r.Right) then code = code OR OutCode.Right
if (y < r.Top) then code = code OR OutCode.Top
if (y > r.Bottom) then code = code OR OutCode.Bottom
ComputeOutCode = code
end function
sub CalculateIntersection r.Left,r.Right,r.Top,r.Bottom, p1.X,p1.Y, p2.X,p2.Y, clipTo, byRef pOut.X, byRef pOut.Y
dx = (p2.X - p1.X)
dy = (p2.Y - p1.Y)
'against div by 0 exceptions
slopeY = 1e10
if dy<>0 then slopeY = dx / dy '; // slope to use for possibly-vertical lines
slopeX = 1e10
if dx<>0 then slopeX = dy / dx '; // slope to use for possibly-horizontal lines
if (clipTo AND OutCode.Top) then
pOut.X=p1.X + slopeY * (r.Top - p1.Y)
pOut.Y=r.Top
exit sub
end if
if (clipTo AND OutCode.Bottom) then
pOut.X=p1.X + slopeY * (r.Bottom - p1.Y)
pOut.Y=r.Bottom
exit sub
end if
if (clipTo AND OutCode.Right) then
pOut.X=r.Right
pOut.Y=p1.Y + slopeX * (r.Right - p1.X)
exit sub
end if
if (clipTo AND OutCode.Left) then
pOut.X=r.Left
pOut.Y=p1.Y + slopeX * (r.Left - p1.X)
exit sub
end if
'throw new ArgumentOutOfRangeException("clipTo = " + clipTo);
end sub
'top level function
sub ClipSegment r.Left,r.Right,r.Top,r.Bottom, p1.X,p1.Y, p2.X,p2.Y, byRef accept, byRef pOut1.X, byRef pOut1.Y, byRef pOut2.X, byRef pOut2.Y
'classify the endpoints of the line
outCodeP1 = ComputeOutCode(p1.X,p1.Y, r.Left, r.Right, r.Top, r.Bottom)
outCodeP2 = ComputeOutCode(p2.X,p2.Y, r.Left, r.Right, r.Top, r.Bottom)
accept = 0
while (1) '// should only iterate twice, at most
'// Case 1:
'// both endpoints are within the clipping region
if ((outCodeP1 OR outCodeP2) = OutCode.Inside) then
accept = 1
exit while
end if
'// Case 2:
'// both endpoints share an excluded region, impossible for a line between them to be within the clipping region
if ((outCodeP1 AND outCodeP2) <> 0) then
exit while
end if
'// Case 3:
'// The endpoints are in different regions, and the segment is partially within the clipping rectangle
'// Select one of the endpoints outside the clipping rectangle
'var outCode = outCodeP1 != OutCode.Inside ? outCodeP1 : outCodeP2;
if outCodeP1 <> OutCode.Inside then outCode = outCodeP1 else outCode = outCodeP2
'// calculate the intersection of the line with the clipping rectangle
'var p = CalculateIntersection(r, p1, p2, outCode);
call CalculateIntersection r.Left,r.Right,r.Top,r.Bottom, p1.X,p1.Y, p2.X,p2.Y, outCode, p.X, p.Y
'// update the point after clipping and recalculate outcode
if (outCode = outCodeP1) then
p1.X = p.X
p1.Y = p.Y
outCodeP1 = ComputeOutCode(p1.X, p1.Y, r.Left, r.Right, r.Top, r.Bottom)
else
p2.X = p.X
p2.Y = p.Y
outCodeP2 = ComputeOutCode(p2.X, p2.Y, r.Left, r.Right, r.Top, r.Bottom)
end if
wend
'// if clipping area contained a portion of the line
if (accept) then
'return new Tuple<PointF, PointF>(p1, p2);
pOut1.X=p1.X
pOut1.Y=p1.Y
pOut2.X=p2.X
pOut2.Y=p2.Y
end if
'else nothing
'// the line did not intersect the clipping area
'return null;
end sub