Graphics 800,600,32,2
SetBuffer BackBuffer()


Type Dot
Field x,y,z
Field selected
End Type


Const PUNKTE=1
Const LINIEN=2


Global selectionmode=PUNKTE

Global mouse_hit=0
Global mouse_hit_x=0
Global mouse_hit_y=0
Global mouse_line.Dot=Null

d1.Dot=createDot(300,225,0)
d2.Dot=createDot(500,225,0)
d3.Dot=createDot(500,375,0)
d4.Dot=createDot(300,375,0)

Repeat
	Cls	
		mouse_speed_x=MouseXSpeed()
		mouse_speed_y=MouseYSpeed()
		drawDots()
		If(MouseDown(1))
			If(mouse_hit=0) Mouse_Hit=1:mouse_hit_x=MouseX():mouse_hit_y=MouseY()
			If(mouse_hit=1)
				Color 255,255,255
				mx=MouseX()
				my=MouseY()
				mx2=mouse_hit_x
				my2=mouse_hit_y
				If(mouse_hit_x>mx)
					a=mx
					mx=mx2
					mx2=a
				EndIf
				If(mouse_hit_y>my)
					a=my
					my=my2
					my2=a
				EndIf 
				Rect mx2,my2,mx-mx2,my-my2,0
			EndIf 
		EndIf
		
		If(mouse_hit=1 And MouseDown(1)=0)
			;fertig gedrückt
			DebugLog "losgelassen"
			mouse_hit=0
			If(selectionmode=PUNKTE) selectBox(MouseX(),MouseY(),KeyDown(29))
			If(selectionmode=LINIEN) mouse_line=selectLine()
		EndIf 
		If(MouseDown(2))
			If(selectionmode=PUNKTE)
				moveDots(mouse_speed_x,mouse_speed_y)
			ElseIf(selectionmode=LINIEN)
				If(mouse_line<>Null) Then moveLine(mouse_speed_x,mouse_speed_y)
			EndIf
		EndIf
		If(KeyHit(2)) triangulate()
		
		If(KeyHit(3))
			If(selectionmode=LINIEN)
				If(mouse_line<>Null)
					splitline(mouse_line)
				EndIf
			EndIf
		EndIf
		If(KeyHit(4))
			If(selectionmode=LINIEN)
				If(mouse_line<>Null)
					splitline(mouse_line,3)
				EndIf
			EndIf
		EndIf
		If(KeyHit(5))
			If(selectionmode=LINIEN)
				If(mouse_line<>Null)
					splitline(mouse_line,4)
				EndIf
			EndIf
		EndIf
		If(KeyHit(6))
			If(selectionmode=LINIEN)
				If(mouse_line<>Null)
					splitline(mouse_line,5)
				EndIf
			EndIf
		EndIf
		If(KeyHit(7))
			If(selectionmode=LINIEN)
				If(mouse_line<>Null)
					splitline(mouse_line,6)
				EndIf
			EndIf
		EndIf
		If(KeyHit(8))
			If(selectionmode=LINIEN)
				If(mouse_line<>Null)
					splitline(mouse_line,7)
				EndIf
			EndIf
		EndIf
		If(KeyHit(9))
			If(selectionmode=LINIEN)
				If(mouse_line<>Null)
					splitline(mouse_line,8)
				EndIf
			EndIf
		EndIf
		If(KeyHit(10))
			If(selectionmode=LINIEN)
				If(mouse_line<>Null)
					splitline(mouse_line,9)
				EndIf
			EndIf
		EndIf
		If(KeyHit(211))
			If(selectionmode=PUNKTE)
				deleteDots()
			ElseIf(selectionmode=LINIEN)
				If(mouse_line<>Null)
					b.Dot=After mouse_line
					If(b=Null) b=First Dot
					Delete b
					Delete mouse_line
				EndIf 
			EndIf
		EndIf	

		If(KeyHit(57))
			If(selectionmode=PUNKTE) 
				selectionmode=LINIEN
			Else
				selectionmode=PUNKTE
			EndIf
		EndIf
		
		If(KeyHit(18))
			If(selectionmode=LINIEN) 
				If(mouse_line<>Null)
					extrudeline(mouse_line)
				EndIf
			EndIf
		EndIf
		
		Select selectionmode
			Case PUNKTE
				Text 0,0, "Linien bearbeiten  [Space] "
				Text 0,20,"Punkte selektieren [Maus1]"
				Text 0,40,"Punkte verschieben [Maus2]"
			Case LINIEN
				Text 0,0, "Punkte bearbeiten  [Space]"
				Text 0,20,"Linie selektieren  [Maus1]"
				Text 0,40,"Linie verschieben  [Maus2]"
				Text 0,60,"Linie teilen       [ 2-9 ]"
				Text 0,80,"Flaeche extrahieren[  e  ]"
		End Select 
	Flip
Until KeyHit(1)

Function drawDots()
	last_Dot.Dot=Last Dot
	For a.Dot=Each Dot
		Color 255,255,255
		
		If(selectionmode=PUNKTE)
			If(a\selected Or (Abs(MouseX()-(a\x))<4 And Abs(MouseY()-(a\y))<4))
				Color 255,0,0
			EndIf
		EndIf
		
		Oval a\x-3,a\y-3,6,6
		Color 255,255,255
		If(selectionmode=LINIEN)
			If(last_Dot=mouse_line)
				Color 255,0,0
			Else
				If(Lines_Intersect(last_Dot\x,last_Dot\y,a\x,a\y,MouseX()-2,MouseY(),MouseX()+2,MouseY()))
					Color 255,0,0
					
					angle#=(ATan2(a\y-last_Dot\y,a\x-last_Dot\x)+360)Mod 360
					DebugLog angle
					
				EndIf
				If(Lines_Intersect(last_Dot\x,last_Dot\y,a\x,a\y,MouseX(),MouseY()-2,MouseX(),MouseY()+2))
					Color 255,0,0
					angle#=(ATan2(a\y-last_Dot\y,a\x-last_Dot\x)+360)Mod 360
					DebugLog angle
				EndIf 
			EndIf			
		EndIf
		If(last_Dot<>Null) Line last_Dot\x,last_Dot\y,a\x,a\y
		last_Dot=a
	Next
End Function 


Function createDot.Dot(px#,py#,pz#)
	a.Dot=New Dot
	a\x=px
	a\y=py
	a\z=pz
	Return a
End Function

Function deleteDots()
	For a.Dot=Each Dot
		If(a\selected) Delete a
	Next
End Function

Function selectBox(mx,my,add=0)
	If(Not add)
		For a.Dot=Each Dot
			a\selected=0
		Next
	EndIf 

	mx2=mouse_hit_x
	my2=mouse_hit_y
	If(mx2>mx)
		b=mx
		mx=mx2
		mx2=b
	EndIf
	If(my2>my)
		b=my
		my=my2
		my2=b
	EndIf 
	
	For a.Dot=Each Dot
		If((a\x)>mx2 And (a\x)<mx And (a\y)>my2 And (a\y)<my)
			DebugLog "markiert"
			a\selected=1
		EndIf
	Next
	
End Function 


Function selectLine.Dot()
	last_Dot.Dot=Last Dot
	For a.Dot=Each Dot
		If(last_Dot<>Null)
			If(Lines_Intersect(last_Dot\x,last_Dot\y,a\x,a\y,MouseX()-2,MouseY(),MouseX()+2,MouseY()))
				DebugLog "gefunden"
				Return last_Dot
			EndIf
			If(Lines_Intersect(last_Dot\x,last_Dot\y,a\x,a\y,MouseX(),MouseY()-2,MouseX(),MouseY()+2))
				DebugLog "gefunden"
				Return last_Dot
			EndIf 
		EndIf
		last_Dot=a
	Next
	Return Null
End Function

Function moveDots(mx,my)
	For a.Dot=Each Dot
		If(a\selected)
			a\x=a\x+mx
			a\y=a\y+my
		EndIf 
	Next
End Function

Function moveLine(mx,my)
	c.Dot=After mouse_line
	If(c=Null) c=First dot
	c\x=c\x+mx
	c\y=c\y+my
	mouse_line\x=mouse_line\x+mx
	mouse_line\y=mouse_line\y+my
End Function


Function Lines_Intersect(ax#, ay#, bx#, by#, cx#, cy#, dx#, dy#)
  rn# = (ay#-cy#)*(dx#-cx#) - (ax#-cx#)*(dy#-cy#)
  rd# = (bx#-ax#)*(dy#-cy#) - (by#-ay#)*(dx#-cx#)
  If rd# = 0 
    Return False
  Else
    sn# = (ay#-cy#)*(bx#-ax#) - (ax#-cx#)*(by#-ay#)
    intersection_ab# = rn# / rd#
    intersection_cd# = sn# / rd#
    intersection_x#  = ax# + intersection_ab#*(bx#-ax#)
    intersection_y#  = ay# + intersection_ab#*(by#-ay#)
    If(intersection_ab>0 And intersection_ab<1 And intersection_cd#>0 And intersection_cd#<1) Return True
	Return False
  EndIf
End Function

Function splitline(a.Dot, parts=2)
	d.Dot=Last dot.Dot
	If(a=Last dot) 
		c.Dot=First dot
	Else
		c.Dot=After a
	EndIf
		
	Local b.Dot[8]
	dif_x#=c\x-a\x
	dif_y#=c\y-a\y
	For i=0 To parts-2
		b[i]=New dot
		b[i]\x=a\x+Float(dif_x/parts)*(i+1)
		b[i]\y=a\y+Float(dif_y/parts)*(i+1)
		If(i=0) 
			Insert b[0] After a
		Else
			Insert b[i] After b[i-1]
		EndIf 
	Next
End Function 

Function extrudeline(a.dot)
	For e.Dot=Each Dot
		e\selected=0
	Next
	b.Dot=After a
	If(b=Null) b=First dot
	c.Dot=New dot
	c\x=a\x
	c\y=a\y
	c\z=a\z
	c\selected=1
	d.Dot=New Dot
	d\x=b\x
	d\y=b\y
	d\z=b\z
	d\selected=1
	Insert c After a
	Insert d After c
	
	
	FlushMouse()
	Repeat
		Cls
			drawDots()
			Text 0,0,"[Maus1] zum absetzen"
			moveDots(MouseXSpeed(),MouseYSpeed())
		Flip
	Until MouseHit(1)
End Function 

Function triangulate()
	file=WriteFile("map.dot")
	
	count=0
	bank=CreateBank(0)
	For a.Dot=Each Dot
		ResizeBank(bank,BankSize(bank)+8)
		PokeInt bank,BankSize(bank)-8,a\x
		PokeInt bank,BankSize(bank)-4,a\y
	Next
	WriteInt file, BankSize(bank)/8
	For a.Dot=Each Dot
		WriteInt file,a\x
		WriteInt file,a\y
	Next
	Cls
	drawDots()
	Color 64,128,64
	last_x=PeekInt(bank,BankSize(bank)-8)
	last_y=PeekInt(bank,BankSize(bank)-4)
	a_x=PeekInt(bank,0)
	a_y=PeekInt(bank,4)
	counter=0
	While(BankSize(bank)>16)
		a_x=PeekInt(bank,counter)
		a_y=PeekInt(bank,counter+4)
		If(counter+16<=BankSize(bank))
			b_x=PeekInt(bank,counter+8)
			b_y=PeekInt(bank,counter+12)
		Else
			b_x=PeekInt(bank,0)
			b_y=PeekInt(bank,4)
		EndIf
		angle#=(ATan2(a_y-last_y,a_x-last_x)+360)Mod 360
		angle2#=(ATan2(b_y-a_y,b_x-a_x)+360)Mod 360
		DebugLog angle2+" - "+angle+"  = "+(360+angle2-angle) Mod 360
		If((360+angle2-angle) Mod 360 <=180 And checkCollisions(b_x,b_y,last_x,last_y))
			DebugLog "machen"
			;dreieck malen
			For i=counter To BankSize(bank)-16 Step 8
				DebugLog "verschiebe"+i
				PokeInt(bank,i,PeekInt(bank,i+8))
				PokeInt(bank,i+4,PeekInt(bank,i+12))
			Next
			ResizeBank(bank,BankSize(bank)-8)
			WriteInt file,last_x
			WriteInt file,last_y
			WriteInt file,a_x
			WriteInt file,a_y
			WriteInt file,b_x
			WriteInt file,b_y

			Line last_x,last_y,a_x,a_y
			Line a_x,a_y,b_x,b_y
			Line b_x,b_y,last_x,last_y
			count=count+1
			Flip
			;normal weiter beim hinteren, da der mittlere schon fertig ist
			last_x=b_x
			last_y=b_y
		Else
			;weiter beim mittleren vertex
			last_x=a_x
			last_y=a_y
			
		EndIf
		counter=counter+8
		
		If(counter+8>BankSize(bank)) counter=0
		DebugLog "nächster durchgang "+counter
		If(KeyHit(1)) Exit
		DebugLog count+" Dreiecke" 
	Wend
	DebugLog "fertig"
	Text 0,0,"fertig"
	Text 0,20,count+" Dreiecke"
	Flip
	While(Not KeyDown(1))
	Wend 
	FlushKeys 
	CloseFile file 
End Function 


Function checkCollisions(a,b,c,d)
	last_Dot.Dot=Last Dot
	For e.Dot=Each Dot
		If(last_Dot<>Null)
			 If(lines_Intersect(last_Dot\x,last_Dot\y,e\x,e\y,a,b,c,d)) Return False
		EndIf
		last_Dot=e
	Next
	Return True
End Function