fix jitter and mouse cursor accuracy
This commit is contained in:
parent
5a1d279b0a
commit
e3054bdb79
3 changed files with 257 additions and 300 deletions
139
pixler.bas
139
pixler.bas
|
|
@ -4,7 +4,7 @@ type statetype
|
|||
bcolor as long
|
||||
offsetx as long
|
||||
offsety as long
|
||||
zoom as single
|
||||
zoom as long
|
||||
brushsize as integer
|
||||
startx as long
|
||||
starty as long
|
||||
|
|
@ -55,7 +55,7 @@ for y=0 to _height-16 step 16
|
|||
next
|
||||
_dest 0
|
||||
state.tool=1
|
||||
state.zoom=1.0
|
||||
state.zoom=1
|
||||
state.offsetx=70+20
|
||||
state.offsety=20
|
||||
state. brushsize=1
|
||||
|
|
@ -66,8 +66,8 @@ addcommand"bcolor ("+hex$(state.bcolor)+")"
|
|||
|
||||
dim lastmx,lastmy
|
||||
dim keyin as string
|
||||
dim mouseworldy as integer
|
||||
dim mouseworldx as integer
|
||||
dim mouseworldy as long
|
||||
dim mouseworldx as long
|
||||
|
||||
dim diffx as integer
|
||||
dim diffy as integer
|
||||
|
|
@ -76,6 +76,7 @@ dim oldheight as integer
|
|||
oldwidth=_width
|
||||
oldheight=_height
|
||||
do
|
||||
' 1. Check for window resizing first
|
||||
if checkresize(_source)=-1 then
|
||||
diffx=_width-oldwidth
|
||||
diffy=_height-oldheight
|
||||
|
|
@ -85,12 +86,10 @@ do
|
|||
oldheight=_height
|
||||
end if
|
||||
|
||||
canvas
|
||||
if showtoolbox then toolbox
|
||||
if showcolorpicker then colorpicker
|
||||
if showcommands then commandlist
|
||||
' 2. Clear the screen BEFORE drawing anything for this frame
|
||||
line (0,0)-(_width-1,_height-1),backgroundcolor1,bf
|
||||
|
||||
'Mouse Handling
|
||||
' 3. Process all inputs and update offsets FIRST
|
||||
while _mouseinput:mw=mw+_mousewheel:wend
|
||||
mouseclicked=0
|
||||
rmouseclicked=0
|
||||
|
|
@ -101,63 +100,43 @@ do
|
|||
|
||||
' Panning (Middle Mouse)
|
||||
if _mousebutton(3) then
|
||||
state.offsetx=int(state.offsetx+(_mousex-lastmx))
|
||||
state.offsety=int(state.offsety+(_mousey-lastmy))
|
||||
state.offsetx=state.offsetx+(_mousex-lastmx)
|
||||
state.offsety=state.offsety+(_mousey-lastmy)
|
||||
end if
|
||||
lastmx=_mousex:lastmy=_mousey
|
||||
|
||||
' Zooming
|
||||
if mw<>0 then
|
||||
' 1. Capture current world position
|
||||
mouseworldx=(_mousex-state.offsetx)/state.zoom
|
||||
mouseworldy=(_mousey-state.offsety)/state.zoom
|
||||
|
||||
' 2. Calculate the new zoom level (Snap to whole numbers)
|
||||
if mw>0 then
|
||||
state.zoom=state.zoom+1
|
||||
else
|
||||
state.zoom=state.zoom-1
|
||||
end if
|
||||
|
||||
' 3. Constrain zoom (Min 1, Max 20)
|
||||
if mw>0 then state.zoom=state.zoom+1 else state.zoom=state.zoom-1
|
||||
if state.zoom<1 then state.zoom=1
|
||||
if state.zoom>20 then state.zoom=20
|
||||
|
||||
' 4. Adjust offsets
|
||||
state.offsetx=_mousex-(mouseworldx*state.zoom)
|
||||
state.offsety=_mousey-(mouseworldy*state.zoom)
|
||||
|
||||
mw=0
|
||||
end if
|
||||
|
||||
' Keyboarding
|
||||
keyin=inkey$
|
||||
select case keyin
|
||||
case "+"
|
||||
state.brushsize=state.brushsize+1
|
||||
addcommand"brushsize ("+tst(state.brushsize)+")"
|
||||
case "-"
|
||||
if state.brushsize>1 then state.brushsize=state.brushsize-1
|
||||
addcommand"brushsize ("+tst(state.brushsize)+")"
|
||||
case chr$(19) ' ctrl+s
|
||||
'TODO: save logic
|
||||
case chr$(27) ' esc
|
||||
menu
|
||||
case "h"
|
||||
state.zoom=1.0
|
||||
state.offsetx=(_width/2)-(_width(layers(0).ihandle)/2)
|
||||
state.offsety=(_height/2)-(_height(layers(0).ihandle)/2)
|
||||
case "t"
|
||||
showtoolbox=not showtoolbox
|
||||
case "c"
|
||||
showcolorpicker=not showcolorpicker
|
||||
case "l"
|
||||
showcommands=not showcommands
|
||||
case "+": state.brushsize=state.brushsize+1: addcommand"brushsize ("+tst(state.brushsize)+")"
|
||||
case "-": if state.brushsize>1 then state.brushsize=state.brushsize-1: addcommand"brushsize ("+tst(state.brushsize)+")"
|
||||
case "h": state.zoom=1: state.offsetx=(_width/2)-(_width(layers(0).ihandle)/2): state.offsety=(_height/2)-(_height(layers(0).ihandle)/2)
|
||||
case "t": showtoolbox=not showtoolbox
|
||||
case "c": showcolorpicker=not showcolorpicker
|
||||
case "l": showcommands=not showcommands
|
||||
end select
|
||||
|
||||
' 4. Draw everything using the freshly updated math
|
||||
canvas
|
||||
if showtoolbox then toolbox
|
||||
if showcolorpicker then colorpicker
|
||||
if showcommands then commandlist
|
||||
|
||||
' 5. Flip the buffer to the monitor cleanly
|
||||
_limit 30
|
||||
_display
|
||||
line (0,0)-(_width-1,_height-1),backgroundcolor1,bf
|
||||
loop
|
||||
|
||||
sub commandlist
|
||||
|
|
@ -366,50 +345,30 @@ sub canvas
|
|||
if showcolorpicker then viewy2=_height-20 else viewy2=_height-1
|
||||
_dest 0
|
||||
|
||||
' 2. Render Layers with Clipping
|
||||
dim srcx1 as long
|
||||
dim srcy1 as long
|
||||
dim srcx2 as long
|
||||
dim srcy2 as long
|
||||
dim drawx1 as long
|
||||
dim drawy1 as long
|
||||
dim drawx2 as long
|
||||
dim drawy2 as long
|
||||
' 2. Render Layers (Let QB64 handle the viewport clipping natively)
|
||||
dim i as integer
|
||||
for i = 0 to ubound(layers)
|
||||
dim img as long: img = layers(i).ihandle
|
||||
dim imgw as integer: imgw = _width(img)
|
||||
dim imgh as integer: imgh = _height(img)
|
||||
|
||||
dim i as integer
|
||||
for i=0 to ubound(layers)
|
||||
dim img as long:img=layers(i).ihandle
|
||||
dim imgw as integer:imgw=_width(img)
|
||||
dim imgh as integer:imgh=_height(img)
|
||||
' Calculate the absolute unclipped destination positions
|
||||
drawx1 = state.offsetx
|
||||
drawy1 = state.offsety
|
||||
drawx2 = state.offsetx + (imgw * state.zoom)
|
||||
drawy2 = state.offsety + (imgh * state.zoom)
|
||||
|
||||
' Current scaled dimensions
|
||||
dim fullscaledw as single:fullscaledw=imgw*state.zoom
|
||||
dim fullscaledh as single:fullscaledh=imgh*state.zoom
|
||||
' Direct 1:1 mapping of the entire source asset
|
||||
srcx1 = 0
|
||||
srcy1 = 0
|
||||
srcx2 = imgw
|
||||
srcy2 = imgh
|
||||
|
||||
' Calculate visible area in screen coordinates (Overlap of image and viewport)
|
||||
drawx1=state.offsetx
|
||||
drawy1=state.offsety
|
||||
drawx2=state.offsetx+fullscaledw
|
||||
drawy2=state.offsety+fullscaledh
|
||||
|
||||
' Clip the destination to the Viewport
|
||||
if drawx1<viewx1 then drawx1=viewx1
|
||||
if drawy1<viewy1 then drawy1=viewy1
|
||||
if drawx2>viewx2 then drawx2=viewx2
|
||||
if drawy2>viewy2 then drawy2=viewy2
|
||||
|
||||
' Only draw if the image is actually inside the viewport
|
||||
if drawx2>drawx1 and drawy2>drawy1 then
|
||||
' Map screen-clipped coordinates back to the source image coordinates
|
||||
srcx1=int((drawx1-state.offsetx)/state.zoom)
|
||||
srcy1=int((drawy1-state.offsety)/state.zoom)
|
||||
srcx2=int((drawx2-state.offsetx)/state.zoom)
|
||||
srcy2=int((drawy2-state.offsety)/state.zoom)
|
||||
|
||||
' Syntax: _PUTIMAGE (destX1, destY1)-(destX2, destY2), sourceHandle, 0, (srcX1, srcY1)-(srcX2, srcY2)
|
||||
_putimage (drawx1,drawy1)-(drawx2,drawy2),img,0,(srcx1,srcy1)-(srcx2,srcy2)
|
||||
end if
|
||||
next
|
||||
' Only draw if the asset is within the general view window range
|
||||
if drawx2 > viewx1 and drawx1 < viewx2 and drawy2 > viewy1 and drawy1 < viewy2 then
|
||||
_putimage (drawx1, drawy1)-(drawx2, drawy2), img, 0, (srcx1, srcy1)-(srcx2, srcy2)
|
||||
end if
|
||||
next
|
||||
_dest layers(2).ihandle:cls,0:_dest 0
|
||||
' 2.5 if the mouse is in ui thats all we need
|
||||
if showtoolbox then
|
||||
|
|
@ -428,11 +387,13 @@ sub canvas
|
|||
end if
|
||||
end if
|
||||
|
||||
' 3. Calculate Canvas Coordinates
|
||||
' 3. Calculate Canvas Coordinates (Center-aligned to the zoom block)
|
||||
dim canx as long
|
||||
dim cany as long
|
||||
canx=int((_mousex-state.offsetx)/state.zoom)
|
||||
cany=int((_mousey-state.offsety)/state.zoom)
|
||||
|
||||
' Add half a zoomed pixel block to align the mouse tip to the block center
|
||||
canx = int((_mousex - state.offsetx + (state.zoom \ 2)) / state.zoom)
|
||||
cany = int((_mousey - state.offsety + (state.zoom \ 2)) / state.zoom)
|
||||
|
||||
static drawcol
|
||||
if _mousebutton(1) then drawcol=state.fcolor
|
||||
|
|
|
|||
4
test.pxl
4
test.pxl
|
|
@ -1,4 +0,0 @@
|
|||
canvas (1024,780)
|
||||
fcolor (FF0D2B45)
|
||||
bcolor (FFFFECD6)
|
||||
gradient (85,74,200,137)
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
$console
|
||||
_screenhide
|
||||
if command$=""then _echo"please specify image file to process":system 1
|
||||
if command$="" then _echo "🫥 please specify image file to process": system 1
|
||||
_screenshow
|
||||
|
||||
type point2d
|
||||
|
|
@ -24,101 +24,110 @@ dim shared done as _byte
|
|||
dim shared mouseclicked as _byte
|
||||
dim shared mbd as _byte
|
||||
|
||||
' Global polygon trace registers
|
||||
' Global polygon trace registers declared as dynamic
|
||||
redim shared contour(4999) as point2d
|
||||
dim shared totalpoints as long
|
||||
|
||||
if _fileexists(command$) then file=command$
|
||||
state.orgimg=_loadimage(file,32)
|
||||
state.handle=_copyimage(state.orgimg)
|
||||
state.overlay=_newimage(_width(state.orgimg),_height(state.orgimg),32)
|
||||
state.levels=10
|
||||
state.threshold=127
|
||||
if _fileexists(command$) then file = command$
|
||||
state.orgimg = _loadimage(file, 32)
|
||||
state.handle = _copyimage(state.orgimg)
|
||||
state.overlay = _newimage(_width(state.orgimg), _height(state.orgimg), 32)
|
||||
state.levels = 10
|
||||
state.threshold = 127
|
||||
updateimage
|
||||
|
||||
screen _newimage(_width(state.orgimg)+200,_height(state.orgimg)+200,32)
|
||||
screen _newimage(_width(state.orgimg) + 200, _height(state.orgimg) + 200, 32)
|
||||
|
||||
do until done
|
||||
cls
|
||||
while _mouseinput:wend
|
||||
mouseclicked=not _mousebutton(1) and mbd
|
||||
mbd=_mousebutton(1)
|
||||
while _mouseinput: wend
|
||||
mouseclicked = not _mousebutton(1) and mbd
|
||||
mbd = _mousebutton(1)
|
||||
|
||||
if state.change then
|
||||
updateimage
|
||||
state.change=0
|
||||
state.change = 0
|
||||
end if
|
||||
|
||||
' Render quantized base image
|
||||
_putimage (0,0),state.handle
|
||||
_putimage (0, 0), state.handle
|
||||
|
||||
' Render the vector transparent overlay shapes on top
|
||||
_putimage (0,0),state.overlay
|
||||
_putimage (0, 0), state.overlay
|
||||
|
||||
' Process interactive trace when clicking inside image viewport
|
||||
if mouseclicked then
|
||||
dim clickx as long,clicky as long
|
||||
clickx=_mousex
|
||||
clicky=_mousey
|
||||
dim clickx as long, clicky as long
|
||||
clickx = _mousex
|
||||
clicky = _mousey
|
||||
|
||||
' Verify click coordinates are safely within the source image canvas bounding box
|
||||
if clickx>=0 and clickx<_width(state.orgimg) and clicky>=0 and clicky<_height(state.orgimg) then
|
||||
if clickx >= 0 and clickx < _width(state.orgimg) and clicky >= 0 and clicky < _height(state.orgimg) then
|
||||
dim targetcolor as _unsigned long
|
||||
|
||||
' Fetch look-up color index from the generated active handle
|
||||
_source state.handle
|
||||
targetcolor=point(clickx,clicky)
|
||||
_source 0 ' Restore background source monitor pointer
|
||||
targetcolor = point(clickx, clicky)
|
||||
_source 0
|
||||
|
||||
' SAFEGUARD 1: Do not attempt to parse pure black background/borders
|
||||
if targetcolor<>_rgb32(0,0,0) and targetcolor<>_rgba32(0,0,0,0) then
|
||||
totalpoints=0
|
||||
tracecontour targetcolor,clickx,clicky
|
||||
' FIX 1: Clear out the old polygon completely by resetting the transparent overlay canvas
|
||||
dim prevdest as long
|
||||
prevdest = _dest
|
||||
_dest state.overlay
|
||||
cls ,_rgb32(0,0,0,0) ' Wipes the canvas clean
|
||||
_dest prevdest
|
||||
|
||||
if totalpoints>=3 and totalpoints<(_width(state.orgimg)*_height(state.orgimg)) then
|
||||
redim _preserve contour(totalpoints-1) as point2d
|
||||
simplifypolygon
|
||||
' FIX 2: Reset the dynamic buffer array to its clean baseline size right here in the main module
|
||||
redim shared contour(4999) as point2d
|
||||
totalpoints = 0
|
||||
|
||||
if totalpoints>=3 then
|
||||
' Build flat 1D coordinate matrix map array (X1, Y1, X2, Y2...)
|
||||
dim polypoints(0 to (totalpoints*2)-1) as long
|
||||
dim i as long
|
||||
dim clipstr as string
|
||||
' Pass the shared dynamic array directly into the tracing routine
|
||||
tracecontour contour(), targetcolor, clickx, clicky
|
||||
|
||||
clipstr="fpolygon("
|
||||
for i=0 to totalpoints-1
|
||||
polypoints(i*2)=contour(i).x
|
||||
polypoints(i*2+1)=contour(i).y
|
||||
if totalpoints >= 3 and totalpoints < (_width(state.orgimg) * _height(state.orgimg)) then
|
||||
redim _preserve contour(totalpoints - 1) as point2d
|
||||
|
||||
clipstr=clipstr+ltrim$(str$(contour(i).x))+","+ltrim$(str$(contour(i).y))
|
||||
if i<totalpoints-1 then clipstr=clipstr+","
|
||||
next i
|
||||
clipstr=clipstr+")"
|
||||
' Pass the dynamic array directly into the simplification routine
|
||||
simplifypolygon contour()
|
||||
|
||||
' Send string array payload safely to system clipboard hardware
|
||||
_clipboard$=clipstr
|
||||
if totalpoints >= 3 then
|
||||
' Build flat 1D coordinate matrix map array (X1, Y1, X2, Y2...)
|
||||
redim polypoints(0 to (totalpoints * 2) - 1) as long
|
||||
dim i as long
|
||||
dim clipstr as string
|
||||
|
||||
' Render transparent vector overlay on overlay handler sheet
|
||||
dim olddest as long
|
||||
olddest=_dest
|
||||
_dest state.overlay
|
||||
clipstr = "fpolygon("
|
||||
for i = 0 to totalpoints - 1
|
||||
polypoints(i * 2) = contour(i).x
|
||||
polypoints(i * 2 + 1) = contour(i).y
|
||||
|
||||
' Render with a semi-transparent green color (Alpha = 100)
|
||||
filledpolygon polypoints(),_rgba32(0,255,0,100)
|
||||
clipstr = clipstr + ltrim$(str$(contour(i).x)) + "," + ltrim$(str$(contour(i).y))
|
||||
if i < totalpoints - 1 then clipstr = clipstr + ","
|
||||
next i
|
||||
clipstr = clipstr + ")"
|
||||
|
||||
_dest olddest
|
||||
end if
|
||||
' Send string array payload safely to system clipboard hardware
|
||||
_clipboard$ = clipstr
|
||||
|
||||
' Render transparent vector overlay on overlay handler sheet
|
||||
dim olddest as long
|
||||
olddest = _dest
|
||||
_dest state.overlay
|
||||
|
||||
' Render with a semi-transparent green color (Alpha = 100)
|
||||
filledpolygon polypoints(), _rgba32(0, 255, 0, 100)
|
||||
|
||||
_dest olddest
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
mouseclicked=0
|
||||
end if
|
||||
|
||||
ol=state.levels
|
||||
ot=state.threshold
|
||||
ol = state.levels
|
||||
ot = state.threshold
|
||||
interface
|
||||
if ol<>state.levels then state.change=-1
|
||||
if ot<>state.threshold then state.change=-1
|
||||
if ol <> state.levels then state.change = -1
|
||||
if ot <> state.threshold then state.change = -1
|
||||
|
||||
_limit 30
|
||||
_display
|
||||
|
|
@ -127,54 +136,54 @@ system
|
|||
'$include: '../include/ui.bm'
|
||||
|
||||
sub interface
|
||||
if button(10,_height-34,60,23,"exit") then done=-1
|
||||
if button(10, _height - 34, 60, 23, "exit") then done = -1
|
||||
color highlightcolor
|
||||
_printstring (10,_height(state.handle)+10),"levels"
|
||||
state.levels=slider(10,_height(state.handle)+28,100,state.levels*10)/10
|
||||
_printstring (10, _height(state.handle) + 10), "levels"
|
||||
state.levels = slider(10, _height(state.handle) + 28, 100, state.levels * 10) / 10
|
||||
color highlightcolor
|
||||
_printstring (118,_height(state.handle)+28),str$(state.levels)
|
||||
_printstring (10,_height(state.handle)+40),"threshold"
|
||||
state.threshold=slider(10,_height(state.handle)+58,100,state.threshold/255*100)/100*255
|
||||
_printstring (118, _height(state.handle) + 28), str$(state.levels)
|
||||
_printstring (10, _height(state.handle) + 40), "threshold"
|
||||
state.threshold = slider(10, _height(state.handle) + 58, 100, state.threshold / 255 * 100) / 100 * 255
|
||||
color highlightcolor
|
||||
_printstring (118,_height(state.handle)+58),str$(state.threshold)
|
||||
_printstring (118, _height(state.handle) + 58), str$(state.threshold)
|
||||
end sub
|
||||
|
||||
sub updateimage
|
||||
dim odest as long
|
||||
dim osource as long
|
||||
odest=_dest
|
||||
osource=_source
|
||||
odest = _dest
|
||||
osource = _source
|
||||
_source state.orgimg
|
||||
_dest state.handle
|
||||
|
||||
dim x as long,y as long,l as integer
|
||||
dim x as long, y as long, l as integer
|
||||
dim numsteps as integer
|
||||
|
||||
if state.levels<2 then state.levels=2
|
||||
numsteps=state.levels-1
|
||||
if state.levels < 2 then state.levels = 2
|
||||
numsteps = state.levels - 1
|
||||
|
||||
for y=0 to _height-1
|
||||
for x=0 to _width-1
|
||||
l=luma(point(x,y))
|
||||
for y = 0 to _height - 1
|
||||
for x = 0 to _width - 1
|
||||
l = luma(point(x, y))
|
||||
|
||||
dim adjustedl as single
|
||||
if state.threshold=0 or state.threshold=255 then
|
||||
adjustedl=l
|
||||
elseif l<=state.threshold then
|
||||
adjustedl=(l/state.threshold)*127.5
|
||||
if state.threshold = 0 or state.threshold = 255 then
|
||||
adjustedl = l
|
||||
elseif l <= state.threshold then
|
||||
adjustedl = (l / state.threshold) * 127.5
|
||||
else
|
||||
adjustedl=127.5+((l-state.threshold)/(255-state.threshold))*127.5
|
||||
adjustedl = 127.5 + ((l - state.threshold) / (255 - state.threshold)) * 127.5
|
||||
end if
|
||||
|
||||
dim currentstep as integer
|
||||
currentstep=int((adjustedl/256)*state.levels)
|
||||
currentstep = int((adjustedl / 256) * state.levels)
|
||||
|
||||
if currentstep<0 then currentstep=0
|
||||
if currentstep>numsteps then currentstep=numsteps
|
||||
if currentstep < 0 then currentstep = 0
|
||||
if currentstep > numsteps then currentstep = numsteps
|
||||
|
||||
l=int(currentstep*(255/numsteps))
|
||||
l = int(currentstep * (255 / numsteps))
|
||||
|
||||
pset (x,y),_rgb32(l)
|
||||
pset (x, y), _rgb32(l)
|
||||
next x
|
||||
next y
|
||||
|
||||
|
|
@ -183,207 +192,198 @@ sub updateimage
|
|||
end sub
|
||||
|
||||
function luma (col as _unsigned long)
|
||||
luma=0.21*_red(col)+0.72*_green(col)+0.07*_blue(col)
|
||||
luma = 0.21 * _red(col) + 0.72 * _green(col) + 0.07 * _blue(col)
|
||||
end function
|
||||
|
||||
' =========================================================================
|
||||
' SUBROUTINE: Solid Filled Scanning Polygon Vector Renderer
|
||||
' =========================================================================
|
||||
sub filledpolygon (points() as long,col as long)
|
||||
dim i as integer,j as integer
|
||||
dim x1 as single,y1 as single,x2 as single,y2 as single
|
||||
sub filledpolygon (points() as long, col as long)
|
||||
dim i as integer, j as integer
|
||||
dim x1 as single, y1 as single, x2 as single, y2 as single
|
||||
dim intersectx as single
|
||||
dim numpoints as integer
|
||||
numpoints=(ubound(points)+1) \ 2
|
||||
numpoints = (ubound(points) + 1) \ 2
|
||||
|
||||
dim intersections(4999) as single ' SAFEGUARD 2: Larger intersection limit
|
||||
dim intersections(4999) as single
|
||||
dim numintersections as integer
|
||||
dim y as long
|
||||
|
||||
for y=0 to _height-1
|
||||
numintersections=0
|
||||
for i=0 to numpoints-1
|
||||
x1=points(i*2)
|
||||
y1=points(i*2+1)
|
||||
x2=points(((i+1) mod numpoints)*2)
|
||||
y2=points(((i+1) mod numpoints)*2+1)
|
||||
for y = 0 to _height - 1
|
||||
numintersections = 0
|
||||
for i = 0 to numpoints - 1
|
||||
x1 = points(i * 2)
|
||||
y1 = points(i * 2 + 1)
|
||||
x2 = points(((i + 1) mod numpoints) * 2)
|
||||
y2 = points(((i + 1) mod numpoints) * 2 + 1)
|
||||
|
||||
if ((y1>y and y2<=y) or (y2>y and y1<=y)) then
|
||||
if y2-y1<>0 then
|
||||
intersectx=x1+(y-y1)*(x2-x1)/(y2-y1)
|
||||
' SAFEGUARD 3: Array bounds protection
|
||||
if numintersections<=ubound(intersections) then
|
||||
intersections(numintersections)=intersectx
|
||||
numintersections=numintersections+1
|
||||
if ((y1 > y and y2 <= y) or (y2 > y and y1 <= y)) then
|
||||
if y2 - y1 <> 0 then
|
||||
intersectx = x1 + (y - y1) * (x2 - x1) / (y2 - y1)
|
||||
if numintersections <= ubound(intersections) then
|
||||
intersections(numintersections) = intersectx
|
||||
numintersections = numintersections + 1
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
next i
|
||||
|
||||
for i=0 to numintersections-1
|
||||
for j=i+1 to numintersections-1
|
||||
if intersections(i)>intersections(j) then
|
||||
swap intersections(i),intersections(j)
|
||||
for i = 0 to numintersections - 1
|
||||
for j = i + 1 to numintersections - 1
|
||||
if intersections(i) > intersections(j) then
|
||||
swap intersections(i), intersections(j)
|
||||
end if
|
||||
next j
|
||||
next i
|
||||
|
||||
for i=0 to numintersections-1 step 2
|
||||
if i+1<numintersections then
|
||||
line (intersections(i),y)-(intersections(i+1),y),col
|
||||
for i = 0 to numintersections - 1 step 2
|
||||
if i + 1 < numintersections then
|
||||
line (intersections(i), y)-(intersections(i + 1), y), col
|
||||
end if
|
||||
next i
|
||||
next y
|
||||
end sub
|
||||
|
||||
' =========================================================================
|
||||
' SUBROUTINE: Moore-Neighbor Contour Tracer
|
||||
' =========================================================================
|
||||
sub tracecontour (targcolor as _unsigned long,mx as long,my as long)
|
||||
dim startx as long,starty as long
|
||||
' FIX 3: Adjusted signature to cleanly receive the dynamic array as a parameter
|
||||
sub tracecontour (poly() as point2d, targcolor as _unsigned long, mx as long, my as long)
|
||||
dim startx as long, starty as long
|
||||
dim foundstart as _byte
|
||||
|
||||
dim oldsource as long
|
||||
oldsource=_source
|
||||
oldsource = _source
|
||||
_source state.handle
|
||||
|
||||
dim y&
|
||||
for y&=my to 0 step -1
|
||||
if point(mx,y&)<>targcolor then
|
||||
startx=mx
|
||||
starty=y&+1
|
||||
foundstart=-1
|
||||
for y& = my to 0 step -1
|
||||
if point(mx, y&) <> targcolor then
|
||||
startx = mx
|
||||
starty = y& + 1
|
||||
foundstart = -1
|
||||
exit for
|
||||
end if
|
||||
next y&
|
||||
|
||||
if not foundstart then
|
||||
startx=mx:starty=my
|
||||
startx = mx: starty = my
|
||||
end if
|
||||
|
||||
dim dx(0 to 7) as integer
|
||||
dim dy(0 to 7) as integer
|
||||
dx(0)=-1:dx(1)=0:dx(2)=1:dx(3)=1:dx(4)=1:dx(5)=0:dx(6)=-1:dx(7)=-1
|
||||
dy(0)=-1:dy(1)=-1:dy(2)=-1:dy(3)=0:dy(4)=1:dy(5)=1:dy(6)=1:dy(7)=0
|
||||
dx(0) = -1: dx(1) = 0: dx(2) = 1: dx(3) = 1: dx(4) = 1: dx(5) = 0: dx(6) = -1: dx(7) = -1
|
||||
dy(0) = -1: dy(1) = -1: dy(2) = -1: dy(3) = 0: dy(4) = 1: dy(5) = 1: dy(6) = 1: dy(7) = 0
|
||||
|
||||
dim currentx as long,currenty as long
|
||||
dim backtrackdir as integer,checkdir as integer
|
||||
dim currentx as long, currenty as long
|
||||
dim backtrackdir as integer, checkdir as integer
|
||||
dim startbacktrackdir as integer
|
||||
|
||||
currentx=startx
|
||||
currenty=starty
|
||||
totalpoints=0
|
||||
currentx = startx
|
||||
currenty = starty
|
||||
totalpoints = 0
|
||||
|
||||
backtrackdir=1
|
||||
startbacktrackdir=1
|
||||
backtrackdir = 1
|
||||
startbacktrackdir = 1
|
||||
|
||||
dim firststep as _byte
|
||||
firststep=-1
|
||||
firststep = -1
|
||||
|
||||
' Calculate absolute ceiling area parameter to handle escape routes
|
||||
dim maxallowedpoints as long
|
||||
maxallowedpoints=_width(state.handle)*_height(state.handle)
|
||||
maxallowedpoints = _width(state.handle) * _height(state.handle)
|
||||
|
||||
do
|
||||
contour(totalpoints).x=currentx
|
||||
contour(totalpoints).y=currenty
|
||||
totalpoints=totalpoints+1
|
||||
poly(totalpoints).x = currentx
|
||||
poly(totalpoints).y = currenty
|
||||
totalpoints = totalpoints + 1
|
||||
|
||||
' SAFEGUARD 4: Break if loop gets stuck spinning in empty coordinates
|
||||
if totalpoints>=maxallowedpoints then
|
||||
totalpoints=0
|
||||
if totalpoints >= maxallowedpoints then
|
||||
totalpoints = 0
|
||||
exit do
|
||||
end if
|
||||
|
||||
if totalpoints>=ubound(contour) then
|
||||
redim _preserve contour(ubound(contour)+1000) as point2d
|
||||
if totalpoints >= ubound(poly) then
|
||||
' Safely scales the array parameter reference across scopes
|
||||
redim _preserve poly(ubound(poly) + 1000) as point2d
|
||||
end if
|
||||
|
||||
checkdir=(backtrackdir+1) mod 8
|
||||
checkdir = (backtrackdir + 1) mod 8
|
||||
dim steps as integer
|
||||
steps=0
|
||||
steps = 0
|
||||
|
||||
do while steps<8
|
||||
dim nx as long,ny as long
|
||||
nx=currentx+dx(checkdir)
|
||||
ny=currenty+dy(checkdir)
|
||||
do while steps < 8
|
||||
dim nx as long, ny as long
|
||||
nx = currentx + dx(checkdir)
|
||||
ny = currenty + dy(checkdir)
|
||||
|
||||
if nx>=0 and nx<_width(state.handle) and ny>=0 and ny<_height(state.handle) then
|
||||
if point(nx,ny)=targcolor then
|
||||
backtrackdir=(checkdir+4) mod 8
|
||||
currentx=nx
|
||||
currenty=ny
|
||||
if nx >= 0 and nx < _width(state.handle) and ny >= 0 and ny < _height(state.handle) then
|
||||
if point(nx, ny) = targcolor then
|
||||
backtrackdir = (checkdir + 4) mod 8
|
||||
currentx = nx
|
||||
currenty = ny
|
||||
|
||||
if firststep then
|
||||
startbacktrackdir=backtrackdir
|
||||
firststep=0
|
||||
startbacktrackdir = backtrackdir
|
||||
firststep = 0
|
||||
end if
|
||||
exit do
|
||||
end if
|
||||
end if
|
||||
|
||||
checkdir=(checkdir+1) mod 8
|
||||
steps=steps+1
|
||||
checkdir = (checkdir + 1) mod 8
|
||||
steps = steps + 1
|
||||
loop
|
||||
|
||||
if steps=8 then exit do
|
||||
if steps = 8 then exit do
|
||||
|
||||
loop until (currentx=startx and currenty=starty and backtrackdir=startbacktrackdir)
|
||||
loop until (currentx = startx and currenty = starty and backtrackdir = startbacktrackdir)
|
||||
_source oldsource
|
||||
end sub
|
||||
|
||||
' =========================================================================
|
||||
' SUBROUTINE: SimplifyPolygon
|
||||
' =========================================================================
|
||||
sub simplifypolygon
|
||||
' FIX 4: Adjusted signature to cleanly receive the dynamic array as a parameter
|
||||
sub simplifypolygon (poly() as point2d)
|
||||
dim numpoints as long
|
||||
numpoints=totalpoints
|
||||
numpoints = totalpoints
|
||||
|
||||
if numpoints>2 then
|
||||
if contour(numpoints-1).x=contour(0).x and contour(numpoints-1).y=contour(0).y then
|
||||
numpoints=numpoints-1
|
||||
if numpoints > 2 then
|
||||
if poly(numpoints - 1).x = poly(0).x and poly(numpoints - 1).y = poly(0).y then
|
||||
numpoints = numpoints - 1
|
||||
end if
|
||||
end if
|
||||
|
||||
if numpoints<3 then exit sub
|
||||
if numpoints < 3 then exit sub
|
||||
|
||||
dim temp(0 to numpoints-1) as point2d
|
||||
dim temp(0 to numpoints - 1) as point2d
|
||||
dim keepcount as long
|
||||
|
||||
temp(0)=contour(0)
|
||||
keepcount=1
|
||||
temp(0) = poly(0)
|
||||
keepcount = 1
|
||||
|
||||
dim i as long
|
||||
for i=1 to numpoints-1
|
||||
dim previdx as long:previdx=i-1
|
||||
dim nextidx as long:nextidx=i+1
|
||||
if nextidx>numpoints-1 then nextidx=0
|
||||
for i = 1 to numpoints - 1
|
||||
dim previdx as long: previdx = i - 1
|
||||
dim nextidx as long: nextidx = i + 1
|
||||
if nextidx > numpoints - 1 then nextidx = 0
|
||||
|
||||
dim dx1 as single:dx1=contour(i).x-contour(previdx).x
|
||||
dim dy1 as single:dy1=contour(i).y-contour(previdx).y
|
||||
dim dx2 as single:dx2=contour(nextidx).x-contour(i).x
|
||||
dim dy2 as single:dy2=contour(nextidx).y-contour(i).y
|
||||
dim dx1 as single: dx1 = poly(i).x - poly(previdx).x
|
||||
dim dy1 as single: dy1 = poly(i).y - poly(previdx).y
|
||||
dim dx2 as single: dx2 = poly(nextidx).x - poly(i).x
|
||||
dim dy2 as single: dy2 = poly(nextidx).y - poly(i).y
|
||||
|
||||
dim crossproduct as single
|
||||
crossproduct=(dx1*dy2)-(dy1*dx2)
|
||||
crossproduct = (dx1 * dy2) - (dy1 * dx2)
|
||||
|
||||
if abs(crossproduct)>0.05 then
|
||||
temp(keepcount)=contour(i)
|
||||
keepcount=keepcount+1
|
||||
if abs(crossproduct) > 0.05 then
|
||||
temp(keepcount) = poly(i)
|
||||
keepcount = keepcount + 1
|
||||
end if
|
||||
next i
|
||||
|
||||
if keepcount>=3 then
|
||||
redim contour(keepcount-1) as point2d
|
||||
for i=0 to keepcount-1
|
||||
contour(i)=temp(i)
|
||||
if keepcount >= 3 then
|
||||
redim poly(keepcount - 1) as point2d
|
||||
for i = 0 to keepcount - 1
|
||||
poly(i) = temp(i)
|
||||
next i
|
||||
totalpoints=keepcount
|
||||
totalpoints = keepcount
|
||||
else
|
||||
redim contour(numpoints-1) as point2d
|
||||
for i=0 to numpoints-1
|
||||
contour(i)=temp(i)
|
||||
redim poly(numpoints - 1) as point2d
|
||||
for i = 0 to numpoints - 1
|
||||
poly(i) = temp(i)
|
||||
next i
|
||||
totalpoints=numpoints
|
||||
totalpoints = numpoints
|
||||
end if
|
||||
end sub
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue