Marching Squares

Share your advanced PureBasic knowledge/code with the community.
Mr.L
Enthusiast
Enthusiast
Posts: 107
Joined: Sun Oct 09, 2011 7:39 am

Marching Squares

Post by Mr.L »

I couldn't find a marching squares example in this forum, so i decided to write one.
Wikipedia:
Marching squares is a computer graphics algorithm that generates contours for a two-dimensional scalar field (rectangular array of individual numerical values)

Code: Select all

EnableExplicit

Structure MetaBall
	x.f
	y.f
	xd.f
	yd.f
	f.f
EndStructure

#Wid = 600
#Hig = 600
#Res = 60
#Size =  #Wid / #Res
#Threshold = 1.0
#NrMetaBalls = 25

Global Dim Metaball.MetaBall(#NrMetaBalls)
Global Dim Field.f(#Res, #Res)

Procedure Initialize()
	Protected n
	
	OpenWindow(0, 0, 0, #Wid, #Hig, "Marching Squares")
	CanvasGadget(0, 0, 0, #Wid, #Hig)

	For n = 0 To #NrMetaBalls - 1
 		Metaball(n)\x = #Wid / 2
 		Metaball(n)\y = #Hig / 2
		Metaball(n)\f = (n + 1) * 750
	Next
EndProcedure

Procedure Update()
	Protected x, y, xb.f, yb.f, f.f
	Protected n, t.f = ElapsedMilliseconds() * 0.00002

	For n = 0 To #NrMetaBalls - 1
		With Metaball(n)
			\xd = Cos(t * (n + 1))
			\yd = Sin(t * (n + 1))
			\x + (#wid * 0.5 - \x) * 0.08 + Sin(\xd) * \yd * (n + 1)
			\y + (#hig * 0.5 - \y) * 0.08 + Cos(\yd) * \xd * (n + 1)
		EndWith
	Next
	
 	For y = 0 To #Res - 1
 		yb = y * #Size
 		For x = 0 To #Res - 1
 			xb = x * #Size
			f = 0
			For n = 0 To #NrMetaBalls - 1
				f + 1.0 / (Pow(Metaball(n)\x - xb, 2) + Pow(Metaball(n)\y - yb, 2) + 0.000000001) * Metaball(n)\f
			Next
			Field(x, y) = f  / #NrMetaBalls
		Next
	Next
EndProcedure

Macro I(a_, b_)
	((1 - f#b_) / (f#a_ - f#b_))
EndMacro

Procedure MarchingSquares()
	Protected x, y, corner
	Protected.f f0, f1, f2, f3
	
	StartVectorDrawing(CanvasVectorOutput(0))
	VectorSourceColor(RGBA(55,55,55,255))
	FillVectorOutput()

 	ScaleCoordinates(DesktopScaledX(#Size), DesktopScaledY(#Size))
 	VectorSourceColor(RGBA(255,255,255,255))
 	
	For y = 0 To #Res - 2
		For x = 0 To #Res - 2
			f0 = Field(x, y)
			f1 = Field(x + 1, y)
			f2 = Field(x, y + 1)
			f3 = Field(x + 1, y + 1)

			corner = 0
			If f0 > #Threshold
				corner | %1000
			EndIf
			If f1 > #Threshold
				corner | %0100
			EndIf
			If f2 > #Threshold
				corner | %0010
			EndIf
			If f3 > #Threshold
				corner | %0001
			EndIf
			
			If corner > %0000 And corner < %1111
				Select corner
					Case %0001
 						MovePathCursor(x + I(3,2), y + 1)
 						AddPathLine(x + 1, y + I(3,1))
  					Case %0010
 						MovePathCursor(x, y + I(2,0))
 						AddPathLine(x + I(3,2), y + 1)
					Case %0011
						MovePathCursor(x, y + I(2,0))
						AddPathLine(x + 1, y + I(3,1))
					Case %0100
						MovePathCursor(x + I(1,0), y)
						AddPathLine(x + 1, y + I(3,1))
 					Case %0101
						MovePathCursor(x + I(1,0), y)
						AddPathLine(x + I(3,2), y + 1)
					Case %0110
						MovePathCursor(x + I(1,0), y)
						AddPathLine(x + 1, y + I(3,1))
						MovePathCursor(x, y + I(2,0))
 						AddPathLine(x + I(3,2), y + 1)
					Case %0111
						MovePathCursor(x, y + I(2,0))
						AddPathLine(x + I(1,0), y)
					Case %1000
						MovePathCursor(x, y + I(2, 0))
						AddPathLine(x + I(1,0), y)
					Case %1001
						MovePathCursor(x, y + I(2, 0))
						AddPathLine(x + I(1,0), y)
						MovePathCursor(x + I(3,2), y + 1)
 						AddPathLine(x + 1, y + I(3,1))
					Case %1010
						MovePathCursor(x + I(1,0), y)
						AddPathLine(x + I(3,2), y + 1)
					Case %1011
						MovePathCursor(x + I(1,0), y)
						AddPathLine(x + 1, y + I(3,1))
					Case %1100
						MovePathCursor(x, y + I(2,0))
						AddPathLine(x + 1, y + I(3,1))
					Case %1101
						MovePathCursor(x, y + I(2,0))
						AddPathLine(x + I(3,2), y + 1)
					Case %1110
						MovePathCursor(x + I(3,2), y + 1)
 						AddPathLine(x + 1, y + I(3,1))
 				EndSelect
 			EndIf
 		Next
 	Next
 	
	StrokePath(0.35)
	StopVectorDrawing()
EndProcedure

Initialize()

Repeat
	Update()
	MarchingSquares()
 	Delay(25)
Until WindowEvent() = #PB_Event_CloseWindow
User avatar
STARGÅTE
Addict
Addict
Posts: 2084
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: Marching Squares

Post by STARGÅTE »

Nice code dome.
I didn't know that so little code could create such an effect.

Pretty useful for a pixel engine.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
User avatar
Caronte3D
Addict
Addict
Posts: 1047
Joined: Fri Jan 22, 2016 5:33 pm
Location: Some Universe

Re: Marching Squares

Post by Caronte3D »

Yeah! 2D Metaballs! 8)
Thanks for sharing! :wink:
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5345
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Marching Squares

Post by Kwai chang caine »

Nice !!!
Thanks for sharing 8)
ImageThe happiness is a road...
Not a destination
Post Reply