XIncludeFile "Vector.pb" XIncludeFile "Line.pb" XIncludeFile "Triangle.pb" XIncludeFile "Handler.pb" ;****************** ;- Parameter Structure ;****************** Prototype StepByStepState(*param) Structure Parameter running.i Map handler.CallbackEntry() windowHandle.i outputSize.Vector2 minDistance.f List triangleList.Triangle() List vertexList.Vector3() ; Debug state currentState.StepByStepState currentTriangle.Triangle shrunkTriangle.Triangle showTriangle.i EndStructure #SHOWTRICURRENT = 1 #SHOWTRISHRUNK = 2 ;******************* ;- GUI ;******************* Procedure initWindow(*windowHandle.Integer, *position.Vector2, *size.Vector2, name.s) InitSprite() InitMouse() *windowHandle\i = OpenWindow(#PB_Any, *position\x, *position\y, *size\x, *size\y, name) OpenWindowedScreen(WindowID(*windowHandle\i),0, 0, *size\x, *size\y) EndProcedure Procedure drawLine(*param.Parameter, *from.Vector3, *to.Vector3, color = $FFFFFF) LineXY(*from\x * *param\outputSize\x, *from\y * *param\outputSize\y, *to\x * *param\outputSize\x, *to\y * *param\outputSize\y, color) EndProcedure Procedure drawTriangle(*param.Parameter, *Triangle.Triangle, color = $FFFFFF) drawLine(*param, *Triangle\a, *triangle\b, color) drawLine(*param, *Triangle\b, *triangle\c, color) drawLine(*param, *Triangle\c, *triangle\a, color) EndProcedure Procedure drawVertex(*param.Parameter, *vertex.Vector3) Circle(*vertex\x * *param\outputSize\x, *vertex\y * *param\outputSize\y, 5) EndProcedure ;****************** ;- Logic ;****************** Procedure addSubDivideTriangle(*param.Parameter, *triangle.Triangle, *vertex.Vector3) ResetList(*param\triangleList()) Define newTriangle.Triangle setTriangle(@newTriangle, *triangle\a, *triangle\b, *vertex) AddElement(*param\triangleList()) copyTriangle(*param\triangleList(), @newTriangle) setTriangle(@newTriangle, *triangle\b, *triangle\c, *vertex) AddElement(*param\triangleList()) copyTriangle(*param\triangleList(), @newTriangle) setTriangle(@newTriangle, *triangle\c, *triangle\a, *vertex) AddElement(*param\triangleList()) copyTriangle(*param\triangleList(), @newTriangle) AddElement(*param\vertexList()) copyVector3(*param\vertexList(), *vertex) EndProcedure Procedure addTriangleToParameter(*param.Parameter, *triangle.Triangle) AddElement(*param\triangleList()) copyTriangle(@*param\triangleList(), *triangle) AddElement(*param\vertexList()) copyVector3(@*param\vertexList(), @*triangle\a) AddElement(*param\vertexList()) copyVector3(@*param\vertexList(), @*triangle\b) AddElement(*param\vertexList()) copyVector3(@*param\vertexList(), @*triangle\c) EndProcedure Procedure initializeSquare(*param.Parameter, *position.Vector3, width.f, height.f) Define currentTriangle.Triangle copyVector3(@currentTriangle\a, *position) copyVector3(@currentTriangle\b, *position) currentTriangle\b\x + width copyVector3(@currentTriangle\c, *position) currentTriangle\c\y + height addTriangleToParameter(*param, @currentTriangle) copyVector3(@currentTriangle\a, *position) currentTriangle\a\x + width copyVector3(@currentTriangle\b, *position) currentTriangle\b\x + width currentTriangle\b\y + height copyVector3(@currentTriangle\c, *position) currentTriangle\c\y + height addTriangleToParameter(*param, @currentTriangle) EndProcedure Procedure calculateNewCorner(*result.Vector3, *a.Vector3, *b.Vector3, *c.Vector3, *param.Parameter) Define ab.Vector3: copyVector3(@ab, *b): subVector3(@ab, *a) Define ac.Vector3: copyVector3(@ac, *c): subVector3(@ac, *a) Define normAB.Vector3: copyVector3(@normAB, @ab) : normVector3(@normAB) Define normAC.Vector3: copyVector3(@normAC, @ac) : normVector3(@normAC) Define sinA.f = Sqr((1 - dotVector3(@normAB, @normAC)) * 0.5) Define lengthH.f = *param\minDistance / sinA Define scaleAB.f = Sqr(lengthH * lengthH - *param\minDistance * *param\minDistance) Define normTri.Vector3: crossVector3(@normTri, @ab, @ac) Define normalAB.Vector3: crossVector3(@normalAB, @normTri, @ab) normVector3(@normalAB) mulVector3Scalar(@normalAB, *param\minDistance) copyVector3(*result, normAB) mulVector3Scalar(*result, scaleAB) addVector3(*result, *a) addVector3(*result, @normalAB) EndProcedure Procedure shrinkTriangle(*param.Parameter, *triangle.Triangle, *shrunkTriangle.Triangle) Define result = #True ; Check, if valid shrink is possible. Define ab.Line3 : setLine3(@ab, *triangle\a, *triangle\b) Define ac.Line3 : setLine3(@ac, *triangle\a, *triangle\c) Define bc.Line3 : setLine3(@bc, *triangle\b, *triangle\c) Define centroid.Vector3 : calculateCentroid(@centroid, *triangle) If (distanceLinePoint(@ab, @centroid) > *param\minDistance And distanceLinePoint(@ac, @centroid) > *param\minDistance And distanceLinePoint(@bc, @centroid) > *param\minDistance) Define a.Vector3: copyVector3(@a, *triangle\a) Define b.Vector3: copyVector3(@b, *triangle\b) Define c.Vector3: copyVector3(@c, *triangle\c) calculateNewCorner(*shrunkTriangle\a, @a, @b, @c, *param) calculateNewCorner(*shrunkTriangle\b, @b, @c, @a, *param) calculateNewCorner(*shrunkTriangle\c, @c, @a, @b, *param) Else result = #False EndIf ProcedureReturn result EndProcedure Procedure calculateRandomPoint(*triangle.Triangle, *point.Vector3) Define baryA.f = 0.001 * Random(1000) Define baryB.f = 0.001 * Random(1000) Define baryC.f = 0.001 * Random(1000) Define sumBary.f = baryA + baryB + baryC + 0.00001 baryA / sumBary baryB / sumBary baryC / sumBary *point\x = (*triangle\a\x * baryA + *triangle\b\x * baryB + *triangle\c\x * baryC) *point\y = (*triangle\a\y * baryA + *triangle\b\y * baryB + *triangle\c\y * baryC) *point\z = (*triangle\a\z * baryA + *triangle\b\z * baryB + *triangle\c\z * baryC) EndProcedure ; Procedure scatterNextTriangle(*param.Parameter) ; ; If (FirstElement(*param\triangleList())) ; Define currentTriangle.Triangle ; copyTriangle(@currentTriangle, *param\triangleList()) ; Define shrunkTriangle.Triangle ; ; If (shrinkTriangle(*param, @currentTriangle, @shrunkTriangle)) ; Define newVertex.Vector3 ; calculateRandomPoint(@shrunkTriangle, @newVertex) ; ; addSubDivideTriangle(*param, @currentTriangle, @newVertex) ; EndIf ; ; FirstElement(*param\triangleList()) ; DeleteElement(*param\triangleList()) ; EndIf ; EndProcedure Declare stepFindTriangle(*param) Procedure stepFinished(*param.Parameter) EndProcedure Procedure stepRandomPointAndSubdivide(*param.Parameter) Define newVertex.Vector3 calculateRandomPoint(@*param\shrunkTriangle, @newVertex) addSubDivideTriangle(*param, @*param\currentTriangle, @newVertex) *param\currentState = @stepFindTriangle() EndProcedure Procedure stepShrinkTriangle(*param.Parameter) If (shrinkTriangle(*param, @*param\currentTriangle, @*param\shrunkTriangle)) *param\showTriangle = #SHOWTRICURRENT + #SHOWTRISHRUNK *param\currentState = @stepRandomPointAndSubdivide() Else *param\currentState = @stepFindTriangle() EndIf EndProcedure Procedure stepFindTriangle(*param.Parameter) *param\showTriangle = 0 If (FirstElement(*param\triangleList())) copyTriangle(*param\currentTriangle, *param\triangleList()) FirstElement(*param\triangleList()) DeleteElement(*param\triangleList()) *param\showTriangle = #SHOWTRICURRENT *param\currentState = @stepShrinkTriangle() Else *param\currentState = @stepFinished() EndIf EndProcedure ;******************* ;- Handlermethods ;******************* Procedure handleCloseWindow(*data, *handleData) Define *dataAccess.Integer = *data *dataAccess\i = #False EndProcedure Procedure handleMouseClick(*data, *handleData) Define *dataAccess.Parameter = *data *dataAccess\currentState(*dataAccess) EndProcedure ;******************* ;- Scatter ;******************* Procedure initScatterParameter(*param.Parameter) Define position.Vector3 : setVector3(@position, 0, 0, 0) Define size.Vector2 : setVector2(@size, 1, 1) initializeSquare(*param, @position, size\x, size\y) *param\minDistance = 0.01 EndProcedure Procedure initParameter(*param.Parameter) *param\running = #True *param\currentState = @stepFindTriangle() initScatterParameter(*param) EndProcedure Procedure initHandler(*param.Parameter) addCallback(*param\handler(), #EVENT_CLOSE, @handleCloseWindow(), @*param\running) addCallback(*param\handler(), #EVENT_MOUSELEFTCLICK, @handleMouseClick(), *param) EndProcedure Procedure startWindow(*param.Parameter) Define winPosition.Vector2 : setVector2(@winPosition, 0, 0) setVector2(@*param\outputSize, 800, 600) initWindow(@*param\windowHandle, @winPosition, @*param\outputSize, "Scatter") EndProcedure Procedure showScatter(*param.Parameter) FlipBuffers() ClearScreen(0) StartDrawing(ScreenOutput()) ForEach *param\triangleList() drawTriangle(*param, *param\triangleList(), RGB(50, 50, 50)) Next ForEach *param\vertexList() drawVertex(*param, *param\vertexList()) Next If (*param\showTriangle & #SHOWTRICURRENT) drawTriangle(*param, *param\currentTriangle) EndIf If (*param\showTriangle & #SHOWTRISHRUNK) drawTriangle(*param, *param\shrunkTriangle, RGB(255, 50, 50)) EndIf StopDrawing() EndProcedure Procedure runScatter() Define param.Parameter initParameter(@param) initHandler(@param) startWindow(@param) While (param\currentState <> @stepFinished()) handleMouseClick(param, #Null) Wend While (param\running) showScatter(@param) handleWindowEvents(param\handler()) Delay(1) Wend EndProcedure ;******************* ;- Main ;******************* runScatter() ; Debug "Original" ; multiLineDebug(toStringTriangle(triangleList())) ; Debug "--------" ; Debug "Shrunk triangle" ; multiLineDebug(toStringTriangle(shrunkTriangle)) ; Debug "Result = " + result ; ForEach triangleList() ; multiLineDebug(toStringTriangle(triangleList())) ; Next ; IDE Options = PureBasic 5.11 (Windows - x64) ; CursorPosition = 335 ; FirstLine = 314 ; Folding = ---- ; EnableAsm ; EnableUnicode ; EnableThread ; EnableXP ; CPU = 1