diff --git a/Source/script/imports/simba.import_polygon.pas b/Source/script/imports/simba.import_polygon.pas index 29ce6ef78..417b1953c 100644 --- a/Source/script/imports/simba.import_polygon.pas +++ b/Source/script/imports/simba.import_polygon.pas @@ -26,6 +26,9 @@ implementation Polygon ======= Polygon type + +Note: + Polygon variable can be cast into a TPointArray in order to use it with TPointArray methods. *) (* @@ -46,6 +49,7 @@ procedure _LapePolygon_Bounds(const Params: PParamArray; const Result: Pointer); ``` function TPolygon.Mean: TPoint; ``` +Returns the mean, or rather the centroid of the polygon. *) procedure _LapePolygon_Mean(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV begin @@ -58,6 +62,7 @@ procedure _LapePolygon_Mean(const Params: PParamArray; const Result: Pointer); L ``` function TPolygon.Area: Double; ``` +Computes the area of the polygon. *) procedure _LapePolygon_Area(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV begin @@ -68,7 +73,7 @@ procedure _LapePolygon_Area(const Params: PParamArray; const Result: Pointer); L TPolygon.IsConvex ----------------- ``` -function TPolygon.IsConvex(Polygon: TPointArray): Boolean; +function TPolygon.IsConvex: Boolean; ``` Returns if the polygon is convex, order does not matter. A concave polygon will return False. *) @@ -97,6 +102,7 @@ procedure _LapePolygon_Contains(const Params: PParamArray; const Result: Pointer function TPolygon.ContainsLine(p,q: TPoint): Boolean; ``` Returns True if the line fits within the bounds of the polygon. +This is determined by checking if the line crosses any of the vertices. *) procedure _LapePolygon_ContainsLine(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV begin @@ -138,7 +144,7 @@ function TPolygon.Triangulate(MinArea: Double = 0; MaxDepth: Int32 = 0): TTriang input does matter, if it fails, try to reverse the Poly with Poly.Reversed() This is a custom algorithm by slacky, based around the concept of trimming "ears", -if you dont like the output, you may have more luck with rolling the Polygon before calling. +if you dont like the output, you may have luck with rolling the Polygon before calling. Two default params exists as well, `MinArea` and `MaxDepth`, they work in tandom, `MinArea` parameter is for setting a minimum size of triangles added to result, and as this method @@ -153,9 +159,10 @@ procedure _LapePolygon_Triangulate(const Params: PParamArray; const Result: Poin (* TPolygon.DouglasPeucker ----------------------- -> function TPolygon.DouglasPeucker(Epsilon: Double): TPolygon; - -Returns the two points that are furthest away from eachother in a polygon. +``` +function TPolygon.DouglasPeucker(Epsilon: Double): TPolygon; +``` +Attempts to simplify the polygon by trimming vertices. *) procedure _LapePolygon_DouglasPeucker(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV begin @@ -165,8 +172,9 @@ procedure _LapePolygon_DouglasPeucker(const Params: PParamArray; const Result: P (* TPolygon.FurthestPoints ----------------------- -> procedure TPolygon.FurthestPoints(out A,B: TPoint); - +``` +procedure TPolygon.FurthestPoints(out A,B: TPoint); +``` Returns the two points that are furthest away from eachother in a polygon. *) procedure _LapePolygon_FurthestPoints(const Params: PParamArray); LAPE_WRAPPER_CALLING_CONV @@ -174,6 +182,21 @@ procedure _LapePolygon_FurthestPoints(const Params: PParamArray); LAPE_WRAPPER_C PPolygon(Params^[0])^.FurthestPoints(PPoint(Params^[1])^, PPoint(Params^[2])^); end; +(* +TPolygon.Connect +----------------- +``` +function TPolygon.Connect: TPointArray; +``` +Connects the polygon vertices in order to make a TPointArray bounding shape. +*) +procedure _LapePolygon_Connect(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV +begin + TPointArray(Result^) := PPolygon(Params^[0])^.Connect; +end; + + + procedure _LapePoint_IN_Polygon(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV begin PBoolean(Result)^ := PPoint(Params^[0])^ in PPolygon(Params^[1])^; @@ -199,7 +222,8 @@ procedure ImportPolygon(Script: TSimbaScript); addGlobalFunc('function TPolygon.Triangulate(MinArea: Single; MaxDepth: Int32): TTriangleArray;', @_LapePolygon_Triangulate); addGlobalFunc('function TPolygon.DouglasPeucker(Epsilon: Double): TPolygon;', @_LapePolygon_DouglasPeucker); addGlobalFunc('procedure TPolygon.FurthestPoints(out A, B: TPoint);', @_LapePolygon_FurthestPoints); - + addGlobalFunc('function TPolygon.Connect: TPointArray', @_LapePolygon_Connect); + addGlobalFunc('operator in(Left: TPoint; Right: TPolygon): Boolean;', @_LapePoint_IN_Polygon); DumpSection := ''; diff --git a/Source/script/imports/simba.import_string.pas b/Source/script/imports/simba.import_string.pas index be5c74b37..d0f724dfe 100644 --- a/Source/script/imports/simba.import_string.pas +++ b/Source/script/imports/simba.import_string.pas @@ -667,6 +667,21 @@ procedure _LapeString_ExtractFloat(const Params: PParamArray; const Result: Poin PDouble(Result)^ := PString(Params^[0])^.ExtractFloat(PInt64(Params^[1])^); end; +(* +String.ExtractNumbers +--------------------- +``` +function String.ExtractNumbers(): TStringArray; +``` +Extract all the numbers found in the string. +The result is a an array of strings, where each string contains a number +extracted from the string. You can now use .ToFloat or .ToInteger on it. +*) +procedure _LapeString_ExtractNumbers(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV +begin + TStringArray(Result^) := String(Params^[0]^).ExtractNumbers(); +end; + (* String.IsAlpha -------------- @@ -1244,7 +1259,8 @@ procedure ImportString(Script: TSimbaScript); addGlobalFunc('function String.Extract(Chars: array of Char): String;', @_LapeString_Extract); addGlobalFunc('function String.ExtractInteger(Default: Int64 = -1): Int64;', @_LapeString_ExtractInteger); addGlobalFunc('function String.ExtractFloat(Default: Double = -1): Double;', @_LapeString_ExtractFloat); - + addGlobalFunc('function String.ExtractNumbers(): TStringArray;', @_LapeString_ExtractNumbers); + addGlobalFunc('function String.Trim: String; overload;', @_LapeString_Trim); addGlobalFunc('function String.Trim(TrimChars: array of Char): String; overload;', @_LapeString_TrimEx); diff --git a/Source/simba.vartype_pointarray.pas b/Source/simba.vartype_pointarray.pas index dc69c43bf..e58bf3f3e 100644 --- a/Source/simba.vartype_pointarray.pas +++ b/Source/simba.vartype_pointarray.pas @@ -2723,8 +2723,8 @@ function TPointArrayHelper.ConcaveHull(Epsilon:Double=2.5; kCount:Int32=5): TPol Buffer.Add(pts); end; - - Result := TPolygon(Buffer.ToArray(False)).DouglasPeucker(Max(2, Epsilon/2)); + + Result := TPolygon(TPointArray(Buffer.ToArray(False)).Border()).DouglasPeucker(Max(2, Epsilon/2)); end; (* diff --git a/Source/simba.vartype_polygon.pas b/Source/simba.vartype_polygon.pas index 41263e9d8..b64670ba3 100644 --- a/Source/simba.vartype_polygon.pas +++ b/Source/simba.vartype_polygon.pas @@ -36,6 +36,7 @@ interface function DouglasPeucker(Epsilon: Double): TPolygon; procedure FurthestPoints(out A,B: TPoint); function Triangulate(MinArea: Single = 0; MaxDepth: Int32 = 0): TTriangleArray; + function Connect: TPointArray; end; PPolygon = ^TPolygon; @@ -49,6 +50,7 @@ implementation Math, simba.math, simba.geometry, + simba.containers, simba.vartype_point, simba.vartype_pointarray; @@ -337,6 +339,27 @@ function TPolygonHelper.Triangulate(MinArea: Single; MaxDepth: Int32): TTriangle end; end; +function TPolygonHelper.Connect: TPointArray; +var + I: Integer; + Buffer: TSimbaPointBuffer; +begin + Buffer.Init(); + + if (Length(Self) > 1) then + begin + for I := 0 to High(Self) - 1 do + begin + Buffer.Add(TPointArray.CreateFromLine(Self[I], Self[I+1])); + Buffer.Pop(); // dont duplicate self[I+1] + end; + Buffer.Add(TPointArray.CreateFromLine(Self[High(Self)], Self[0])); + Buffer.Pop(); // dont duplicate self[0] + end; + + Result := Buffer.ToArray(False); +end; + operator in(const P: TPoint; const Poly: TPolygon): Boolean; begin Result := Poly.Contains(P); diff --git a/Source/simba.vartype_string.pas b/Source/simba.vartype_string.pas index 07dbb8a2d..fee03d841 100644 --- a/Source/simba.vartype_string.pas +++ b/Source/simba.vartype_string.pas @@ -116,6 +116,7 @@ TRegExprMatch = record function Extract(const Chars: array of Char): String; function ExtractInteger(Default: Int64 = -1): Int64; function ExtractFloat(Default: Double = -1): Double; + function ExtractNumbers(): TStringArray; function Trim: String; overload; function Trim(const TrimChars: array of Char): String; overload; @@ -742,6 +743,44 @@ function TSimbaStringHelper.ExtractFloat(Default: Double): Double; Result := StrToFloatDef(Self.Extract(['.','-','0','1','2','3','4','5','6','7','8','9']), Default); end; +(* +String.ExtractNumbers +--------------------- +``` +function String.ExtractNumbers(): TStringArray; +``` +Extract all the numbers found in the string. +The result is a an array of strings, where each string contains a number +extracted from the string. You can now use .ToFloat or .ToInteger on it. +*) +function TSimbaStringHelper.ExtractNumbers(): TStringArray; +var + i,c,l: Int32; + function Next(var i: Int32): Int32; begin Inc(i);Result:=i; end; +begin + c := 0; + L := Length(Self); + i := 1; + while i <= Length(Self) do + begin + if Self[i] in ['0'..'9'] then + begin + SetLength(Result, c+1); + + Result[c] := Self[i]; + while (Next(i) <= L) and (Self[i] in ['0'..'9']) do Result[c] += Self[i]; + if (i <= L) and (Self[i] = '.') then + begin + Result[c] += Self[i]; + while (Next(i) <= L) and (Self[i] in ['0'..'9']) do Result[c] += Self[i]; + end; + if (i > L) then Break; + Inc(c); + end; + Inc(i); + end; +end; + function TSimbaStringHelper.Trim: String; begin Result := SysUtils.Trim(Self);