diff --git a/Source/script/imports/simba.import_box.pas b/Source/script/imports/simba.import_box.pas index 4f24b6508..e37187d5f 100644 --- a/Source/script/imports/simba.import_box.pas +++ b/Source/script/imports/simba.import_box.pas @@ -70,11 +70,11 @@ procedure _LapeBox_Create2(const Params: PParamArray; const Result: Pointer); LA (* TBox.Area --------- -> property TBox.Area: Integer; +> property TBox.Area: Int64; *) procedure _LapeBox_Area(const Params: PParamArray; const Result: Pointer); LAPE_WRAPPER_CALLING_CONV begin - PInteger(Result)^ := PBox(Params^[0])^.Area; + PInt64(Result)^ := PBox(Params^[0])^.Area; end; (* @@ -374,7 +374,7 @@ procedure ImportBox(Compiler: TSimbaScript_Compiler); addProperty('TBox', 'Width', 'Integer', @_LapeBox_Width); addProperty('TBox', 'Height', 'Integer', @_LapeBox_Height); addProperty('TBox', 'Center', 'TPoint', @_LapeBox_Center); - addProperty('TBox', 'Area', 'Integer', @_LapeBox_Area); + addProperty('TBox', 'Area', 'Int64', @_LapeBox_Area); addProperty('TBox', 'Size', 'TSize', @_LapeBox_Size_Read); addGlobalFunc('function TBox.RandomPoint: TPoint', @_LapeBox_RandomPoint); diff --git a/Source/simba.vartype_box.pas b/Source/simba.vartype_box.pas index a17a17a5a..622a544c8 100644 --- a/Source/simba.vartype_box.pas +++ b/Source/simba.vartype_box.pas @@ -22,8 +22,8 @@ TBoxHelper = record helper for TBox function GetCenter: TPoint; inline; function GetWidth: Integer; inline; function GetHeight: Integer; inline; - function GetSize: TSize; - function GetArea: Integer; + function GetSize: TSize; inline; + function GetArea: Int64; inline; public const ZERO: TBox = (X1: 0; Y1: 0; X2: 0; Y2: 0); @@ -60,7 +60,7 @@ TBoxHelper = record helper for TBox property Width: Integer read GetWidth; property Height: Integer read GetHeight; property Center: TPoint read GetCenter; - property Area: Integer read GetArea; + property Area: Int64 read GetArea; property Size: TSize read GetSize; end; @@ -135,7 +135,7 @@ function TBoxHelper.EqualDimensions(Other: TBox): Boolean; Result := (Self.Width = Other.Width) and (Self.Height = Other.Height); end; -function TBoxHelper.GetArea: Integer; +function TBoxHelper.GetArea: Int64; begin Result := (Width * Height); end; diff --git a/Source/simba.vartype_pointarray.pas b/Source/simba.vartype_pointarray.pas index 948b01de1..e5ac020a5 100644 --- a/Source/simba.vartype_pointarray.pas +++ b/Source/simba.vartype_pointarray.pas @@ -1292,30 +1292,46 @@ function TPointArrayHelper.Grow(Iterations: Integer): TPointArray; function TPointArrayHelper.Unique: TPointArray; var - Matrix: TBooleanMatrix; - I, Count: Integer; + Area, Width, Index: Integer; + Box: TBox; + Seen: TBooleanArray; + SrcPtr, DstPtr: PPoint; + SrcUpper: PtrUInt; begin - if (Length(Self) > 0) then - begin - SetLength(Result, Length(Self)); + if (High(Self) < 0) then Exit([]); + if (High(Self) = 0) then Exit([Self[0]]); - Count := 0; - with Self.Bounds() do + { Fallback to safe dictionary: + * Fewer than 1 in area of 5000 + * Larger than 512MB in memory (approx 25K*25K area) + } + Box := Self.Bounds; + Area := Box.Area; + Width := Box.Width; + if (Area * SizeOf(TPoint) > $20000000) or + (Length(Self) / Area < 0.0002) then + Exit(specialize TArrayUnique.Unique(Self)); + + SetLength(Result, Length(Self)); + SetLength(Seen, Area); + + SrcUpper := PtrUInt(@Self[High(Self)]); + SrcPtr := @Self[0]; + DstPtr := @Result[0]; + + while (PtrUInt(SrcPtr) <= SrcUpper) do + begin + Index := (SrcPtr^.Y - Box.Y1) * Width + (SrcPtr^.X - Box.X1); + if not Seen[Index] then begin - Matrix.SetSize(Width, Height); + Seen[Index] := True; - for I := 0 to High(Self) do - if not Matrix[Self[I].Y - Y1, Self[I].X - X1] then - begin - Matrix[Self[I].Y - Y1, Self[I].X - X1] := True; - Result[Count] := Self[I]; - Inc(Count); - end; + DstPtr^ := SrcPtr^; + Inc(DstPtr); end; - - SetLength(Result, Count); - end else - Result := []; + Inc(SrcPtr); + end; + SetLength(Result, (PtrUInt(DstPtr) - PtrUInt(@Result[0])) div SizeOf(TPoint)); end; function TPointArrayHelper.ReduceByDistance(Dist: Integer): TPointArray;