Calculating hidden surfaces for 3D objects

Everything related to 3D programming
User avatar
Michael Vogel
Addict
Addict
Posts: 2677
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Calculating hidden surfaces for 3D objects

Post by Michael Vogel »

Hi, tested a nice graphics library from Stargate and now I started to make something similar to show (convex) objects in 3D...
...hopefully some of you have soe experience in doing such stuff and maybe someone can give e a hint for calculating which surfaces needs to be drawn before others.

In the example below you can see what's going on - rotating the objects are done using the cursor keys (use shift to move the object), some object data will be displayed by using the keys 'D' and 'I'...

Code: Select all

; Define

	EnableExplicit

	#WX=1200
	#WY=850

	#ZoomScale=0.1
	#ZweiPi=#PI+#PI
	#PiHalbe=#PI/2
	#PiTeil=#PI/18
	#PiRadiant=#PI/180
	#PiGrad=180/#PI

	; ------------------------------------------------------------------------------------

	Structure DotType
		x.d;			skaliert
		y.d;			skaliert
		z.d;			skaliert
		_x.i;		2D-Transformation
		_y.i;		2D-Transformation
		;_rb.i;		3D-Punkt-Distanz (rot/blau)
		_distance.q;	Z-Distanz zum Betrachter
	EndStructure

	Structure ObjectType
		Type.i;		Punkt, Linie, Oberfläche (3 oder 4 Punkte)
		Point.i[4];	Punktkoordinaten
		Color.i;		Flächenfarbe
		Outline.i;	Linienfarbe
		Centre.i;		Flächenmittelpunkt
		Visible.i;	sichtbares Segment
	EndStructure

	Structure SorterType
		Object.i
		Distance.q
	EndStructure

	Structure Mat
		x.d[4]
		y.d[4]
		z.d[4]
		t.d[4]
	EndStructure

	Structure SettingType
		ShowOutline.i
		ShowSurface.i
		ShowPoints.i
		ShowInformation.i
		ModeCalculation.i
		ModeRotation.i
		ModeFill.i
		ModeLine.i
		Optimizer.i
		ZoomFactor.i
		ShowThreeD.i;			3D-Darstellung
		ThreeD_Distance.i;		Punktabstand für 3D-Effekt;					-		-		-
		ThreeD_Left.i;			Farbfilter für das linke Auge (rot)				-		-		-
		ThreeD_Right.i;		...rechtes Auge (grün, blau)					-		-		-
	EndStructure

	; ------------------------------------------------------------------------------------

	Global MaxElements=	25000

	Global.Mat Matrix, Calc, RotXMat, RotYMat, RotZMat, Camera, TempMat
	Global Dim Dot.DotType(MaxElements)
	Global Dim Object.ObjectType(MaxElements)
	Global Dim Sorter.SorterType(MaxElements)

	; Bildschirmgröße für Graphikfenster
	Global ScreenX=GetSystemMetrics_(#SM_CXSCREEN)
	Global ScreenY=GetSystemMetrics_(#SM_CYSCREEN)
	Global Screen_X=ScreenX-1
	Global Screen_Y=ScreenY-1
	Global ScreenZ
	Global OffsetX=ScreenX>>1
	Global OffsetY=ScreenY>>1

	; Skalierung für 3D-Transformation
	Global.d ViewX, ViewY, ViewZ, Scale
	Global.d AngleX, AngleY, AngleZ;		Rotationswinkel (per Maus auswählbar)
	Global.d XdivPi=#PI/OffsetX;			Skalierung, um genau eine Drehung nach 'X' zu erlauben
	Global.d YdivPi=#PI/OffsetY;			Skalierung, um genau eine Drehung nach 'Y' zu erlauben
	Global.d RealZoomFactor;				skalierte Vergrößerung

	Global CounterPoints, CounterObjects
	Global OptCamera; =OptCameraZ
	Global OptCameraX, OptCameraY

	Global Setting.SettingType

	; ------------------------------------------------------------------------------------

	OptCamera=		500

	With Setting
		\ShowSurface=	1
		\ShowOutline=	0
		\ZoomFactor=	25
		\ModeRotation=	1
		\ModeFill=	1
		\Optimizer=	1
	EndWith

	; ------------------------------------------------------------------------------------

	Enumeration
		#Win
		#Canvas
		;
		#ShiftLeft
		#ShiftRight
		#ShiftUp
		#ShiftDown
		#RotateLeft
		#RotateRight
		#RotateUp
		#RotateDown
		#PerspectiveMinus
		#PerspectivePlus
		#ResetView
		#ToggleRotation
		#ToggleLine
		#ToggleFill
		#ToggleCalcMode
		#ToggleOutline
		#ToggleSurface
		#TogglePoints
		#ToggleInformation
	EndEnumeration

	; ------------------------------------------------------------------------------------

	Macro StrM(value)
		RSet(StrD(value,2),8)
	EndMacro
	Macro CreateLine(p1,p2,outline)

		CreateObject(#ObjectTypeLine,p1,p2,#Null,#Null,#Null,outline)

	EndMacro
	Macro CreateRectangle(p1,p2,p3,p4,color,outline)

		CreateObject(#ObjectTypeRectangle,p1,p2,p3,p4,color,outline)

	EndMacro

; EndDefine

Procedure Distance(dot)

	With Dot(dot)
		ProcedureReturn Sqr(Pow(ViewX-OptCameraX+\x,2)+Pow(ViewY-OptCameraY+\y,2)+Pow(ViewZ-OptCamera+\z,2))
		ProcedureReturn Sqr(Pow(ViewX-\x,2)+Pow(ViewY-\y,2)+Pow(ViewZ-\z,2))
		ProcedureReturn Sqr(Pow(OptCameraX-\x,2)+Pow(OptCameraY-\y,2)+Pow(OptCamera-\z,2))
	EndWith

EndProcedure

Procedure SetNorm(*m.mat)
	*m\x[0]=1 : *m\y[0]=0 : *m\z[0]=0 : *m\t[0]=0
	*m\x[1]=0 : *m\y[1]=1 : *m\z[1]=0 : *m\t[1]=0
	*m\x[2]=0 : *m\y[2]=0 : *m\z[2]=1 : *m\t[2]=0
	*m\x[3]=0 : *m\y[3]=0 : *m\z[3]=0 : *m\t[3]=1
EndProcedure
Procedure SetTransformation(*m.mat,x.d,y.d,z.d)
	*m\x[0]=1 : *m\y[0]=0 : *m\z[0]=0 : *m\t[0]=0
	*m\x[1]=0 : *m\y[1]=1 : *m\z[1]=0 : *m\t[1]=0
	*m\x[2]=0 : *m\y[2]=0 : *m\z[2]=1 : *m\t[2]=0
	*m\x[3]=x : *m\y[3]=y : *m\z[3]=z : *m\t[3]=1
EndProcedure
Procedure SetCamera(x,y,z.d)
	OptCameraX=x
	OptCameraY=y
	OptCamera=z
	Camera\x[0]=1 : Camera\y[0]=0 : Camera\z[0]=0 : Camera\t[0]=0
	Camera\x[1]=0 : Camera\y[1]=1 : Camera\z[1]=0 : Camera\t[1]=0
	Camera\x[2]=0 : Camera\y[2]=0 : Camera\z[2]=1 : Camera\t[2]=0
	Camera\x[3]=x : Camera\y[3]=y : Camera\z[3]=z : Camera\t[3]=1
EndProcedure
Procedure SetScale(*m.mat,x.d,y.d,z.d)
	*m\x[0]=x : *m\y[0]=0 : *m\z[0]=0 : *m\t[0]=0
	*m\x[1]=0 : *m\y[1]=y : *m\z[1]=0 : *m\t[1]=0
	*m\x[2]=0 : *m\y[2]=0 : *m\z[2]=z : *m\t[2]=0
	*m\x[3]=0 : *m\y[3]=0 : *m\z[3]=0 : *m\t[3]=1
EndProcedure
Procedure SetRotX(*m.mat,angle.d)
	Protected s.d=Sin(angle)
	Protected c.d=Cos(angle)
	*m\x[0]=1 : *m\y[0]=0 : *m\z[0]=0 : *m\t[0]=0
	*m\x[1]=0 : *m\y[1]=c : *m\z[1]=s : *m\t[1]=0
	*m\x[2]=0 : *m\y[2]=-s : *m\z[2]=c : *m\t[2]=0
	*m\x[3]=0 : *m\y[3]=0 : *m\z[3]=0 : *m\t[3]=1
EndProcedure
Procedure SetRotY(*m.mat,angle.d)
	Protected s.d=Sin(angle)
	Protected c.d=Cos(angle)
	*m\x[0]=c : *m\y[0]=0 : *m\z[0]=s : *m\t[0]=0
	*m\x[1]=0 : *m\y[1]=1 : *m\z[1]=0 : *m\t[1]=0
	*m\x[2]=-s : *m\y[2]=0 : *m\z[2]=c : *m\t[2]=0
	*m\x[3]=0 : *m\y[3]=0 : *m\z[3]=0 : *m\t[3]=1
EndProcedure
Procedure SetRotZ(*m.mat,angle.d)
	Protected s.d=Sin(angle)
	Protected c.d=Cos(angle)
	*m\x[0]=c : *m\y[0]=s : *m\z[0]=0 : *m\t[0]=0
	*m\x[1]=-s : *m\y[1]=c : *m\z[1]=0 : *m\t[1]=0
	*m\x[2]=0 : *m\y[2]=0 : *m\z[2]=1 : *m\t[2]=0
	*m\x[3]=0 : *m\y[3]=0 : *m\z[3]=0 : *m\t[3]=1
EndProcedure
Procedure Multiply(*m.mat,*n.mat,*result.mat)

	TempMat\x[0]=*m\x[0]**n\x[0] + *m\x[1]**n\y[0] + *m\x[2]**n\z[0] + *m\x[3]**n\t[0]
	TempMat\y[0]=*m\y[0]**n\x[0] + *m\y[1]**n\y[0] + *m\y[2]**n\z[0] + *m\y[3]**n\t[0]
	TempMat\z[0]=*m\z[0]**n\x[0] + *m\z[1]**n\y[0] + *m\z[2]**n\z[0] + *m\z[3]**n\t[0]
	TempMat\t[0]=*m\t[0]**n\x[0] + *m\t[1]**n\y[0] + *m\t[2]**n\z[0] + *m\t[3]**n\t[0]

	TempMat\x[1]=*m\x[0]**n\x[1] + *m\x[1]**n\y[1] + *m\x[2]**n\z[1] + *m\x[3]**n\t[1]
	TempMat\y[1]=*m\y[0]**n\x[1] + *m\y[1]**n\y[1] + *m\y[2]**n\z[1] + *m\y[3]**n\t[1]
	TempMat\z[1]=*m\z[0]**n\x[1] + *m\z[1]**n\y[1] + *m\z[2]**n\z[1] + *m\z[3]**n\t[1]
	TempMat\t[1]=*m\t[0]**n\x[1] + *m\t[1]**n\y[1] + *m\t[2]**n\z[1] + *m\t[3]**n\t[1]

	TempMat\x[2]=*m\x[0]**n\x[2] + *m\x[1]**n\y[2] + *m\x[2]**n\z[2] + *m\x[3]**n\t[2]
	TempMat\y[2]=*m\y[0]**n\x[2] + *m\y[1]**n\y[2] + *m\y[2]**n\z[2] + *m\y[3]**n\t[2]
	TempMat\z[2]=*m\z[0]**n\x[2] + *m\z[1]**n\y[2] + *m\z[2]**n\z[2] + *m\z[3]**n\t[2]
	TempMat\t[2]=*m\t[0]**n\x[2] + *m\t[1]**n\y[2] + *m\t[2]**n\z[2] + *m\t[3]**n\t[2]

	TempMat\x[3]=*m\x[0]**n\x[3] + *m\x[1]**n\y[3] + *m\x[2]**n\z[3] + *m\x[3]**n\t[3]
	TempMat\y[3]=*m\y[0]**n\x[3] + *m\y[1]**n\y[3] + *m\y[2]**n\z[3] + *m\y[3]**n\t[3]
	TempMat\z[3]=*m\z[0]**n\x[3] + *m\z[1]**n\y[3] + *m\z[2]**n\z[3] + *m\z[3]**n\t[3]
	TempMat\t[3]=*m\t[0]**n\x[3] + *m\t[1]**n\y[3] + *m\t[2]**n\z[3] + *m\t[3]**n\t[3]

	*result\x[0]=TempMat\x[0]
	*result\x[1]=TempMat\x[1]
	*result\x[2]=TempMat\x[2]
	*result\x[3]=TempMat\x[3]
	*result\y[0]=TempMat\y[0]
	*result\y[1]=TempMat\y[1]
	*result\y[2]=TempMat\y[2]
	*result\y[3]=TempMat\y[3]
	*result\z[0]=TempMat\z[0]
	*result\z[1]=TempMat\z[1]
	*result\z[2]=TempMat\z[2]
	*result\z[3]=TempMat\z[3]
	*result\t[0]=TempMat\t[0]
	*result\t[1]=TempMat\t[1]
	*result\t[2]=TempMat\t[2]
	*result\t[3]=TempMat\t[3]

EndProcedure
Procedure ShowMat(*m.mat,title.s="")

	Debug "- "+title+RSet(" ",38-Len(title),"-")
	Debug "X"+StrM(*m\x[0])+" |"+StrM(*m\x[1])+" |"+StrM(*m\x[2])+" |"+StrM(*m\x[3])
	Debug "Y"+StrM(*m\y[0])+" |"+StrM(*m\y[1])+" |"+StrM(*m\y[2])+" |"+StrM(*m\y[3])
	Debug "Z"+StrM(*m\z[0])+" |"+StrM(*m\z[1])+" |"+StrM(*m\z[2])+" |"+StrM(*m\z[3])
	Debug "T"+StrM(*m\t[0])+" |"+StrM(*m\t[1])+" |"+StrM(*m\t[2])+" |"+StrM(*m\t[3])

	Macro DebugMat
		ShowMat(@Camera,"Camera")
		ShowMat(@Matrix,"Matrix")
		ShowMat(@Calc,"Calc")
	EndMacro

EndProcedure

Procedure CreatePoint(x.d,y.d,z.d)

	Protected i

	If Setting\Optimizer; 					Punkt in den gespeicherten Punkten suchen...
		i=CounterPoints
		While i
			With Dot(i)
				If \x=x And \y=y And \z=z
					Break
				EndIf
			EndWith
			i-1
		Wend
	EndIf

	If i=0 And CounterPoints<MaxElements;	neuer Punkt
		CounterPoints+1
		i=CounterPoints
	EndIf

	With Dot(i);						Koordinaten setzen
		\x=x
		\y=y
		\z=z
	EndWith

	ProcedureReturn i

EndProcedure
Procedure CreateObject(type,a,b,c,d,color,outline=#Null)

	Enumeration
		#ObjectTypeDot
		#ObjectTypeLine
		#ObjectTypeTriangle
		#ObjectTypeRectangle
	EndEnumeration

	If CounterObjects<MaxElements
		CounterObjects+1

		With Object(CounterObjects)
			\Type=type
			\Point[0]=a
			\Point[1]=b
			\Point[2]=c
			\Point[3]=d
			\Color=color
			\Outline=outline
			Select type
			Case #ObjectTypeLine
				\Centre=CreatePoint((Dot(a)\x+Dot(b)\x)/2,(Dot(a)\y+Dot(b)\y)/2,(Dot(a)\z+Dot(b)\z)/2)
			Case #ObjectTypeRectangle
				\Centre=CreatePoint((Dot(a)\x+Dot(b)\x+Dot(c)\x+Dot(d)\x)/4,(Dot(a)\y+Dot(b)\y+Dot(c)\y+Dot(d)\y)/4,(Dot(a)\z+Dot(b)\z+Dot(c)\z+Dot(d)\z)/4)
			EndSelect
		EndWith

		ProcedureReturn CounterObjects
	EndIf

	ProcedureReturn #Null

EndProcedure
Procedure CreateBox(ax.d,ay.d,az.d, bx.d,by.d,bz.d,color.i,outline.i=#Null)

	Protected p1,p2,p3,p4,p5,p6,p7,p8

	bx+ax
	by+ay
	bz+az

	p1=CreatePoint(ax,ay,az)
	p2=CreatePoint(bx,ay,az)
	p3=CreatePoint(bx,by,az)
	p4=CreatePoint(ax,by,az)

	p5=CreatePoint(ax,ay,bz)
	p6=CreatePoint(bx,ay,bz)
	p7=CreatePoint(bx,by,bz)
	p8=CreatePoint(ax,by,bz)


	If outline
		CreateLine(p1,p2,outline)
		CreateLine(p2,p3,outline)
		CreateLine(p3,p4,outline)
		CreateLine(p4,p1,outline)

		CreateLine(p5,p6,outline)
		CreateLine(p6,p7,outline)
		CreateLine(p7,p8,outline)
		CreateLine(p8,p5,outline)

		CreateLine(p1,p5,outline)
		CreateLine(p2,p6,outline)
		CreateLine(p3,p7,outline)
		CreateLine(p4,p8,outline)
	EndIf

	CreateRectangle(p1,p2,p3,p4,color,outline)
	CreateRectangle(p1,p2,p6,p5,color,outline)
	CreateRectangle(p2,p3,p7,p6,color,outline)
	CreateRectangle(p3,p4,p8,p7,color,outline)
	CreateRectangle(p4,p1,p5,p8,color,outline)
	CreateRectangle(p5,p6,p7,p8,color,outline)


EndProcedure
Procedure Redraw()

	Protected.i i,n
	Protected.d x,y,z
	Protected.s s

	Protected FillMode
	Protected.d LineMode

	StartVectorDrawing(CanvasVectorOutput(#Canvas))
	VectorFont(FontID(0))
	;VectorSourceColor($C0FFFFFF)
	VectorSourceColor($FFFFFFFF)
	FillVectorOutput()

	FillMode=Setting\ModeFill*$FF000000
	LineMode=Setting\ModeLine+0.8


	If Setting\ShowInformation
		VectorSourceColor($FF000080)
		MovePathCursor(20,20)
		DrawVectorText("Viewpoint: "+Str(ViewX)+" | "+Str(ViewY)+" | "+Str(ViewZ))
		MovePathCursor(20,40)
		DrawVectorText("Camera: "+Str(OptCameraX)+" | "+Str(OptCameraY)+" | "+Str(OptCamera))
	EndIf


	If Setting\ShowSurface
		While i<CounterObjects
			i+1
			n=Sorter(i)\Object
			With Object(n)
				Select \type
				Case #ObjectTypeRectangle
					MovePathCursor(Dot(\Point[0])\_x,Dot(\Point[0])\_y)
					AddPathLine(Dot(\Point[1])\_x,Dot(\Point[1])\_y)
					AddPathLine(Dot(\Point[2])\_x,Dot(\Point[2])\_y)
					AddPathLine(Dot(\Point[3])\_x,Dot(\Point[3])\_y)
					ClosePath()
					VectorSourceColor(\Color|FillMode)
					FillPath(#PB_Path_Preserve)
					VectorSourceColor(\Outline)
					StrokePath(LineMode,#PB_Path_RoundCorner)

					If Setting\ShowInformation
						s=Str(i)+" (#"+Str(n)+") "+Str(Dot(\Centre)\_distance)
						s=Str(Distance(\Centre))
						Debug s
						MovePathCursor(Dot(\Centre)\_x-VectorTextWidth(s)/2,Dot(\Centre)\_y-VectorTextHeight(s)/2)
						VectorSourceColor($FF000000)
						DrawVectorText(s)
					EndIf

				EndSelect
			EndWith
		Wend
	EndIf

	If Setting\ShowOutline
		LineMode=Setting\ModeLine+1
		n=0
		While n<CounterObjects
			n+1
			With Object(n)
				Select \type
				Case #ObjectTypeLine
					If \Outline
						MovePathCursor(Dot(\Point[0])\_x,Dot(\Point[0])\_y)
						AddPathLine(Dot(\Point[1])\_x,Dot(\Point[1])\_y)
						VectorSourceColor(\Outline)
						StrokePath(LineMode,#PB_Path_RoundEnd)
					EndIf
				EndSelect
			EndWith
		Wend
	EndIf

	If Setting\ShowPoints
		x=120
		y=20+Setting\ShowInformation*60
		z=1

		n=0
		While n<CounterPoints
			n+1
			VectorSourceColor($FF000000+$A0<<(8*n%3))

			With Object(n)
				AddPathCircle(Dot(n)\_x,Dot(n)\_y,3)
				FillPath()
				MovePathCursor(Dot(n)\_x,Dot(n)\_y)
				AddPathLine(x,y)
				StrokePath(1)
				s=StrF(Dot(n)\_distance,2)
				MovePathCursor(x-z*VectorTextWidth(s),y-VectorTextHeight(s)/2)
				DrawVectorText(s)
				y+18
				If y>#WY-30
					x=#WX-100
					y=20
					z=0
				EndIf
			EndWith
		Wend
	EndIf

	StopVectorDrawing()

EndProcedure
Procedure Recalc(mode)

	Protected i
	Protected maxdist.q

	Multiply(@Camera,@Matrix,@Calc)
	DebugMat

	RealZoomFactor=Setting\ZoomFactor * #ZoomScale

	For i=1 To CounterPoints
		With Dot(i)
			ViewX = \x*calc\x[0] + \y*calc\x[1] + \z*calc\x[2] + calc\x[3]
			ViewY = \x*calc\y[0] + \y*calc\y[1] + \z*calc\y[2] + calc\y[3]
			ViewZ = \x*calc\z[0] + \y*calc\z[1] + \z*calc\z[2] + calc\z[3]

			Scale=OptCamera/ViewZ
			\_x=ViewX*Scale*RealZoomFactor+OffsetX
			\_y=ViewY*Scale*RealZoomFactor+OffsetY
			\_distance=Scale*10000000
			;\_distance=Int(Scale*10000000)*10000-(Abs(\_x-OffsetX)+Abs(\_y-OffsetY))/100
			;\_rb=(Opt3DDistance+OptZoomFactor)/(ViewZ+32)
		EndWith
	Next i

	For i=1 To CounterObjects
		With Sorter(i)
			\Object=i
			If Setting\ModeCalculation
				If 0
					maxdist=#Null
					If maxdist < Dot(Object(i)\Point[0])\_distance
						maxdist=Dot(Object(i)\Point[0])\_distance
					EndIf
					If maxdist < Dot(Object(i)\Point[1])\_distance
						maxdist=Dot(Object(i)\Point[1])\_distance
					EndIf
					If maxdist < Dot(Object(i)\Point[2])\_distance
						maxdist=Dot(Object(i)\Point[2])\_distance
					EndIf
					If maxdist < Dot(Object(i)\Point[3])\_distance
						maxdist=Dot(Object(i)\Point[3])\_distance
					EndIf
					\Distance=maxdist
				Else
					maxdist=Dot(Object(i)\Point[0])\_distance
					If maxdist > Dot(Object(i)\Point[1])\_distance
						maxdist=Dot(Object(i)\Point[1])\_distance
					EndIf
					If maxdist > Dot(Object(i)\Point[2])\_distance
						maxdist=Dot(Object(i)\Point[2])\_distance
					EndIf
					If maxdist > Dot(Object(i)\Point[3])\_distance
						maxdist=Dot(Object(i)\Point[3])\_distance
					EndIf
					\Distance=maxdist
				EndIf
			Else
				\Distance=Dot(Object(i)\Centre)\_distance;			Distanz Mittelpunkt
				;\Distance=Distance(Object(i)\Centre)
			EndIf
		EndWith
	Next i
	SortStructuredArray(Sorter(),#PB_Sort_Ascending,OffsetOf(SorterType\Distance),TypeOf(SorterType\Distance),1,CounterObjects)

	If mode
		Redraw()
	EndIf

EndProcedure
Procedure Rotation()

	SetRotX(@RotXMat,AngleY)
	SetRotZ(@RotYMat,AngleX)
	SetRotY(@RotZMat,AngleZ)

	Multiply(@RotXMat,@RotYMat,@Matrix)
	Multiply(@Matrix,@RotZMat,@Matrix)

	Recalc(#True)

EndProcedure

Procedure DoObjects(demo)

	Select demo

	Case 0
		CreateBox(0,0,0, 100,100,100,$E0f0a060,$80000000)
		CreateBox(200,0,0, 100,100,100,$E0f060a0,$80000000)
		CreateBox(0,200,0, 100,100,100,$E0c0a0f0,$80000000)
		CreateBox(0,0,200, 100,100,100,$E0c0f0a0,$80000000)

	Case 1
		CreateBox(0,0,0, 100,100,100,$E0f0a060,$80000000)
		;CreateBox(120,0,0, 80,100,80,$E0f060a0,$80000000)
		;CreateBox(0,0,120, 60,100,60,$E0c0a0f0,$80000000)
		;CreateBox(120,0,120, 40,100,40,$E0c0f0a0,$80000000)
		CreateBox(0,0,105, 10,100,10,$10a0f060,$80000000)
		;CreateBox(105,0,105, 10,100,10,$10a0f060,$80000000)
	
	EndSelect

EndProcedure
Procedure Main()

	LoadFont(0,"Segoe UI",8)

	OpenWindow(#Win,8,8,#WX,#WY,"Cursor-Keys, Zoom +/-     Options: O=Outline S=Surfaces, L=Lines, D=Dots     Modes: F=Fill, R=Rotation, C=Depth     Other: P=Perspective, I=Debugging")
	CanvasGadget(#Canvas,0,0,#WX,#WY)

	AddKeyboardShortcut(#Win,#PB_Shortcut_Left|#PB_Shortcut_Shift,#ShiftLeft)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Right|#PB_Shortcut_Shift,#ShiftRight)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Up|#PB_Shortcut_Shift,#ShiftUp)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Down|#PB_Shortcut_Shift,#ShiftDown)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Left,#RotateLeft)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Right,#RotateRight)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Up,#RotateUp)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Down,#RotateDown)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Back,#ResetView)
	AddKeyboardShortcut(#Win,#PB_Shortcut_C,#ToggleCalcMode)
	AddKeyboardShortcut(#Win,#PB_Shortcut_D,#TogglePoints)
	AddKeyboardShortcut(#Win,#PB_Shortcut_F,#ToggleFill)
	AddKeyboardShortcut(#Win,#PB_Shortcut_I,#ToggleInformation)
	AddKeyboardShortcut(#Win,#PB_Shortcut_L,#ToggleLine)
	AddKeyboardShortcut(#Win,#PB_Shortcut_O,#ToggleOutline)
	AddKeyboardShortcut(#Win,#PB_Shortcut_P,#PerspectivePlus)
	AddKeyboardShortcut(#Win,#PB_Shortcut_P|#PB_Shortcut_Shift,#PerspectiveMinus)
	AddKeyboardShortcut(#Win,#PB_Shortcut_R,#ToggleRotation)
	AddKeyboardShortcut(#Win,#PB_Shortcut_S,#ToggleSurface)

	; ------------------------------------------------------------------------------------

	DoObjects(1)

	; ------------------------------------------------------------------------------------

	OptCameraX=-100
	OptCameraY=50
	OptCamera=1000
	AngleX=Radian(0)
	AngleY=Radian(-170)
	AngleZ=Radian(20)


	SetCamera(OptCameraX,OptCameraY,OptCamera)
	SetNorm(@Matrix)
	Rotation()

	Repeat
		Select WindowEvent()
		Case #PB_Event_Gadget,#PB_Event_Menu
			Select EventGadget()
			Case #ShiftLeft
				SetCamera(OptCameraX-30,OptCameraY,OptCamera)
				Recalc(#True)
			Case #ShiftRight
				SetCamera(OptCameraX+30,OptCameraY,OptCamera)
				Recalc(#True)
			Case #ShiftUp
				SetCamera(OptCameraX,OptCameraY-30,OptCamera)
				Recalc(#True)
			Case #ShiftDown
				SetCamera(OptCameraX,OptCameraY+30,OptCamera)
				Recalc(#True)
			Case #RotateLeft
				If Setting\ModeRotation
					AngleZ-#PiTeil
					If AngleZ<0 : AngleZ+#ZweiPi : EndIf
				Else
					AngleX-#PiTeil
					If AngleX<0 : AngleX+#ZweiPi : EndIf
				EndIf
				Rotation()
			Case #RotateRight
				If Setting\ModeRotation
					AngleZ+#PiTeil
					If AngleZ>#ZweiPi : AngleZ-#ZweiPi : EndIf
				Else
					AngleX+#PiTeil
					If AngleX>#ZweiPi : AngleX-#ZweiPi : EndIf
				EndIf
				Rotation()
			Case #RotateUp
				AngleY-#PiTeil
				Rotation()
			Case #RotateDown
				AngleY+#PiTeil
				Rotation()
			Case #ToggleOutline
				Setting\ShowOutline!1
				Redraw()
			Case #ToggleSurface
				Setting\ShowSurface!1
				Redraw()
			Case #TogglePoints
				Setting\ShowPoints!1
				Redraw()
			Case #ToggleCalcMode
				Setting\ModeCalculation!1
				Recalc(#True)
			Case #ToggleInformation
				Setting\ShowInformation!1
				Redraw()
			Case #ToggleFill
				Setting\ModeFill!1
				Redraw()
			Case #ToggleLine
				Setting\ModeLine!1
				Redraw()
			Case #ToggleRotation
				Setting\ModeRotation!1
			Case #PerspectivePlus
				If OptCamera>300
					SetCamera(OptCameraX,OptCameraY,OptCamera-50)
					Recalc(#True)
				EndIf
			Case  #PerspectiveMinus
				If OptCamera<3000
					SetCamera(OptCameraX,OptCameraY,OptCamera+50)
					Recalc(#True)
				EndIf
			Case #ResetView
				AngleX=0 : AngleY=0 : AngleZ=0
				ViewX=0  : ViewY=0  : ViewZ=0
				SetCamera(0,0,1000)
				SetNorm(@Matrix)
				Rotation()
				Recalc(#True)
			EndSelect

		Case #PB_Event_CloseWindow
			End

		Case #WM_CHAR
			Select EventwParam()
			Case '+'
				If OptCamera>300
					Setting\ZoomFactor+1
					Recalc(#True)
				EndIf
			Case '-'
				If Setting\ZoomFactor>1 : Setting\ZoomFactor-1 : EndIf
				Recalc(#True)

			EndSelect

		EndSelect
	ForEver

EndProcedure

Main()
End

User avatar
Caronte3D
Addict
Addict
Posts: 1053
Joined: Fri Jan 22, 2016 5:33 pm
Location: Some Universe

Re: Calculating hidden surfaces for 3D objects

Post by Caronte3D »

I haven't seen your example, but often the way to tell which faces are hidden is to check their vertices and find if they are ordered clockwise or counterclockwise.
User avatar
Demivec
Addict
Addict
Posts: 4090
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: Calculating hidden surfaces for 3D objects

Post by Demivec »

Just a side question, why all the extra code in this procedure?

Code: Select all

Procedure Distance(dot)

	With Dot(dot)
		ProcedureReturn Sqr(Pow(ViewX-OptCameraX+\x,2)+Pow(ViewY-OptCameraY+\y,2)+Pow(ViewZ-OptCamera+\z,2))
		ProcedureReturn Sqr(Pow(ViewX-\x,2)+Pow(ViewY-\y,2)+Pow(ViewZ-\z,2))
		ProcedureReturn Sqr(Pow(OptCameraX-\x,2)+Pow(OptCameraY-\y,2)+Pow(OptCamera-\z,2))
	EndWith

EndProcedure
Only the first ProcedureReturn statement will ever be executed.
User avatar
Michael Vogel
Addict
Addict
Posts: 2677
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Calculating hidden surfaces for 3D objects

Post by Michael Vogel »

Caronte3D wrote: Sat Jan 29, 2022 11:22 am I haven't seen your example, but often the way to tell which faces are hidden is to check their vertices and find if they are ordered clockwise or counterclockwise.
Fine, this could sort some surfaces out which don't need to be drawn - anyhow this is not a problem for the moment and will also work with convex objects only. So I'm not sure if I will implement that - even it should be not that difficult.
Will have a look at that, thought of implementing the Painter's algorithm (which may also work for convex objects only) but this seems to be more tricky than expected. :|
Demivec wrote: Sat Jan 29, 2022 12:08 pm Just a side question, why all the extra code in this procedure?
The program is still in a alpha version like testing phase, different distance calculations have been tried to do 'z' ordering for draw the surfaces at the far end first and the nearest surces at last. So you see all my attempts I've used for testing.

The code does work in principal but the closer objects are the more my method fails. Change DoObjects(1) to DoObject(0) and everything works (nearly) perfect.
User avatar
Caronte3D
Addict
Addict
Posts: 1053
Joined: Fri Jan 22, 2016 5:33 pm
Location: Some Universe

Re: Calculating hidden surfaces for 3D objects

Post by Caronte3D »

Michael Vogel wrote: Sat Jan 29, 2022 2:40 pm ...and will also work with convex objects only.
Maybe you can draw first the far away faces, so you can use concave objects :wink:
User avatar
Michael Vogel
Addict
Addict
Posts: 2677
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Calculating hidden surfaces for 3D objects

Post by Michael Vogel »

Caronte3D wrote: Sat Jan 29, 2022 4:09 pmMaybe you can draw first the far away faces, so you can use concave objects :wink:
Implemented to ignore hidden faces (\visibility=..., shortcut 'H' toggle mode) and two simple sorting modes ('C' toggles) are given, but each one works fine in some cases and fail in other situations. Anyhow, interesting stuff :lol:

If anyone wants to play with it, the actual code is below - still think that it doesn't look that bad for technical drawings - as soon the surfaces issue can be sorted out, I'll add more objects (pyramids, prism, etc.)

Code: Select all

; Define

	EnableExplicit

	#WX=1200
	#WY=850

	#ZoomScale=0.05
	#ZweiPi=#PI+#PI
	#PiHalbe=#PI/2
	#PiTeil=#PI/36
	#PiRadiant=#PI/180
	#PiGrad=180/#PI

	#MarkerCiphers=1
	#MarkerLength=4
	#MarkerWidth=45*#PI/180


	#ColorPaper=	$FFFFFFFF
	#ColorFront=	$C0E0E0F0
	#ColorWood=	$E05090B0
	#ColorDistance=$f0004020

	; ------------------------------------------------------------------------------------

	Structure DotType
		x.d;			skaliert
		y.d;			skaliert
		z.d;			skaliert
		_x.i;		2D-Transformation
		_y.i;		2D-Transformation
		;_rb.i;		3D-Punkt-Distanz (rot/blau)
		_distance.q;	Z-Distanz zum Betrachter
		type.i;		zum Debuggen etc.
	EndStructure

	Structure ObjectType
		Type.i;		Punkt, Linie, Oberfläche (3 oder 4 Punkte)
		Point.i[4];	Punktkoordinaten
		Color.i;		Flächenfarbe
		Outline.i;	Linienfarbe
		Centre.i;		Flächenmittelpunkt
		Visible.i;	sichtbares Segment
		Info.s;		Marker
	EndStructure

	Structure SorterType
		Object.i
		Distance.q
	EndStructure

	Structure Mat
		x.d[4]
		y.d[4]
		z.d[4]
		t.d[4]
	EndStructure

	Structure SettingType
		ShowOutline.i
		ShowSurface.i
		ShowPoints.i
		ShowHidden.i
		ShowDebugInformation.i
		ShowInformation.i
		ShowMarker.i
		ModeCalculation.i
		ModeRotation.i
		ModeFill.i
		ModeLine.i
		Optimizer.i
		ZoomFactor.i
		ShowThreeD.i;			3D-Darstellung
		ThreeD_Distance.i;		Punktabstand für 3D-Effekt;					-		-		-
		ThreeD_Left.i;			Farbfilter für das linke Auge (rot)				-		-		-
		ThreeD_Right.i;		...rechtes Auge (grün, blau)					-		-		-
	EndStructure

	; ------------------------------------------------------------------------------------

	Global MaxElements=	25000

	Global.Mat Matrix, Calc, RotXMat, RotYMat, RotZMat, Camera, TempMat
	Global Dim Dot.DotType(MaxElements)
	Global Dim Object.ObjectType(MaxElements)
	Global Dim Sorter.SorterType(MaxElements)

	; Bildschirmgröße für Graphikfenster
	Global ScreenX=GetSystemMetrics_(#SM_CXSCREEN)
	Global ScreenY=GetSystemMetrics_(#SM_CYSCREEN)
	Global Screen_X=ScreenX-1
	Global Screen_Y=ScreenY-1
	Global ScreenZ
	Global OffsetX=ScreenX>>1
	Global OffsetY=ScreenY>>1

	; Skalierung für 3D-Transformation
	Global.d ViewX, ViewY, ViewZ, Scale
	Global.d AngleX, AngleY, AngleZ;		Rotationswinkel (per Maus auswählbar)
	Global.d XdivPi=#PI/OffsetX;			Skalierung, um genau eine Drehung nach 'X' zu erlauben
	Global.d YdivPi=#PI/OffsetY;			Skalierung, um genau eine Drehung nach 'Y' zu erlauben
	Global.d RealZoomFactor;				skalierte Vergrößerung

	Global CounterPoints, CounterObjects
	Global OptCamera; =OptCameraZ
	Global OptCameraX, OptCameraY

	Global Setting.SettingType

	; ------------------------------------------------------------------------------------

	OptCamera=		500

	With Setting
		\ShowInformation=1
		\ShowSurface=	1
		\ShowOutline=	0
		\ShowMarker=	1
		\ZoomFactor=	25
		\ModeRotation=	1
		\ModeFill=	1
		\Optimizer=	1
	EndWith

	; ------------------------------------------------------------------------------------

	Enumeration
		#Win
		#Canvas
		;
		#ShiftLeft
		#ShiftRight
		#ShiftUp
		#ShiftDown
		#RotateLeft
		#RotateRight
		#RotateUp
		#RotateDown
		#PerspectiveMinus
		#PerspectivePlus
		#ZoomMinus
		#ZoomPlus
		#ResetView
		#ToggleRotation
		#ToggleLine
		#ToggleMarker
		#ToggleFill
		#ToggleHidden
		#ToggleCalcMode
		#ToggleOutline
		#ToggleSurface
		#TogglePoints
		#ToggleInformation
		#ToggleDebugInformation
	EndEnumeration

	Enumeration
		#TypeDefaultDot
		#TypeCentreLine
		#TypeCentreTriangle
		#TypeCentreRectangle
	EndEnumeration

	; ------------------------------------------------------------------------------------

	Macro StrM(value)
		RSet(StrD(value,2),8)
	EndMacro
	Macro AddLine(p1,p2,outline)

		CreateObject(#ObjectTypeLine,p1,p2,#Null,#Null,#Null,outline)

	EndMacro
	Macro AddTriangle(p1,p2,p3,color,outline)

		CreateObject(#ObjectTypeTriangle,p1,p2,p3,#Null,color,outline)

	EndMacro
	Macro AddRectangle(p1,p2,p3,p4,color,outline)

		CreateObject(#ObjectTypeRectangle,p1,p2,p3,p4,color,outline)

	EndMacro

; EndDefine

Procedure GetViewDistance(dot)

	With Dot(dot)
		ProcedureReturn Sqr(Pow(ViewX-OptCameraX+\x,2)+Pow(ViewY-OptCameraY+\y,2)+Pow(ViewZ-OptCamera+\z,2))
		ProcedureReturn Sqr(Pow(ViewX-\x,2)+Pow(ViewY-\y,2)+Pow(ViewZ-\z,2))
		ProcedureReturn Sqr(Pow(OptCameraX-\x,2)+Pow(OptCameraY-\y,2)+Pow(OptCamera-\z,2))
	EndWith

EndProcedure
Procedure.d GetLength(a,b)

	ProcedureReturn Sqr(Pow(Dot(a)\x-Dot(b)\x,2)+Pow(Dot(a)\y-Dot(b)\y,2)+Pow(Dot(a)\z-Dot(b)\z,2))

EndProcedure
Procedure.d GetAngle(x1,y1,x2,y2,up=0)

	If x1>x2 And up
		ProcedureReturn ATan2(x1-x2,y1-y2)
	Else
		ProcedureReturn ATan2(x2-x1,y2-y1)
	EndIf

	;ProcedureReturn ATan((y2-y1)/(x2-x1))
	;ProcedureReturn Degree(ATan((y2-y1)/(x2-x1)))

EndProcedure
Procedure SetNorm(*m.mat)
	*m\x[0]=1 : *m\y[0]=0 : *m\z[0]=0 : *m\t[0]=0
	*m\x[1]=0 : *m\y[1]=1 : *m\z[1]=0 : *m\t[1]=0
	*m\x[2]=0 : *m\y[2]=0 : *m\z[2]=1 : *m\t[2]=0
	*m\x[3]=0 : *m\y[3]=0 : *m\z[3]=0 : *m\t[3]=1
EndProcedure
Procedure SetTransformation(*m.mat,x.d,y.d,z.d)
	*m\x[0]=1 : *m\y[0]=0 : *m\z[0]=0 : *m\t[0]=0
	*m\x[1]=0 : *m\y[1]=1 : *m\z[1]=0 : *m\t[1]=0
	*m\x[2]=0 : *m\y[2]=0 : *m\z[2]=1 : *m\t[2]=0
	*m\x[3]=x : *m\y[3]=y : *m\z[3]=z : *m\t[3]=1
EndProcedure
Procedure SetCamera(x,y,z.d)
	OptCameraX=x
	OptCameraY=y
	OptCamera=z
	Camera\x[0]=1 : Camera\y[0]=0 : Camera\z[0]=0 : Camera\t[0]=0
	Camera\x[1]=0 : Camera\y[1]=1 : Camera\z[1]=0 : Camera\t[1]=0
	Camera\x[2]=0 : Camera\y[2]=0 : Camera\z[2]=1 : Camera\t[2]=0
	Camera\x[3]=x : Camera\y[3]=y : Camera\z[3]=z : Camera\t[3]=1
EndProcedure
Procedure SetScale(*m.mat,x.d,y.d,z.d)
	*m\x[0]=x : *m\y[0]=0 : *m\z[0]=0 : *m\t[0]=0
	*m\x[1]=0 : *m\y[1]=y : *m\z[1]=0 : *m\t[1]=0
	*m\x[2]=0 : *m\y[2]=0 : *m\z[2]=z : *m\t[2]=0
	*m\x[3]=0 : *m\y[3]=0 : *m\z[3]=0 : *m\t[3]=1
EndProcedure
Procedure SetRotX(*m.mat,angle.d)
	Protected s.d=Sin(angle)
	Protected c.d=Cos(angle)
	*m\x[0]=1 : *m\y[0]=0 : *m\z[0]=0 : *m\t[0]=0
	*m\x[1]=0 : *m\y[1]=c : *m\z[1]=s : *m\t[1]=0
	*m\x[2]=0 : *m\y[2]=-s : *m\z[2]=c : *m\t[2]=0
	*m\x[3]=0 : *m\y[3]=0 : *m\z[3]=0 : *m\t[3]=1
EndProcedure
Procedure SetRotY(*m.mat,angle.d)
	Protected s.d=Sin(angle)
	Protected c.d=Cos(angle)
	*m\x[0]=c : *m\y[0]=0 : *m\z[0]=s : *m\t[0]=0
	*m\x[1]=0 : *m\y[1]=1 : *m\z[1]=0 : *m\t[1]=0
	*m\x[2]=-s : *m\y[2]=0 : *m\z[2]=c : *m\t[2]=0
	*m\x[3]=0 : *m\y[3]=0 : *m\z[3]=0 : *m\t[3]=1
EndProcedure
Procedure SetRotZ(*m.mat,angle.d)
	Protected s.d=Sin(angle)
	Protected c.d=Cos(angle)
	*m\x[0]=c : *m\y[0]=s : *m\z[0]=0 : *m\t[0]=0
	*m\x[1]=-s : *m\y[1]=c : *m\z[1]=0 : *m\t[1]=0
	*m\x[2]=0 : *m\y[2]=0 : *m\z[2]=1 : *m\t[2]=0
	*m\x[3]=0 : *m\y[3]=0 : *m\z[3]=0 : *m\t[3]=1
EndProcedure
Procedure Multiply(*m.mat,*n.mat,*result.mat)

	TempMat\x[0]=*m\x[0]**n\x[0] + *m\x[1]**n\y[0] + *m\x[2]**n\z[0] + *m\x[3]**n\t[0]
	TempMat\y[0]=*m\y[0]**n\x[0] + *m\y[1]**n\y[0] + *m\y[2]**n\z[0] + *m\y[3]**n\t[0]
	TempMat\z[0]=*m\z[0]**n\x[0] + *m\z[1]**n\y[0] + *m\z[2]**n\z[0] + *m\z[3]**n\t[0]
	TempMat\t[0]=*m\t[0]**n\x[0] + *m\t[1]**n\y[0] + *m\t[2]**n\z[0] + *m\t[3]**n\t[0]

	TempMat\x[1]=*m\x[0]**n\x[1] + *m\x[1]**n\y[1] + *m\x[2]**n\z[1] + *m\x[3]**n\t[1]
	TempMat\y[1]=*m\y[0]**n\x[1] + *m\y[1]**n\y[1] + *m\y[2]**n\z[1] + *m\y[3]**n\t[1]
	TempMat\z[1]=*m\z[0]**n\x[1] + *m\z[1]**n\y[1] + *m\z[2]**n\z[1] + *m\z[3]**n\t[1]
	TempMat\t[1]=*m\t[0]**n\x[1] + *m\t[1]**n\y[1] + *m\t[2]**n\z[1] + *m\t[3]**n\t[1]

	TempMat\x[2]=*m\x[0]**n\x[2] + *m\x[1]**n\y[2] + *m\x[2]**n\z[2] + *m\x[3]**n\t[2]
	TempMat\y[2]=*m\y[0]**n\x[2] + *m\y[1]**n\y[2] + *m\y[2]**n\z[2] + *m\y[3]**n\t[2]
	TempMat\z[2]=*m\z[0]**n\x[2] + *m\z[1]**n\y[2] + *m\z[2]**n\z[2] + *m\z[3]**n\t[2]
	TempMat\t[2]=*m\t[0]**n\x[2] + *m\t[1]**n\y[2] + *m\t[2]**n\z[2] + *m\t[3]**n\t[2]

	TempMat\x[3]=*m\x[0]**n\x[3] + *m\x[1]**n\y[3] + *m\x[2]**n\z[3] + *m\x[3]**n\t[3]
	TempMat\y[3]=*m\y[0]**n\x[3] + *m\y[1]**n\y[3] + *m\y[2]**n\z[3] + *m\y[3]**n\t[3]
	TempMat\z[3]=*m\z[0]**n\x[3] + *m\z[1]**n\y[3] + *m\z[2]**n\z[3] + *m\z[3]**n\t[3]
	TempMat\t[3]=*m\t[0]**n\x[3] + *m\t[1]**n\y[3] + *m\t[2]**n\z[3] + *m\t[3]**n\t[3]

	*result\x[0]=TempMat\x[0]
	*result\x[1]=TempMat\x[1]
	*result\x[2]=TempMat\x[2]
	*result\x[3]=TempMat\x[3]
	*result\y[0]=TempMat\y[0]
	*result\y[1]=TempMat\y[1]
	*result\y[2]=TempMat\y[2]
	*result\y[3]=TempMat\y[3]
	*result\z[0]=TempMat\z[0]
	*result\z[1]=TempMat\z[1]
	*result\z[2]=TempMat\z[2]
	*result\z[3]=TempMat\z[3]
	*result\t[0]=TempMat\t[0]
	*result\t[1]=TempMat\t[1]
	*result\t[2]=TempMat\t[2]
	*result\t[3]=TempMat\t[3]

EndProcedure
Procedure ShowMat(*m.mat,title.s="")

	Debug "- "+title+RSet(" ",38-Len(title),"-")
	Debug "X"+StrM(*m\x[0])+" |"+StrM(*m\x[1])+" |"+StrM(*m\x[2])+" |"+StrM(*m\x[3])
	Debug "Y"+StrM(*m\y[0])+" |"+StrM(*m\y[1])+" |"+StrM(*m\y[2])+" |"+StrM(*m\y[3])
	Debug "Z"+StrM(*m\z[0])+" |"+StrM(*m\z[1])+" |"+StrM(*m\z[2])+" |"+StrM(*m\z[3])
	Debug "T"+StrM(*m\t[0])+" |"+StrM(*m\t[1])+" |"+StrM(*m\t[2])+" |"+StrM(*m\t[3])

	Macro DebugMat
		ShowMat(@Camera,"Camera")
		ShowMat(@Matrix,"Matrix")
		ShowMat(@Calc,"Calc")
	EndMacro

EndProcedure

Procedure CreatePoint(x.d,y.d,z.d,type=#TypeDefaultDot)

	Protected i

	If Setting\Optimizer; 					Punkt in den gespeicherten Punkten suchen...
		i=CounterPoints
		While i
			With Dot(i)
				If \x=x And \y=y And \z=z
					Break
				EndIf
			EndWith
			i-1
		Wend
	EndIf

	If i=0 And CounterPoints<MaxElements;	neuer Punkt
		CounterPoints+1
		i=CounterPoints
	EndIf

	With Dot(i);						Koordinaten setzen
		\x=x
		\y=y
		\z=z
		\type=type
	EndWith

	ProcedureReturn i

EndProcedure
Procedure CreateObject(type,a,b,c,d,color,outline=#Null)

	Enumeration
		#ObjectTypeDot
		#ObjectTypeLine
		#ObjectTypeMarker
		#ObjectTypeTriangle
		#ObjectTypeRectangle
	EndEnumeration

	If CounterObjects<MaxElements
		CounterObjects+1

		With Object(CounterObjects)
			\Type=type
			\Point[0]=a
			\Point[1]=b
			\Point[2]=c
			\Point[3]=d
			\Color=color
			\Outline=outline
			Select type
			Case #ObjectTypeLine
				\Centre=CreatePoint((Dot(a)\x+Dot(b)\x)/2,(Dot(a)\y+Dot(b)\y)/2,(Dot(a)\z+Dot(b)\z)/2,#TypeCentreLine)
			Case #ObjectTypeTriangle
				;;;\Centre=CreatePoint((Dot(a)\x+Dot(b)\x)/2,(Dot(a)\y+Dot(b)\y)/2,(Dot(a)\z+Dot(b)\z)/2,#TypeCentreTriangle)
			Case #ObjectTypeRectangle
				Debug "JAU "+Str(CounterPoints)
				\Centre=CreatePoint((Dot(a)\x+Dot(b)\x+Dot(c)\x+Dot(d)\x)/4,(Dot(a)\y+Dot(b)\y+Dot(c)\y+Dot(d)\y)/4,(Dot(a)\z+Dot(b)\z+Dot(c)\z+Dot(d)\z)/4,#TypeCentreRectangle)
			EndSelect
		EndWith

		ProcedureReturn CounterObjects
	EndIf

	ProcedureReturn #Null

EndProcedure
Procedure CreateLine(ax.d,ay.d,az.d, bx.d,by.d,bz.d,color.i)

	Protected o,p1,p2

	p1=CreatePoint(ax,ay,az)
	p2=CreatePoint(bx,by,bz)

	o=AddLine(p1,p2,color)

EndProcedure
Procedure CreateMarker(ax.d,ay.d,az.d, bx.d,by.d,bz.d,color.i)

	Protected o,p1,p2

	p1=CreatePoint(ax,ay,az)
	p2=CreatePoint(bx,by,bz)

	o=AddLine(p1,p2,color)
	If o
		With Object(o)
			\Type=#ObjectTypeMarker
			\Info=StrD(GetLength(p1,p2),#MarkerCiphers);	oder mit *Pow(10,#MarkerCiphers) als Integer speichern)
		EndWith
	EndIf

EndProcedure
Procedure CreateBox(ax.d,ay.d,az.d, bx.d,by.d,bz.d,color.i,outline.i=#Null)

	Protected p1,p2,p3,p4,p5,p6,p7,p8

	bx+ax
	by+ay
	bz+az

	p1=CreatePoint(ax,ay,az)
	p2=CreatePoint(bx,ay,az)
	p3=CreatePoint(bx,by,az)
	p4=CreatePoint(ax,by,az)

	p5=CreatePoint(ax,ay,bz)
	p6=CreatePoint(bx,ay,bz)
	p7=CreatePoint(bx,by,bz)
	p8=CreatePoint(ax,by,bz)

	; DEBUGGING

	If outline
		AddLine(p1,p2,outline)
		AddLine(p2,p3,outline)
		AddLine(p3,p4,outline)
		AddLine(p4,p1,outline)

		AddLine(p5,p6,outline)
		AddLine(p6,p7,outline)
		AddLine(p7,p8,outline)
		AddLine(p8,p5,outline)

		AddLine(p1,p5,outline)
		AddLine(p2,p6,outline)
		AddLine(p3,p7,outline)
		AddLine(p4,p8,outline)
	EndIf

	AddRectangle(p4,p3,p2,p1,color,outline);	Uhrzeigersinn...
	AddRectangle(p1,p2,p6,p5,color,outline)
	AddRectangle(p2,p3,p7,p6,color,outline)
	AddRectangle(p3,p4,p8,p7,color,outline)
	AddRectangle(p4,p1,p5,p8,color,outline)
	AddRectangle(p5,p6,p7,p8,color,outline)


EndProcedure
Procedure CreatePyramid(ax.d,ay.d,az.d, bx.d,by.d,bz.d, height.d, color.i,outline.i=#Null)

	Protected p1,p2,p3,p4,p5

	bx+ax
	by+ay
	bz+az

	p1=CreatePoint(ax,ay,az)
	p2=CreatePoint(bx,ay,az)
	p3=CreatePoint(bx,by,az)
	p4=CreatePoint(ax,by,az)

	p5=CreatePoint(ax,ay,bz);**** Mittelpunkt verschoben um Höhe

	If outline
		AddLine(p1,p2,outline)
		AddLine(p2,p3,outline)
		AddLine(p3,p4,outline)
		AddLine(p4,p1,outline)

		AddLine(p1,p5,outline)
		AddLine(p2,p5,outline)
		AddLine(p3,p5,outline)
		AddLine(p4,p5,outline)
	EndIf

	AddRectangle(p4,p3,p2,p1,color,outline);	Uhrzeigersinn...

	AddTriangle(p1,p2,p5,color,outline)
	AddTriangle(p2,p3,p5,color,outline)
	AddTriangle(p3,p4,p5,color,outline)
	AddTriangle(p4,p1,p5,color,outline)


EndProcedure
Procedure Redraw()

	Protected.i i,n
	Protected.d x,y,z
	Protected.i x0,y0,x1,y1,x2,y2
	Protected.s s
	Protected.d angle
	Protected.i ObjectsShown, ObjectsHidden

	Protected FillMode
	Protected.d LineMode

	StartVectorDrawing(CanvasVectorOutput(#Canvas))
	VectorFont(FontID(0))
	;VectorSourceColor($C0FFFFFF)
	VectorSourceColor(#ColorPaper)
	FillVectorOutput()

	FillMode=Setting\ModeFill*$FF000000
	LineMode=Setting\ModeLine+0.8


	If Setting\ShowSurface
		While i<CounterObjects
			i+1
			n=Sorter(i)\Object
			With Object(n)
				Select \type
				Case #ObjectTypeRectangle
					If \Visible Or Setting\ShowHidden
						ObjectsShown+1
						MovePathCursor(Dot(\Point[0])\_x,Dot(\Point[0])\_y)
						AddPathLine(Dot(\Point[1])\_x,Dot(\Point[1])\_y)
						AddPathLine(Dot(\Point[2])\_x,Dot(\Point[2])\_y)
						AddPathLine(Dot(\Point[3])\_x,Dot(\Point[3])\_y)
						ClosePath()
						VectorSourceColor(\Color|FillMode)
						FillPath(#PB_Path_Preserve)
						VectorSourceColor(\Outline)
						StrokePath(LineMode,#PB_Path_RoundCorner)

						If Setting\ShowDebugInformation
							s=Str(i)+"=#"+Str(n)+":"+Str(Dot(\Centre)\_distance)
							;s=Str(Distance(\Centre))
							MovePathCursor(Dot(\Centre)\_x-VectorTextWidth(s)/2,Dot(\Centre)\_y-VectorTextHeight(s)/2)
							VectorSourceColor($FF000000)
							DrawVectorText(s)
						EndIf
					Else
						ObjectsHidden+1
					EndIf

				Case #ObjectTypeMarker
					If Setting\ShowMarker
						VectorSourceColor(\Outline)
						x1=Dot(\Point[0])\_x
						y1=Dot(\Point[0])\_y
						x2=Dot(\Point[1])\_x
						y2=Dot(\Point[1])\_y
						x0=Dot(\Centre)\_x
						y0=Dot(\Centre)\_y

						angle=GetAngle(x1,y1,x2,y2,#Null)
						MovePathCursor(x1,y1)
						AddPathLine(x2,y2)
						StrokePath(LineMode,#PB_Path_RoundCorner)

						MovePathCursor(x1,y1)
						angle+#MarkerWidth
						AddPathLine(x1+Cos(angle)*#MarkerLength,y1+Sin(angle)*#MarkerLength)
						angle-#MarkerWidth*2
						AddPathLine(x1+Cos(angle)*#MarkerLength,y1+Sin(angle)*#MarkerLength)
						angle+#MarkerWidth
						AddPathLine(x1,y1)
						StrokePath(1,#PB_Path_RoundCorner|#PB_Path_Preserve)
						FillPath()

						MovePathCursor(x2,y2)
						angle+#MarkerWidth
						AddPathLine(x2-Cos(angle)*#MarkerLength,y2-Sin(angle)*#MarkerLength)
						angle-#MarkerWidth*2
						AddPathLine(x2-Cos(angle)*#MarkerLength,y2-Sin(angle)*#MarkerLength)
						angle+#MarkerWidth
						AddPathLine(x2,y2)
						StrokePath(1,#PB_Path_RoundCorner|#PB_Path_Preserve)
						FillPath()

						angle=Degree(GetAngle(x1,y1,x2,y2,#True))
						RotateCoordinates(x0,y0,angle)
						MovePathCursor(x0-VectorTextWidth(\Info)/2,y0-VectorTextHeight(\Info)/2)
						AddPathText(\Info)
						VectorSourceColor(#ColorPaper)
						StrokePath(5,#PB_Path_RoundCorner|#PB_Path_Preserve)
						VectorSourceColor(\Outline)
						FillPath()
						RotateCoordinates(x0,y0,-angle)
					EndIf

				EndSelect
			EndWith
		Wend
	EndIf

	If Setting\ShowOutline
		LineMode=Setting\ModeLine+1
		n=0
		While n<CounterObjects
			n+1
			With Object(n)
				Select \type
				Case #ObjectTypeLine
					If \Outline
						MovePathCursor(Dot(\Point[0])\_x,Dot(\Point[0])\_y)
						AddPathLine(Dot(\Point[1])\_x,Dot(\Point[1])\_y)
						VectorSourceColor(\Outline)
						StrokePath(LineMode,#PB_Path_RoundEnd)
					EndIf
				EndSelect
			EndWith
		Wend
	EndIf

	If Setting\ShowPoints
		x=120
		y=20+Setting\ShowInformation*60
		z=1
		i=0

		n=0
		While n<CounterPoints
			n+1

			With Dot(n)
				If \Type=#TypeCentreRectangle Or Setting\ShowDebugInformation=#Null
					i+1
					VectorSourceColor($FF000000+$A0<<(8*i%3))
					AddPathCircle(Dot(n)\_x,Dot(n)\_y,3)
					FillPath()
					MovePathCursor(Dot(n)\_x,Dot(n)\_y)
					AddPathLine(x,y)
					StrokePath(1)
					s=Str(n)+": "+StrF(Dot(n)\_distance,2)
					MovePathCursor(x-z*VectorTextWidth(s),y-VectorTextHeight(s)/2)
					DrawVectorText(s)
					y+14
					If y>#WY-30
						x=#WX-100
						y=20
						z=0
					EndIf
				EndIf
			EndWith
		Wend
	EndIf


	If Setting\ShowInformation
		VectorSourceColor($FF000080)
		MovePathCursor(20,20)
		DrawVectorText("Viewpoint: "+Str(ViewX)+" | "+Str(ViewY)+" | "+Str(ViewZ))
		MovePathCursor(20,35)
		DrawVectorText("Camera: "+Str(OptCameraX)+" | "+Str(OptCameraY)+" | "+Str(OptCamera))
		MovePathCursor(20,50)
		DrawVectorText("Objects: "+Str(ObjectsShown)+" shown, "+Str(ObjectsHidden)+" hidden")
	EndIf


	StopVectorDrawing()

EndProcedure
Procedure Recalc(mode)

	Protected i
	Protected maxdist.q

	Multiply(@Camera,@Matrix,@Calc)
	DebugMat

	RealZoomFactor=Setting\ZoomFactor * #ZoomScale

	For i=1 To CounterPoints
		With Dot(i)
			ViewX = \x*calc\x[0] + \y*calc\x[1] + \z*calc\x[2] + calc\x[3]
			ViewY = \x*calc\y[0] + \y*calc\y[1] + \z*calc\y[2] + calc\y[3]
			ViewZ = \x*calc\z[0] + \y*calc\z[1] + \z*calc\z[2] + calc\z[3]

			Scale=OptCamera/ViewZ
			\_x=ViewX*Scale*RealZoomFactor+OffsetX
			\_y=ViewY*Scale*RealZoomFactor+OffsetY
			\_distance=Scale*100000;00
			;\_distance=Int(Scale*10000000)*10000-(Abs(\_x-OffsetX)+Abs(\_y-OffsetY))/100
			;\_rb=(Opt3DDistance+OptZoomFactor)/(ViewZ+32)
		EndWith
	Next i

	For i=1 To CounterObjects
		With Sorter(i)
			\Object=i
			If Setting\ModeCalculation
				maxdist=Dot(Object(i)\Point[0])\_distance
				If maxdist > Dot(Object(i)\Point[1])\_distance
					maxdist=Dot(Object(i)\Point[1])\_distance
				EndIf
				If maxdist > Dot(Object(i)\Point[2])\_distance
					maxdist=Dot(Object(i)\Point[2])\_distance
				EndIf
				If maxdist > Dot(Object(i)\Point[3])\_distance
					maxdist=Dot(Object(i)\Point[3])\_distance
				EndIf
				\Distance=maxdist
			Else
				\Distance=Dot(Object(i)\Centre)\_distance;			Distanz Mittelpunkt
				;\Distance=Distance(Object(i)\Centre)
			EndIf
		EndWith

		With Object(i)
			Select \Type
			Case #ObjectTypeRectangle
				\Visible=Bool((Dot(\Point[3])\_x-Dot(\Point[0])\_x)*(Dot(\Point[1])\_y-Dot(\Point[0])\_y)-(Dot(\Point[3])\_y-Dot(\Point[0])\_y)*(Dot(\Point[1])\_x-Dot(\Point[0])\_x)>0)
			Case #ObjectTypeTriangle
			Default
				\Visible=#True
			EndSelect

		EndWith

	Next i
	SortStructuredArray(Sorter(),#PB_Sort_Ascending,OffsetOf(SorterType\Distance),TypeOf(SorterType\Distance),1,CounterObjects)

	If mode
		Redraw()
	EndIf

EndProcedure
Procedure Rotation()

	SetRotX(@RotXMat,AngleY)
	SetRotZ(@RotYMat,AngleX)
	SetRotY(@RotZMat,AngleZ)

	Multiply(@RotXMat,@RotYMat,@Matrix)
	Multiply(@Matrix,@RotZMat,@Matrix)

	Recalc(#True)

EndProcedure

Procedure DoObjects(demo)

	Select demo

	Case 0
		CreateBox(0,0,0, 100,100,100,$E0f0a060,$80000000)
		CreateBox(200,0,0, 100,100,100,$E0f060a0,$80000000)
		CreateBox(0,200,0, 100,100,100,$E0c0a0f0,$80000000)
		CreateBox(0,0,200, 100,100,100,$E0c0f0a0,$80000000)

	Case 1
		CreateBox(0,0,0, 100,100,100,$E0f0a060,$80000000)
		;CreateBox(120,0,0, 80,100,80,$E0f060a0,$80000000)
		;CreateBox(0,0,120, 60,100,60,$E0c0a0f0,$80000000)
		;CreateBox(120,0,120, 40,100,40,$E0c0f0a0,$80000000)
		CreateBox(0,0,105, 10,100,10,$80a0f060,$80000000)
		CreateBox(-15,0,90, 10,100,10,$80f060a0,$80000000)
		;CreateBox(105,0,105, 10,100,10,$10a0f060,$80000000)
		CreateMarker(0,0,130, 100,0,130, $FFFF0000)
	EndSelect

EndProcedure
Procedure Main()

	LoadFont(0,"Segoe UI",8)

	OpenWindow(#Win,8,8,#WX,#WY,"Cursor-Keys, Zoom +/-     Options: O=Outline S=Surfaces, L=Lines     Modes: H=Hide, F=Fill, R=Rotation, C=Depth     Other: P=Perspective, D,I,J=Debugging")
	CanvasGadget(#Canvas,0,0,#WX,#WY)

	AddKeyboardShortcut(#Win,#PB_Shortcut_Left|#PB_Shortcut_Shift,#ShiftLeft)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Right|#PB_Shortcut_Shift,#ShiftRight)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Up|#PB_Shortcut_Shift,#ShiftUp)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Down|#PB_Shortcut_Shift,#ShiftDown)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Left,#RotateLeft)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Right,#RotateRight)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Up,#RotateUp)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Down,#RotateDown)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Back,#ResetView)
	AddKeyboardShortcut(#Win,#PB_Shortcut_C,#ToggleCalcMode)
	AddKeyboardShortcut(#Win,#PB_Shortcut_D,#TogglePoints)
	AddKeyboardShortcut(#Win,#PB_Shortcut_F,#ToggleFill)
	AddKeyboardShortcut(#Win,#PB_Shortcut_H,#ToggleHidden)
	AddKeyboardShortcut(#Win,#PB_Shortcut_I,#ToggleInformation)
	AddKeyboardShortcut(#Win,#PB_Shortcut_J,#ToggleDebugInformation)
	AddKeyboardShortcut(#Win,#PB_Shortcut_L,#ToggleLine)
	AddKeyboardShortcut(#Win,#PB_Shortcut_M,#ToggleMarker)
	AddKeyboardShortcut(#Win,#PB_Shortcut_O,#ToggleOutline)
	AddKeyboardShortcut(#Win,#PB_Shortcut_P,#PerspectivePlus)
	AddKeyboardShortcut(#Win,#PB_Shortcut_P|#PB_Shortcut_Shift,#PerspectiveMinus)
	AddKeyboardShortcut(#Win,#PB_Shortcut_R,#ToggleRotation)
	AddKeyboardShortcut(#Win,#PB_Shortcut_S,#ToggleSurface)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Z,#ZoomPlus)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Z|#PB_Shortcut_Shift,#ZoomMinus)

	; ------------------------------------------------------------------------------------

	DoObjects(1)

	; ------------------------------------------------------------------------------------

	OptCameraX=-100
	OptCameraY=50
	OptCamera=1000
	AngleX=Radian(0)
	AngleY=Radian(-170)
	AngleZ=Radian(20)


	SetCamera(OptCameraX,OptCameraY,OptCamera)
	SetNorm(@Matrix)
	Rotation()

	Repeat
		Select WindowEvent()
		Case #PB_Event_Gadget,#PB_Event_Menu
			Select EventGadget()
			Case #ShiftLeft
				SetCamera(OptCameraX-30,OptCameraY,OptCamera)
				Recalc(#True)
			Case #ShiftRight
				SetCamera(OptCameraX+30,OptCameraY,OptCamera)
				Recalc(#True)
			Case #ShiftUp
				SetCamera(OptCameraX,OptCameraY-30,OptCamera)
				Recalc(#True)
			Case #ShiftDown
				SetCamera(OptCameraX,OptCameraY+30,OptCamera)
				Recalc(#True)
			Case #RotateLeft
				If Setting\ModeRotation
					AngleZ-#PiTeil
					If AngleZ<0 : AngleZ+#ZweiPi : EndIf
				Else
					AngleX-#PiTeil
					If AngleX<0 : AngleX+#ZweiPi : EndIf
				EndIf
				Rotation()
			Case #RotateRight
				If Setting\ModeRotation
					AngleZ+#PiTeil
					If AngleZ>#ZweiPi : AngleZ-#ZweiPi : EndIf
				Else
					AngleX+#PiTeil
					If AngleX>#ZweiPi : AngleX-#ZweiPi : EndIf
				EndIf
				Rotation()
			Case #RotateUp
				AngleY-#PiTeil
				Rotation()
			Case #RotateDown
				AngleY+#PiTeil
				Rotation()
			Case #ToggleOutline
				Setting\ShowOutline!1
				Redraw()
			Case #ToggleSurface
				Setting\ShowSurface!1
				Redraw()
			Case #TogglePoints
				Setting\ShowPoints!1
				Redraw()
			Case #ToggleHidden
				Setting\ShowHidden!1
				Redraw()
			Case #ToggleCalcMode
				Setting\ModeCalculation!1
				Recalc(#True)
			Case #ToggleInformation
				Setting\ShowInformation!1
				Redraw()
			Case #ToggleDebugInformation
				Setting\ShowDebugInformation!1
				Redraw()
			Case #ToggleFill
				Setting\ModeFill!1
				Redraw()
			Case #ToggleLine
				Setting\ModeLine!1
				Redraw()
			Case #ToggleMarker
				Setting\ShowMarker!1
				Redraw()
			Case #ToggleRotation
				Setting\ModeRotation!1
			Case #PerspectivePlus
				If OptCamera>300
					SetCamera(OptCameraX,OptCameraY,OptCamera-50)
					Recalc(#True)
				EndIf
			Case  #PerspectiveMinus
				If OptCamera<3000
					SetCamera(OptCameraX,OptCameraY,OptCamera+50)
					Recalc(#True)
				EndIf
			Case #ResetView
				AngleX=0 : AngleY=0 : AngleZ=0
				ViewX=0  : ViewY=0  : ViewZ=0
				SetCamera(0,0,1000)
				SetNorm(@Matrix)
				Rotation()
				Recalc(#True)
			Case #ZoomPlus
				If OptCamera>300
					Setting\ZoomFactor+1
					Recalc(#True)
				EndIf
			Case #ZoomMinus
				If Setting\ZoomFactor>1
					Setting\ZoomFactor-1
					Recalc(#True)
				EndIf

			EndSelect

		Case #PB_Event_CloseWindow
			End

		Case #WM_CHAR
			Select EventwParam()
			Case '+'
				If OptCamera>300
					Setting\ZoomFactor+1
					Recalc(#True)
				EndIf
			Case '-'
				If Setting\ZoomFactor>1
					Setting\ZoomFactor-1
					Recalc(#True)
				EndIf
			EndSelect

		EndSelect
	ForEver

EndProcedure

Main()
End

User avatar
Michael Vogel
Addict
Addict
Posts: 2677
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Calculating hidden surfaces for 3D objects

Post by Michael Vogel »

Short update - I've implemented the detection of overlaying objects (GetIntersections), the results are displayed after pressing the shortcuts 'J' and 'B'. Next step was resorting, so objects with larger distances in the overlapping area are going to the back (MoveBehind). To see the improvements, you can press 'C' to change the calculation mode.

The result is better now, but still far from perfect (press cursor right after starting the program and you'll see some issues already, more errors are seen when switching DoObjects for showing the second demo).

Code: Select all

; Define

	EnableExplicit

	#WX=1200
	#WY=850

	#ZoomScale=0.05
	#ZweiPi=#PI+#PI
	#PiHalbe=#PI/2
	#PiTeil=#PI/36
	#PiRadiant=#PI/180
	#PiGrad=180/#PI

	#MarkerCiphers=1
	#MarkerLength=4
	#MarkerWidth=45*#PI/180


	#ColorPaper=	$FFFFFFFF
	#ColorFront=		$C0E0E0F0
	#ColorWood=	$E05090B0
	#ColorDistance=	$f0004020

	#MinCoordinate=-9999999
	#MaxCoordinate= 9999999

	#Debug=1

	; ------------------------------------------------------------------------------------

	Structure MaximaType
		Min.i
		Max.i
	EndStructure

	Structure DotType
		x.d;			skaliert
		y.d;			skaliert
		z.d;			skaliert
		_x.i;		2D-Transformation
		_y.i;		2D-Transformation
		;_rb.i;		3D-Punkt-Distanz (rot/blau)
		_distance.q;	Z-Distanz zum Betrachter
		type.i;		zum Debuggen etc.
	EndStructure

	Structure ObjectType
		Type.i;		Punkt, Linie, Oberfläche (3 oder 4 Punkte)
		Point.i[4];	Punktkoordinaten
		MaximaX.MaximaType
		MaximaY.MaximaType
		MaximaZ.MaximaType
		Color.i;		Flächenfarbe
		Outline.i;	Linienfarbe
		Centre.i;		Flächenmittelpunkt
		Visible.i;	sichtbares Segment
		Info.s;		Marker
	EndStructure

	Structure SorterType
		Object.i
		Distance.q
		Reverse.i
	EndStructure

	Structure Mat
		x.d[4]
		y.d[4]
		z.d[4]
		t.d[4]
	EndStructure

	Structure IntersectionType
		ObjectA.i
		ObjectB.i
		; Mittelpunkt der Schnittfläche
		x.i
		y.i
		; Eckpunkte der Schnittfläche
		CompilerIf #Debug
			x1.i
			y1.i
			x2.i
			y2.i
		CompilerEndIf
		; Reihenfolge
		AoverB.i
	EndStructure


	Structure SettingType
		ShowOutline.i
		ShowSurface.i
		ShowPoints.i
		ShowHidden.i
		ShowInformation.i
		ShowDebugInformation.i
		ShowObjectInformation.i
		ShowMarker.i
		ModeCalculation.i
		ModeRotation.i
		ModeFill.i
		ModeLine.i
		Optimizer.i
		ZoomFactor.i
		ShowThreeD.i;			3D-Darstellung
		ThreeD_Distance.i;		Punktabstand für 3D-Effekt;					-		-		-
		ThreeD_Left.i;			Farbfilter für das linke Auge (rot)				-		-		-
		ThreeD_Right.i;		...rechtes Auge (grün, blau)					-		-		-
	EndStructure

	; ------------------------------------------------------------------------------------

	Global MaxElements=	25000

	Global.Mat Matrix, Calc, RotXMat, RotYMat, RotZMat, Camera, TempMat
	Global Dim Dot.DotType(MaxElements);							Dot(0) wird für den Offset verwendet
	Global Dim Object.ObjectType(MaxElements)
	Global Dim Sorter.SorterType(MaxElements)
	Global Dim Intersection.IntersectionType(MaxElements)

	; Bildschirmgröße für Graphikfenster
	Global ScreenX=GetSystemMetrics_(#SM_CXSCREEN)
	Global ScreenY=GetSystemMetrics_(#SM_CYSCREEN)
	Global Screen_X=ScreenX-1
	Global Screen_Y=ScreenY-1
	Global ScreenZ
	Global OffsetX=ScreenX>>1
	Global OffsetY=ScreenY>>1

	; Skalierung für 3D-Transformation
	Global.d ViewX, ViewY, ViewZ, Scale
	Global.d AngleX, AngleY, AngleZ;		Rotationswinkel (per Maus auswählbar)
	Global.d XdivPi=#PI/OffsetX;			Skalierung, um genau eine Drehung nach 'X' zu erlauben
	Global.d YdivPi=#PI/OffsetY;			Skalierung, um genau eine Drehung nach 'Y' zu erlauben
	Global.d RealZoomFactor;				skalierte Vergrößerung

	Global CounterDots, CounterObjects, CounterIntersections
	Global OptCamera; =OptCameraZ
	Global OptCameraX, OptCameraY

	Global Setting.SettingType

	; ------------------------------------------------------------------------------------

	OptCamera=		500

	With Setting
		\ShowInformation=1
		\ShowSurface=	1
		\ShowOutline=	0
		\ShowMarker=	1
		\ZoomFactor=	25
		\ModeRotation=	1
		\ModeFill=	1
		\Optimizer=	1
	EndWith

	; ------------------------------------------------------------------------------------

	Enumeration
		#Win
		#Canvas
		;
		#MoveLeft
		#MoveRight
		#MoveUp
		#MoveDown
		#ShiftLeft
		#ShiftRight
		#ShiftUp
		#ShiftDown
		#RotateLeft
		#RotateRight
		#RotateUp
		#RotateDown
		#PerspectiveMinus
		#PerspectivePlus
		#ZoomMinus
		#ZoomPlus
		#ResetView
		#CalculationMode
		#ToggleRotation
		#ToggleLine
		#ToggleMarker
		#ToggleFill
		#ToggleHidden
		#ToggleOutline
		#ToggleSurface
		#TogglePoints
		#ToggleInformation
		#ToggleDebugInformation
		#ToggleObjectInformation
	EndEnumeration

	Enumeration
		#DotTypeDefault
		#DotTypeCentreLine
		#DotTypeCentreTriangle
		#DotTypeCentreRectangle
	EndEnumeration

	Enumeration
		#ObjectTypeDot
		#ObjectTypeLine
		#ObjectTypeMarker
		#ObjectTypeTriangle
		#ObjectTypeRectangle
	EndEnumeration

	Enumeration
		#CalculationModeIntersection
		#CalculationModeCenter
		#CalculationModeFirstPoint
		#CalculationModeLastPoint
	EndEnumeration


	Global Dim ObjectDots(#ObjectTypeRectangle)

	ObjectDots(#ObjectTypeDot)=1
	ObjectDots(#ObjectTypeLine)=2
	ObjectDots(#ObjectTypeMarker)=2
	ObjectDots(#ObjectTypeTriangle)=3
	ObjectDots(#ObjectTypeRectangle)=4


	; ------------------------------------------------------------------------------------

	Macro StrM(value)
		RSet(StrD(value,2),8)
	EndMacro
	Macro AddLine(p1,p2,outline)

		CreateObject(#ObjectTypeLine,p1,p2,#Null,#Null,#Null,outline)

	EndMacro
	Macro AddTriangle(p1,p2,p3,color,outline)

		CreateObject(#ObjectTypeTriangle,p1,p2,p3,#Null,color,outline)

	EndMacro
	Macro AddRectangle(p1,p2,p3,p4,color,outline)

		CreateObject(#ObjectTypeRectangle,p1,p2,p3,p4,color,outline)

	EndMacro
	Macro AddPathRectangle(x1,y1,x2,y2)
		AddPathBox(x1,y1,(x2)-(x1),(y2)-(y1))
	EndMacro

	; ------------------------------------------------------------------------------------

	Procedure.i Max(a,b)
		If a>b
			ProcedureReturn a
		Else
			ProcedureReturn b
		EndIf
	EndProcedure
	Procedure.i Min(a,b)
		If a<b
			ProcedureReturn a
		Else
			ProcedureReturn b
		EndIf
	EndProcedure
	Procedure.s IfStr(bool,yes.s,no.s)
		If bool
			ProcedureReturn yes
		Else
			ProcedureReturn no
		EndIf
	EndProcedure

	; ------------------------------------------------------------------------------------


; EndDefine

Procedure.s GetObjectType(type)

	ProcedureReturn StringField("Dot.Line.Marker.Triangle.Rectangle.-.-.-.-",type+1,".")

EndProcedure
Procedure.s GetObjectInfo(object,verbose=#Null)

	Protected.i i
	Protected.s s

	With Object(object)
		For i=0 To 3
			s+", "+Str(\Point[i])
		Next i
		s=GetObjectType(\Type)+" object.  Dots: "+Mid(s,3)

		If verbose
			s="#"+Str(object)+": "+s
		EndIf
	EndWith

	;s=s+#CR$+"*"

	ProcedureReturn s

EndProcedure
Procedure GetViewDistance(dot)

	With Dot(dot)
		ProcedureReturn Sqr(Pow(ViewX-OptCameraX+\x,2)+Pow(ViewY-OptCameraY+\y,2)+Pow(ViewZ-OptCamera+\z,2))
		ProcedureReturn Sqr(Pow(ViewX-\x,2)+Pow(ViewY-\y,2)+Pow(ViewZ-\z,2))
		ProcedureReturn Sqr(Pow(OptCameraX-\x,2)+Pow(OptCameraY-\y,2)+Pow(OptCamera-\z,2))
	EndWith

EndProcedure
Procedure.d GetLength(a,b)

	ProcedureReturn Sqr(Pow(Dot(a)\x-Dot(b)\x,2)+Pow(Dot(a)\y-Dot(b)\y,2)+Pow(Dot(a)\z-Dot(b)\z,2))

EndProcedure
Procedure GetMedianDistance(x,y,object)

	Protected i,dots
	Protected.d a,b,total
	Protected.d Dim t(4)

	With Object(object)
		dots=ObjectDots(\Type)-1
		For i=0 To dots
			a=x-Dot(\Point[i])\_x
			b=y-Dot(\Point[i])\_y
			t(i)=Sqr(a*a+b*b)
			total+t(i)
		Next i

		a=0
		For i=0 To dots
			t(i)=total/t(i)
			a+t(i)
		Next i
		;Debug a

		b=0
		For i=0 To dots
			b+Dot(\Point[i])\_distance*t(i)/a
		Next i

	EndWith

	ProcedureReturn b

EndProcedure

Procedure.d GetAngle(x1,y1,x2,y2,up=0)

	If x1>x2 And up
		ProcedureReturn ATan2(x1-x2,y1-y2)
	Else
		ProcedureReturn ATan2(x2-x1,y2-y1)
	EndIf

	;ProcedureReturn ATan((y2-y1)/(x2-x1))
	;ProcedureReturn Degree(ATan((y2-y1)/(x2-x1)))

EndProcedure
Macro SorterCopy(source,destination)
	; Debug "copy "+Str(source)+" to "+Str(destination)
	Sorter(destination)\Distance=Sorter(source)\Distance
	Sorter(destination)\Object=Sorter(source)\Object
	Sorter(destination)\Reverse=Sorter(source)\Reverse
EndMacro
Procedure MoveBehind(oo,up)

	Protected i,poo,pup

	poo=Sorter(oo)\Reverse
	pup=Sorter(up)\Reverse

	If poo<pup
		SorterCopy(poo,0)
		While poo<pup
			SorterCopy(poo+1,poo)
			poo+1
		Wend
		SorterCopy(0,pup)

		For i=1 To CounterObjects
			Sorter(Sorter(i)\Object)\Reverse=i
		Next i
	EndIf

EndProcedure

Procedure.i Intersect(*a.MaximaType,*b.MaximaType)

	If *a\Min >= *b\Max Or *a\Max <= *b\Min
		ProcedureReturn #False
	Else
		ProcedureReturn #True
	EndIf

EndProcedure
Procedure.i CalcMaxima()

	Protected i,j,c,n

	i=0
	While i<CounterObjects
		i+1
		If Object(i)\Visible=#True
			With Object(i)
				;If \Type=#ObjectTypeRectangle
				;Debug GetObjectInfo(i,1)
				\MaximaX\Max=#MinCoordinate
				\MaximaX\Min=#MaxCoordinate
				\MaximaY\Max=#MinCoordinate
				\MaximaY\Min=#MaxCoordinate
				\MaximaZ\Max=#MinCoordinate
				\MaximaZ\Min=#MaxCoordinate

				n=ObjectDots(\Type)
				While n
					n-1
					c=Dot(\Point[n])\_x
					If \MaximaX\Min>c : \MaximaX\Min=c : EndIf
					If \MaximaX\Max<c : \MaximaX\Max=c : EndIf
					c=Dot(\Point[n])\_y
					If \MaximaY\Min>c : \MaximaY\Min=c : EndIf
					If \MaximaY\Max<c : \MaximaY\Max=c : EndIf
					c=Dot(\Point[n])\_distance
					If \MaximaZ\Min>c : \MaximaZ\Min=c : EndIf
					If \MaximaZ\Max<c : \MaximaZ\Max=c : EndIf
				Wend

				;Debug "X: "+\MaximaX\Min+" ... " +\MaximaX\Max
				;Debug "Y: "+\MaximaY\Min+" ... " +\MaximaY\Max
				;Debug "Z: "+\MaximaZ\Min+" ... " +\MaximaZ\Max
				;EndIf
			EndWith
		EndIf

	Wend

EndProcedure
Procedure.i GetIntersections()

	Protected.i i,j,c,n
	Protected.MaximaType mx,my,mz

	CounterIntersections=#Null

	i=0
	While i<CounterObjects
		i+1
		If Object(i)\Visible=#True And Object(i)\Type=#ObjectTypeRectangle
			Debug GetObjectInfo(i,1)
			With Object(i)
				mx\Min=\MaximaX\Min
				mx\Max=\MaximaX\Max
				my\Min=\MaximaY\Min
				my\Max=\MaximaY\Max
				mz\Min=\MaximaZ\Min
				mz\Max=\MaximaZ\Max
			EndWith

			j=i+1
			While j<CounterObjects
				j+1
				If Object(j)\Visible=#True And Object(j)\Type=#ObjectTypeRectangle
					With Object(j)
						If Intersect(\MaximaX,mx)
							If Intersect(\MaximaY,my)
								If Intersect(\MaximaZ,mz)
									CounterIntersections+1
									Intersection(CounterIntersections)\ObjectA=i
									Intersection(CounterIntersections)\ObjectB=j
									Intersection(CounterIntersections)\x=(Max(mx\Min,\MaximaX\Min)+Min(mx\Max,\MaximaX\Max))/2
									Intersection(CounterIntersections)\y=(Max(my\Min,\MaximaY\Min)+Min(my\Max,\MaximaY\Max))/2
									CompilerIf #Debug
										Intersection(CounterIntersections)\x1=Max(mx\Min,\MaximaX\Min)
										Intersection(CounterIntersections)\y1=Max(my\Min,\MaximaY\Min)
										Intersection(CounterIntersections)\x2=Min(mx\Max,\MaximaX\Max)
										Intersection(CounterIntersections)\y2=Min(my\Max,\MaximaY\Max)
									CompilerEndIf
									;Debug GetMedianDistance(Intersection(CounterIntersections)\x,Intersection(CounterIntersections)\y,i)
									;Debug GetMedianDistance(Intersection(CounterIntersections)\x,Intersection(CounterIntersections)\y,j)
									Intersection(CounterIntersections)\AoverB=Bool(GetMedianDistance(Intersection(CounterIntersections)\x,Intersection(CounterIntersections)\y,i) > GetMedianDistance(Intersection(CounterIntersections)\x,Intersection(CounterIntersections)\y,j))
									Debug "> "+Str(j)+IfStr(Intersection(CounterIntersections)\AoverB," ok"," up")+"  X:"+Str(mx\Min)+"-"+Str(mx\Max)+" : "+Str(\MaximaX\Min)+"-"+Str(\MaximaX\Max)+" Y:"+Str(my\Min)+"-"+Str(my\Max)+" : "+Str(\MaximaY\Min)+"-"+Str(\MaximaY\Max)
									If Intersection(CounterIntersections)\AoverB
										MoveBehind(Intersection(CounterIntersections)\ObjectA,Intersection(CounterIntersections)\ObjectB)
									Else
										MoveBehind(Intersection(CounterIntersections)\ObjectB,Intersection(CounterIntersections)\ObjectA)
									EndIf
								EndIf
							EndIf
						EndIf
					EndWith
				EndIf
			Wend
		EndIf
	Wend

EndProcedure
Procedure.d GetObjectRelation(a,b)

	Protected.i i
	Protected.s s

	Debug "Compare "+Str(a)+" + "+Str(b)

	Debug GetObjectInfo(a)
	Debug GetObjectInfo(b)

EndProcedure

Procedure SetNorm(*m.mat)
	*m\x[0]=1 : *m\y[0]=0 : *m\z[0]=0 : *m\t[0]=0
	*m\x[1]=0 : *m\y[1]=1 : *m\z[1]=0 : *m\t[1]=0
	*m\x[2]=0 : *m\y[2]=0 : *m\z[2]=1 : *m\t[2]=0
	*m\x[3]=0 : *m\y[3]=0 : *m\z[3]=0 : *m\t[3]=1
EndProcedure
Procedure SetTransformation(*m.mat,x.d,y.d,z.d)
	*m\x[0]=1 : *m\y[0]=0 : *m\z[0]=0 : *m\t[0]=0
	*m\x[1]=0 : *m\y[1]=1 : *m\z[1]=0 : *m\t[1]=0
	*m\x[2]=0 : *m\y[2]=0 : *m\z[2]=1 : *m\t[2]=0
	*m\x[3]=x : *m\y[3]=y : *m\z[3]=z : *m\t[3]=1
EndProcedure
Procedure SetCamera(x,y,z.d)
	OptCameraX=x
	OptCameraY=y
	OptCamera=z
	Camera\x[0]=1 : Camera\y[0]=0 : Camera\z[0]=0 : Camera\t[0]=0
	Camera\x[1]=0 : Camera\y[1]=1 : Camera\z[1]=0 : Camera\t[1]=0
	Camera\x[2]=0 : Camera\y[2]=0 : Camera\z[2]=1 : Camera\t[2]=0
	Camera\x[3]=x : Camera\y[3]=y : Camera\z[3]=z : Camera\t[3]=1
EndProcedure
Procedure SetScale(*m.mat,x.d,y.d,z.d)
	*m\x[0]=x : *m\y[0]=0 : *m\z[0]=0 : *m\t[0]=0
	*m\x[1]=0 : *m\y[1]=y : *m\z[1]=0 : *m\t[1]=0
	*m\x[2]=0 : *m\y[2]=0 : *m\z[2]=z : *m\t[2]=0
	*m\x[3]=0 : *m\y[3]=0 : *m\z[3]=0 : *m\t[3]=1
EndProcedure
Procedure SetRotX(*m.mat,angle.d)
	Protected s.d=Sin(angle)
	Protected c.d=Cos(angle)
	*m\x[0]=1 : *m\y[0]=0 : *m\z[0]=0 : *m\t[0]=0
	*m\x[1]=0 : *m\y[1]=c : *m\z[1]=s : *m\t[1]=0
	*m\x[2]=0 : *m\y[2]=-s : *m\z[2]=c : *m\t[2]=0
	*m\x[3]=0 : *m\y[3]=0 : *m\z[3]=0 : *m\t[3]=1
EndProcedure
Procedure SetRotY(*m.mat,angle.d)
	Protected s.d=Sin(angle)
	Protected c.d=Cos(angle)
	*m\x[0]=c : *m\y[0]=0 : *m\z[0]=s : *m\t[0]=0
	*m\x[1]=0 : *m\y[1]=1 : *m\z[1]=0 : *m\t[1]=0
	*m\x[2]=-s : *m\y[2]=0 : *m\z[2]=c : *m\t[2]=0
	*m\x[3]=0 : *m\y[3]=0 : *m\z[3]=0 : *m\t[3]=1
EndProcedure
Procedure SetRotZ(*m.mat,angle.d)
	Protected s.d=Sin(angle)
	Protected c.d=Cos(angle)
	*m\x[0]=c : *m\y[0]=s : *m\z[0]=0 : *m\t[0]=0
	*m\x[1]=-s : *m\y[1]=c : *m\z[1]=0 : *m\t[1]=0
	*m\x[2]=0 : *m\y[2]=0 : *m\z[2]=1 : *m\t[2]=0
	*m\x[3]=0 : *m\y[3]=0 : *m\z[3]=0 : *m\t[3]=1
EndProcedure
Procedure Multiply(*m.mat,*n.mat,*result.mat)

	TempMat\x[0]=*m\x[0]**n\x[0] + *m\x[1]**n\y[0] + *m\x[2]**n\z[0] + *m\x[3]**n\t[0]
	TempMat\y[0]=*m\y[0]**n\x[0] + *m\y[1]**n\y[0] + *m\y[2]**n\z[0] + *m\y[3]**n\t[0]
	TempMat\z[0]=*m\z[0]**n\x[0] + *m\z[1]**n\y[0] + *m\z[2]**n\z[0] + *m\z[3]**n\t[0]
	TempMat\t[0]=*m\t[0]**n\x[0] + *m\t[1]**n\y[0] + *m\t[2]**n\z[0] + *m\t[3]**n\t[0]

	TempMat\x[1]=*m\x[0]**n\x[1] + *m\x[1]**n\y[1] + *m\x[2]**n\z[1] + *m\x[3]**n\t[1]
	TempMat\y[1]=*m\y[0]**n\x[1] + *m\y[1]**n\y[1] + *m\y[2]**n\z[1] + *m\y[3]**n\t[1]
	TempMat\z[1]=*m\z[0]**n\x[1] + *m\z[1]**n\y[1] + *m\z[2]**n\z[1] + *m\z[3]**n\t[1]
	TempMat\t[1]=*m\t[0]**n\x[1] + *m\t[1]**n\y[1] + *m\t[2]**n\z[1] + *m\t[3]**n\t[1]

	TempMat\x[2]=*m\x[0]**n\x[2] + *m\x[1]**n\y[2] + *m\x[2]**n\z[2] + *m\x[3]**n\t[2]
	TempMat\y[2]=*m\y[0]**n\x[2] + *m\y[1]**n\y[2] + *m\y[2]**n\z[2] + *m\y[3]**n\t[2]
	TempMat\z[2]=*m\z[0]**n\x[2] + *m\z[1]**n\y[2] + *m\z[2]**n\z[2] + *m\z[3]**n\t[2]
	TempMat\t[2]=*m\t[0]**n\x[2] + *m\t[1]**n\y[2] + *m\t[2]**n\z[2] + *m\t[3]**n\t[2]

	TempMat\x[3]=*m\x[0]**n\x[3] + *m\x[1]**n\y[3] + *m\x[2]**n\z[3] + *m\x[3]**n\t[3]
	TempMat\y[3]=*m\y[0]**n\x[3] + *m\y[1]**n\y[3] + *m\y[2]**n\z[3] + *m\y[3]**n\t[3]
	TempMat\z[3]=*m\z[0]**n\x[3] + *m\z[1]**n\y[3] + *m\z[2]**n\z[3] + *m\z[3]**n\t[3]
	TempMat\t[3]=*m\t[0]**n\x[3] + *m\t[1]**n\y[3] + *m\t[2]**n\z[3] + *m\t[3]**n\t[3]

	*result\x[0]=TempMat\x[0]
	*result\x[1]=TempMat\x[1]
	*result\x[2]=TempMat\x[2]
	*result\x[3]=TempMat\x[3]
	*result\y[0]=TempMat\y[0]
	*result\y[1]=TempMat\y[1]
	*result\y[2]=TempMat\y[2]
	*result\y[3]=TempMat\y[3]
	*result\z[0]=TempMat\z[0]
	*result\z[1]=TempMat\z[1]
	*result\z[2]=TempMat\z[2]
	*result\z[3]=TempMat\z[3]
	*result\t[0]=TempMat\t[0]
	*result\t[1]=TempMat\t[1]
	*result\t[2]=TempMat\t[2]
	*result\t[3]=TempMat\t[3]

EndProcedure
Procedure MoveObjects(x,y)

	Protected i,n

	While i<=CounterDots
		With Dot(i)
			\x+x
			\z+y
		EndWith
		i+1
	Wend

EndProcedure
Procedure ShowMat(*m.mat,title.s="")

	Debug "- "+title+RSet(" ",38-Len(title),"-")
	Debug "X"+StrM(*m\x[0])+" |"+StrM(*m\x[1])+" |"+StrM(*m\x[2])+" |"+StrM(*m\x[3])
	Debug "Y"+StrM(*m\y[0])+" |"+StrM(*m\y[1])+" |"+StrM(*m\y[2])+" |"+StrM(*m\y[3])
	Debug "Z"+StrM(*m\z[0])+" |"+StrM(*m\z[1])+" |"+StrM(*m\z[2])+" |"+StrM(*m\z[3])
	Debug "T"+StrM(*m\t[0])+" |"+StrM(*m\t[1])+" |"+StrM(*m\t[2])+" |"+StrM(*m\t[3])

	Macro DebugMat
		ShowMat(@Camera,"Camera")
		ShowMat(@Matrix,"Matrix")
		ShowMat(@Calc,"Calc")
	EndMacro

EndProcedure
Procedure ShowObjects()

	Protected i
	Protected s.s

	While i<CounterObjects
		i+1
		With Object(i)
			s="#"+RSet(Str(i),2,"0")+" order "+RSet(Str(Sorter(i)\Reverse),2,"0")+" "+GetObjectType(\Type)+": "+IfStr(\Visible,"visible","hidden")
			Debug s
		EndWith
	Wend

EndProcedure

Procedure CreatePoint(x.d,y.d,z.d,type=#DotTypeDefault)

	Protected i

	If Setting\Optimizer; 					Punkt in den gespeicherten Punkten suchen...
		i=CounterDots
		While i
			With Dot(i)
				If \x=x And \y=y And \z=z
					Break
				EndIf
			EndWith
			i-1
		Wend
	EndIf

	If i=0 And CounterDots<MaxElements;	neuer Punkt
		CounterDots+1
		i=CounterDots
	EndIf

	With Dot(i);						Koordinaten setzen
		\x=x
		\y=y
		\z=z
		\type=type
	EndWith

	ProcedureReturn i

EndProcedure
Procedure CreateObject(type,a,b,c,d,color,outline=#Null)

	If CounterObjects<MaxElements
		CounterObjects+1

		With Object(CounterObjects)
			\Type=type
			\Point[0]=a
			\Point[1]=b
			\Point[2]=c
			\Point[3]=d
			\Color=color
			\Outline=outline
			Select type
			Case #ObjectTypeLine,#ObjectTypeMarker
				\Centre=CreatePoint((Dot(a)\x+Dot(b)\x)/2,(Dot(a)\y+Dot(b)\y)/2,(Dot(a)\z+Dot(b)\z)/2,#DotTypeCentreLine)
			Case #ObjectTypeTriangle
				Debug "TRIANGLE"
				;;;\Centre=CreatePoint((Dot(a)\x+Dot(b)\x)/2,(Dot(a)\y+Dot(b)\y)/2,(Dot(a)\z+Dot(b)\z)/2,#TypeCentreTriangle)
			Case #ObjectTypeRectangle
				;Debug "JAU "+Str(CounterPoints)
				\Centre=CreatePoint((Dot(a)\x+Dot(b)\x+Dot(c)\x+Dot(d)\x)/4,(Dot(a)\y+Dot(b)\y+Dot(c)\y+Dot(d)\y)/4,(Dot(a)\z+Dot(b)\z+Dot(c)\z+Dot(d)\z)/4,#DotTypeCentreRectangle)
			Case #ObjectTypeDot
				\Centre=Dot(a)
			EndSelect
		EndWith

		ProcedureReturn CounterObjects
	EndIf

	ProcedureReturn #Null

EndProcedure
Procedure CreateLine(ax.d,ay.d,az.d, bx.d,by.d,bz.d,color.i)

	Protected o,p1,p2

	p1=CreatePoint(ax,ay,az)
	p2=CreatePoint(bx,by,bz)

	o=AddLine(p1,p2,color)

EndProcedure
Procedure CreateMarker(ax.d,ay.d,az.d, bx.d,by.d,bz.d,color.i)

	Protected o,p1,p2

	p1=CreatePoint(ax,ay,az)
	p2=CreatePoint(bx,by,bz)

	o=AddLine(p1,p2,color)
	If o
		With Object(o)
			\Type=#ObjectTypeMarker
			\Info=StrD(GetLength(p1,p2),#MarkerCiphers);	oder mit *Pow(10,#MarkerCiphers) als Integer speichern)
		EndWith
	EndIf

EndProcedure
Procedure CreateBox(ax.d,ay.d,az.d, bx.d,by.d,bz.d,color.i,outline.i=#Null)

	Protected p1,p2,p3,p4,p5,p6,p7,p8

	bx+ax
	by+ay
	bz+az

	p1=CreatePoint(ax,ay,az)
	p2=CreatePoint(bx,ay,az)
	p3=CreatePoint(bx,by,az)
	p4=CreatePoint(ax,by,az)

	p5=CreatePoint(ax,ay,bz)
	p6=CreatePoint(bx,ay,bz)
	p7=CreatePoint(bx,by,bz)
	p8=CreatePoint(ax,by,bz)

	; DEBUGGING

	If outline
		AddLine(p1,p2,outline)
		AddLine(p2,p3,outline)
		AddLine(p3,p4,outline)
		AddLine(p4,p1,outline)

		AddLine(p5,p6,outline)
		AddLine(p6,p7,outline)
		AddLine(p7,p8,outline)
		AddLine(p8,p5,outline)

		AddLine(p1,p5,outline)
		AddLine(p2,p6,outline)
		AddLine(p3,p7,outline)
		AddLine(p4,p8,outline)
	EndIf

	AddRectangle(p4,p3,p2,p1,color,outline);	Uhrzeigersinn...
	AddRectangle(p1,p2,p6,p5,color,outline)
	AddRectangle(p2,p3,p7,p6,color,outline)
	AddRectangle(p3,p4,p8,p7,color,outline)
	AddRectangle(p4,p1,p5,p8,color,outline)
	AddRectangle(p5,p6,p7,p8,color,outline)


EndProcedure
Procedure CreatePyramid(ax.d,ay.d,az.d, bx.d,by.d,bz.d, height.d, color.i,outline.i=#Null)

	Protected p1,p2,p3,p4,p5

	bx+ax
	by+ay
	bz+az

	p1=CreatePoint(ax,ay,az)
	p2=CreatePoint(bx,ay,az)
	p3=CreatePoint(bx,by,az)
	p4=CreatePoint(ax,by,az)

	p5=CreatePoint(ax,ay,bz);**** Mittelpunkt verschoben um Höhe

	If outline
		AddLine(p1,p2,outline)
		AddLine(p2,p3,outline)
		AddLine(p3,p4,outline)
		AddLine(p4,p1,outline)

		AddLine(p1,p5,outline)
		AddLine(p2,p5,outline)
		AddLine(p3,p5,outline)
		AddLine(p4,p5,outline)
	EndIf

	AddRectangle(p4,p3,p2,p1,color,outline);	Uhrzeigersinn...

	AddTriangle(p1,p2,p5,color,outline)
	AddTriangle(p2,p3,p5,color,outline)
	AddTriangle(p3,p4,p5,color,outline)
	AddTriangle(p4,p1,p5,color,outline)


EndProcedure
Procedure Redraw()

	Protected.i i,n
	Protected.d x,y,z
	Protected.i x0,y0,x1,y1,x2,y2
	Protected.s s
	Protected.d angle
	Protected.i ObjectsShown, ObjectsHidden

	Protected FillMode
	Protected.d LineMode

	StartVectorDrawing(CanvasVectorOutput(#Canvas))
	VectorFont(FontID(0))
	;VectorSourceColor($C0FFFFFF)
	VectorSourceColor(#ColorPaper)
	FillVectorOutput()

	FillMode=Setting\ModeFill*$FF000000
	LineMode=Setting\ModeLine+0.8


	; --- Oberflächen ------------------------------------------------------------------------------

	If Setting\ShowSurface
		While i<CounterObjects
			i+1
			n=Sorter(i)\Object
			With Object(n)
				Select \type
				Case #ObjectTypeRectangle
					If \Visible Or Setting\ShowHidden
						ObjectsShown+1
						MovePathCursor(Dot(\Point[0])\_x,Dot(\Point[0])\_y)
						AddPathLine(Dot(\Point[1])\_x,Dot(\Point[1])\_y)
						AddPathLine(Dot(\Point[2])\_x,Dot(\Point[2])\_y)
						AddPathLine(Dot(\Point[3])\_x,Dot(\Point[3])\_y)
						ClosePath()
						VectorSourceColor(\Color|FillMode)
						FillPath(#PB_Path_Preserve)
						VectorSourceColor(\Outline)
						StrokePath(LineMode,#PB_Path_RoundCorner)

					Else
						ObjectsHidden+1
					EndIf

				Case #ObjectTypeMarker
					If Setting\ShowMarker
						VectorSourceColor(\Outline)
						x1=Dot(\Point[0])\_x
						y1=Dot(\Point[0])\_y
						x2=Dot(\Point[1])\_x
						y2=Dot(\Point[1])\_y
						x0=Dot(\Centre)\_x
						y0=Dot(\Centre)\_y

						angle=GetAngle(x1,y1,x2,y2,#Null)
						MovePathCursor(x1,y1)
						AddPathLine(x2,y2)
						StrokePath(LineMode,#PB_Path_RoundCorner)

						MovePathCursor(x1,y1)
						angle+#MarkerWidth
						AddPathLine(x1+Cos(angle)*#MarkerLength,y1+Sin(angle)*#MarkerLength)
						angle-#MarkerWidth*2
						AddPathLine(x1+Cos(angle)*#MarkerLength,y1+Sin(angle)*#MarkerLength)
						angle+#MarkerWidth
						AddPathLine(x1,y1)
						StrokePath(1,#PB_Path_RoundCorner|#PB_Path_Preserve)
						FillPath()

						MovePathCursor(x2,y2)
						angle+#MarkerWidth
						AddPathLine(x2-Cos(angle)*#MarkerLength,y2-Sin(angle)*#MarkerLength)
						angle-#MarkerWidth*2
						AddPathLine(x2-Cos(angle)*#MarkerLength,y2-Sin(angle)*#MarkerLength)
						angle+#MarkerWidth
						AddPathLine(x2,y2)
						StrokePath(1,#PB_Path_RoundCorner|#PB_Path_Preserve)
						FillPath()

						angle=Degree(GetAngle(x1,y1,x2,y2,#True))
						RotateCoordinates(x0,y0,angle)
						MovePathCursor(x0-VectorTextWidth(\Info)/2,y0-VectorTextHeight(\Info)/2)
						AddPathText(\Info)
						VectorSourceColor(#ColorPaper)
						StrokePath(5,#PB_Path_RoundCorner|#PB_Path_Preserve)
						VectorSourceColor(\Outline)
						FillPath()
						RotateCoordinates(x0,y0,-angle)
					EndIf

				EndSelect
			EndWith
		Wend
	EndIf


	; --- Lines ------------------------------------------------------------------------------

	If Setting\ShowOutline
		LineMode=Setting\ModeLine+1
		n=0
		While n<CounterObjects
			n+1
			With Object(n)
				Select \type
				Case #ObjectTypeLine
					If \Outline
						MovePathCursor(Dot(\Point[0])\_x,Dot(\Point[0])\_y)
						AddPathLine(Dot(\Point[1])\_x,Dot(\Point[1])\_y)
						VectorSourceColor(\Outline)
						StrokePath(LineMode,#PB_Path_RoundEnd)
					EndIf
				EndSelect
			EndWith
		Wend
	EndIf


	; --- Dot Information ------------------------------------------------------------------------------
	If Setting\ShowPoints
		x=120
		y=20+Setting\ShowInformation*60
		z=1
		i=0

		n=0
		While n<CounterDots
			n+1

			With Dot(n)
				If \Type=#DotTypeCentreRectangle Or Setting\ShowDebugInformation=#Null
					i+1
					VectorSourceColor($FF000000+$A0<<(8*i%3))
					AddPathCircle(Dot(n)\_x,Dot(n)\_y,3)
					FillPath()
					MovePathCursor(Dot(n)\_x,Dot(n)\_y)
					AddPathLine(x,y)
					StrokePath(1)
					s=Str(n)+": "+StrF(Dot(n)\_distance,2)
					MovePathCursor(x-z*VectorTextWidth(s),y-VectorTextHeight(s)/2)
					DrawVectorText(s)
					y+14
					If y>#WY-30
						x=#WX-100
						y=20
						z=0
					EndIf
				EndIf
			EndWith
		Wend
	EndIf


	; --- Object Information ------------------------------------------------------------------------------
	If Setting\ShowObjectInformation
		x=240
		y=20+Setting\ShowInformation*60
		z=1
		i=0

		n=0
		While n<CounterObjects
			n+1

			With Object(n)
				If \Visible And Bool(\Type=#ObjectTypeRectangle Or Setting\ShowDebugInformation=0)
					i+1
					VectorSourceColor($FF000000+$A0<<(8*i%3))
					AddPathCircle(Dot(\Centre)\_x,Dot(\Centre)\_y,3)
					FillPath()
					MovePathCursor(Dot(\Centre)\_x,Dot(\Centre)\_y)
					AddPathLine(x,y)
					StrokePath(1)
					s="#"+Str(n)+": "+GetObjectInfo(n)
					MovePathCursor(x-z*VectorTextWidth(s),y-VectorTextHeight(s)/2)
					DrawVectorText(s)
					y+14
					If y>#WY-30
						x=#WX-250
						y=20
						z=0
					EndIf
				EndIf
			EndWith
		Wend
	EndIf


	; --- Surface Information ------------------------------------------------------------------------------
	If Setting\ShowDebugInformation
		i=0
		While i<CounterObjects
			i+1
			With Object(i)
				Select \type
				Case #ObjectTypeRectangle
					If \Visible Or Setting\ShowHidden
						s="#"+Str(i)+":"+Str(Dot(\Centre)\_distance)
						;s=Str(Distance(\Centre))
						MovePathCursor(Dot(\Centre)\_x-VectorTextWidth(s)/2,Dot(\Centre)\_y-VectorTextHeight(s)/2)
						AddPathText(s)
						VectorSourceColor($FFFFFFFF)
						StrokePath(3,#PB_Path_Preserve|#PB_Path_RoundCorner)
						VectorSourceColor($FF000000)
						FillPath()
					EndIf
				EndSelect
			EndWith
		Wend

		If Setting\ShowObjectInformation
			i=0
			While i<CounterIntersections
				i+1
				With Intersection(i)
					VectorSourceColor($FF3030FF)
					CompilerIf #Debug
						AddPathRectangle(\x1,\y1,\x2,\y2)
						StrokePath(2)
					CompilerEndIf
					AddPathCircle(\x,\y,2)
					FillPath()
				EndWith
			Wend
		EndIf

	EndIf


	; --- General Information ------------------------------------------------------------------------------
	If Setting\ShowInformation
		VectorSourceColor($FF000080)
		MovePathCursor(20,20)
		DrawVectorText("Viewpoint: "+Str(ViewX)+" | "+Str(ViewY)+" | "+Str(ViewZ)+",  Offset ("+Str(Dot(0)\x)+"|"+Str(Dot(0)\z)+")")
		MovePathCursor(20,35)
		DrawVectorText("Camera: "+Str(OptCameraX)+" | "+Str(OptCameraY)+" | "+Str(OptCamera)+",  Mode: "+StringField("Intersections.Center.First.Last :(",Setting\ModeCalculation+1,"."))
		MovePathCursor(20,50)
		DrawVectorText("Objects: "+Str(ObjectsShown)+" shown, "+Str(ObjectsHidden)+" hidden")
	EndIf


	StopVectorDrawing()

EndProcedure
Procedure Recalc(mode)

	Protected i

	Multiply(@Camera,@Matrix,@Calc)
	DebugMat

	RealZoomFactor=Setting\ZoomFactor * #ZoomScale

	For i=1 To CounterDots
		With Dot(i)
			ViewX = \x*calc\x[0] + \y*calc\x[1] + \z*calc\x[2] + calc\x[3]
			ViewY = \x*calc\y[0] + \y*calc\y[1] + \z*calc\y[2] + calc\y[3]
			ViewZ = \x*calc\z[0] + \y*calc\z[1] + \z*calc\z[2] + calc\z[3]

			Scale=OptCamera/ViewZ
			\_x=ViewX*Scale*RealZoomFactor+OffsetX
			\_y=ViewY*Scale*RealZoomFactor+OffsetY
			\_distance=Scale*100000;00
			;\_distance=Int(Scale*10000000)*10000-(Abs(\_x-OffsetX)+Abs(\_y-OffsetY))/100
			;\_rb=(Opt3DDistance+OptZoomFactor)/(ViewZ+32)
		EndWith
	Next i


	For i=1 To CounterObjects
		With Object(i)
			Select \Type
			Case #ObjectTypeRectangle
				\Visible=Bool((Dot(\Point[3])\_x-Dot(\Point[0])\_x)*(Dot(\Point[1])\_y-Dot(\Point[0])\_y)-(Dot(\Point[3])\_y-Dot(\Point[0])\_y)*(Dot(\Point[1])\_x-Dot(\Point[0])\_x)>0)
			Case #ObjectTypeTriangle
			Default
				\Visible=#True
			EndSelect
		EndWith
	Next i

	CalcMaxima()

	For i=1 To CounterObjects
		With Sorter(i)
			\Object=i
			Select Setting\ModeCalculation
			Case #CalculationModeIntersection
				\Distance=Dot(Object(i)\Centre)\_distance
			Case #CalculationModeCenter
				\Distance=Dot(Object(i)\Centre)\_distance;			Distanz Mittelpunkt
			Case #CalculationModeFirstPoint
				\Distance=Object(i)\MaximaZ\Min;					nähester Punkt
			Case #CalculationModeLastPoint
				\Distance=Object(i)\MaximaZ\Max;					entferntester Punkt
			EndSelect
		EndWith
	Next i

	SortStructuredArray(Sorter(),#PB_Sort_Ascending,OffsetOf(SorterType\Distance),TypeOf(SorterType\Distance),1,CounterObjects)
	For i=1 To CounterObjects
		Sorter(Sorter(i)\Object)\Reverse=i
	Next i

	; 	Protected n
	; 	DataSection
	; 		Data.i 1,2,12,9,10,6,3,4,5,7,8,11
	; 	EndDataSection
	; 	For i=1 To 12
	; 		Read.i n
	; 		Sorter(n)\Reverse=i
	; 	Next i
	;
	; 	SortStructuredArray(Sorter(),#PB_Sort_Descending,OffsetOf(SorterType\Reverse),TypeOf(SorterType\Distance),1,CounterObjects)
	; 	For i=1 To CounterObjects
	; 		Sorter(Sorter(i)\Object)\Reverse=i
	; 	Next i
	;
	; 	With Sorter(9)
	; 		Sorter(0)\Distance=\Distance
	; 		Sorter(0)\Object=\Object
	; 		Sorter(0)\Reverse=\Reverse
	; 		\Distance=Sorter(11)\Distance
	; 		\Object=Sorter(11)\Object
	; 		\Reverse=Sorter(11)\Reverse
	; 	EndWith
	; 	With Sorter(11)
	; 		\Distance=Sorter(0)\Distance
	; 		\Object=Sorter(0)\Object
	; 		\Reverse=Sorter(0)\Reverse
	; 	EndWith

	If Setting\ModeCalculation=#CalculationModeIntersection
		GetIntersections()
	EndIf

	;GetObjectRelation(13,14)
	ShowObjects()

	If mode
		Redraw()
	EndIf

EndProcedure
Procedure Rotation()

	;Protected.mat test

	SetRotX(@RotXMat,AngleY)
	SetRotZ(@RotYMat,AngleX)
	SetRotY(@RotZMat,AngleZ)

	;SetTransformation(@test,0,0,0)
	;Multiply(@RotXMat,@test,@RotXMat)
	;Multiply(@RotYMat,@test,@RotYMat)
	;Multiply(@RotZMat,@test,@RotZMat)

	Multiply(@RotXMat,@RotYMat,@Matrix)
	Multiply(@Matrix,@RotZMat,@Matrix)

	;SetTransformation(@test,50,50,50)
	;Multiply(@Matrix,@test,@Matrix)

	Recalc(#True)

EndProcedure

Procedure DoObjects(demo)

	Protected Outline

	Select demo

	Case 0
		CreateBox(0,0,0, 100,100,100,$E0f0a060,$80000000)
		CreateBox(200,0,0, 100,100,100,$E0f060a0,$80000000)
		CreateBox(0,200,0, 100,100,100,$E0c0a0f0,$80000000)
		CreateBox(0,0,200, 100,100,100,$E0c0f0a0,$80000000)

	Case 1
		Outline=$80000000
		;Outline=$00000000
		CreateBox(0,0,0, 100,100,100,$E0f0a060,Outline)
		CreateBox(0,0,105, 10,100,10,$80a0f060,Outline)
		If 1
			CreateBox(18,0,105, 10,85,10,$80a060f0,Outline)
			CreateBox(36,0,105, 10,70,10,$80f0f060,Outline)
			CreateBox(54,0,105, 10,55,10,$8060a0f0,Outline)
			CreateBox(72,0,105, 10,40,10,$8060f0f0,Outline)
			CreateBox(90,0,105, 10,25,10,$80f060a0,Outline)
		EndIf
		;CreateBox(120,0,0, 80,100,80,$E0f060a0,Outline)
		;CreateBox(0,0,120, 60,100,60,$E0c0a0f0,Outline)
		;CreateBox(120,0,120, 40,100,40,$E0c0f0a0,Outline)
		;CreateBox(105,0,105, 10,100,10,$10a0f060,Outline)
		CreateMarker(0,0,130, 100,0,130, $FFFF0000)

	Case 2
		; unten
		CreateBox(0,0,0, 62,50,60, #ColorFront,$40000000)
		CreateBox(63,0,0, 62,50,60, #ColorFront,$40000000)
		CreateBox(126,0,0, 62,50,60, #ColorFront,$40000000)
		CreateBox(189,0,0, 62,50,40, #ColorFront,$40000000)
		; mittig
		CreateBox(0,51,0, 62,25,60, #ColorFront,$40000000)
		CreateBox(63,51,0, 62,25,60, #ColorFront,$40000000)
		CreateBox(126,51,0, 62,25,60, #ColorFront,$40000000)
		CreateBox(189,51,0, 62,25,40, #ColorFront,$40000000)
		; links/rechts
		CreateBox(0,77,0, 62,130,60, #ColorFront,$40000000)
		CreateBox(189,77,0, 62,130,40, #ColorFront,$40000000)
		; oben
		CreateBox(0,208,0, 62,50,60, #ColorFront,$40000000)
		CreateBox(63,208,0, 62,50,40, #ColorFront,$40000000)
		CreateBox(126,208,0, 62,50,40, #ColorFront,$40000000)
		CreateBox(189,208,0, 62,50,40, #ColorFront,$40000000)
		; Platten
		CreateBox(62,77,0, 2,130,60, #ColorWood,$40000000)
		CreateBox(62,207,40, 2,50,20, #ColorWood,$40000000)
		CreateBox(62,207,0, 125,2,42, #ColorWood,$40000000)
		CreateBox(62,76,0, 125,2,60, #ColorWood,$40000000)
		CreateBox(187,0,40, 2,76,20, #ColorWood,$40000000)
		CreateBox(187,76,0, 2,131,40, #ColorWood,$40000000)

		CreateMarker(0,0,100, 62,0,100, #ColorDistance)
		CreateMarker(0,0,80, 251,0,80, #ColorDistance)
		CreateMarker(-30,0,0, -30,257,0, #ColorDistance)
		CreateMarker(270,0,0, 270,0,40, #ColorDistance)
		CreateMarker(290,0,0, 290,0,60, #ColorDistance)

	EndSelect

EndProcedure
Procedure Main()

	LoadFont(0,"Segoe UI",8)

	OpenWindow(#Win,8,8,#WX,#WY,"Cursor-Keys, Zoom +/-     Options: O=Outline S=Surfaces, L=Lines     Modes: H=Hide, F=Fill, R=Rotation, C=Depth     Other: P=Perspective, D,I,J=Debugging")
	CanvasGadget(#Canvas,0,0,#WX,#WY)

	AddKeyboardShortcut(#Win,#PB_Shortcut_Left|#PB_Shortcut_Shift,#ShiftLeft)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Right|#PB_Shortcut_Shift,#ShiftRight)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Up|#PB_Shortcut_Shift,#ShiftUp)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Down|#PB_Shortcut_Shift,#ShiftDown)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Left,#RotateLeft)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Right,#RotateRight)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Up,#RotateUp)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Down,#RotateDown)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Back,#ResetView)
	AddKeyboardShortcut(#Win,#PB_Shortcut_B,#ToggleObjectInformation)
	AddKeyboardShortcut(#Win,#PB_Shortcut_C,#CalculationMode)
	AddKeyboardShortcut(#Win,#PB_Shortcut_C|#PB_Shortcut_Shift,#CalculationMode)
	AddKeyboardShortcut(#Win,#PB_Shortcut_D,#TogglePoints)
	AddKeyboardShortcut(#Win,#PB_Shortcut_F,#ToggleFill)
	AddKeyboardShortcut(#Win,#PB_Shortcut_H,#ToggleHidden)
	AddKeyboardShortcut(#Win,#PB_Shortcut_I,#ToggleInformation)
	AddKeyboardShortcut(#Win,#PB_Shortcut_J,#ToggleDebugInformation)
	AddKeyboardShortcut(#Win,#PB_Shortcut_L,#ToggleLine)
	AddKeyboardShortcut(#Win,#PB_Shortcut_M,#ToggleMarker)
	AddKeyboardShortcut(#Win,#PB_Shortcut_O,#ToggleOutline)
	AddKeyboardShortcut(#Win,#PB_Shortcut_P,#PerspectivePlus)
	AddKeyboardShortcut(#Win,#PB_Shortcut_P|#PB_Shortcut_Shift,#PerspectiveMinus)
	AddKeyboardShortcut(#Win,#PB_Shortcut_R,#ToggleRotation)
	AddKeyboardShortcut(#Win,#PB_Shortcut_S,#ToggleSurface)
	AddKeyboardShortcut(#Win,#PB_Shortcut_X,#MoveRight)
	AddKeyboardShortcut(#Win,#PB_Shortcut_X|#PB_Shortcut_Shift,#MoveLeft)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Y,#MoveUp)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Y|#PB_Shortcut_Shift,#MoveDown)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Z,#ZoomPlus)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Z|#PB_Shortcut_Shift,#ZoomMinus)

	; ------------------------------------------------------------------------------------

	DoObjects(1)

	; ------------------------------------------------------------------------------------

	OptCameraX=-100
	OptCameraY=50
	OptCamera=1000
	AngleX=Radian(0)
	AngleY=Radian(-170)
	AngleZ=Radian(20)


	SetCamera(OptCameraX,OptCameraY,OptCamera)
	SetNorm(@Matrix)
	Rotation()

	Repeat
		Select WaitWindowEvent()
		Case #PB_Event_Gadget,#PB_Event_Menu
			Select EventGadget()
			Case #ShiftLeft
				SetCamera(OptCameraX-30,OptCameraY,OptCamera)
				Recalc(#True)
			Case #ShiftRight
				SetCamera(OptCameraX+30,OptCameraY,OptCamera)
				Recalc(#True)
			Case #ShiftUp
				SetCamera(OptCameraX,OptCameraY-30,OptCamera)
				Recalc(#True)
			Case #ShiftDown
				SetCamera(OptCameraX,OptCameraY+30,OptCamera)
				Recalc(#True)
			Case #MoveLeft
				MoveObjects(-10,0)
				Recalc(#True)
			Case #MoveRight
				MoveObjects(10,0)
				Recalc(#True)
			Case #MoveUp
				MoveObjects(0,10)
				Recalc(#True)
			Case #MoveDown
				MoveObjects(0,-10)
				Recalc(#True)
			Case #RotateLeft
				If Setting\ModeRotation
					AngleZ-#PiTeil
					If AngleZ<0 : AngleZ+#ZweiPi : EndIf
				Else
					AngleX-#PiTeil
					If AngleX<0 : AngleX+#ZweiPi : EndIf
				EndIf
				Rotation()
			Case #RotateRight
				If Setting\ModeRotation
					AngleZ+#PiTeil
					If AngleZ>#ZweiPi : AngleZ-#ZweiPi : EndIf
				Else
					AngleX+#PiTeil
					If AngleX>#ZweiPi : AngleX-#ZweiPi : EndIf
				EndIf
				Rotation()
			Case #RotateUp
				AngleY-#PiTeil
				Rotation()
			Case #RotateDown
				AngleY+#PiTeil
				Rotation()
			Case #ToggleOutline
				Setting\ShowOutline!1
				Redraw()
			Case #ToggleSurface
				Setting\ShowSurface!1
				Redraw()
			Case #TogglePoints
				Setting\ShowPoints!1
				Setting\ShowObjectInformation*Bool(Setting\ShowPoints=0)
				Redraw()
			Case #ToggleHidden
				Setting\ShowHidden!1
				Redraw()
			Case #CalculationMode
				Setting\ModeCalculation=(Setting\ModeCalculation+1+((GetKeyState_(#VK_SHIFT)>>6)&2))&3
				Recalc(#True)
			Case #ToggleInformation
				Setting\ShowInformation!1
				Redraw()
			Case #ToggleDebugInformation
				Setting\ShowDebugInformation!1
				Redraw()
			Case #ToggleObjectInformation
				Setting\ShowObjectInformation!1
				Setting\ShowPoints*Bool(Setting\ShowObjectInformation=0)
				Redraw()
			Case #ToggleFill
				Setting\ModeFill!1
				Redraw()
			Case #ToggleLine
				Setting\ModeLine!1
				Redraw()
			Case #ToggleMarker
				Setting\ShowMarker!1
				Redraw()
			Case #ToggleRotation
				Setting\ModeRotation!1
			Case #PerspectivePlus
				If OptCamera>300
					SetCamera(OptCameraX,OptCameraY,OptCamera-50)
					Recalc(#True)
				EndIf
			Case  #PerspectiveMinus
				If OptCamera<3000
					SetCamera(OptCameraX,OptCameraY,OptCamera+50)
					Recalc(#True)
				EndIf
			Case #ResetView
				AngleX=0 : AngleY=0 : AngleZ=0
				ViewX=0  : ViewY=0  : ViewZ=0
				SetCamera(0,0,1000)
				SetNorm(@Matrix)
				Rotation()
				Recalc(#True)
			Case #ZoomPlus
				If OptCamera>300
					Setting\ZoomFactor+1
					Recalc(#True)
				EndIf
			Case #ZoomMinus
				If Setting\ZoomFactor>1
					Setting\ZoomFactor-1
					Recalc(#True)
				EndIf

			EndSelect

		Case #PB_Event_CloseWindow
			End

		Case #WM_CHAR
			Select EventwParam()
			Case '+'
				If OptCamera>300
					Setting\ZoomFactor+1
					Recalc(#True)
				EndIf
			Case '-'
				If Setting\ZoomFactor>1
					Setting\ZoomFactor-1
					Recalc(#True)
				EndIf
			EndSelect

		EndSelect
	ForEver

EndProcedure

Main()
End
User avatar
Michael Vogel
Addict
Addict
Posts: 2677
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Calculating hidden surfaces for 3D objects

Post by Michael Vogel »

Slowing down a little bit...
...as sorting the surfaces order needs a reliable calculation of their distances. So the procedure CreateIntersection has been done to check if objects need to be investigated in more detail. But there are two puzzles to be solved then:
1. an anchor point within the overlapping part of the two objects (done in the 2D representation)
2. original points (3D) on the two overlapping objects close to this anchor point

The anchor point was done by chosing the center of the overlapping coordinates (\x=(Max(*mx\Min,\MaximaX\Min)+Min(*mx\Max,\MaximaX\Max))/2, \y=...) which could be outside an object in certain cases. Now a new GetIntersectionAnchor has been generated, slowing down everything.

The original 3D calculation is also done not very fast and elegant, GetPointNearDot is the procedure which needs also some optimizing in the future.

Status - simple scenes like DoObjects(1) are doing fine now, the more complex DoObjects(2) still fails here and there...

Code: Select all

; Define

	; Version 0.6a - Michael Vogel

	; --- DEBUGGING ONLY ---
	Global c1von,c1bis,c2von,c2bis
	Global sort1.s,sort2.s
	Global mem1,mem2
	Global pointinfo.s
	; --- DEBUGGING ONLY ---


	EnableExplicit

	#WX=1200
	#WY=850

	#Iterationn=20

	#ZoomScale=0.05
	#ZweiPi=#PI+#PI
	#PiHalbe=#PI/2
	#PiTeil=#PI/36
	#PiRadiant=#PI/180
	#PiGrad=180/#PI

	#MarkerCiphers=1
	#MarkerLength=4
	#MarkerWidth=45*#PI/180

	#MaxInteger=	1<<31-1

	#ColorPaper=	$FFFFFFFF
	#ColorFront=	$C0E0E0F0
	#ColorWood=	$E05090B0
	#ColorDistance=	$f0004020

	#MinCoordinate=-#MaxInteger
	#MaxCoordinate= #MaxInteger

	#Debug=1

	; ------------------------------------------------------------------------------------

	Structure MaximaType
		Min.i
		Max.i
	EndStructure

	Structure DotType
		x.d;			skaliert
		y.d;			skaliert
		z.d;			skaliert
		_x.i;		2D-Transformation
		_y.i;		2D-Transformation
		;_rb.i;		3D-Punkt-Distanz (rot/blau)
		_distance.q;	Z-Distanz zum Betrachter
		type.i;		zum Debuggen etc.
	EndStructure

	Structure ObjectType
		Type.i;		Punkt, Linie, Oberfläche (3 oder 4 Punkte)
		Dot.i[4];		Punktkoordinaten
		MaximaX.MaximaType
		MaximaY.MaximaType
		MaximaZ.MaximaType
		Color.i;		Flächenfarbe
		Outline.i;	Linienfarbe
		Centre.i;		Flächenmittelpunkt
		Visible.i;	sichtbares Segment
		Info.s;		Marker
	EndStructure

	Structure SorterType
		Object.i
		Distance.q
		Reverse.i
	EndStructure

	Structure Mat
		x.d[4]
		y.d[4]
		z.d[4]
		t.d[4]
	EndStructure

	Structure IntersectionType
		ObjectA.i
		ObjectB.i
		; Mittelpunkt der Schnittfläche
		x.i
		y.i
		; Eckpunkte der Schnittfläche
		CompilerIf #Debug
			x1.i
			y1.i
			x2.i
			y2.i
			info.s
			pinfo.s
		CompilerEndIf
		; Reihenfolge
		AoverB.i
	EndStructure


	Structure SettingType
		ShowOutline.i
		ShowSurface.i
		ShowPoints.i
		ShowHidden.i
		ShowInformation.i
		ShowDebugInformation.i
		ShowObjectInformation.i
		ShowIntersectionInformation.i
		ShowMarker.i
		ModeCalculation.i
		ModeRotation.i
		ModeFill.i
		ModeLine.i
		Optimizer.i
		ZoomFactor.i
		ShowThreeD.i;			3D-Darstellung
		ThreeD_Distance.i;		Punktabstand für 3D-Effekt;					-		-		-
		ThreeD_Left.i;			Farbfilter für das linke Auge (rot)				-		-		-
		ThreeD_Right.i;		...rechtes Auge (grün, blau)					-		-		-
	EndStructure

	; ------------------------------------------------------------------------------------

	Global MaxElements=	25000

	Global.Mat Matrix, Calc, RotXMat, RotYMat, RotZMat, Camera, TempMat
	Global Dim Dot.DotType(MaxElements);							Dot(0) wird für den Offset verwendet
	Global Dim Object.ObjectType(MaxElements)
	Global Dim Sorter.SorterType(MaxElements)
	Global Dim Intersection.IntersectionType(MaxElements)

	; Bildschirmgröße für Graphikfenster
	Global ScreenX=GetSystemMetrics_(#SM_CXSCREEN)
	Global ScreenY=GetSystemMetrics_(#SM_CYSCREEN)
	Global Screen_X=ScreenX-1
	Global Screen_Y=ScreenY-1
	Global ScreenZ
	Global OffsetX=#WX>>1;ScreenX>>1
	Global OffsetY=#WY>>1;ScreenY>>1

	; Skalierung für 3D-Transformation
	Global.d ViewX, ViewY, ViewZ
	Global.d AngleX, AngleY, AngleZ;		Rotationswinkel (per Maus auswählbar)
	Global.d XdivPi=#PI/OffsetX;			Skalierung, um genau eine Drehung nach 'X' zu erlauben
	Global.d YdivPi=#PI/OffsetY;			Skalierung, um genau eine Drehung nach 'Y' zu erlauben
	Global.d RealZoomFactor;				skalierte Vergrößerung

	Global CounterDots, CounterObjects, CounterIntersections
	Global OptCamera; =OptCameraZ
	Global OptCameraX, OptCameraY

	Global Setting.SettingType

	; ------------------------------------------------------------------------------------

	OptCamera=		500

	With Setting
		\ShowInformation=1
		\ShowSurface=	1
		\ShowOutline=	0
		\ShowMarker=	1
		\ZoomFactor=	25
		\ModeRotation=	1
		\ModeFill=	1
		\Optimizer=	1
	EndWith

	; ------------------------------------------------------------------------------------

	Enumeration
		#Win
		#Canvas
		;
		#MoveLeft
		#MoveRight
		#MoveUp
		#MoveDown
		#ShiftLeft
		#ShiftRight
		#ShiftUp
		#ShiftDown
		#RotateLeft
		#RotateRight
		#RotateUp
		#RotateDown
		#PerspectiveMinus
		#PerspectivePlus
		#ZoomMinus
		#ZoomPlus
		#ResetView
		#CalculationMode
		#ToggleRotation
		#ToggleLine
		#ToggleMarker
		#ToggleFill
		#ToggleHidden
		#ToggleIntersection
		#ToggleOutline
		#ToggleSurface
		#TogglePoints
		#ToggleInformation
		#ToggleDebugInformation
		#ToggleObjectInformation
	EndEnumeration

	Enumeration
		#DotTypeDefault
		#DotTypeCentreLine
		#DotTypeCentreTriangle
		#DotTypeCentreRectangle
	EndEnumeration

	Enumeration
		#ObjectTypeDot
		#ObjectTypeLine
		#ObjectTypeMarker
		#ObjectTypeTriangle
		#ObjectTypeRectangle
	EndEnumeration

	Enumeration
		#CalculationModeIntersection
		#CalculationModeCenter
		#CalculationModeFirstPoint
		#CalculationModeLastPoint
	EndEnumeration


	Global Dim ObjectDots(#ObjectTypeRectangle)

	ObjectDots(#ObjectTypeDot)=1
	ObjectDots(#ObjectTypeLine)=2
	ObjectDots(#ObjectTypeMarker)=2
	ObjectDots(#ObjectTypeTriangle)=3
	ObjectDots(#ObjectTypeRectangle)=4


	; ------------------------------------------------------------------------------------

	Declare.i InsidePolygon(x,y,object)
	Declare RecalcDot(i)

	; ------------------------------------------------------------------------------------

	Macro StrM(value)
		RSet(StrD(value,2),8)
	EndMacro
	Macro AddLine(p1,p2,outline)

		CreateObject(#ObjectTypeLine,p1,p2,#Null,#Null,#Null,outline)

	EndMacro
	Macro AddTriangle(p1,p2,p3,color,outline)

		CreateObject(#ObjectTypeTriangle,p1,p2,p3,#Null,color,outline)

	EndMacro
	Macro AddRectangle(p1,p2,p3,p4,color,outline)

		CreateObject(#ObjectTypeRectangle,p1,p2,p3,p4,color,outline)

	EndMacro
	Macro AddPathRectangle(x1,y1,x2,y2)
		AddPathBox(x1,y1,(x2)-(x1),(y2)-(y1))
	EndMacro

	; ------------------------------------------------------------------------------------

	Procedure.i Max(a,b)
		If a>b
			ProcedureReturn a
		Else
			ProcedureReturn b
		EndIf
	EndProcedure
	Procedure.i Min(a,b)

		If a<b
			ProcedureReturn a
		Else
			ProcedureReturn b
		EndIf
	EndProcedure
	Procedure.s StrDot(l)

		Protected s.s=Str(l)
		Protected i.i=Len(s)

		While i>3
			i-3
			;s=Left(s,i)+"."+StringMid(@s,i,#MaxString)
			s=InsertString(s,".",i+1)
		Wend

		ProcedureReturn s

	EndProcedure
	Procedure.s IfStr(bool,yes.s,no.s)
		If bool
			ProcedureReturn yes
		Else
			ProcedureReturn no
		EndIf
	EndProcedure
	Procedure.s DotInfo(object,dotnr)

		ProcedureReturn "#"+RSet(Str(Object(object)\Dot[dotnr]),2)+": "+StrDot(Dot(Object(object)\Dot[dotnr])\_x)+"|"+StrDot(Dot(Object(object)\Dot[dotnr])\_y)+", "+StrDot(Dot(Object(object)\Dot[dotnr])\_distance)

	EndProcedure
	Macro Bit(value,bit)
		((value)>>(bit-1)&1)
	EndMacro

	; ------------------------------------------------------------------------------------


; EndDefine

Procedure.s GetObjectType(type)

	ProcedureReturn StringField("Dot.Line.Marker.Triangle.Rectangle.-.-.-.-",type+1,".")

EndProcedure
Procedure.s GetObjectInfo(object,verbose=#Null)

	Protected.i i
	Protected.s s

	With Object(object)
		For i=0 To 3
			s+", "+Str(\Dot[i])
		Next i
		s=GetObjectType(\Type)+" object.  Dots: "+Mid(s,3)

		If verbose
			s="#"+Str(object)+": "+s
		EndIf
	EndWith

	;s=s+#CR$+"*"

	ProcedureReturn s

EndProcedure
Procedure GetViewDistance(dot)

	With Dot(dot)
		ProcedureReturn Sqr(Pow(ViewX-OptCameraX+\x,2)+Pow(ViewY-OptCameraY+\y,2)+Pow(ViewZ-OptCamera+\z,2))
		ProcedureReturn Sqr(Pow(ViewX-\x,2)+Pow(ViewY-\y,2)+Pow(ViewZ-\z,2))
		ProcedureReturn Sqr(Pow(OptCameraX-\x,2)+Pow(OptCameraY-\y,2)+Pow(OptCamera-\z,2))
	EndWith

EndProcedure
Procedure.d GetDotDistance(a,b)

	ProcedureReturn Sqr(Pow(Dot(a)\x-Dot(b)\x,2)+Pow(Dot(a)\y-Dot(b)\y,2)+Pow(Dot(a)\z-Dot(b)\z,2))

EndProcedure
Procedure.i GetXyDistance(x,y,dot)

	x-Dot(dot)\_x
	y-Dot(dot)\_y
	x*x
	y*y

	ProcedureReturn x+y

EndProcedure
Procedure ShowDot(dot,info.s="")

	With Dot(dot)
		Debug "."+Str(dot)+": "+Str(\x)+"|"+Str(\y)+"|"+Str(\z)+" ("+Str(\_x)+"|"+Str(\_y)+") - "+StrDot(\_distance)+" '"+info+"'"
	EndWith

EndProcedure
Procedure GetPointNearDot(x,y,object)

	; Suche Punkt auf bestehendem Objekt, welcher möglichst nahe einem Bildpunkt liegt

	Protected.d ax,ay,az
	Protected.d bx,by,bz
	Protected.d dx,dy,dz
	Protected.d ox,oy,oz
	Protected i,j,n,m1,m2
	Protected best,dist,max
	Protected b1,b2

	If InsidePolygon(x,y,object)

		Debug "--- "+Str(x)+"|"+Str(y)+" in Objekt "+Str(object)+" ---"
		;StartDrawing(CanvasOutput(#Canvas)); <->

		With Object(object)
			If \Type=#ObjectTypeRectangle
				; Eckpunkt nahe der Bildschirmkoordinate suchen...
				max=#MaxInteger
				i=ObjectDots(\Type)
				While i
					i-1
					dist=GetXyDistance(x,y,\Dot[i])
					; ShowDot(\Dot[i],StrDot(dist))
					If dist<max
						max=dist
						best=i
					EndIf
				Wend

				; Vektor zum nächsten Eckpunkt vormerken...
				b1=(best+1)%ObjectDots(\Type)
				b2=(best+ObjectDots(\Type)-1)%ObjectDots(\Type)
				;If GetXyDistance(x,y,\Dot[b1])>GetXyDistance(x,y,\Dot[b2])
				;	Swap b1,b2
				;EndIf
				n=\Dot[best]
				ShowDot(n)

				m1=\Dot[b1]
				ax=Dot(m1)\x-Dot(n)\x
				ay=Dot(m1)\y-Dot(n)\y
				az=Dot(m1)\z-Dot(n)\z

				m2=\Dot[b2]
				bx=Dot(m2)\x-Dot(n)\x
				by=Dot(m2)\y-Dot(n)\y
				bz=Dot(m2)\z-Dot(n)\z


				Debug Str(n)+" ("+Str(Dot(n)\x)+"|"+Str(Dot(n)\y)+"|"+Str(Dot(n)\z)+") To "+Str(m1)+" delta: "+Str(bx)+"|"+Str(by)+"|"+Str(bz)

				; Punkte entlang des Vektors berechnen...
				max=#MaxInteger
				For i=0 To #Iterationn
					For j=0 To #Iterationn
						Dot(0)\x=Dot(n)\x+ax*i/#Iterationn+bx*j/#Iterationn
						Dot(0)\y=Dot(n)\y+ay*i/#Iterationn+by*j/#Iterationn
						Dot(0)\z=Dot(n)\z+az*i/#Iterationn+bz*j/#Iterationn
						RecalcDot(0)
						; ...und bei Annäherung merken...
						dist=GetXyDistance(x,y,#Null)
						;Box(Dot(0)\_x,Dot(0)\_y,2,2,#Black)
						If dist<max
							;Debug "Iteration "+Str(i)+"/"+Str(j)+" "+Str(Dot(0)\x)+"|"+Str(Dot(0)\y)+"|"+Str(Dot(0)\z)+" = "+Str(Dot(0)\_x)+"|"+Str(Dot(0)\_y)+" d:"+StrDot(dist)
							;Box(Dot(0)\_x,Dot(0)\_y,2,2,#Cyan)
							max=dist
							m1=i
							m2=j
							ox=Dot(0)\x
							oy=Dot(0)\y
							oz=Dot(0)\z
							; Debug Str(dx)+" | "+Str(dy)+" | "+Str(dz)+" = "+Str(Dot(0)\_x)+" | "+Str(Dot(0)\_y)
						EndIf
					Next j
				Next i


				; das ist nun der beste Punkt
				Dot(0)\x=ox
				Dot(0)\y=oy
				Dot(0)\z=oz
				Dot(0)\type=#DotTypeDefault
				RecalcDot(#Null)
				pointinfo=Str(ox)+"|"+Str(oy)+"|"+Str(oz)+"("+Str(Dot(0)\_x)+","+Str(Dot(0)\_y)+")"

				; 				StartDrawing(CanvasOutput(#Canvas))
				; 				Box(Dot(0)\_x-2,Dot(0)\_y-2,4,4,#Red)
				; 				DrawText(Dot(0)\_x+10,Dot(0)\_y-2,Str(object),#Red,#White)
				; 				StopDrawing(); <->

				ShowDot(10)
				ProcedureReturn #True

			EndIf
		EndWith

	EndIf

	ProcedureReturn #Null

EndProcedure
Procedure GetMedianDistance(x,y,object)

	Protected i,dots
	Protected.d a,b,total
	Protected.d Dim t(4)

	With Object(object)
		dots=ObjectDots(\Type)-1
		For i=0 To dots
			a=x-Dot(\Dot[i])\_x
			b=y-Dot(\Dot[i])\_y
			t(i)=Sqr(a*a+b*b)
			total+t(i)
		Next i

		a=0
		For i=0 To dots
			t(i)=total/t(i)
			a+t(i)
		Next i
		;Debug a

		b=0
		For i=0 To dots
			b+Dot(\Dot[i])\_distance*t(i)/a
		Next i

	EndWith

	ProcedureReturn b

EndProcedure
Procedure ShowMat(*m.mat,title.s="")

	Debug "- "+title+RSet(" ",38-Len(title),"-")
	Debug "X"+StrM(*m\x[0])+" |"+StrM(*m\x[1])+" |"+StrM(*m\x[2])+" |"+StrM(*m\x[3])
	Debug "Y"+StrM(*m\y[0])+" |"+StrM(*m\y[1])+" |"+StrM(*m\y[2])+" |"+StrM(*m\y[3])
	Debug "Z"+StrM(*m\z[0])+" |"+StrM(*m\z[1])+" |"+StrM(*m\z[2])+" |"+StrM(*m\z[3])
	Debug "T"+StrM(*m\t[0])+" |"+StrM(*m\t[1])+" |"+StrM(*m\t[2])+" |"+StrM(*m\t[3])

	Macro DebugMat
		ShowMat(@Camera,"Camera")
		ShowMat(@Matrix,"Matrix")
		ShowMat(@Calc,"Calc")
	EndMacro

EndProcedure
Procedure ShowObjects(verbose)

	Protected i
	Protected s.s
	Protected t.s

	While i<CounterObjects
		i+1
		t+" > "+Str(Sorter(i)\Object)
		If verbose
			With Object(i)
				s="#"+RSet(Str(i),2,"0")+" order "+RSet(Str(Sorter(i)\Reverse),2,"0")+" "+GetObjectType(\Type)+": "+IfStr(\Visible,"visible","hidden")
				Debug s
			EndWith
		EndIf
	Wend

	Debug "  Draw "+Mid(t,4)

EndProcedure
Procedure ShowSorter(s.s="")

	Protected i

	Debug "--- "+s+"---"
	For i=1 To CounterObjects
		Debug "#"+Str(i)+": "+Str(Sorter(i)\Object)+", "+Sorter(i)\Reverse
	Next i

EndProcedure

Procedure.d GetAngle(x1,y1,x2,y2,up=0)

	If x1>x2 And up
		ProcedureReturn ATan2(x1-x2,y1-y2)
	Else
		ProcedureReturn ATan2(x2-x1,y2-y1)
	EndIf

	;ProcedureReturn ATan((y2-y1)/(x2-x1))
	;ProcedureReturn Degree(ATan((y2-y1)/(x2-x1)))

EndProcedure
Macro SorterCopy(source,destination)
	; Debug "copy "+Str(source)+" to "+Str(destination)
	Sorter(destination)\Distance=Sorter(source)\Distance
	Sorter(destination)\Object=Sorter(source)\Object
	Sorter(destination)\Reverse=Sorter(source)\Reverse
EndMacro
Procedure MoveBehind(oo,up)

	Protected i,poo,pup

	poo=Sorter(oo)\Reverse
	pup=Sorter(up)\Reverse

	If poo<pup
		SorterCopy(poo,0)
		While poo<pup
			SorterCopy(poo+1,poo)
			poo+1
		Wend
		SorterCopy(0,pup)

		For i=1 To CounterObjects
			Sorter(Sorter(i)\Object)\Reverse=i
		Next i
	EndIf

EndProcedure

Procedure.i InsidePolygon(x,y,object)

	Protected s.s
	Protected i,j,c
	Protected b1,b2,b3
	Protected dx,dy
	Protected dots

	; int pnpoly(int npol, float *xp, float *yp, float x, float y)
	; {
	;    int i, j, c = 0;
	;    For (i = 0, j = npol-1; i < npol; j = i++) {
	;      If ((((yp[i] <= y) && (y < yp[j])) ||
	;         ((yp[j] <= y) && (y < yp[i]))) &&
	;         (x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i]))
	;        c = !c;
	;    }
	;    Return c;
	; }

	With Object(object)
		dots=ObjectDots(\Type)
		While i<dots
			s=s+Str(Dot(\Dot[i])\_x)+","+Str(Dot(\Dot[i])\_y)+"; "
			j=(i+dots-1)%dots
			b1=Bool( (Dot(\Dot[i])\_y <= y) And (y < Dot(\Dot[j])\_y) )
			b2=Bool( (Dot(\Dot[j])\_y <= y) And (y < Dot(\Dot[i])\_y) )
			If b1 Or b2
				dx=(Dot(\Dot[j])\_x-Dot(\Dot[i])\_x)
				dy=(Dot(\Dot[j])\_y-Dot(\Dot[i])\_y)
				If ( x < dx * (y-Dot(\Dot[i])\_y) / dy + Dot(\Dot[i])\_x)
					c!1
				EndIf
			EndIf
			i+1
		Wend
	EndWith

	;Debug s+" --> "+Str(c)
	ProcedureReturn c

EndProcedure
Procedure.i IntersectPolygon(a,b)

	Protected s.s
	Protected i,dots
	Protected in

	With Object(a)
		dots=ObjectDots(\Type)
		While i<dots
			s=s+Str(Dot(\Dot[i])\_x)+","+Str(Dot(\Dot[i])\_y)+"; "
			If InsidePolygon(Dot(\Dot[i])\_x,Dot(\Dot[i])\_y,b)
				;Debug "JUHU "+s
				ProcedureReturn #True
			EndIf
			i+1
		Wend
	EndWith

	;Debug s
	ProcedureReturn #Null

EndProcedure
Procedure GetIntersectionAnchor(x1,y1,x2,y2,object1,object2,*m.point,draw=#Null)

	Protected n,x,y
	Protected.q mx,my

	#Speedup=1

	If draw
		VectorSourceColor($a02080f0)
	EndIf

	For x=x1 To x2 Step #Speedup
		For y=y1 To y2 Step #Speedup
			If InsidePolygon(x,y,object1)
				If InsidePolygon(x,y,object2)
					mx+x
					my+y
					n+1
					If draw
						AddPathCircle(x,y,1)
						FillPath()
					EndIf
				EndIf
			EndIf
		Next y
	Next x

	If n
		mx/n
		my/n
		If draw
			AddPathCircle(mx,my,1)
		EndIf
		If *m
			*m\x=mx
			*m\y=my
		EndIf
		ProcedureReturn #True
	EndIf

	ProcedureReturn #Null

EndProcedure
Procedure CreateIntersection(i,j,*mx.MaximaType,*my.MaximaType)

	Protected s.s
	Protected n,di,dj
	Protected m.Point

	With Object(j)

		CounterIntersections+1
		Intersection(CounterIntersections)\ObjectA=i
		Intersection(CounterIntersections)\ObjectB=j
		If 0
			Intersection(CounterIntersections)\x=(Max(*mx\Min,\MaximaX\Min)+Min(*mx\Max,\MaximaX\Max))/2
			Intersection(CounterIntersections)\y=(Max(*my\Min,\MaximaY\Min)+Min(*my\Max,\MaximaY\Max))/2
		Else
			If GetIntersectionAnchor(Max(*mx\Min,\MaximaX\Min),Max(*my\Min,\MaximaY\Min),Min(*mx\Max,\MaximaX\Max),Min(*my\Max,\MaximaY\Max),i,j,@m)
				Intersection(CounterIntersections)\x=m\x
				Intersection(CounterIntersections)\y=m\y
			Else
				Debug "PANIK - keine Überlappung?!"
			EndIf
		EndIf
		CompilerIf #Debug
			Intersection(CounterIntersections)\x1=Max(*mx\Min,\MaximaX\Min)
			Intersection(CounterIntersections)\y1=Max(*my\Min,\MaximaY\Min)
			Intersection(CounterIntersections)\x2=Min(*mx\Max,\MaximaX\Max)
			Intersection(CounterIntersections)\y2=Min(*my\Max,\MaximaY\Max)
		CompilerEndIf

		;Debug GetMedianDistance(Intersection(CounterIntersections)\x,Intersection(CounterIntersections)\y,i)
		;Debug GetMedianDistance(Intersection(CounterIntersections)\x,Intersection(CounterIntersections)\y,j)

		Intersection(CounterIntersections)\AoverB=Bool(GetMedianDistance(Intersection(CounterIntersections)\x,Intersection(CounterIntersections)\y,i) > GetMedianDistance(Intersection(CounterIntersections)\x,Intersection(CounterIntersections)\y,j))

		Protected dx,dy
		dx=Intersection(CounterIntersections)\x
		dy=Intersection(CounterIntersections)\y
		s=Str(j)+IfStr(IntersectPolygon(i,j),"* "," ")+IfStr(Intersection(CounterIntersections)\AoverB,"ok","up")
		Debug "> "+s+"  X:"+Str(*mx\Min)+"-"+Str(*mx\Max)+" : "+Str(\MaximaX\Min)+"-"+Str(\MaximaX\Max)+" Y:"+Str(*my\Min)+"-"+Str(*my\Max)+" : "+Str(\MaximaY\Min)+"-"+Str(\MaximaY\Max)
		; Debug "* ---: "+StrDot(dx)+"|"+StrDot(dy)+", "+StrDot(GetMedianDistance(dx,dy,i))+" > "+StrDot(GetMedianDistance(dx,dy,j))

		CompilerIf #Debug
			If 0
				Debug "a "+DotInfo(i,0)+" - "+DotInfo(j,0)
				Debug "b "+DotInfo(i,1)+" - "+DotInfo(j,1)
				Debug "c "+DotInfo(i,2)+" - "+DotInfo(j,2)
				Debug "d "+DotInfo(i,3)+" - "+DotInfo(j,3)

				; 				Protected n,d
				; 				Protected max1,max2
				; 				;Protected mem1,mem2
				;
				; 				max1=#MaxInteger
				; 				max2=#MaxInteger
				; 				For n=c1von To c1bis
				; 					d=(Dot(n)\_x-dx)*(Dot(n)\_x-dx)+(Dot(n)\_y-dy)*(Dot(n)\_y-dy)
				; 					If d<max1
				; 						max1=d
				; 						mem1=n
				; 					EndIf
				; 				Next n
				; 				For n=c2von To c2bis
				; 					d=(Dot(n)\_x-dx)*(Dot(n)\_x-dx)+(Dot(n)\_y-dy)*(Dot(n)\_y-dy)
				; 					If d<max2
				; 						max2=d
				; 						mem2=n
				; 					EndIf
				; 				Next n
				;
				; 				Debug Str(mem1)+" = "+StrDot(Dot(mem1)\_distance)
				; 				Debug Str(mem2)+" = "+StrDot(Dot(mem2)\_distance)
			EndIf

			Intersection(CounterIntersections)\pinfo="{}"
			If GetPointNearDot(Intersection(CounterIntersections)\x,Intersection(CounterIntersections)\y,i)
				Intersection(CounterIntersections)\pinfo=Str(i)+":"+Str(j)+" "+pointinfo
				di=Dot(0)\_distance
				If GetPointNearDot(Intersection(CounterIntersections)\x,Intersection(CounterIntersections)\y,j)
					Intersection(CounterIntersections)\pinfo+" * "+pointinfo
					dj=Dot(0)\_distance
					n=Bool(di>dj)
					If n<>Intersection(CounterIntersections)\AoverB
						Debug "CHANGE ORDER (to "+IfStr(Intersection(CounterIntersections)\AoverB,"ok","up")+")"
						Intersection(CounterIntersections)\AoverB=n
					EndIf
				EndIf

			EndIf

			; 			n=Bool(Dot(mem1)\_distance<Dot(mem2)\_distance)
			; 			If n<>Intersection(CounterIntersections)\AoverB
			; 				Debug "CHANGE ORDER (to "+IfStr(Intersection(CounterIntersections)\AoverB,"ok","up")+")"
			; 				Intersection(CounterIntersections)\AoverB=n
			; 			EndIf

			Intersection(CounterIntersections)\info="#"+Str(i)+"/"+s+"|"+StrDot(GetMedianDistance(Intersection(CounterIntersections)\x,Intersection(CounterIntersections)\y,i))+"/"+StrDot(GetMedianDistance(Intersection(CounterIntersections)\x,Intersection(CounterIntersections)\y,j))
		CompilerEndIf

		If Intersection(CounterIntersections)\AoverB
			MoveBehind(Intersection(CounterIntersections)\ObjectA,Intersection(CounterIntersections)\ObjectB)
		Else
			MoveBehind(Intersection(CounterIntersections)\ObjectB,Intersection(CounterIntersections)\ObjectA)
		EndIf
		ShowObjects(#Null)

	EndWith

EndProcedure
Procedure.i Intersect(*a.MaximaType,*b.MaximaType)

	If *a\Min >= *b\Max Or *a\Max <= *b\Min
		ProcedureReturn #False
	Else
		ProcedureReturn #True
	EndIf

EndProcedure
Procedure.i CalcMaxima()

	Protected i,j,c,n

	i=0
	While i<CounterObjects
		i+1
		If Object(i)\Visible=#True
			With Object(i)
				;If \Type=#ObjectTypeRectangle
				;Debug GetObjectInfo(i,1)
				\MaximaX\Max=#MinCoordinate
				\MaximaX\Min=#MaxCoordinate
				\MaximaY\Max=#MinCoordinate
				\MaximaY\Min=#MaxCoordinate
				\MaximaZ\Max=#MinCoordinate
				\MaximaZ\Min=#MaxCoordinate

				n=ObjectDots(\Type)
				While n
					n-1
					c=Dot(\Dot[n])\_x
					If \MaximaX\Min>c : \MaximaX\Min=c : EndIf
					If \MaximaX\Max<c : \MaximaX\Max=c : EndIf
					c=Dot(\Dot[n])\_y
					If \MaximaY\Min>c : \MaximaY\Min=c : EndIf
					If \MaximaY\Max<c : \MaximaY\Max=c : EndIf
					c=Dot(\Dot[n])\_distance
					If \MaximaZ\Min>c : \MaximaZ\Min=c : EndIf
					If \MaximaZ\Max<c : \MaximaZ\Max=c : EndIf
				Wend

				;Debug "X: "+\MaximaX\Min+" ... " +\MaximaX\Max
				;Debug "Y: "+\MaximaY\Min+" ... " +\MaximaY\Max
				;Debug "Z: "+\MaximaZ\Min+" ... " +\MaximaZ\Max
				;EndIf
			EndWith
		EndIf

	Wend

EndProcedure
Procedure.i GetIntersections()

	Protected.i i,j,c,n
	Protected.MaximaType mx,my,mz
	Protected s.s

	CounterIntersections=#Null

	i=0
	While i<CounterObjects
		i+1
		If Object(i)\Visible=#True And Object(i)\Type=#ObjectTypeRectangle
			Debug GetObjectInfo(i,1)
			With Object(i)
				mx\Min=\MaximaX\Min
				mx\Max=\MaximaX\Max
				my\Min=\MaximaY\Min
				my\Max=\MaximaY\Max
				mz\Min=\MaximaZ\Min
				mz\Max=\MaximaZ\Max
			EndWith

			j=i
			While j<CounterObjects
				j+1
				If Object(j)\Visible=#True And Object(j)\Type=#ObjectTypeRectangle
					With Object(j)
						If 0
							If Intersect(\MaximaX,mx)
								If Intersect(\MaximaY,my)
									If Intersect(\MaximaZ,mz)
										CreateIntersection(i,j,mx,my)
									EndIf
								EndIf
							EndIf
						Else
							; Debug "Check "+Str(i)+" / "+Str(j)+"..."
							If IntersectPolygon(i,j) Or IntersectPolygon(j,i); wegen 369,571, 352,359, 337,375, 356,588 und 352,555, 595,635, 595,421, 334,343 bzw. Polygon in Polygon
								;If i+j=7
								CreateIntersection(i,j,mx,my)
								;EndIf
							EndIf
						EndIf
					EndWith
				EndIf
			Wend
		EndIf
	Wend

EndProcedure

Procedure.d GetObjectRelation(a,b)

	Protected.i i
	Protected.s s

	Debug "Compare "+Str(a)+" + "+Str(b)

	Debug GetObjectInfo(a)
	Debug GetObjectInfo(b)

EndProcedure

Procedure SetNorm(*m.mat)
	*m\x[0]=1 : *m\y[0]=0 : *m\z[0]=0 : *m\t[0]=0
	*m\x[1]=0 : *m\y[1]=1 : *m\z[1]=0 : *m\t[1]=0
	*m\x[2]=0 : *m\y[2]=0 : *m\z[2]=1 : *m\t[2]=0
	*m\x[3]=0 : *m\y[3]=0 : *m\z[3]=0 : *m\t[3]=1
EndProcedure
Procedure SetTransformation(*m.mat,x.d,y.d,z.d)
	*m\x[0]=1 : *m\y[0]=0 : *m\z[0]=0 : *m\t[0]=0
	*m\x[1]=0 : *m\y[1]=1 : *m\z[1]=0 : *m\t[1]=0
	*m\x[2]=0 : *m\y[2]=0 : *m\z[2]=1 : *m\t[2]=0
	*m\x[3]=x : *m\y[3]=y : *m\z[3]=z : *m\t[3]=1
EndProcedure
Procedure SetCamera(x,y,z.d)
	OptCameraX=x
	OptCameraY=y
	OptCamera=z
	Camera\x[0]=1 : Camera\y[0]=0 : Camera\z[0]=0 : Camera\t[0]=0
	Camera\x[1]=0 : Camera\y[1]=1 : Camera\z[1]=0 : Camera\t[1]=0
	Camera\x[2]=0 : Camera\y[2]=0 : Camera\z[2]=1 : Camera\t[2]=0
	Camera\x[3]=x : Camera\y[3]=y : Camera\z[3]=z : Camera\t[3]=1
EndProcedure
Procedure SetScale(*m.mat,x.d,y.d,z.d)
	*m\x[0]=x : *m\y[0]=0 : *m\z[0]=0 : *m\t[0]=0
	*m\x[1]=0 : *m\y[1]=y : *m\z[1]=0 : *m\t[1]=0
	*m\x[2]=0 : *m\y[2]=0 : *m\z[2]=z : *m\t[2]=0
	*m\x[3]=0 : *m\y[3]=0 : *m\z[3]=0 : *m\t[3]=1
EndProcedure
Procedure SetRotX(*m.mat,angle.d)
	Protected s.d=Sin(angle)
	Protected c.d=Cos(angle)
	*m\x[0]=1 : *m\y[0]=0 : *m\z[0]=0 : *m\t[0]=0
	*m\x[1]=0 : *m\y[1]=c : *m\z[1]=s : *m\t[1]=0
	*m\x[2]=0 : *m\y[2]=-s : *m\z[2]=c : *m\t[2]=0
	*m\x[3]=0 : *m\y[3]=0 : *m\z[3]=0 : *m\t[3]=1
EndProcedure
Procedure SetRotY(*m.mat,angle.d)
	Protected s.d=Sin(angle)
	Protected c.d=Cos(angle)
	*m\x[0]=c : *m\y[0]=0 : *m\z[0]=s : *m\t[0]=0
	*m\x[1]=0 : *m\y[1]=1 : *m\z[1]=0 : *m\t[1]=0
	*m\x[2]=-s : *m\y[2]=0 : *m\z[2]=c : *m\t[2]=0
	*m\x[3]=0 : *m\y[3]=0 : *m\z[3]=0 : *m\t[3]=1
EndProcedure
Procedure SetRotZ(*m.mat,angle.d)
	Protected s.d=Sin(angle)
	Protected c.d=Cos(angle)
	*m\x[0]=c : *m\y[0]=s : *m\z[0]=0 : *m\t[0]=0
	*m\x[1]=-s : *m\y[1]=c : *m\z[1]=0 : *m\t[1]=0
	*m\x[2]=0 : *m\y[2]=0 : *m\z[2]=1 : *m\t[2]=0
	*m\x[3]=0 : *m\y[3]=0 : *m\z[3]=0 : *m\t[3]=1
EndProcedure
Procedure Multiply(*m.mat,*n.mat,*result.mat)

	TempMat\x[0]=*m\x[0]**n\x[0] + *m\x[1]**n\y[0] + *m\x[2]**n\z[0] + *m\x[3]**n\t[0]
	TempMat\y[0]=*m\y[0]**n\x[0] + *m\y[1]**n\y[0] + *m\y[2]**n\z[0] + *m\y[3]**n\t[0]
	TempMat\z[0]=*m\z[0]**n\x[0] + *m\z[1]**n\y[0] + *m\z[2]**n\z[0] + *m\z[3]**n\t[0]
	TempMat\t[0]=*m\t[0]**n\x[0] + *m\t[1]**n\y[0] + *m\t[2]**n\z[0] + *m\t[3]**n\t[0]

	TempMat\x[1]=*m\x[0]**n\x[1] + *m\x[1]**n\y[1] + *m\x[2]**n\z[1] + *m\x[3]**n\t[1]
	TempMat\y[1]=*m\y[0]**n\x[1] + *m\y[1]**n\y[1] + *m\y[2]**n\z[1] + *m\y[3]**n\t[1]
	TempMat\z[1]=*m\z[0]**n\x[1] + *m\z[1]**n\y[1] + *m\z[2]**n\z[1] + *m\z[3]**n\t[1]
	TempMat\t[1]=*m\t[0]**n\x[1] + *m\t[1]**n\y[1] + *m\t[2]**n\z[1] + *m\t[3]**n\t[1]

	TempMat\x[2]=*m\x[0]**n\x[2] + *m\x[1]**n\y[2] + *m\x[2]**n\z[2] + *m\x[3]**n\t[2]
	TempMat\y[2]=*m\y[0]**n\x[2] + *m\y[1]**n\y[2] + *m\y[2]**n\z[2] + *m\y[3]**n\t[2]
	TempMat\z[2]=*m\z[0]**n\x[2] + *m\z[1]**n\y[2] + *m\z[2]**n\z[2] + *m\z[3]**n\t[2]
	TempMat\t[2]=*m\t[0]**n\x[2] + *m\t[1]**n\y[2] + *m\t[2]**n\z[2] + *m\t[3]**n\t[2]

	TempMat\x[3]=*m\x[0]**n\x[3] + *m\x[1]**n\y[3] + *m\x[2]**n\z[3] + *m\x[3]**n\t[3]
	TempMat\y[3]=*m\y[0]**n\x[3] + *m\y[1]**n\y[3] + *m\y[2]**n\z[3] + *m\y[3]**n\t[3]
	TempMat\z[3]=*m\z[0]**n\x[3] + *m\z[1]**n\y[3] + *m\z[2]**n\z[3] + *m\z[3]**n\t[3]
	TempMat\t[3]=*m\t[0]**n\x[3] + *m\t[1]**n\y[3] + *m\t[2]**n\z[3] + *m\t[3]**n\t[3]

	*result\x[0]=TempMat\x[0]
	*result\x[1]=TempMat\x[1]
	*result\x[2]=TempMat\x[2]
	*result\x[3]=TempMat\x[3]
	*result\y[0]=TempMat\y[0]
	*result\y[1]=TempMat\y[1]
	*result\y[2]=TempMat\y[2]
	*result\y[3]=TempMat\y[3]
	*result\z[0]=TempMat\z[0]
	*result\z[1]=TempMat\z[1]
	*result\z[2]=TempMat\z[2]
	*result\z[3]=TempMat\z[3]
	*result\t[0]=TempMat\t[0]
	*result\t[1]=TempMat\t[1]
	*result\t[2]=TempMat\t[2]
	*result\t[3]=TempMat\t[3]

EndProcedure
Procedure MoveObjects(x,y)

	Protected i,n

	While i<=CounterDots
		With Dot(i)
			\x+x
			\z+y
		EndWith
		i+1
	Wend

EndProcedure

Procedure CreatePoint(x.d,y.d,z.d,type=#DotTypeDefault)

	Protected i

	If Setting\Optimizer; 					Punkt in den gespeicherten Punkten suchen...
		i=CounterDots
		While i
			With Dot(i)
				If \x=x And \y=y And \z=z
					Break
				EndIf
			EndWith
			i-1
		Wend
	EndIf

	If i=0 And CounterDots<MaxElements;	neuer Punkt
		CounterDots+1
		i=CounterDots
	EndIf

	With Dot(i);						Koordinaten setzen
		\x=x
		\y=y
		\z=z
		\type=type
	EndWith

	ProcedureReturn i

EndProcedure
Procedure CreateObject(type,a,b,c,d,color,outline=#Null)

	If CounterObjects<MaxElements
		CounterObjects+1

		With Object(CounterObjects)
			\Type=type
			\Dot[0]=a
			\Dot[1]=b
			\Dot[2]=c
			\Dot[3]=d
			\Color=color
			\Outline=outline
			Select type
			Case #ObjectTypeLine,#ObjectTypeMarker
				\Centre=CreatePoint((Dot(a)\x+Dot(b)\x)/2,(Dot(a)\y+Dot(b)\y)/2,(Dot(a)\z+Dot(b)\z)/2,#DotTypeCentreLine)
			Case #ObjectTypeTriangle
				Debug "TRIANGLE"
				;;;\Centre=CreatePoint((Dot(a)\x+Dot(b)\x)/2,(Dot(a)\y+Dot(b)\y)/2,(Dot(a)\z+Dot(b)\z)/2,#TypeCentreTriangle)
			Case #ObjectTypeRectangle
				;Debug "JAU "+Str(CounterPoints)
				\Centre=CreatePoint((Dot(a)\x+Dot(b)\x+Dot(c)\x+Dot(d)\x)/4,(Dot(a)\y+Dot(b)\y+Dot(c)\y+Dot(d)\y)/4,(Dot(a)\z+Dot(b)\z+Dot(c)\z+Dot(d)\z)/4,#DotTypeCentreRectangle)
			Case #ObjectTypeDot
				\Centre=Dot(a)
			EndSelect
		EndWith

		ProcedureReturn CounterObjects
	EndIf

	ProcedureReturn #Null

EndProcedure
Procedure CreateLine(ax.d,ay.d,az.d, bx.d,by.d,bz.d,color.i)

	Protected o,p1,p2

	p1=CreatePoint(ax,ay,az)
	p2=CreatePoint(bx,by,bz)

	o=AddLine(p1,p2,color)

EndProcedure
Procedure CreateMarker(ax.d,ay.d,az.d, bx.d,by.d,bz.d,color.i)

	Protected o,p1,p2

	p1=CreatePoint(ax,ay,az)
	p2=CreatePoint(bx,by,bz)

	o=AddLine(p1,p2,color)
	If o
		With Object(o)
			\Type=#ObjectTypeMarker
			\Info=StrD(GetDotDistance(p1,p2),#MarkerCiphers);	oder mit *Pow(10,#MarkerCiphers) als Integer speichern)
		EndWith
	EndIf

EndProcedure
Procedure CreateBox(ax.d,ay.d,az.d, bx.d,by.d,bz.d,color.i,outline.i=#Null,elements=$FFFFF)

	Protected p1,p2,p3,p4,p5,p6,p7,p8
	Protected x,y

	Enumeration
		#Null
		#ElementSurfaceBottom
		#ElementSurfaceFront
		#ElementSurfaceLeft
		#ElementSurfaceBack
		#ElementSurfaceRight
		#ElementSurfaceTop
		#ElementLineBackBottom
		#ElementLineBackRight
		#ElementLineBackTop
		#ElementLineBackLeft
		#ElementLineFrontBottom
		#ElementLineFrontRight
		#ElementLineFrontTop
		#ElementLineFrontLeft
		#ElementLineBottomLeft
		#ElementLineBottomRight
		#ElementLineTopLeft
		#ElementLineTopRight
	EndEnumeration

	bx+ax
	by+ay
	bz+az

	p1=CreatePoint(ax,ay,az)
	p2=CreatePoint(bx,ay,az)
	p3=CreatePoint(bx,by,az)
	p4=CreatePoint(ax,by,az)

	p5=CreatePoint(ax,ay,bz)
	p6=CreatePoint(bx,ay,bz)
	p7=CreatePoint(bx,by,bz)
	p8=CreatePoint(ax,by,bz)

	; DEBUGGING

	If outline
		If Bit(elements,#ElementLineBackBottom)
			AddLine(p1,p2,outline)
		EndIf
		If Bit(elements,#ElementLineBackRight)
			AddLine(p2,p3,outline)
		EndIf
		If Bit(elements,#ElementLineBackTop)
			AddLine(p3,p4,outline)
		EndIf
		If Bit(elements,#ElementLineBackLeft)
			AddLine(p4,p1,outline)
		EndIf
		If Bit(elements,#ElementLineFrontBottom)
			AddLine(p5,p6,outline)
		EndIf
		If Bit(elements,#ElementLineFrontRight)
			AddLine(p6,p7,outline)
		EndIf
		If Bit(elements,#ElementLineFrontTop)
			AddLine(p7,p8,outline)
		EndIf
		If Bit(elements,#ElementLineFrontLeft)
			AddLine(p8,p5,outline)
		EndIf
		If Bit(elements,#ElementLineBottomLeft)
			AddLine(p1,p5,outline)
		EndIf
		If Bit(elements,#ElementLineBottomRight)
			AddLine(p2,p6,outline)
		EndIf
		If Bit(elements,#ElementLineTopRight)
			AddLine(p3,p7,outline)
		EndIf
		If Bit(elements,#ElementLineTopLeft)
			AddLine(p4,p8,outline)
		EndIf
	EndIf

	#DebugPoints=1;6

	If Bit(elements,#ElementSurfaceBack)
		AddRectangle(p4,p3,p2,p1,color,outline);	Uhrzeigersinn...
	EndIf
	If Bit(elements,#ElementSurfaceBottom)
		AddRectangle(p1,p2,p6,p5,color,outline)
	EndIf
	If Bit(elements,#ElementSurfaceRight)
		If #Debug And CounterObjects=2; 3
			AddRectangle(p2,p3,p7,p6,color|$80,outline)
			; 			c1von=CounterDots
			; 			For x=0 To #DebugPoints
			; 				For y=0 To #DebugPoints
			; 					CreatePoint(Dot(p2)\x,Dot(p2)\y+(Dot(p3)\y-Dot(p2)\y)*y/#DebugPoints,Dot(p3)\z+(Dot(p7)\z-Dot(p3)\z)*x/#DebugPoints)
			; 				Next y
			; 			Next x
			; 			c1bis=CounterDots
		Else
			AddRectangle(p2,p3,p7,p6,color,outline)
		EndIf
	EndIf
	If Bit(elements,#ElementSurfaceTop)
		AddRectangle(p3,p4,p8,p7,color,outline)
	EndIf
	If Bit(elements,#ElementSurfaceLeft)
		AddRectangle(p4,p1,p5,p8,color,outline)
	EndIf
	If Bit(elements,#ElementSurfaceFront)
		Debug CounterObjects
		If #Debug And CounterObjects=1; 2
			AddRectangle(p5,p6,p7,p8,color|$C000,outline)
			; 			c2von=CounterDots
			; 			For x=0 To #DebugPoints
			; 				For y=0 To #DebugPoints
			; 					CreatePoint(Dot(p5)\x+(Dot(p6)\x-Dot(p5)\x)*x/#DebugPoints,Dot(p6)\y+(Dot(p7)\y-Dot(p6)\y)*y/#DebugPoints,Dot(p6)\z)
			; 				Next y
			; 			Next x
			; 			c2bis=CounterDots
		Else
			AddRectangle(p5,p6,p7,p8,color,outline)
		EndIf
	EndIf


EndProcedure
Procedure CreatePyramid(ax.d,ay.d,az.d, bx.d,by.d,bz.d, height.d, color.i,outline.i=#Null)

	Protected p1,p2,p3,p4,p5

	bx+ax
	by+ay
	bz+az

	p1=CreatePoint(ax,ay,az)
	p2=CreatePoint(bx,ay,az)
	p3=CreatePoint(bx,by,az)
	p4=CreatePoint(ax,by,az)

	p5=CreatePoint(ax,ay,bz);**** Mittelpunkt verschoben um Höhe

	If outline
		AddLine(p1,p2,outline)
		AddLine(p2,p3,outline)
		AddLine(p3,p4,outline)
		AddLine(p4,p1,outline)

		AddLine(p1,p5,outline)
		AddLine(p2,p5,outline)
		AddLine(p3,p5,outline)
		AddLine(p4,p5,outline)
	EndIf

	AddRectangle(p4,p3,p2,p1,color,outline);	Uhrzeigersinn...

	AddTriangle(p1,p2,p5,color,outline)
	AddTriangle(p2,p3,p5,color,outline)
	AddTriangle(p3,p4,p5,color,outline)
	AddTriangle(p4,p1,p5,color,outline)


EndProcedure
Procedure Redraw()

	Protected.i i,n,m
	Protected.i color
	Protected.d x,y,z
	Protected.i x0,y0,x1,y1,x2,y2
	Protected.s s
	Protected.d angle
	Protected.i ObjectsShown, ObjectsHidden

	Protected FillMode
	Protected.d LineMode

	StartVectorDrawing(CanvasVectorOutput(#Canvas))
	VectorFont(FontID(0))
	;VectorSourceColor($C0FFFFFF)
	VectorSourceColor(#ColorPaper)
	FillVectorOutput()

	FillMode=Setting\ModeFill*$FF000000
	LineMode=Setting\ModeLine+0.8


	; --- Oberflächen ------------------------------------------------------------------------------

	If Setting\ShowSurface
		While i<CounterObjects
			i+1
			n=Sorter(i)\Object
			With Object(n)
				Select \type
				Case #ObjectTypeRectangle
					If \Visible Or Setting\ShowHidden
						ObjectsShown+1
						MovePathCursor(Dot(\Dot[0])\_x,Dot(\Dot[0])\_y)
						AddPathLine(Dot(\Dot[1])\_x,Dot(\Dot[1])\_y)
						AddPathLine(Dot(\Dot[2])\_x,Dot(\Dot[2])\_y)
						AddPathLine(Dot(\Dot[3])\_x,Dot(\Dot[3])\_y)
						ClosePath()
						VectorSourceColor(\Color|FillMode)
						FillPath(#PB_Path_Preserve)
						VectorSourceColor(\Outline)
						StrokePath(LineMode,#PB_Path_RoundCorner)

					Else
						ObjectsHidden+1
					EndIf

				Case #ObjectTypeMarker
					If Setting\ShowMarker
						VectorSourceColor(\Outline)
						x1=Dot(\Dot[0])\_x
						y1=Dot(\Dot[0])\_y
						x2=Dot(\Dot[1])\_x
						y2=Dot(\Dot[1])\_y
						x0=Dot(\Centre)\_x
						y0=Dot(\Centre)\_y

						angle=GetAngle(x1,y1,x2,y2,#Null)
						MovePathCursor(x1,y1)
						AddPathLine(x2,y2)
						StrokePath(LineMode,#PB_Path_RoundCorner)

						MovePathCursor(x1,y1)
						angle+#MarkerWidth
						AddPathLine(x1+Cos(angle)*#MarkerLength,y1+Sin(angle)*#MarkerLength)
						angle-#MarkerWidth*2
						AddPathLine(x1+Cos(angle)*#MarkerLength,y1+Sin(angle)*#MarkerLength)
						angle+#MarkerWidth
						AddPathLine(x1,y1)
						StrokePath(1,#PB_Path_RoundCorner|#PB_Path_Preserve)
						FillPath()

						MovePathCursor(x2,y2)
						angle+#MarkerWidth
						AddPathLine(x2-Cos(angle)*#MarkerLength,y2-Sin(angle)*#MarkerLength)
						angle-#MarkerWidth*2
						AddPathLine(x2-Cos(angle)*#MarkerLength,y2-Sin(angle)*#MarkerLength)
						angle+#MarkerWidth
						AddPathLine(x2,y2)
						StrokePath(1,#PB_Path_RoundCorner|#PB_Path_Preserve)
						FillPath()

						angle=Degree(GetAngle(x1,y1,x2,y2,#True))
						RotateCoordinates(x0,y0,angle)
						MovePathCursor(x0-VectorTextWidth(\Info)/2,y0-VectorTextHeight(\Info)/2)
						AddPathText(\Info)
						VectorSourceColor(#ColorPaper)
						StrokePath(5,#PB_Path_RoundCorner|#PB_Path_Preserve)
						VectorSourceColor(\Outline)
						FillPath()
						RotateCoordinates(x0,y0,-angle)
					EndIf

				EndSelect
			EndWith
		Wend
	EndIf


	; --- Lines ------------------------------------------------------------------------------

	If Setting\ShowOutline
		LineMode=Setting\ModeLine+1
		n=0
		While n<CounterObjects
			n+1
			With Object(n)
				Select \type
				Case #ObjectTypeLine
					If \Outline
						MovePathCursor(Dot(\Dot[0])\_x,Dot(\Dot[0])\_y)
						AddPathLine(Dot(\Dot[1])\_x,Dot(\Dot[1])\_y)
						VectorSourceColor(\Outline)
						StrokePath(LineMode,#PB_Path_RoundEnd)
					EndIf
				EndSelect
			EndWith
		Wend
	EndIf


	; --- Dot Information ------------------------------------------------------------------------------
	If Setting\ShowPoints
		x=120
		y=20+Setting\ShowInformation*60
		z=1
		i=0

		n=0
		While n<CounterDots
			n+1

			With Dot(n)
				If \Type=#DotTypeCentreRectangle Or Setting\ShowDebugInformation=#Null
					i+1
					color=$A0<<(8*i%3)
					VectorSourceColor($FF000000|color)
					AddPathCircle(Dot(n)\_x,Dot(n)\_y,3)
					FillPath()
					MovePathCursor(Dot(n)\_x,Dot(n)\_y)
					AddPathLine(x,y)
					; 					If mem1+mem2 And n<>mem1 And n<>mem2
					; 						VectorSourceColor($80000000|color)
					; 					EndIf
					StrokePath(1)
					; 					If n=mem1 Or n=mem2
					; 						VectorSourceColor($FF00FFFF)
					; 						AddPathBox(x-z*VectorTextWidth(s),y-VectorTextHeight(s)/2,VectorTextWidth(s),VectorTextHeight(s))
					; 						FillPath()
					; 						VectorSourceColor($FF000000|color)
					; 					EndIf

					s=Str(n)+": "+StrF(Dot(n)\_distance,2)
					MovePathCursor(x-z*VectorTextWidth(s),y-VectorTextHeight(s)/2)
					DrawVectorText(s)

					y+14
					If y>#WY-30
						x=#WX-100
						y=20
						z=0
					EndIf
				EndIf
			EndWith
		Wend
	EndIf


	; --- Object Information ------------------------------------------------------------------------------
	If Setting\ShowObjectInformation
		x=240
		y=20+Setting\ShowInformation*60
		z=1
		i=0

		n=0
		While n<CounterObjects
			n+1

			With Object(n)
				If \Visible And Bool(\Type=#ObjectTypeRectangle Or Setting\ShowDebugInformation=0)
					i+1
					VectorSourceColor($FF000000+$A0<<(8*i%3))
					AddPathCircle(Dot(\Centre)\_x,Dot(\Centre)\_y,3)
					FillPath()
					If Setting\ShowDebugInformation=0
						MovePathCursor(Dot(\Centre)\_x+6,Dot(\Centre)\_y-8)
						AddPathText(Str(n))
						VectorSourceColor($FFFFFFFF)
						StrokePath(3,#PB_Path_Preserve|#PB_Path_RoundCorner)
						VectorSourceColor($FF000000+$A0<<(8*i%3))
						FillPath()
					EndIf
					MovePathCursor(Dot(\Centre)\_x,Dot(\Centre)\_y)
					AddPathLine(x,y)
					StrokePath(1)
					s="#"+Str(n)+": "+GetObjectInfo(n)
					MovePathCursor(x-z*VectorTextWidth(s),y-VectorTextHeight(s)/2)
					DrawVectorText(s)
					y+14
					If y>#WY-30
						x=#WX-250
						y=20
						z=0
					EndIf
				EndIf
			EndWith
		Wend
	EndIf


	; --- Surface Information ------------------------------------------------------------------------------
	If Setting\ShowDebugInformation
		i=0
		While i<CounterObjects
			i+1
			With Object(i)
				Select \type
				Case #ObjectTypeRectangle
					If \Visible Or Setting\ShowHidden
						s="#"+Str(i)+":"+Str(Dot(\Centre)\_distance)
						;s=Str(Distance(\Centre))
						MovePathCursor(Dot(\Centre)\_x-VectorTextWidth(s)/2,Dot(\Centre)\_y-VectorTextHeight(s)/2)
						AddPathText(s)
						VectorSourceColor($FFFFFFFF)
						StrokePath(3,#PB_Path_Preserve|#PB_Path_RoundCorner)
						VectorSourceColor($FF000000)
						FillPath()
					EndIf
				EndSelect
			EndWith
		Wend

		If Setting\ShowObjectInformation
			i=0
			While i<CounterIntersections
				i+1
				With Intersection(i)
					VectorSourceColor($FF3030FF)
					CompilerIf #Debug
						AddPathRectangle(\x1,\y1,\x2,\y2)
						StrokePath(2)
						x=\x+60+Random(30)
						y=\y+Random(50)-25
						MovePathCursor(x,y)
						AddPathLine(\x,\y)
						VectorSourceColor($FFFFFFFF)
						StrokePath(3,#PB_Path_Preserve|#PB_Path_RoundEnd)
						VectorSourceColor($FF000090)
						StrokePath(1)
						MovePathCursor(x+5,y-5)
						AddPathText(\info)
						VectorSourceColor($FFFFFFFF)
						StrokePath(4,#PB_Path_Preserve|#PB_Path_RoundCorner)
						VectorSourceColor($FF000090)
						FillPath()
					CompilerEndIf
					AddPathCircle(\x,\y,2)
					FillPath()
				EndWith
			Wend
		EndIf

	EndIf


	; --- Intersection Information ------------------------------------------------------------------------------
	If Setting\ShowIntersectionInformation
		i=0
		While i<CounterIntersections
			i+1
			With Intersection(i)
				x=\x-OffsetX
				y=\y-OffsetY
				x1=OffsetX+Cos(ATan2(x,y))*450
				y1=OffsetY+Sin(ATan2(x,y))*400
				MovePathCursor(\x,\y)
				AddPathLine(x1,y1)
				VectorSourceColor($a0FFFFFF)
				StrokePath(3,#PB_Path_Preserve|#PB_Path_RoundCorner)
				VectorSourceColor($F00000F0)
				StrokePath(1,#PB_Path_RoundCorner)

				AddPathBox(\x-1,\y-1,3,3)
				VectorSourceColor($FFFFFFFF)
				StrokePath(3,#PB_Path_Preserve|#PB_Path_RoundCorner)
				VectorSourceColor($FF000000)
				FillPath()

				AddPathBox(\x1,\y1,\x2-\x1,\y2-\y1)
				VectorSourceColor($50FFFFFF)
				StrokePath(3,#PB_Path_Preserve|#PB_Path_RoundCorner)
				VectorSourceColor($C00000F0)
				StrokePath(1,#PB_Path_RoundCorner)

				If Intersection(i)\ObjectA=18 Or Intersection(i)\ObjectB=18
					GetIntersectionAnchor(\x1,\y1,\x2,\y2,Intersection(i)\ObjectA,Intersection(i)\ObjectB,#Null,#True)
				EndIf

				MovePathCursor(x1-VectorTextWidth(\pinfo)/2,y1-10)
				AddPathText(\pinfo)
				VectorSourceColor($a0FFFFFF)
				StrokePath(3,#PB_Path_Preserve|#PB_Path_RoundCorner)
				VectorSourceColor($F00000F0)
				FillPath()

				s=StringField(\pinfo,2,"(")
				x=Val(s)
				s=StringField(s,2,",")
				y=Val(s)
				If x And y
					AddPathBox(x-1,y-1,3,3)
					VectorSourceColor($FFFFFFFF)
					StrokePath(3,#PB_Path_Preserve|#PB_Path_RoundCorner)
					VectorSourceColor($FF00F000)
					FillPath()
				EndIf
				s=StringField(\pinfo,3,"(")
				x=Val(s)
				s=StringField(s,2,",")
				y=Val(s)
				If x And y
					AddPathBox(x-1,y-1,3,3)
					VectorSourceColor($FFFFFFFF)
					StrokePath(3,#PB_Path_Preserve|#PB_Path_RoundCorner)
					VectorSourceColor($FFF000F0)
					FillPath()
				EndIf

			EndWith
		Wend

	EndIf


	; --- General Information ------------------------------------------------------------------------------
	If Setting\ShowInformation
		VectorSourceColor($FF000080)
		MovePathCursor(20,20)
		DrawVectorText("Viewpoint: "+Str(ViewX)+" | "+Str(ViewY)+" | "+Str(ViewZ)+",  Angles "+Str(Degree(AngleX))+"° "+Str(Degree(AngleY))+"° "+Str(Degree(AngleZ))+"°, Offset "+Str(Dot(0)\x)+"|"+Str(Dot(0)\z))
		MovePathCursor(20,35)
		DrawVectorText("Camera: "+Str(OptCameraX)+" | "+Str(OptCameraY)+" | "+Str(OptCamera)+",  Mode: "+StringField("Intersections.Center.First.Last :(",Setting\ModeCalculation+1,"."))
		MovePathCursor(20,50)
		DrawVectorText("Objects: "+Str(ObjectsShown)+" shown, "+Str(ObjectsHidden)+" hidden  "+sort1+" >>"+sort2)
	EndIf


	StopVectorDrawing()

EndProcedure
Procedure RecalcDot(i)

	Protected.d Scale

	With Dot(i)
		ViewX = \x*calc\x[0] + \y*calc\x[1] + \z*calc\x[2] + calc\x[3]
		ViewY = \x*calc\y[0] + \y*calc\y[1] + \z*calc\y[2] + calc\y[3]
		ViewZ = \x*calc\z[0] + \y*calc\z[1] + \z*calc\z[2] + calc\z[3]

		Scale=OptCamera/ViewZ
		\_x=ViewX*Scale*RealZoomFactor+OffsetX
		\_y=ViewY*Scale*RealZoomFactor+OffsetY
		\_distance=Scale*1000000
		;\_distance=Int(Scale*10000000)*10000-(Abs(\_x-OffsetX)+Abs(\_y-OffsetY))/100
		;\_rb=(Opt3DDistance+OptZoomFactor)/(ViewZ+32)
	EndWith

EndProcedure
Procedure Recalc(mode)

	Protected i

	Multiply(@Camera,@Matrix,@Calc)
	DebugMat

	RealZoomFactor=Setting\ZoomFactor * #ZoomScale

	For i=1 To CounterDots
		RecalcDot(i)
	Next i


	For i=1 To CounterObjects
		With Object(i)
			Select \Type
			Case #ObjectTypeRectangle
				\Visible=Bool((Dot(\Dot[3])\_x-Dot(\Dot[0])\_x)*(Dot(\Dot[1])\_y-Dot(\Dot[0])\_y)-(Dot(\Dot[3])\_y-Dot(\Dot[0])\_y)*(Dot(\Dot[1])\_x-Dot(\Dot[0])\_x)>0)
			Case #ObjectTypeTriangle
			Default
				\Visible=#True
			EndSelect
		EndWith
	Next i

	CalcMaxima()

	For i=1 To CounterObjects
		With Sorter(i)
			\Object=i
			Select Setting\ModeCalculation
			Case #CalculationModeIntersection
				\Distance=Dot(Object(i)\Centre)\_distance
			Case #CalculationModeCenter
				\Distance=Dot(Object(i)\Centre)\_distance;			Distanz Mittelpunkt
			Case #CalculationModeFirstPoint
				\Distance=Object(i)\MaximaZ\Min;					nähester Punkt
			Case #CalculationModeLastPoint
				\Distance=Object(i)\MaximaZ\Max;					entferntester Punkt
			EndSelect
		EndWith
	Next i

	SortStructuredArray(Sorter(),#PB_Sort_Ascending,OffsetOf(SorterType\Distance),TypeOf(SorterType\Distance),1,CounterObjects)
	For i=1 To CounterObjects
		Sorter(Sorter(i)\Object)\Reverse=i
	Next i

	sort1=""
	For i=1 To CounterObjects
		sort1+" "+Str(Sorter(i)\Object)
	Next i


	; 	Protected n
	; 	DataSection
	; 		Data.i 1,2,12,9,10,6,3,4,5,7,8,11
	; 	EndDataSection
	; 	For i=1 To 12
	; 		Read.i n
	; 		Sorter(n)\Reverse=i
	; 	Next i
	;
	; 	SortStructuredArray(Sorter(),#PB_Sort_Descending,OffsetOf(SorterType\Reverse),TypeOf(SorterType\Distance),1,CounterObjects)
	; 	For i=1 To CounterObjects
	; 		Sorter(Sorter(i)\Object)\Reverse=i
	; 	Next i
	;
	; 	With Sorter(9)
	; 		Sorter(0)\Distance=\Distance
	; 		Sorter(0)\Object=\Object
	; 		Sorter(0)\Reverse=\Reverse
	; 		\Distance=Sorter(11)\Distance
	; 		\Object=Sorter(11)\Object
	; 		\Reverse=Sorter(11)\Reverse
	; 	EndWith
	; 	With Sorter(11)
	; 		\Distance=Sorter(0)\Distance
	; 		\Object=Sorter(0)\Object
	; 		\Reverse=Sorter(0)\Reverse
	; 	EndWith

	If Setting\ModeCalculation=#CalculationModeIntersection
		GetIntersections()
	EndIf

	sort2=""
	For i=1 To CounterObjects
		sort2+" "+Str(Sorter(i)\Object)
	Next i

	;GetObjectRelation(13,14)
	;ShowObjects()

	If mode
		Redraw()
	EndIf

EndProcedure
Procedure Rotation()

	;Protected.mat test

	SetRotX(@RotXMat,AngleY)
	SetRotZ(@RotYMat,AngleX)
	SetRotY(@RotZMat,AngleZ)

	;SetTransformation(@test,0,0,0)
	;Multiply(@RotXMat,@test,@RotXMat)
	;Multiply(@RotYMat,@test,@RotYMat)
	;Multiply(@RotZMat,@test,@RotZMat)

	Multiply(@RotXMat,@RotYMat,@Matrix)
	Multiply(@Matrix,@RotZMat,@Matrix)

	;SetTransformation(@test,50,50,50)
	;Multiply(@Matrix,@test,@Matrix)

	Recalc(#True)

EndProcedure
Procedure ZoomPlus()

	If Setting\ZoomFactor<60
		Setting\ZoomFactor+1
		Recalc(#True)
	ElseIf Setting\ZoomFactor<150
		Setting\ZoomFactor+2
		Recalc(#True)
	ElseIf Setting\ZoomFactor<300
		Setting\ZoomFactor+5
		Recalc(#True)
	EndIf

EndProcedure
Procedure ZoomMinus()

	If Setting\ZoomFactor>150
		Setting\ZoomFactor-5
		Recalc(#True)
	ElseIf Setting\ZoomFactor>60
		Setting\ZoomFactor-2
		Recalc(#True)
	ElseIf Setting\ZoomFactor>1
		Setting\ZoomFactor-1
		Recalc(#True)
	EndIf

EndProcedure
Procedure DoObjects(demo)

	Protected Surface
	Protected Outline
	Protected Elements=$FFFFF
	Protected Bug

	Select demo

	Case 0
		CreateBox(0,0,0, 100,100,100,$E0f0a060,$80000000)
		CreateBox(200,0,0, 100,100,100,$E0f060a0,$80000000)
		CreateBox(0,200,0, 100,100,100,$E0c0a0f0,$80000000)
		CreateBox(0,0,200, 100,100,100,$E0c0f0a0,$80000000)

	Case 1
		Bug=%111111
		;Bug=%100*1
		Outline=$80000000
		;Outline=$00000000
		Elements=$fffff
		;Elements=$32
		;Elements=$12
		Surface=$C0f0a060

		CreateBox(0,0,0, 100,100,100,Surface,Outline,Elements)
		If Bit(Bug,1)	:	CreateBox(0,0,105, 10,100,10,$80a0f060,Outline,Elements)	: EndIf
		If Bit(Bug,2)	:	CreateBox(18,0,105, 10,85,10,$80a060f0,Outline,Elements)	: EndIf
		If Bit(Bug,3)	:	CreateBox(36,0,105, 10,70,10,$80f0f060,Outline,Elements)	: EndIf
		If Bit(Bug,4)	:	CreateBox(54,0,105, 10,55,10,$8060a0f0,Outline,Elements)	: EndIf
		If Bit(Bug,5)	:	CreateBox(72,0,105, 10,40,10,$8060f0f0,Outline,Elements)	: EndIf
		If Bit(Bug,6)	:	CreateBox(90,0,105, 10,25,10,$80f060a0,Outline,Elements)	: EndIf
		;CreateBox(120,0,0, 80,100,80,$E0f060a0,Outline,Elements)
		;CreateBox(0,0,120, 60,100,60,$E0c0a0f0,Outline,Elements)
		;CreateBox(120,0,120, 40,100,40,$E0c0f0a0,Outline,Elements)
		;CreateBox(105,0,105, 10,100,10,$10a0f060,Outline,Elements)
		CreateMarker(0,0,130, 100,0,130, $FFFF0000)

	Case 2
		; unten
		CreateBox(0,0,0, 62,50,60, #ColorFront,$40000000)
		CreateBox(63,0,0, 62,50,60, #ColorFront,$40000000)
		CreateBox(126,0,0, 62,50,60, #ColorFront,$40000000)
		CreateBox(189,0,0, 62,50,40, #ColorFront,$40000000)
		; mittig
		CreateBox(0,51,0, 62,25,60, #ColorFront,$40000000)
		CreateBox(63,51,0, 62,24,60, #ColorFront,$40000000)
		CreateBox(126,51,0, 62,24,60, #ColorFront,$40000000)
		CreateBox(189,51,0, 62,25,40, #ColorFront,$40000000)
		; links/rechts
		CreateBox(0,77,0, 62,130,60, #ColorFront,$40000000)
		CreateBox(189,77,0, 62,130,40, #ColorFront,$40000000)
		; oben
		CreateBox(0,208,0, 62,50,60, #ColorFront,$40000000)
		CreateBox(63,208,0, 62,50,40, #ColorFront,$40000000)
		CreateBox(126,208,0, 62,50,40, #ColorFront,$40000000)
		CreateBox(189,208,0, 62,50,40, #ColorFront,$40000000)
		; Platten
		CreateBox(62,77,0, 2,130,60, #ColorWood,$40000000)
		CreateBox(62,206,40, 2,50,20, #ColorWood,$40000000)
		CreateBox(62,206,0, 125,2,42, #ColorWood,$40000000)
		CreateBox(62,76,0, 125,2,60, #ColorWood,$40000000)
		CreateBox(187,0,40, 2,76,20, #ColorWood,$40000000)
		CreateBox(187,76,0, 2,131,40, #ColorWood,$40000000)
		; Marker
		CreateMarker(0,0,100, 62,0,100, #ColorDistance)
		CreateMarker(0,0,80, 251,0,80, #ColorDistance)
		CreateMarker(-30,0,0, -30,257,0, #ColorDistance)
		CreateMarker(270,0,0, 270,0,40, #ColorDistance)
		CreateMarker(290,0,0, 290,0,60, #ColorDistance)

	EndSelect

EndProcedure
Procedure Main()

	Protected x,y,n

	LoadFont(0,"Segoe UI",8)

	OpenWindow(#Win,8,8,#WX,#WY,"Cursor-Keys, Zoom +/-     Options: O=Outline S=Surfaces, L=Lines     Modes: H=Hide, F=Fill, R=Rotation, C=Depth     Other: P=Perspective, B,D,I,J,N=Debugging")
	CanvasGadget(#Canvas,0,0,#WX,#WY)

	AddKeyboardShortcut(#Win,#PB_Shortcut_Left|#PB_Shortcut_Shift,#ShiftLeft)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Right|#PB_Shortcut_Shift,#ShiftRight)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Up|#PB_Shortcut_Shift,#ShiftUp)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Down|#PB_Shortcut_Shift,#ShiftDown)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Left,#RotateLeft)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Right,#RotateRight)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Up,#RotateUp)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Down,#RotateDown)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Back,#ResetView)
	AddKeyboardShortcut(#Win,#PB_Shortcut_B,#ToggleObjectInformation)
	AddKeyboardShortcut(#Win,#PB_Shortcut_C,#CalculationMode)
	AddKeyboardShortcut(#Win,#PB_Shortcut_C|#PB_Shortcut_Shift,#CalculationMode)
	AddKeyboardShortcut(#Win,#PB_Shortcut_D,#TogglePoints)
	AddKeyboardShortcut(#Win,#PB_Shortcut_F,#ToggleFill)
	AddKeyboardShortcut(#Win,#PB_Shortcut_H,#ToggleHidden)
	AddKeyboardShortcut(#Win,#PB_Shortcut_I,#ToggleInformation)
	AddKeyboardShortcut(#Win,#PB_Shortcut_J,#ToggleDebugInformation)
	AddKeyboardShortcut(#Win,#PB_Shortcut_L,#ToggleLine)
	AddKeyboardShortcut(#Win,#PB_Shortcut_M,#ToggleMarker)
	AddKeyboardShortcut(#Win,#PB_Shortcut_N,#ToggleIntersection)
	AddKeyboardShortcut(#Win,#PB_Shortcut_O,#ToggleOutline)
	AddKeyboardShortcut(#Win,#PB_Shortcut_P,#PerspectivePlus)
	AddKeyboardShortcut(#Win,#PB_Shortcut_P|#PB_Shortcut_Shift,#PerspectiveMinus)
	AddKeyboardShortcut(#Win,#PB_Shortcut_R,#ToggleRotation)
	AddKeyboardShortcut(#Win,#PB_Shortcut_S,#ToggleSurface)
	AddKeyboardShortcut(#Win,#PB_Shortcut_X,#MoveRight)
	AddKeyboardShortcut(#Win,#PB_Shortcut_X|#PB_Shortcut_Shift,#MoveLeft)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Y,#MoveUp)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Y|#PB_Shortcut_Shift,#MoveDown)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Z,#ZoomPlus)
	AddKeyboardShortcut(#Win,#PB_Shortcut_Z|#PB_Shortcut_Shift,#ZoomMinus)

	; ------------------------------------------------------------------------------------

	DoObjects(1)

	; ------------------------------------------------------------------------------------

	OptCameraX=-100
	OptCameraY=50
	OptCamera=1000
	AngleX=Radian(0)
	AngleY=Radian(-170)
	AngleZ=Radian(30)

	If 0
		OptCameraX=-50
		OptCameraY=-10
		OptCamera=1000
		AngleX=Radian(0)
		AngleY=Radian(-140)
		AngleZ=Radian(30)
		Setting\ZoomFactor*2
	EndIf

	If 0
		OptCameraX=0
		OptCameraY=-60
		OptCamera=1000
		AngleX=Radian(0)
		AngleY=Radian(250)
		AngleZ=Radian(40)
		Setting\ZoomFactor*2
	EndIf


	SetCamera(OptCameraX,OptCameraY,OptCamera)
	SetNorm(@Matrix)
	Rotation()

	; ------------------------
	If 0
		x=502
		y=616
		n=2;Bool(GetKeyState_(#VK_SHIFT)&128)+2
		;StartDrawing(CanvasOutput(#Canvas))
		If GetPointNearDot(x,y,n); Dot(0)
			StartDrawing(CanvasOutput(#Canvas))
			DrawingMode(#PB_2DDrawing_Outlined)
			Box(x-5,y-5,12,12,#Black)
			DrawingMode(#PB_2DDrawing_Default)
			DrawText(#WX-100,0,StrDot(Dot(0)\_distance)+"  ",#Red,#White)
		EndIf
		DrawText(0,0,Str(x)+" | "+Str(y)+"    ",#Black,#White)
		ShowDot(0)
		StopDrawing()
	EndIf
	; ------------------------

	Repeat
		Select WaitWindowEvent()
		Case #PB_Event_Gadget,#PB_Event_Menu
			Select EventGadget()
			Case #Canvas
				If EventType()=#PB_EventType_MouseMove
					x=GetGadgetAttribute(#Canvas,#PB_Canvas_MouseX)
					y=GetGadgetAttribute(#Canvas,#PB_Canvas_MouseY)
					StartDrawing(CanvasOutput(#Canvas))
					n=Bool(GetKeyState_(#VK_SHIFT)&128)+2
					If GetPointNearDot(x,y,n); Dot(0)
						Box(x,y,2,2,#Red)
						DrawText(#WX-100,(n-2)*20,StrDot(Dot(0)\_distance)+"  ",#Red,#White)
					EndIf
					DrawText(0,0,Str(x)+" | "+Str(y)+"    ",#Black,#White)
					ShowDot(0)
					StopDrawing()
				EndIf
			Case #ShiftLeft
				SetCamera(OptCameraX-30,OptCameraY,OptCamera)
				Recalc(#True)
			Case #ShiftRight
				SetCamera(OptCameraX+30,OptCameraY,OptCamera)
				Recalc(#True)
			Case #ShiftUp
				SetCamera(OptCameraX,OptCameraY-30,OptCamera)
				Recalc(#True)
			Case #ShiftDown
				SetCamera(OptCameraX,OptCameraY+30,OptCamera)
				Recalc(#True)
			Case #MoveLeft
				MoveObjects(-10,0)
				Recalc(#True)
			Case #MoveRight
				MoveObjects(10,0)
				Recalc(#True)
			Case #MoveUp
				MoveObjects(0,10)
				Recalc(#True)
			Case #MoveDown
				MoveObjects(0,-10)
				Recalc(#True)
			Case #RotateLeft
				If Setting\ModeRotation
					AngleZ-#PiTeil
					If AngleZ<0 : AngleZ+#ZweiPi : EndIf
				Else
					AngleX-#PiTeil
					If AngleX<0 : AngleX+#ZweiPi : EndIf
				EndIf
				Rotation()
			Case #RotateRight
				If Setting\ModeRotation
					AngleZ+#PiTeil
					If AngleZ>#ZweiPi : AngleZ-#ZweiPi : EndIf
				Else
					AngleX+#PiTeil
					If AngleX>#ZweiPi : AngleX-#ZweiPi : EndIf
				EndIf
				Rotation()
			Case #RotateUp
				AngleY-#PiTeil
				Rotation()
			Case #RotateDown
				AngleY+#PiTeil
				Rotation()
			Case #ToggleOutline
				Setting\ShowOutline!1
				Redraw()
			Case #ToggleSurface
				Setting\ShowSurface!1
				Redraw()
			Case #TogglePoints
				Setting\ShowPoints!1
				Setting\ShowObjectInformation*Bool(Setting\ShowPoints=0)
				Redraw()
			Case #ToggleHidden
				Setting\ShowHidden!1
				Redraw()
			Case #CalculationMode
				Setting\ModeCalculation=(Setting\ModeCalculation+1+((GetKeyState_(#VK_SHIFT)>>6)&2))&3
				Recalc(#True)
			Case #ToggleInformation
				Setting\ShowInformation!1
				Redraw()
			Case #ToggleDebugInformation
				Setting\ShowDebugInformation!1
				Redraw()
			Case #ToggleObjectInformation
				Setting\ShowObjectInformation!1
				Setting\ShowPoints*Bool(Setting\ShowObjectInformation=0)
				Redraw()
			Case #ToggleFill
				Setting\ModeFill!1
				Redraw()
			Case #ToggleLine
				Setting\ModeLine!1
				Redraw()
			Case #ToggleMarker
				Setting\ShowMarker!1
				Redraw()
			Case #ToggleIntersection
				Setting\ShowIntersectionInformation!1
				Redraw()
			Case #ToggleRotation
				Setting\ModeRotation!1
			Case #PerspectivePlus
				If OptCamera>300
					SetCamera(OptCameraX,OptCameraY,OptCamera-50)
					Recalc(#True)
				EndIf
			Case  #PerspectiveMinus
				If OptCamera<3000
					SetCamera(OptCameraX,OptCameraY,OptCamera+50)
					Recalc(#True)
				EndIf
			Case #ResetView
				AngleX=0 : AngleY=0 : AngleZ=0
				ViewX=0  : ViewY=0  : ViewZ=0
				SetCamera(0,0,1000)
				SetNorm(@Matrix)
				Rotation()
				Recalc(#True)
			Case #ZoomPlus
				ZoomPlus()
			Case #ZoomMinus
				ZoomMinus()

			EndSelect

		Case #PB_Event_CloseWindow
			End

		Case #WM_CHAR
			Select EventwParam()
			Case '+'
				ZoomPlus()
			Case '-'
				ZoomMinus()
			EndSelect

		EndSelect
	ForEver

EndProcedure

Main()
End
Post Reply