unit DoublePoint;
interface
uses
SysUtils, Types, Classes, D2D1, asnum;
type
TPointD = record
X, Y: Double;
class operator Implicit(const APoint: TPoint): TPointD;
class operator Implicit(const APoint: TPointF): TPointD;
class operator Implicit(const APoint: TPointD): TD2D1Point2F;
class operator Implicit(const APoint: TD2D1Point2F): TPointD;
class operator Add(const L, R: TPointD): TPointD; inline;
class operator Subtract(const L, R: TPointD): TPointD; inline;
class operator Multiply(const s: Double; const u: TPointD): TPointD; inline;
class operator Negative(const u: TPointD): TPointD; inline;
class operator Divide(const u: TPointD; const s: Double): TPointD; inline;
class operator Equal(const Left, Right: TPointD): Boolean; inline;
class operator NotEqual(const Left, Right: TPointD): Boolean; inline;
class function Distance(const u, v: TPointD): Double; static;
function Norm: Double; inline;
function Normalized: TPointD; inline;
constructor Create(const X, Y: Double); overload;
constructor Create(const AVector: TRealVector); overload;
function TryToInt(out APoint: TPoint): Boolean;
procedure Offset(const X, Y: Double);
end;
TVectorD = TPointD;
TSizeD = record
Width, Height: Double;
class operator Implicit(const ASize: TSizeF): TSizeD;
class operator Implicit(const ASize: TSize ): TSizeD;
class operator Equal(const Left, Right: TSizeD): Boolean;
class operator NotEqual(const Left, Right: TSizeD): Boolean;
constructor Create(const AWidth, AHeight: Double);
function Area: Double; inline;
end;
TRectD = record
strict private
function GetWidth: Double; inline;
procedure SetWidth(const Value: Double);
function GetHeight: Double; inline;
procedure SetHeight(const Value: Double);
function GetSize: TSizeD;
procedure SetSize(const Value: TSizeD);
public
class operator Implicit(const ARect: TRectD): TD2DRectF;
class operator Equal(const Left, Right: TRectD): Boolean; inline;
class operator NotEqual(const Left, Right: TRectD): Boolean; inline;
constructor Create(const ALeft, ATop, ARight, ABottom: Double); overload;
constructor Create(const ATopLeft, ABottomRight: TPointD); overload;
function Area: Double; inline;
property Width: Double read GetWidth write SetWidth;
property Height: Double read GetHeight write SetHeight;
function TryToInt(out ARect: TRect): Boolean;
property Size: TSizeD read GetSize write SetSize;
function MidPoint: TPointD;
procedure Offset(const X, Y: Double);
public
case Boolean of
False:
(
Left, Top, Right, Bottom: Double
);
True:
(
TopLeft: TPointD;
BottomRight: TPointD;
)
end;
implementation
uses
Math;
class operator TPointD.Add(const L, R: TPointD): TPointD;
begin
Result.X := L.X + R.X;
Result.Y := L.Y + R.Y;
end;
constructor TPointD.Create(const X, Y: Double);
begin
Self.X := X;
Self.Y := Y;
end;
constructor TPointD.Create(const AVector: TRealVector);
begin
if AVector.Dimension = 2 then
begin
X := AVector[0];
Y := AVector[1];
end
else
raise Exception.Create('Vector must be two-dimensional.');
end;
class function TPointD.Distance(const u, v: TPointD): Double;
begin
Result := (u - v).Norm;
end;
class operator TPointD.Divide(const u: TPointD; const s: Double): TPointD;
begin
Result := (1/s) * u;
end;
class operator TPointD.Equal(const Left, Right: TPointD): Boolean;
begin
Result := (Left.X = Right.X) and (Left.Y = Right.Y);
end;
class operator TPointD.Implicit(const APoint: TPointD): TD2D1Point2F;
begin
Result.x := APoint.X;
Result.y := APoint.Y;
end;
class operator TPointD.Implicit(const APoint: TPointF): TPointD;
begin
Result.X := APoint.X;
Result.Y := APoint.Y;
end;
class operator TPointD.Multiply(const s: Double; const u: TPointD): TPointD;
begin
Result.X := s * u.X;
Result.Y := s * u.Y;
end;
class operator TPointD.Negative(const u: TPointD): TPointD;
begin
Result.X := -u.X;
Result.Y := -u.Y;
end;
function TPointD.Norm: Double;
begin
Result := Hypot(X, Y);
end;
function TPointD.Normalized: TPointD;
begin
Result := Self / Self.Norm;
end;
class operator TPointD.NotEqual(const Left, Right: TPointD): Boolean;
begin
Result := not (Left = Right);
end;
procedure TPointD.Offset(const X, Y: Double);
begin
Self.X := Self.X + X;
Self.Y := Self.Y + Y;
end;
class operator TPointD.Subtract(const L, R: TPointD): TPointD;
begin
Result.X := L.X - R.X;
Result.Y := L.Y - R.Y;
end;
function TPointD.TryToInt(out APoint: TPoint): Boolean;
begin
Result := InRange(X, Integer.MinValue, Integer.MaxValue) and
InRange(Y, Integer.MinValue, Integer.MaxValue);
if Result then
APoint := Point(Round(X), Round(Y));
end;
class operator TPointD.Implicit(const APoint: TPoint): TPointD;
begin
Result.X := APoint.X;
Result.Y := APoint.Y;
end;
class operator TPointD.Implicit(const APoint: TD2D1Point2F): TPointD;
begin
Result.X := APoint.x;
Result.Y := APoint.y;
end;
function TRectD.Area: Double;
begin
if (Left < Right) and (Top < Bottom) then
Result := (Right - Left) * (Bottom - Top)
else
Result := 0.0;
end;
constructor TRectD.Create(const ATopLeft, ABottomRight: TPointD);
begin
TopLeft := ATopLeft;
BottomRight := ABottomRight;
end;
class operator TRectD.Equal(const Left, Right: TRectD): Boolean;
begin
Result := (Left.TopLeft = Right.TopLeft) and (Left.BottomRight = Right.BottomRight);
end;
constructor TRectD.Create(const ALeft, ATop, ARight, ABottom: Double);
begin
Left := ALeft;
Top := ATop;
Right := ARight;
Bottom := ABottom;
end;
function TRectD.GetHeight: Double;
begin
if Top < Bottom then
Result := Bottom - Top
else
Result := 0.0;
end;
class operator TRectD.Implicit(const ARect: TRectD): TD2DRectF;
begin
Result.left := ARect.Left;
Result.top := ARect.Top;
Result.right := ARect.Right;
Result.bottom := ARect.Bottom;
end;
function TRectD.MidPoint: TPointD;
begin
Result.X := (Self.Left + Self.Right) / 2;
Result.Y := (Self.Top + Self.Bottom) / 2;
end;
class operator TRectD.NotEqual(const Left, Right: TRectD): Boolean;
begin
Result := not (Left = Right);
end;
procedure TRectD.Offset(const X, Y: Double);
begin
TopLeft.Offset(X, Y);
BottomRight.Offset(X, Y);
end;
procedure TRectD.SetHeight(const Value: Double);
begin
Bottom := Top + Value;
end;
procedure TRectD.SetSize(const Value: TSizeD);
begin
Right := Left + Value.Width;
Bottom := Top + Value.Height;
end;
procedure TRectD.SetWidth(const Value: Double);
begin
Right := Left + Value;
end;
function TRectD.GetSize: TSizeD;
begin
Result.Width := Self.Width;
Result.Height := Self.Height;
end;
function TRectD.TryToInt(out ARect: TRect): Boolean;
begin
Result :=
TopLeft.TryToInt(ARect.TopLeft)
and
BottomRight.TryToInt(ARect.BottomRight);
end;
function TRectD.GetWidth: Double;
begin
if Left < Right then
Result := Right - Left
else
Result := 0.0;
end;
function TSizeD.Area: Double;
begin
Result := Width * Height;
end;
constructor TSizeD.Create(const AWidth, AHeight: Double);
begin
Self.Width := AWidth;
Self.Height := AHeight;
end;
class operator TSizeD.Equal(const Left, Right: TSizeD): Boolean;
begin
Result := (Left.Width = Right.Width) and (Left.Height = Right.Height);
end;
class operator TSizeD.Implicit(const ASize: TSize): TSizeD;
begin
Result.Width := ASize.Width;
Result.Height := ASize.Height;
end;
class operator TSizeD.NotEqual(const Left, Right: TSizeD): Boolean;
begin
Result := not (Left = Right);
end;
class operator TSizeD.Implicit(const ASize: TSizeF): TSizeD;
begin
Result.Width := ASize.Width;
Result.Height := ASize.Height;
end;
end.