2D polygon generation

Blitz3D Forums/Blitz3D Beginners Area/2D polygon generation

kmick(Posted 2004) [#1]
I first created this function to give myself some extra polys to play with. So far Iv'e just used it in a screen saver.
THE PROBLEM IS, the octogon, decagon,dodecagon have gaps between some of the corners. And the 11 gon(whatever thats called) has an uneven side. I originally thought that it was due to coordinates not being floating point numbers, but it's mostly the even numbers giving me problem. Any help would be greatly appreciated.
Graphics 320,240,16,2
AutoMidHandle(True)
size = 3

Print "Press mouse button to change polygons......"
WaitMouse
While Not KeyDown(1)
Cls
polygon = PolyImage(size,100,0,255,255,255)

DrawImage polygon,320/2,240/2
FreeImage polygon
Text 320/2,240/2,size + " sides",1,1
WaitMouse


size = size + 1
If size > 12 Then size = 3

Wend

End



;Creates an image of a polygon and returns it to specified handle
;****************************************************************

Function PolyImage(numSides,size,rotation,r,g,b)

Color r,g,b

polygon = CreateImage(size*2,size*2)
SetBuffer ImageBuffer(polygon)
Origin size,size

rotationSolver = rotation + 90

sides= 360/numSides

degrees = 0-rotationSolver

a = 0


;Generate coordinates of the polygon corners with polar coordinate system based on sin/cos
;*****************************************************************************************
Repeat
 

	y = Sin(degrees)*size 
	
	x = Cos(degrees)*size 
	;Plot x,y
	
	a = a + 1
	
	Select a
		Case 1
			px1 = x
			py1 = y
		Case 2
			px2 = x
			py2 = y
		Case 3
			px3 = x
			py3 = y
		Case 4
			px4 = x
			py4 = y
		Case 5
			px5 = x
			py5 = y
		Case 6
			px6 = x
			py6 = y
		Case 7
			px7 = x
			py7 = y	
		Case 8	
			px8 = x
			py8 = y
		Case 9	
			px9 = x
			py9 = y
		Case 10	
			px10 = x
			py10 = y
		Case 11	
			px11 = x
			py11 = y
		Case 12	
			px12 = x
			py12 = y


	End Select
	
degrees = degrees + sides	

Until degrees > 360



;draw sides of polygons based on corners coordinates
Select numSides
	Case 3
		Line px1,py1,px2,py2
		Line px2,py2,px3,py3
		Line px3,py3,px1,py1
		
	Case 4
		Line px1,py1,px2,py2
		Line px2,py2,px3,py3
		Line px3,py3,px4,py4
		Line px4,py4,px1,py1


	Case 5
		Line px1,py1,px2,py2
		Line px2,py2,px3,py3
		Line px3,py3,px4,py4
		Line px4,py4,px5,py5
		Line px5,py5,px1,py1

	Case 6
		Line px1,py1,px2,py2
		Line px2,py2,px3,py3
		Line px3,py3,px4,py4
		Line px4,py4,px5,py5
		Line px5,py5,px6,py6
		Line px6,py6,px1,py1 
		
	Case 7
		Line px1,py1,px2,py2
		Line px2,py2,px3,py3
		Line px3,py3,px4,py4
		Line px4,py4,px5,py5
		Line px5,py5,px6,py6
		Line px6,py6,px7,py7
		Line px7,py7,px1,py1
		
	Case 8
		Line px1,py1,px2,py2
		Line px2,py2,px3,py3
		Line px3,py3,px4,py4
		Line px4,py4,px5,py5
		Line px5,py5,px6,py6
		Line px6,py6,px7,py7
		Line px7,py7,px8,py8
		Line px8,py8,px1,py1

	Case 9
		Line px1,py1,px2,py2
		Line px2,py2,px3,py3
		Line px3,py3,px4,py4
		Line px4,py4,px5,py5
		Line px5,py5,px6,py6
		Line px6,py6,px7,py7
		Line px7,py7,px8,py8
		Line px8,py8,px9,py9
		Line px9,py9,px1,py1

	Case 10
		Line px1,py1,px2,py2
		Line px2,py2,px3,py3
		Line px3,py3,px4,py4
		Line px4,py4,px5,py5
		Line px5,py5,px6,py6
		Line px6,py6,px7,py7
		Line px7,py7,px8,py8
		Line px8,py8,px9,py9
		Line px9,py9,px10,py10
		Line px10,py10,px1,py1

	Case 11
		Line px1,py1,px2,py2
		Line px2,py2,px3,py3
		Line px3,py3,px4,py4
		Line px4,py4,px5,py5
		Line px5,py5,px6,py6
		Line px6,py6,px7,py7
		Line px7,py7,px8,py8
		Line px8,py8,px9,py9
		Line px9,py9,px10,py10
		Line px10,py10,px11,py11
		Line px11,py11,px1,py1

	Case 12
		Line px1,py1,px2,py2
		Line px2,py2,px3,py3
		Line px3,py3,px4,py4
		Line px4,py4,px5,py5
		Line px5,py5,px6,py6
		Line px6,py6,px7,py7
		Line px7,py7,px8,py8
		Line px8,py8,px9,py9
		Line px9,py9,px10,py10
		Line px10,py10,px11,py11
		Line px11,py11,px12,py12
		Line px12,py12,px1,py1
End Select

SetBuffer FrontBuffer()

Return polygon

End Function  ;PolyImage()



WolRon(Posted 2004) [#2]
Well, first of all, I would change all of your position variables to floating point numbers. You actually only have to do this the first time the variable is used in the code if you don't feel like changing all of them.

11 sided polygons do not have angles that are integers.
360/11 = 32.727272727272727272727272727273

This is why your last side is shorter.


kmick(Posted 2004) [#3]
Thanx for the reply WolRon. Unfortunatly, that doesn't work. Although I agree with you on 11. 8,10,and 12 give me even results. The math problem has to be somewhere else.


kmick(Posted 2004) [#4]
And on another note. Can coordinates be other than whole numbers?


TomToad(Posted 2004) [#5]
change polygon = CreateImage(size*2,size*2) to polygon = CreateImage(size*2+1,size*2+1) or change y = Sin(degrees)*size and x = cos(degrees)*size to y = Sin(degrees)*(size - 1) and x = Cos(degrees)*(size - 1)

Edit: reason for the gaps is that your plotting off the edge of the image by 1 pixel.


kmick(Posted 2004) [#6]
Tom....good eyes. I knew it was something stupid, I just could not see it.
Thanks.


TomToad(Posted 2004) [#7]
Well, not really. Noticed you put in a function to rotate the ploygons. Thought I'd make use of it and see if the problem was caused by the angle of the lines. Then I noticed that all the gaps appeared either at the very bottom or at the very right edge, that's when I realized that it must be drawing off the edge of the image buffer. So I changed DrawImage to DrawBlock (so it wouldn't draw transparent) then colored the background of the screen red. Then it was easy to notice the lines drawing off the rectangle. Had you not put in that rotation function, I might still be trying to figure out your problem.


kmick(Posted 2004) [#8]
Thats kinda funny. If I never put in the rotation, I might have figured it out. Putting in the rotation allowed you to fix it. Cool nun the less.
Thanks again.


PGF(Posted 2004) [#9]
That is a strange and not very good way to do the loop. what if you want say 37 sides ?

How about this:

Const ScreenWidth = 640
Const ScreenHeight = 480

Const CentreX = ScreenWidth / 2
Const CentreY = ScreenHeight / 2

Graphics ScreenWidth, ScreenHeight, 16, 2
AutoMidHandle(True)
Sides = 3

Print "Press mouse button to change polygons......"
WaitMouse

While True
	If KeyHit(1)
		Exit
	EndIf
		
	X = MouseX() - CentreX 
	Y = MouseY() - CentreY
	Size# = Sqr(X * X + Y * Y)
	Rot# = ATan2(Y, X)
	Polygon = PolyImage2(Sides, Size, Rot, 255, 255, 255)

	SetBuffer BackBuffer()
	Cls
	TileImage Polygon, CentreX, CentreY
	FreeImage Polygon
	Text CentreX, CentreY, "Sides = " + Sides + "  Rot = " + Rot, 1, 1
	Flip True

	If MouseHit(1)
		Sides = Sides + 1
		If Sides > 12 Then Sides = 3
	EndIf

Wend

End

;Creates an image of a polygon and returns it to specified handle
;****************************************************************
Function PolyImage2(numSides, size, rotation, r, g, b)

	Color r, g, b
	
	polygon = CreateImage(size * 2 + 1, size * 2 + 1)
	SetBuffer ImageBuffer(polygon)
	Origin size,size

	Local OldX#, OldY#
	Local NewX#, NewY#
	Local AngleStep# = 360 / numSides
	Local Angle#
	
	For i = 0 To numSides
		Angle = i * AngleStep + rotation
		OldX = NewX
		OldY = NewY
		NewX = size * Cos(Angle)
		NewY = size * Sin(Angle)
		If (i <> 0)
			Line OldX, OldY, NewX, NewY
		EndIf
	Next
	
	Return polygon
End Function

The function is not only a lot shorter but more flexible as numSides can be anything with no need to add code.

I also added a bit more functionality in the mainline like rotating the polygon according to the mouse position and tiling the image for a cool but cheap effect. Hence the switch to continuous drawing and flip etc.


kmick(Posted 2004) [#10]
That is alot shorter. And better for equilateral shapes. In fact that is very similar to how i was originally writing it. I chose this method because it allowed me to more easily prototype other shapes based on the same numbers like pentangles and hexangles. It also gives me more direct control over the individual coordinates for non equilateral shapes, instead of effecting each pair equally. Eventually it will all be much more economical. And as for the amount of sides.....I definitely agree , But I also figured once you get past 15 or so, you would be better off using the oval command.
I DO VERY MUCH APPRECIATE THE IMPROVEMENT TO MY CODE.
Thanks PGF.