UPhysics2DTypes.pas
上传用户:zkjn0718
上传日期:2021-01-01
资源大小:776k
文件大小:39k
源码类别:
Delphi/CppBuilder
开发平台:
Delphi
- unit UPhysics2DTypes;
- { This unit is written based on Box2D whose author is Erin Catto (http://www.gphysics.com)
- All type names follow the Delphi custom Txxx and xxx means the corresponding
- type in cpp source.
- Because versions before Delphi 2007 don't support operator overloading, so
- I write two versions of all math operations for vector and matrix, etc. But
- later I found that the version without operator overloading runs faster.
- So if you want a better performance, DEFINE BETTER_PERFORMANCE in Physics2D.inc
- which will UNDEFINE OP_OVERLOAD even if you are using Delphi 2010.
- This library supports three kinds of floats, Single(32bit), Double(64bit) and
- Extended(80bit).
- flags EXTENDED_PRECISION DOUBLE_PRECISION
- Extended ON whatever
- Double(default) OFF ON
- Single OFF OFF
- There is also a flag SINGLE_PRECISION in the include file but it doesn't affect
- Float type definition.
- All assertions are ignored.
- Translator: Qianyuan Wang(王乾元)
- Contact me: http://hi.baidu.com/wqyfavor
- wqyfavor@163.com
- QQ: 466798985 }
- interface
- {$I Physics2D.inc}
- uses
- Math, Classes, SysUtils,
- {$IFDEF HANDLE_EXCEPTION}
- UPhysics2DMessages,
- {$ENDIF}
- Dialogs;
- type
- Int8 = ShortInt;
- Int16 = SmallInt;
- Int32 = Integer;
- UInt8 = Byte;
- UInt16 = Word;
- UInt32 = Cardinal;
- PUInt16 = ^UInt16;
- // If handle exception and give localizable messages. Messages are stored in UPhysics2DMessages.pas
- {$IFDEF HANDLE_EXCEPTION}
- TPhysics2DExceptionCode = (ecDivByZero);
- TPhysics2DException = class(Exception)
- constructor Create(ErrorCode: TPhysics2DExceptionCode);
- end;
- {$ENDIF}
- // Float type
- PFloat = ^Float;
- {$IFDEF EXTENDED_PRECISION}
- Float = Extended;
- {$ELSE}
- {$IFDEF DOUBLE_PRECISION}
- Float = Double;
- {$ELSE}
- Float = Single;
- {$ENDIF}
- {$ENDIF}
- Float32 = Single;
- Float64 = Double;
- Float80 = Extended;
- const
- {$IFDEF EXTENDED_PRECISION}
- FLT_EPSILON = 1.084202172485504E-19;
- FLT_MAX = MaxExtended;
- {$ELSE}
- {$IFDEF DOUBLE_PRECISION}
- FLT_EPSILON = 2.2204460492503131e-16;
- FLT_MAX = MaxDouble;
- {$ELSE}
- FLT_EPSILON = 1.192092896e-7;
- FLT_MAX = MaxSingle;
- {$ENDIF}
- {$ENDIF}
- function IsValid(f: Float): Boolean; {$IFNDEF OP_OVERLOAD}overload;{$ENDIF}
- type
- PVector2 = ^TVector2;
- TVector2 = record
- x, y: Float;
- {$IFDEF OP_OVERLOAD}
- function IsValid: Boolean; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function Length: Float; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function SqrLength: Float; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function Normalize: Float; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure SetZero; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure SetNegative; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure SetValue(x, y: Float); {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- class function From(const x, y: Float): TVector2; static; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- // Operators
- class operator Negative(const AValue: TVector2): TVector2; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- class operator Add(const Left, Right: TVector2): TVector2; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- class operator Subtract(const Left, Right: TVector2): TVector2; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- class operator Multiply(const Left: TVector2; const Right: Single): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- class operator Multiply(const Left: TVector2; const Right: Double): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- class operator Multiply(const Left: TVector2; const Right: Extended): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- class operator Multiply(const Left: Single; const Right: TVector2): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- class operator Multiply(const Left: Double; const Right: TVector2): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- class operator Multiply(const Left: Extended; const Right: TVector2): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- class operator Divide(const Left: TVector2; const Right: Single): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- class operator Divide(const Left: TVector2; const Right: Double): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- class operator Divide(const Left: TVector2; const Right: Extended): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure AddBy(const Operand: TVector2); {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure SubtractBy(const Operand: TVector2); {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure MultiplyBy(const Operand: Single); overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure MultiplyBy(const Operand: Double); overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure MultiplyBy(const Operand: Extended); overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure DivideBy(const Operand: Single); overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure DivideBy(const Operand: Double); overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure DivideBy(const Operand: Extended); overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- {$ENDIF}
- end;
- TVectorArray4 = array[0..3] of TVector2;
- TMatrix22 = record
- col1, col2: TVector2;
- {$IFDEF OP_OVERLOAD}
- procedure SetIdentity;
- procedure SetZero;
- procedure SetValue(const _col1, _col2: TVector2); overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- /// Initialize this matrix using an angle. This matrix becomes
- /// an orthonormal rotation matrix.
- procedure SetValue(angle: Float); overload;
- function Invert: TMatrix22;
- function Solve(const b: TVector2): TVector2; // Solve A * x = b, where b is a column vector.
- // Operators
- class operator Negative(const AValue: TMatrix22): TMatrix22;
- class operator Add(const Left, Right: TMatrix22): TMatrix22;
- class operator Subtract(const Left, Right: TMatrix22): TMatrix22;
- {$ENDIF}
- end;
- /// A transform contains translation and rotation. It is used to represent
- /// the position and orientation of rigid bodies.
- Tb2XForm = record
- position: TVector2;
- R: TMatrix22;
- {$IFDEF OP_OVERLOAD}
- procedure SetIdentity;
- class function From(const position: TVector2; const R: TMatrix22): Tb2XForm; static;
- {$ENDIF}
- end;
- /// This describes the motion of a body/shape for TOI computation.
- /// Shapes are defined with respect to the body origin, which may
- /// no coincide with the center of mass. However, to support dynamics
- /// we must interpolate the center of mass position.
- Tb2Sweep = record
- localCenter: TVector2; // local center of mass position
- c0, c: TVector2; // center world positions
- a0, a: Float; // world angles
- t0: Float; // time interval = [t0,1], where t0 is in [0,1]
- {$IFDEF OP_OVERLOAD}
- /// Get the interpolated transform at a specific time.
- /// @param t the normalized time in [0,1].
- procedure GetXForm(var xf: Tb2XForm; t: Float);
- /// Advance the sweep forward, yielding a new initial state.
- /// @param t the new initial time.
- procedure Advance(t: Float);
- {$ENDIF}
- end;
- const
- b2Vec2_Zero: TVector2 = (X: 0.0; Y: 0.0);
- b2Mat22_identity: TMatrix22 = (col1: (X: 1.0; Y: 0.0); col2: (X: 0.0; Y: 1.0));
- b2XForm_identity: Tb2XForm = (position: (X: 0.0; Y: 0.0); R: (col1: (X: 1.0; Y: 0.0); col2: (X: 0.0; Y: 1.0)));
- const
- UInt8_MAX = $FF;
- UINT16_MAX = $FFFF;
- b2_maxManifoldPoints = 2;
- b2_maxPolygonVertices = 8;
- b2_maxProxies = 512; // this must be a power of two
- b2_maxPairs = 8 * b2_maxProxies; // this must be a power of two
- b2_nullFeature: UInt8 = UInt8_MAX;
- b2_nullPair: UInt16 = UINT16_MAX;
- b2_nullProxy: UInt16 = UINT16_MAX;
- b2_tableCapacity = b2_maxPairs; // must be a power of two
- b2_tableMask = b2_tableCapacity - 1; // should be (b2_tableCapacity - 1) but won't compile.
- B2BROADPHASE_MAX = UINT16_MAX;
- b2_invalid: UInt16 = B2BROADPHASE_MAX;
- b2_nullEdge: UInt16 = B2BROADPHASE_MAX;
- // Dynamics
- /// A small length used as a collision and constraint tolerance. Usually it is
- /// chosen to be numerically significant, but visually insignificant.
- b2_linearSlop = 0.005; // 0.5 cm
- /// A small angle used as a collision and constraint tolerance. Usually it is
- /// chosen to be numerically significant, but visually insignificant.
- b2_angularSlop = 2.0 / 180.0 * Pi; // 2 degrees
- /// Continuous collision detection (CCD) works with core, shrunken shapes. This is the
- /// amount by which shapes are automatically shrunk to work with CCD. This must be
- /// larger than b2_linearSlop.
- b2_toiSlop = 8.0 * b2_linearSlop;
- /// Maximum number of contacts to be handled to solve a TOI island.
- b2_maxTOIContactsPerIsland: Int32 = 32;
- /// A velocity threshold for elastic collisions. Any collision with a relative linear
- /// velocity below this threshold will be treated as inelastic.
- b2_velocityThreshold = 1.0; // 1 m/s
- /// The maximum linear position correction used when solving constraints. This helps to
- /// prevent overshoot.
- b2_maxLinearCorrection = 0.2; // 20 cm
- /// The maximum angular position correction used when solving constraints. This helps to
- /// prevent overshoot.
- b2_maxAngularCorrection = 8.0 / 180.0 * Pi; // 8 degrees
- /// The maximum linear velocity of a body. This limit is very large and is used
- /// to prevent numerical problems. You shouldn't need to adjust this.
- b2_maxLinearVelocity = 200.0;
- b2_maxLinearVelocitySquared = b2_maxLinearVelocity * b2_maxLinearVelocity;
- /// The maximum angular velocity of a body. This limit is very large and is used
- /// to prevent numerical problems. You shouldn't need to adjust this.
- b2_maxAngularVelocity = 250.0;
- b2_maxAngularVelocitySquared = b2_maxAngularVelocity * b2_maxAngularVelocity;
- /// This scale factor controls how fast overlap is resolved. Ideally this would be 1 so
- /// that overlap is removed in one time step. However using values close to 1 often lead
- /// to overshoot.
- b2_contactBaumgarte = 0.2;
- // Sleep
- /// The time that a body must be still before it will go to sleep.
- b2_timeToSleep = 0.5; // half a second
- /// A body cannot sleep if its linear velocity is above this tolerance.
- b2_linearSleepTolerance = 0.01; // 1 cm/s
- /// A body cannot sleep if its angular velocity is above this tolerance.
- b2_angularSleepTolerance = 2.0 / 180.0; // 2 degrees/s
- function MakeVector(x, y: Float): TVector2; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure SetZero(var v: TVector2); {$IFNDEF OP_OVERLOAD}overload;{$ENDIF} {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure SetValue(var v: TVector2; ax, ay: Float); {$IFNDEF OP_OVERLOAD}overload;{$ENDIF} {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- {$IFNDEF OP_OVERLOAD}
- // For TVector2
- function IsValid(const v: TVector2): Boolean; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function Length(const v: TVector2): Float; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function SqrLength(const v: TVector2): Float; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function Normalize(var v: TVector2): Float; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure SetNegative(var v: TVector2); {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function Negative(const AValue: TVector2): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function Add(const Left, Right: TVector2): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function Add(const p1, p2, p3: TVector2): TVector2; overload;
- function Subtract(const Left, Right: TVector2): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function Multiply(const Left: TVector2; const Right: Single): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function Multiply(const Left: TVector2; const Right: Double): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function Multiply(const Left: TVector2; const Right: Extended): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function Divide(const Left: TVector2; const Right: Single): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function Divide(const Left: TVector2; const Right: Double): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function Divide(const Left: TVector2; const Right: Extended): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure AddBy(var v: TVector2; const Operand: TVector2); {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure SubtractBy(var v: TVector2; const Operand: TVector2); {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure MultiplyBy(var v: TVector2; const Operand: Single); overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure MultiplyBy(var v: TVector2; const Operand: Double); overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure MultiplyBy(var v: TVector2; const Operand: Extended); overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure DivideBy(var v: TVector2; const Operand: Single); overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure DivideBy(var v: TVector2; const Operand: Double); overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure DivideBy(var v: TVector2; const Operand: Extended); overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- // For TMatrix22
- procedure SetIdentity(var m: TMatrix22); overload;
- procedure SetZero(var m: TMatrix22); overload;
- procedure SetValue(var m: TMatrix22; const _col1, _col2: TVector2); overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure SetValue(var m: TMatrix22; angle: Float); overload;
- function Invert(const m: TMatrix22): TMatrix22;
- function Solve(const m: TMatrix22; const b: TVector2): TVector2; // Solve A * x = b, where b is a column vector.
- function Negative(const AValue: TMatrix22): TMatrix22; overload;
- function Add(const Left, Right: TMatrix22): TMatrix22; overload;
- function Add(const m1, m2, m3: TMatrix22): TMatrix22; overload;
- function Subtract(const Left, Right: TMatrix22): TMatrix22; overload;
- // For T2bXForm
- procedure SetIdentity(var xf: Tb2XForm); overload;
- // For Tb2Sweep
- procedure GetXForm(const Sweep: Tb2Sweep; var xf: Tb2XForm; t: Float);
- procedure Advance(var Sweep: Tb2Sweep; t: Float);
- {$ENDIF}
- function b2MixFriction(friction1, friction2: Float): Float; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function b2MixRestitution(restitution1, restitution2: Float): Float; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function b2Max(const a, b: Float): Float; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function b2Max(const a, b: TVector2): TVector2; overload;
- function b2Min(const a, b: Float): Float; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function b2Min(const a, b: TVector2): TVector2; overload;
- function b2Max(const a, b: Int32): Int32; overload;
- function b2Min(const a, b: Int32): Int32; overload;
- procedure b2Swap(var a, b: Float); overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure b2Swap(var a, b: Int32); overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- procedure b2Swap(var a, b: TVector2); overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function b2Clamp(const a, low, high: TVector2): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function b2Clamp(const a, low, high: Float): Float; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function b2Dot(const a, b: TVector2): Float; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function b2Cross(const a, b: TVector2): Float; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function b2Cross(const a: TVector2; s: Float): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function b2Cross(s: Float; const a: TVector2): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function b2Mul(const A: TMatrix22; const v: TVector2): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function b2MulT(const A: TMatrix22; const v: TVector2): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function b2Distance(const a, b: TVector2): Float; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function b2DistanceSquared(const a, b: TVector2): Float; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function b2Mul(const A, B: TMatrix22): TMatrix22; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function b2MulT(const A, B: TMatrix22): TMatrix22; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function b2Mul(const T: Tb2XForm; const v: TVector2): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function b2MulT(const T: Tb2XForm; const v: TVector2): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function b2Abs(const a: TVector2): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- function b2Abs(const a: TMatrix22): TMatrix22; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- {$IFDEF EXTENDED_PRECISION}
- procedure SinCos(const Theta: Extended; var Sin, Cos: Extended);
- {$ELSE}
- {$IFDEF DOUBLE_PRECISION}
- procedure SinCos(const Theta: Double; var Sin, Cos: Double);
- {$ELSE}
- procedure SinCos(const Theta: Single; var Sin, Cos: Single);
- {$ENDIF}
- {$ENDIF}
- implementation
- {$IFDEF EXTENDED_PRECISION}
- procedure SinCos(const Theta: Extended; var Sin, Cos: Extended);
- asm
- FLD Theta
- FSINCOS
- FSTP TBYTE PTR [EDX] // cosine
- FSTP TBYTE PTR [EAX] // sine
- end;
- {$ELSE}
- {$IFDEF DOUBLE_PRECISION}
- procedure SinCos(const Theta: Double; var Sin, Cos: Double);
- asm
- FLD Theta
- FSINCOS
- FSTP QWORD PTR [EDX] // cosine
- FSTP QWORD PTR [EAX] // sine
- end;
- {$ELSE}
- procedure SinCos(const Theta: Single; var Sin, Cos: Single);
- asm
- FLD Theta
- FSINCOS
- FSTP DWORD PTR [EDX] // cosine
- FSTP DWORD PTR [EAX] // sine
- end;
- {$ENDIF}
- {$ENDIF}
- function MakeVector(x, y: Float): TVector2;
- begin
- Result.x := x;
- Result.y := y;
- end;
- procedure SetZero(var v: TVector2);
- begin
- with v do
- begin
- x := 0.0;
- y := 0.0;
- end;
- end;
- procedure SetValue(var v: TVector2; ax, ay: Float);
- begin
- with v do
- begin
- x := ax;
- y := ay;
- end;
- end;
- {$IFNDEF OP_OVERLOAD}
- function IsValid(const v: TVector2): Boolean;
- begin
- Result := UPhysics2DTypes.IsValid(v.x) and UPhysics2DTypes.IsValid(v.y);
- end;
- function Length(const v: TVector2): Float;
- begin
- with v do
- Result := Sqrt(x * x + y * y);
- end;
- function SqrLength(const v: TVector2): Float;
- begin
- with v do
- Result := x * x + y * y;
- end;
- function Normalize(var v: TVector2): Float;
- begin
- Result := Length(v);
- if Result < FLT_EPSILON then
- begin
- Result := 0.0;
- Exit;
- end;
- with v do
- begin
- x := x / Result;
- y := y / Result;
- end;
- end;
- procedure SetNegative(var v: TVector2);
- begin
- with v do
- begin
- x := -x;
- y := -y;
- end;
- end;
- function Negative(const AValue: TVector2): TVector2;
- begin
- Result.x := -AValue.x;
- Result.y := -AValue.y;
- end;
- function Add(const Left, Right: TVector2): TVector2;
- begin
- Result.x := Left.x + Right.x;
- Result.y := Left.y + Right.y;
- end;
- function Add(const p1, p2, p3: TVector2): TVector2;
- begin
- Result.x := p1.x + p2.x + p3.x;
- Result.y := p1.y + p2.y + p3.y;
- end;
- function Subtract(const Left, Right: TVector2): TVector2;
- begin
- Result.x := Left.x - Right.x;
- Result.y := Left.y - Right.y;
- end;
- function Multiply(const Left: TVector2; const Right: Single): TVector2;
- begin
- Result.x := Left.x * Right;
- Result.y := Left.y * Right;
- end;
- function Multiply(const Left: TVector2; const Right: Double): TVector2;
- begin
- Result.x := Left.x * Right;
- Result.y := Left.y * Right;
- end;
- function Multiply(const Left: TVector2; const Right: Extended): TVector2;
- begin
- Result.x := Left.x * Right;
- Result.y := Left.y * Right;
- end;
- function Divide(const Left: TVector2; const Right: Single): TVector2;
- begin
- Result.x := Left.x / Right;
- Result.y := Left.y / Right;
- end;
- function Divide(const Left: TVector2; const Right: Double): TVector2;
- begin
- Result.x := Left.x / Right;
- Result.y := Left.y / Right;
- end;
- function Divide(const Left: TVector2; const Right: Extended): TVector2;
- begin
- Result.x := Left.x / Right;
- Result.y := Left.y / Right;
- end;
- procedure AddBy(var v: TVector2; const Operand: TVector2);
- begin
- with v do
- begin
- x := x + Operand.x;
- y := y + Operand.y;
- end;
- end;
- procedure SubtractBy(var v: TVector2; const Operand: TVector2);
- begin
- with v do
- begin
- x := x - Operand.x;
- y := y - Operand.y;
- end;
- end;
- procedure MultiplyBy(var v: TVector2; const Operand: Single);
- begin
- with v do
- begin
- x := x * Operand;
- y := y * Operand;
- end;
- end;
- procedure MultiplyBy(var v: TVector2; const Operand: Double);
- begin
- with v do
- begin
- x := x * Operand;
- y := y * Operand;
- end;
- end;
- procedure MultiplyBy(var v: TVector2; const Operand: Extended);
- begin
- with v do
- begin
- x := x * Operand;
- y := y * Operand;
- end;
- end;
- procedure DivideBy(var v: TVector2; const Operand: Single);
- begin
- with v do
- begin
- x := x / Operand;
- y := y / Operand;
- end;
- end;
- procedure DivideBy(var v: TVector2; const Operand: Double);
- begin
- with v do
- begin
- x := x / Operand;
- y := y / Operand;
- end;
- end;
- procedure DivideBy(var v: TVector2; const Operand: Extended);
- begin
- with v do
- begin
- x := x / Operand;
- y := y / Operand;
- end;
- end;
- procedure SetIdentity(var m: TMatrix22);
- begin
- with m do
- begin
- col1.x := 1.0;
- col2.x := 0.0;
- col1.y := 0.0;
- col2.y := 1.0;
- end;
- end;
- procedure SetZero(var m: TMatrix22);
- begin
- with m do
- begin
- col1.x := 0.0;
- col2.x := 0.0;
- col1.y := 0.0;
- col2.y := 0.0;
- end;
- end;
- procedure SetValue(var m: TMatrix22; const _col1, _col2: TVector2);
- begin
- with m do
- begin
- col1 := _col1;
- col2 := _col2;
- end;
- end;
- procedure SetValue(var m: TMatrix22; angle: Float);
- var
- c, s: Float;
- begin
- SinCos(angle, s, c);
- with m do
- begin
- col1.x := c;
- col2.x := -s;
- col1.y := s;
- col2.y := c;
- end;
- end;
- function Invert(const m: TMatrix22): TMatrix22;
- var
- a, b, c, d, det: Float;
- begin
- with m do
- begin
- a := col1.x;
- b := col2.x;
- c := col1.y;
- d := col2.y;
- end;
- det := a * d - b * c;
- {$IFDEF HANDLE_EXCEPTION}
- if IsZero(det) then
- raise TPhysics2DException.Create(ecDivByZero);
- {$ENDIF}
- det := 1.0 / det;
- with Result do
- begin
- col1.x := det * d;
- col2.x := -det * b;
- col1.y := -det * c;
- col2.y := det * a;
- end;
- end;
- function Solve(const m: TMatrix22; const b: TVector2): TVector2;
- var
- a11, a12, a21, a22, det: Float;
- begin
- with m do
- begin
- a11 := col1.x;
- a12 := col2.x;
- a21 := col1.y;
- a22 := col2.y;
- end;
- det := a11 * a22 - a12 * a21;
- {$IFDEF HANDLE_EXCEPTION}
- if IsZero(det) then
- raise TPhysics2DException.Create(ecDivByZero);
- {$ENDIF}
- det := 1.0 / det;
- Result.x := det * (a22 * b.x - a12 * b.y);
- Result.y := det * (a11 * b.y - a21 * b.x);
- end;
- function Negative(const AValue: TMatrix22): TMatrix22;
- begin
- with Result do
- begin
- col1.x := -AValue.col1.x;
- col1.y := -AValue.col1.y;
- col2.x := -AValue.col2.x;
- col2.y := -AValue.col2.y;
- end;
- end;
- function Add(const Left, Right: TMatrix22): TMatrix22;
- begin
- with Result do
- begin
- col1.x := Left.col1.x + Right.col1.x;
- col1.y := Left.col1.y + Right.col1.y;
- col2.x := Left.col2.x + Right.col2.x;
- col2.y := Left.col2.y + Right.col2.y;
- end;
- end;
- function Add(const m1, m2, m3: TMatrix22): TMatrix22;
- begin
- with Result do
- begin
- col1.x := m1.col1.x + m2.col1.x + m3.col1.x;
- col1.y := m1.col1.y + m2.col1.y + m3.col1.y;
- col2.x := m1.col2.x + m2.col2.x + m3.col2.x;
- col2.y := m1.col2.y + m2.col2.y + m3.col2.y;
- end;
- end;
- function Subtract(const Left, Right: TMatrix22): TMatrix22;
- begin
- with Result do
- begin
- col1.x := Left.col1.x - Right.col1.x;
- col1.y := Left.col1.y - Right.col1.y;
- col2.x := Left.col2.x - Right.col2.x;
- col2.y := Left.col2.y - Right.col2.y;
- end;
- end;
- procedure SetIdentity(var xf: Tb2XForm);
- begin
- with xf do
- begin
- SetZero(position);
- SetIdentity(R);
- end;
- end;
- procedure GetXForm(const Sweep: Tb2Sweep; var xf: Tb2XForm; t: Float);
- var
- alpha: Float;
- begin
- with Sweep do
- begin
- // center = p + R * localCenter
- if (1.0 - t0 > FLT_EPSILON) then
- begin
- alpha := (t - t0) / (1.0 - t0);
- xf.position := Add(Multiply(c0, 1.0 - alpha), Multiply(c, alpha));
- SetValue(xf.R, (1.0 - alpha) * a0 + alpha * a);
- end
- else
- begin
- // center = p + R * localCenter
- xf.position := c;
- SetValue(xf.R, a);
- end;
- // Shift to origin
- SubtractBy(xf.position, b2Mul(xf.R, localCenter));
- end;
- end;
- procedure Advance(var Sweep: Tb2Sweep; t: Float);
- var
- alpha: Float;
- begin
- with Sweep do
- begin
- if (t0 < t) and (t0 < 1.0 - FLT_EPSILON) then
- begin
- alpha := (t - t0) / (1.0 - t0);
- c0 := Add(Multiply(c0, 1.0 - alpha), Multiply(c, alpha));
- a0 := (1.0 - alpha) * a0 + alpha * a;
- t0 := t;
- end;
- end;
- end;
- {$ENDIF}
- /// Friction mixing law. Feel free to customize this.
- function b2MixFriction(friction1, friction2: Float): Float; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- begin
- Result := Sqrt(friction1 * friction2);
- end;
- /// Restitution mixing law. Feel free to customize this.
- function b2MixRestitution(restitution1, restitution2: Float): Float; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- begin
- if restitution1 > restitution2 then
- Result := restitution1
- else
- Result := restitution2;
- end;
- function b2Max(const a, b: Float): Float;
- begin
- if a >= b then
- Result := a
- else
- Result := b;
- end;
- function b2Max(const a, b: TVector2): TVector2;
- begin
- Result.x := b2Max(a.x, b.x);
- Result.y := b2Max(a.y, b.y);
- end;
- function b2Min(const a, b: Float): Float;
- begin
- if a >= b then
- Result := b
- else
- Result := a;
- end;
- function b2Min(const a, b: TVector2): TVector2;
- begin
- Result.x := b2Min(a.x, b.x);
- Result.y := b2Min(a.y, b.y);
- end;
- function b2Max(const a, b: Int32): Int32;
- begin
- if a >= b then
- Result := a
- else
- Result := b;
- end;
- function b2Min(const a, b: Int32): Int32;
- begin
- if a >= b then
- Result := b
- else
- Result := a;
- end;
- procedure b2Swap(var a, b: Float);
- var
- tmp: Float;
- begin
- tmp := a;
- a := b;
- b := tmp;
- end;
- procedure b2Swap(var a, b: Int32);
- var
- tmp: Int32;
- begin
- tmp := a;
- a := b;
- b := tmp;
- end;
- procedure b2Swap(var a, b: TVector2);
- var
- tmp: TVector2;
- begin
- tmp := a;
- a := b;
- b := tmp;
- end;
- function b2Clamp(const a, low, high: TVector2): TVector2;
- begin
- Result := b2Max(low, b2Min(a, high));
- end;
- function b2Clamp(const a, low, high: Float): Float;
- begin
- Result := b2Max(low, b2Min(a, high));
- end;
- function IsValid(f: Float): Boolean; {$IFNDEF OP_OVERLOAD}overload;{$ENDIF}
- begin
- Result := not (IsNan(f) or IsInfinite(f));
- end;
- /// Peform the dot product on two vectors.
- function b2Dot(const a, b: TVector2): Float; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- begin
- Result := a.x * b.x + a.y * b.y;
- end;
- /// Perform the cross product on two vectors. In 2D this produces a scalar.
- function b2Cross(const a, b: TVector2): Float; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- begin
- Result := a.x * b.y - a.y * b.x;
- end;
- /// Perform the cross product on a vector and a scalar. In 2D this produces a vector.
- function b2Cross(const a: TVector2; s: Float): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- begin
- Result.x := s * a.y;
- Result.y := -s * a.x;
- end;
- /// Perform the cross product on a scalar and a vector. In 2D this produces a vector.
- function b2Cross(s: Float; const a: TVector2): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- begin
- Result.x := -s * a.y;
- Result.y := s * a.x;
- end;
- /// Multiply a matrix times a vector. If a rotation matrix is provided,
- /// then this transforms the vector from one frame to another.
- function b2Mul(const A: TMatrix22; const v: TVector2): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- begin
- Result.x := A.col1.x * v.x + A.col2.x * v.y;
- Result.y := A.col1.y * v.x + A.col2.y * v.y;
- end;
- /// Multiply a matrix transpose times a vector. If a rotation matrix is provided,
- /// then this transforms the vector from one frame to another (inverse transform).
- function b2MulT(const A: TMatrix22; const v: TVector2): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- begin
- Result.x := b2Dot(v, A.col1);
- Result.y := b2Dot(v, A.col2);
- end;
- {$IFDEF OP_OVERLOAD}
- function b2Distance(const a, b: TVector2): Float; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- begin
- Result := (a - b).Length;
- end;
- function b2DistanceSquared(const a, b: TVector2): Float; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- begin
- Result := (a - b).SqrLength;
- end;
- {$ELSE}
- function b2Distance(const a, b: TVector2): Float; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- begin
- Result := Length(Subtract(a, b));
- end;
- function b2DistanceSquared(const a, b: TVector2): Float; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- begin
- Result := SqrLength(Subtract(a, b));
- end;
- {$ENDIF}
- // A * B
- function b2Mul(const A, B: TMatrix22): TMatrix22; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- begin
- Result.col1 := b2Mul(A, B.col1);
- Result.col2 := b2Mul(A, B.col2);
- end;
- // A^T * B
- function b2MulT(const A, B: TMatrix22): TMatrix22; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- var
- c1, c2: TVector2;
- begin
- with Result do
- begin
- col1.x := b2Dot(A.col1, B.col1);
- col1.y := b2Dot(A.col2, B.col1);
- col2.x := b2Dot(A.col1, B.col2);
- col2.y := b2Dot(A.col2, B.col2);
- end;
- end;
- {$IFDEF OP_OVERLOAD}
- function b2Mul(const T: Tb2XForm; const v: TVector2): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- begin
- Result := T.position + b2Mul(T.R, v);
- end;
- {$ELSE}
- function b2Mul(const T: Tb2XForm; const v: TVector2): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- var
- tmp: TVector2;
- begin
- tmp := b2Mul(T.R, v);
- Result.x := T.position.x + tmp.x;
- Result.y := T.position.y + tmp.y;
- end;
- {$ENDIF}
- {$IFDEF OP_OVERLOAD}
- function b2MulT(const T: Tb2XForm; const v: TVector2): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- begin
- Result := b2MulT(T.R, v - T.position);
- end;
- {$ELSE}
- // unfinished
- function b2MulT(const T: Tb2XForm; const v: TVector2): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- var
- tmp: TVector2;
- begin
- tmp := Subtract(v, T.position);
- Result := b2MulT(T.R, tmp);
- end;
- {$ENDIF}
- function b2Abs(const a: TVector2): TVector2; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- begin
- Result.x := Abs(a.x);
- Result.y := Abs(a.y);
- end;
- function b2Abs(const a: TMatrix22): TMatrix22; overload; {$IFDEF INLINE_AVAIL}inline;{$ENDIF}
- begin
- Result.col1 := b2Abs(a.col1);
- Result.col2 := b2Abs(a.col2);
- end;
- {$IFDEF HANDLE_EXCEPTION}
- constructor TPhysics2DException.Create(ErrorCode: TPhysics2DExceptionCode);
- begin
- case ErrorCode of
- ecDivByZero: ;
- end;
- end;
- {$ENDIF}
- { TVector2 }
- {$IFDEF OP_OVERLOAD}
- function TVector2.IsValid: Boolean;
- begin
- Result := UPhysics2DTypes.IsValid(x) and UPhysics2DTypes.IsValid(y);
- end;
- function TVector2.Length: Float;
- begin
- Result := Sqrt(x * x + y * y);
- end;
- function TVector2.Normalize: Float;
- begin
- Result := Length();
- if Result < FLT_EPSILON then
- begin
- Result := 0.0;
- Exit;
- end;
- x := x / Result;
- y := y / Result;
- end;
- procedure TVector2.SetZero;
- begin
- x := 0.0;
- y := 0.0;
- end;
- procedure TVector2.SetNegative;
- begin
- x := -x;
- y := -y;
- end;
- procedure TVector2.SetValue(x, y: Float);
- begin
- Self.x := x;
- Self.y := y;
- end;
- function TVector2.SqrLength: Float;
- begin
- Result := x * x + y * y;
- end;
- class function TVector2.From(const x, y: Float): TVector2;
- begin
- Result.x := x;
- Result.y := y;
- end;
- class operator TVector2.Negative(const AValue: TVector2): TVector2;
- begin
- Result.x := -AValue.x;
- Result.y := -AValue.y;
- end;
- class operator TVector2.Add(const Left, Right: TVector2): TVector2;
- begin
- Result.x := Left.x + Right.x;
- Result.y := Left.y + Right.y;
- end;
- class operator TVector2.Subtract(const Left, Right: TVector2): TVector2;
- begin
- Result.x := Left.x - Right.x;
- Result.y := Left.y - Right.y;
- end;
- class operator TVector2.Multiply(const Left: TVector2; const Right: Single): TVector2;
- begin
- Result.x := Left.x * Right;
- Result.y := Left.y * Right;
- end;
- class operator TVector2.Multiply(const Left: TVector2; const Right: Double): TVector2;
- begin
- Result.x := Left.x * Right;
- Result.y := Left.y * Right;
- end;
- class operator TVector2.Multiply(const Left: TVector2; const Right: Extended): TVector2;
- begin
- Result.x := Left.x * Right;
- Result.y := Left.y * Right;
- end;
- class operator TVector2.Multiply(const Left: Single; const Right: TVector2): TVector2;
- begin
- Result.x := Left * Right.x;
- Result.y := Left * Right.y;
- end;
- class operator TVector2.Multiply(const Left: Double; const Right: TVector2): TVector2;
- begin
- Result.x := Left * Right.x;
- Result.y := Left * Right.y;
- end;
- class operator TVector2.Multiply(const Left: Extended; const Right: TVector2): TVector2;
- begin
- Result.x := Left * Right.x;
- Result.y := Left * Right.y;
- end;
- class operator TVector2.Divide(const Left: TVector2; const Right: Single): TVector2;
- begin
- Result.x := Left.x / Right;
- Result.y := Left.y / Right;
- end;
- class operator TVector2.Divide(const Left: TVector2; const Right: Double): TVector2;
- begin
- Result.x := Left.x / Right;
- Result.y := Left.y / Right;
- end;
- class operator TVector2.Divide(const Left: TVector2; const Right: Extended): TVector2;
- begin
- Result.x := Left.x / Right;
- Result.y := Left.y / Right;
- end;
- procedure TVector2.AddBy(const Operand: TVector2);
- begin
- x := x + Operand.x;
- y := y + Operand.y;
- end;
- procedure TVector2.SubtractBy(const Operand: TVector2);
- begin
- x := x - Operand.x;
- y := y - Operand.y;
- end;
- procedure TVector2.MultiplyBy(const Operand: Single);
- begin
- x := x * Operand;
- y := y * Operand;
- end;
- procedure TVector2.MultiplyBy(const Operand: Double);
- begin
- x := x * Operand;
- y := y * Operand;
- end;
- procedure TVector2.MultiplyBy(const Operand: Extended);
- begin
- x := x * Operand;
- y := y * Operand;
- end;
- procedure TVector2.DivideBy(const Operand: Single);
- begin
- x := x / Operand;
- y := y / Operand;
- end;
- procedure TVector2.DivideBy(const Operand: Double);
- begin
- x := x / Operand;
- y := y / Operand;
- end;
- procedure TVector2.DivideBy(const Operand: Extended);
- begin
- x := x / Operand;
- y := y / Operand;
- end;
- {$ENDIF}
- { TMatrix22 }
- {$IFDEF OP_OVERLOAD}
- procedure TMatrix22.SetIdentity;
- begin
- col1.x := 1.0;
- col2.x := 0.0;
- col1.y := 0.0;
- col2.y := 1.0;
- end;
- procedure TMatrix22.SetZero;
- begin
- col1.x := 0.0;
- col2.x := 0.0;
- col1.y := 0.0;
- col2.y := 0.0;
- end;
- procedure TMatrix22.SetValue(const _col1, _col2: TVector2);
- begin
- col1 := _col1;
- col2 := _col2;
- end;
- procedure TMatrix22.SetValue(angle: Float);
- var
- c, s: Float;
- begin
- SinCos(angle, s, c);
- col1.x := c;
- col2.x := -s;
- col1.y := s;
- col2.y := c;
- end;
- function TMatrix22.Invert: TMatrix22;
- var
- a, b, c, d, det: Float;
- begin
- a := col1.x;
- b := col2.x;
- c := col1.y;
- d := col2.y;
- det := a * d - b * c;
- {$IFDEF HANDLE_EXCEPTION}
- if IsZero(det) then
- raise TPhysics2DException.Create(ecDivByZero);
- {$ENDIF}
- det := 1.0 / det;
- with Result do
- begin
- col1.x := det * d;
- col2.x := -det * b;
- col1.y := -det * c;
- col2.y := det * a;
- end;
- end;
- function TMatrix22.Solve(const b: TVector2): TVector2;
- var
- a11, a12, a21, a22, det: Float;
- begin
- a11 := col1.x;
- a12 := col2.x;
- a21 := col1.y;
- a22 := col2.y;
- det := a11 * a22 - a12 * a21;
- {$IFDEF HANDLE_EXCEPTION}
- if IsZero(det) then
- raise TPhysics2DException.Create(ecDivByZero);
- {$ENDIF}
- det := 1.0 / det;
- Result.x := det * (a22 * b.x - a12 * b.y);
- Result.y := det * (a11 * b.y - a21 * b.x);
- end;
- class operator TMatrix22.Negative(const AValue: TMatrix22): TMatrix22;
- begin
- with Result do
- begin
- col1.x := -AValue.col1.x;
- col1.y := -AValue.col1.y;
- col2.x := -AValue.col2.x;
- col2.y := -AValue.col2.y;
- end;
- end;
- class operator TMatrix22.Add(const Left, Right: TMatrix22): TMatrix22;
- begin
- with Result do
- begin
- col1.x := Left.col1.x + Right.col1.x;
- col1.y := Left.col1.y + Right.col1.y;
- col2.x := Left.col2.x + Right.col2.x;
- col2.y := Left.col2.y + Right.col2.y;
- end;
- end;
- class operator TMatrix22.Subtract(const Left, Right: TMatrix22): TMatrix22;
- begin
- with Result do
- begin
- col1.x := Left.col1.x - Right.col1.x;
- col1.y := Left.col1.y - Right.col1.y;
- col2.x := Left.col2.x - Right.col2.x;
- col2.y := Left.col2.y - Right.col2.y;
- end;
- end;
- {$ENDIF}
- { Tb2XForm }
- {$IFDEF OP_OVERLOAD}
- procedure Tb2XForm.SetIdentity;
- begin
- position.SetZero;
- R.SetIdentity;
- end;
- class function Tb2XForm.From(const position: TVector2; const R: TMatrix22): Tb2XForm;
- begin
- Result.position := position;
- Result.R := R;
- end;
- {$ENDIF}
- { Tb2Sweep }
- {$IFDEF OP_OVERLOAD}
- procedure Tb2Sweep.GetXForm(var xf: Tb2XForm; t: Float);
- var
- alpha: Float;
- begin
- if (1.0 - t0 > FLT_EPSILON) then
- begin
- alpha := (t - t0) / (1.0 - t0);
- xf.position := (1.0 - alpha) * c0 + alpha * c;
- xf.R.SetValue((1.0 - alpha) * a0 + alpha * a);
- end
- else
- begin
- // center = p + R * localCenter
- xf.position := c;
- xf.R.SetValue(a);
- end;
- // Shift to origin
- xf.position.SubtractBy(b2Mul(xf.R, localCenter));
- end;
- procedure Tb2Sweep.Advance(t: Float);
- var
- alpha: Float;
- begin
- if (t0 < t) and (t0 < 1.0 - FLT_EPSILON) then
- begin
- alpha := (t - t0) / (1.0 - t0);
- c0 := (1.0 - alpha) * c0 + alpha * c;
- a0 := (1.0 - alpha) * a0 + alpha * a;
- t0 := t;
- end;
- end;
- {$ENDIF}
- end.