Code: Select all
;###########################################################
;# #
;# Sutherland-Hodgeman polygon clipping algorithm #
;# 1.0 #
;# Ported to Hollywood by Lazi from wikipedia article: #
;# #
;###########################################################
Const #_INSIDE = 0; // 0000
Const #_LEFT = 1; // 0001
Const #_RIGHT = 2; // 0010
Const #_BOTTOM = 4; // 0100
Const #_TOP = 8; // 1000
;// Compute the bit code For a point (x, y) using the clip rectangle
;// bounded diagonally by (xmin, ymin), and (xmax, ymax)
;// ASSUME THAT xmax , xmin , ymax and ymin are global constants.
Function ComputeOutCode(x, y, idx)
Local code = #_INSIDE; // initialised as being inside of clip window
If (x < w_xmin) ; To the left of clip window
code = code | #_LEFT
ElseIf (x > w_xmax) ; To the right of clip window
code = code | #_RIGHT
EndIf
If (y < w_ymin) ; below the clip window
code = code | #_TOP
ElseIf (y > w_ymax) ; above the clip window
code = code | #_BOTTOM
EndIf
If idx Then code=code &idx
Return (code)
EndFunction
; Cohen&Sutherland clipping algorithm clips a line from
; P0 = (x0, y0) to P1 = (x1, y1) against a rectangle with
; diagonal from (xmin, ymin) to (xmax, ymax).
Function CohenSutherlandLineClip(x0, y0, x1, y1,idx)
; compute outcodes for P0, P1, and whatever point lies outside the clip rectangle
Local outcode0 = ComputeOutCode(x0, y0,idx)
Local outcode1 = ComputeOutCode(x1, y1,idx)
Local accept = False
Repeat
If ((outcode0 | outcode1) = 0) ; Bitwise OR is 0. Trivially accept and get out of loop
accept = True
Break
ElseIf (outcode0 & outcode1) ; Bitwise AND is not 0. Trivially reject and get out of loop
Break
Else
; failed both tests, so calculate the line segment to clip
; from an outside point to an intersection with clip edge
Local x, y
; At least one endpoint is outside the clip rectangle; pick it.
Local outcodeout=IIf(outcode0, outcode0, outcode1)
; Now find the intersection point;
; use formulas y = y0 + slope * (x - x0), x = x0 + (1 / slope) * (y - y0)
If (outcodeOut & #_TOP) ;// point is below the clip rectangle
x = x0 + (x1 - x0) * (w_ymin - y0) / (y1 - y0)
y = w_ymin
ElseIf (outcodeOut & #_BOTTOM) ;// point is above the clip rectangle
x = x0 + (x1 - x0) * (w_ymax - y0) / (y1 - y0)
y = w_ymax
ElseIf (outcodeOut & #_RIGHT) ;// point is To the right of clip rectangle
y = y0 + (y1 - y0) * (w_xmax - x0) / (x1 - x0)
x = w_xmax
ElseIf (outcodeOut & #_LEFT) ;// point is To the left of clip rectangle
y = y0 + (y1 - y0) * (w_xmin - x0) / (x1 - x0)
x = w_xmin
EndIf
; Now we move outside point to intersection point to clip
; and get ready for next pass.
If (outcodeOut = outcode0)
x0 = x
y0 = y
outcode0 = ComputeOutCode(x0, y0,idx)
Else
x1 = x
y1 = y
outcode1 = ComputeOutCode(x1, y1, idx)
EndIf
EndIf
Forever
If (accept)
Return(x0, y0, x1, y1)
Else
Return(False)
EndIf
EndFunction
Function PolygonClipping(vertex,x,y)
Local cropped={}
Local n=ListItems(vertex)/2
Local idxs={#_TOP,#_BOTTOM,#_LEFT,#_RIGHT}
Local i, idx, nxt
Local x1,y1,x2,y2
nxt,idx=NextItem(idxs,nil)
While GetType(nxt) <> #NIL
If n
InsertItem(vertex,vertex[0])
InsertItem(vertex,vertex[1])
For i=0 To n-1
If not ComputeOutCode (vertex[i*2]+x , vertex[i*2+1]+y, idx) ;#_INSIDE
InsertItem (cropped , vertex[i*2])
InsertItem (cropped , vertex[i*2+1])
If ComputeOutCode (vertex[(i+1)*2]+x , vertex[(i+1)*2+1]+y, idx) ; <> #_INSIDE
x1,y1,x2,y2 = CohenSutherlandLineClip (vertex[i*2]+x , vertex[i*2+1]+y , vertex[(i+1)*2]+x , vertex[(i+1)*2+1]+y, idx)
InsertItem (cropped , x2-x)
InsertItem (cropped , y2-y)
EndIf
Else
If not ComputeOutCode (vertex[(i+1)*2]+x , vertex[(i+1)*2+1]+y, idx) ;= #_INSIDE
x1,y1,x2,y2 = CohenSutherlandLineClip (vertex[i*2]+x , vertex[i*2+1]+y , vertex[(i+1)*2]+x , vertex[(i+1)*2+1]+y, idx)
InsertItem (cropped , x1-x)
InsertItem (cropped , y1-y)
EndIf
EndIf
Next
EndIf
nxt,idx=NextItem(idxs,nxt)
n=ListItems(cropped)/2
vertex=copytable(cropped)
cropped={}
Wend
Return(vertex,n)
EndFunction
;cropping window position
w_xmax=GetAttribute(#DISPLAY,0,#ATTRWIDTH) -30
w_ymax=GetAttribute(#DISPLAY,0,#ATTRHEIGHT)-30
w_xmin=30
w_ymin=30
vertex={0,0,20,0,20,80,60,50,60,-20,100,120,-20,120,0,0}
Repeat
x=MouseX()
y=MouseY()
SetFillStyle(#FILLNONE)
Box(w_xmin,w_ymin,w_xmax-w_xmin,w_ymax-w_ymin,#YELLOW)
SetFillStyle(#FILLCOLOR)
Polygon(x,y,vertex,8,#WHITE)
cropped,points=PolygonClipping(CopyTable(vertex),x,y)
If points>0 Then Polygon(x,y,cropped,points,#RED)
Wait(2)
Cls
Forever