Castle Game Engine: CastleTriangles

# Unit CastleTriangles
Description | Uses | Classes, Interfaces, Objects and Records | Functions and Procedures | Types | Constants | Variables
## Description Triangles. Triangle is a `TTriangle<point-type>` type. Where `<point-type>` is such suffix that vector type `TVector<point-type>` exists. For example, we have TVector3Single type that represents a point in 3D space, so you can use TTriangle3Single to represent triangle in 3D space. There are also 2D triangles like TTriangle2Single and TTriangle2Double. Triangle's three points must not be collinear, i.e. routines in this unit generally don't accept "degenerated" triangles that are not really triangles. So 3D triangle must unambiguously define some plane in the 3D space. The only function in this unit that is able to handle "degenerated" triangles is IsValidTriangle, which is exactly used to check whether the triangle is degenerated. Since every valid triangle unambiguously determines some plane in the 3D space, it also determines it's normal vector. In this unit, when dealing with normal vectors, I use two names: TriangleNormal means that this is the normalized (i.e. scaled to length 1.0) normal vector. TriangleDir means that this is not necessarily normalized normal vector. ## Uses CastleUtils CastleVectors CastleGenericLists ## Overview ### Classes, Interfaces, Objects and Records
Name | Description
--- | ---
record `T3DTriangleGeometry` | Triangle expressed in particular coordinate system, for T3DTriangle.
Object `T3DTriangle` | 3D triangle.
Object `TFaceIndex` | Describe a range of indexes where the face (polygon and such) is located.
### Functions and Procedures
`function Triangle3Single(const T: TTriangle3Double): TTriangle3Single; overload;`
`function Triangle3Single(const p0, p1, p2: TVector3Single): TTriangle3Single; overload;`
`function Triangle3Double(const T: TTriangle3Single): TTriangle3Double; overload;`
`function Triangle3Double(const p0, p1, p2: TVector3Double): TTriangle3Double; overload;`
`function IsValidTriangle(const Tri: TTriangle3Single): boolean; overload;`
`function IsValidTriangle(const Tri: TTriangle3Double): boolean; overload;`
`function TriangleDir(const Tri: TTriangle3Single): TVector3Single; overload;`
`function TriangleDir(const Tri: TTriangle3Double): TVector3Double; overload;`
`function TriangleDir(const p0, p1, p2: TVector3Single): TVector3Single; overload;`
`function TriangleDir(const p0, p1, p2: TVector3Double): TVector3Double; overload;`
`function TriangleNormal(const Tri: TTriangle3Single): TVector3Single; overload;`
`function TriangleNormal(const Tri: TTriangle3Double): TVector3Double; overload;`
`function TriangleNormal(const p0, p1, p2: TVector3Single): TVector3Single; overload;`
`function TriangleNormal(const p0, p1, p2: TVector3Double): TVector3Double; overload;`
`function TriangleTransform(const Tri: TTriangle3Single; const M: TMatrix4Single): TTriangle3Single; overload;`
`function TriangleTransform(const Tri: TTriangle3Double; const M: TMatrix4Double): TTriangle3Double; overload;`
`function IndexedTriangleNormal(const Indexes: TVector3Cardinal; VerticesArray: PVector3Single; VerticesStride: integer): TVector3Single;`
`function TriangleArea(const Tri: TTriangle3Single): Single; overload;`
`function TriangleArea(const Tri: TTriangle3Double): Double; overload;`
`function TriangleAreaSqr(const Tri: TTriangle3Single): Single; overload;`
`function TriangleAreaSqr(const Tri: TTriangle3Double): Double; overload;`
`function TrianglePlane(const Tri: TTriangle3Single): TVector4Single; overload;`
`function TrianglePlane(const Tri: TTriangle3Double): TVector4Double; overload;`
`function TrianglePlane(const p0, p1, p2: TVector3Single): TVector4Single; overload;`
`function TrianglePlane(const p0, p1, p2: TVector3Double): TVector4Double; overload;`
`function TriangleNormPlane(const Tri: TTriangle3Single): TVector4Single; overload;`
`function TriangleNormPlane(const Tri: TTriangle3Double): TVector4Double; overload;`
`function IsPointWithinTriangle2d(const P: TVector2Single; const Tri: TTriangle2Single): boolean; overload;`
`function IsPointWithinTriangle2d(const P: TVector2Double; const Tri: TTriangle2Double): boolean; overload;`
`function IsPointOnTrianglePlaneWithinTriangle(const P: TVector3Single; const Tri: TTriangle3Single; const TriDir: TVector3Single): boolean; overload;`
`function IsPointOnTrianglePlaneWithinTriangle(const P: TVector3Double; const Tri: TTriangle3Double; const TriDir: TVector3Double): boolean; overload;`
`function IsTriangleSegmentCollision(const Tri: TTriangle3Single; const TriPlane: TVector4Single; const pos1, pos2: TVector3Single): boolean; overload;`
`function IsTriangleSegmentCollision(const Tri: TTriangle3Double; const TriPlane: TVector4Double; const pos1, pos2: TVector3Double): boolean; overload;`
`function IsTriangleSegmentCollision(const Tri: TTriangle3Single; const pos1, pos2: TVector3Single): boolean; overload;`
`function IsTriangleSegmentCollision(const Tri: TTriangle3Double; const pos1, pos2: TVector3Double): boolean; overload;`
`function IsTriangleSphereCollision(const Tri: TTriangle3Single; const TriPlane: TVector4Single; const SphereCenter: TVector3Single; SphereRadius: Single): boolean; overload;`
`function IsTriangleSphereCollision(const Tri: TTriangle3Double; const TriPlane: TVector4Double; const SphereCenter: TVector3Double; SphereRadius: Double): boolean; overload;`
`function IsTriangleSphereCollision(const Tri: TTriangle3Single; const SphereCenter: TVector3Single; SphereRadius: Single): boolean; overload;`
`function IsTriangleSphereCollision(const Tri: TTriangle3Double; const SphereCenter: TVector3Double; SphereRadius: Double): boolean; overload;`
`function TryTriangleSegmentCollision(var Intersection: TVector3Single; const Tri: TTriangle3Single; const TriPlane: TVector4Single; const Pos1, Pos2: TVector3Single): boolean; overload;`
`function TryTriangleSegmentCollision(var Intersection: TVector3Double; const Tri: TTriangle3Double; const TriPlane: TVector4Double; const Pos1, Pos2: TVector3Double): boolean; overload;`
`function TryTriangleSegmentDirCollision(var Intersection: TVector3Single; const Tri: TTriangle3Single; const TriPlane: TVector4Single; const Segment0, SegmentVector: TVector3Single): boolean; overload;`
`function TryTriangleSegmentDirCollision(var Intersection: TVector3Double; const Tri: TTriangle3Double; const TriPlane: TVector4Double; const Segment0, SegmentVector: TVector3Double): boolean; overload;`
`function TryTriangleSegmentDirCollision(var Intersection: TVector3Single; var T: Single; const Tri: TTriangle3Single; const TriPlane: TVector4Single; const Segment0, SegmentVector: TVector3Single): boolean; overload;`
`function TryTriangleSegmentDirCollision(var Intersection: TVector3Double; var T: Double; const Tri: TTriangle3Double; const TriPlane: TVector4Double; const Segment0, SegmentVector: TVector3Double): boolean; overload;`
`function TryTriangleRayCollision(var Intersection: TVector3Single; const Tri: TTriangle3Single; const TriPlane: TVector4Single; const RayOrigin, RayDirection: TVector3Single): boolean; overload;`
`function TryTriangleRayCollision(var Intersection: TVector3Double; const Tri: TTriangle3Double; const TriPlane: TVector4Double; const RayOrigin, RayDirection: TVector3Double): boolean; overload;`
`function TryTriangleRayCollision(var Intersection: TVector3Single; var T: Single; const Tri: TTriangle3Single; const TriPlane: TVector4Single; const RayOrigin, RayDirection: TVector3Single): boolean; overload;`
`function TryTriangleRayCollision(var Intersection: TVector3Double; var T: Double; const Tri: TTriangle3Double; const TriPlane: TVector4Double; const RayOrigin, RayDirection: TVector3Double): boolean; overload;`
`function SampleTrianglePoint(const Tri: TTriangle3Single): TVector3Single;`
`function Barycentric(const Triangle: TTriangle3Single; const Point: TVector3Single): TVector3Single;`
`function IndexedConvexPolygonNormal( Indices: PArray_Longint; IndicesCount: integer; Verts: PVector3Single; const VertsCount: Integer; const ResultForIncorrectPoly: TVector3Single): TVector3Single; overload;`
`function IndexedConvexPolygonNormal( Indices: PArray_Longint; IndicesCount: integer; Verts: PVector3Single; const VertsCount: Integer; const VertsStride: PtrUInt; const ResultForIncorrectPoly: TVector3Single): TVector3Single; overload;`
`function IndexedConvexPolygonArea( Indices: PArray_Longint; IndicesCount: integer; Verts: PArray_Vector3Single; const VertsCount: Integer): Single; overload;`
`function IndexedConvexPolygonArea( Indices: PArray_Longint; IndicesCount: integer; Verts: PVector3Single; const VertsCount: Integer; const VertsStride: PtrUInt): Single; overload;`
`function IsPolygon2dCCW(Verts: PArray_Vector2Single; const VertsCount: Integer): Single; overload;`
`function IsPolygon2dCCW(const Verts: array of TVector2Single): Single; overload;`
`function Polygon2dArea(Verts: PArray_Vector2Single; const VertsCount: Integer): Single; overload;`
`function Polygon2dArea(const Verts: array of TVector2Single): Single; overload;`
`function TriangleToNiceStr(const t: TTriangle2Single): string; overload;`
`function TriangleToNiceStr(const t: TTriangle2Double): string; overload;`
`function TriangleToNiceStr(const t: TTriangle3Single): string; overload;`
`function TriangleToNiceStr(const t: TTriangle3Double): string; overload;`
`function TriangleToRawStr(const t: TTriangle3Single): string; overload;`
`function TriangleToRawStr(const t: TTriangle3Double): string; overload;`
### Types
`TTriangle2Single = packed array[0..2]of TVector2Single;`
`PTriangle2Single = ˆTTriangle2Single;`
`TTriangle2Double = packed array[0..2]of TVector2Double;`
`PTriangle2Double = ˆTTriangle2Double;`
`TTriangle2Extended = packed array[0..2]of TVector2Extended;`
`PTriangle2Extended = ˆTTriangle2Extended;`
`TTriangle3Single = packed array[0..2]of TVector3Single;`
`PTriangle3Single = ˆTTriangle3Single;`
`TTriangle3Double = packed array[0..2]of TVector3Double;`
`PTriangle3Double = ˆTTriangle3Double;`
`TTriangle3Extended = packed array[0..2]of TVector3Extended;`
`PTriangle3Extended = ˆTTriangle3Extended;`
`TTriangle4Single = packed array[0..2]of TVector4Single;`
`PTriangle4Single = ˆTTriangle4Single;`
`P3DTriangle = ˆT3DTriangle;`
`T3DTriangleIgnoreFunc = function ( const Sender: TObject; const Triangle: P3DTriangle): boolean of object;`
`TFaceIndexesList = specialize TGenericStructList<TFaceIndex>;`
### Constants
`UnknownFaceIndex: TFaceIndex = (IndexBegin: -1; IndexEnd: -1);`
## Description ### Functions and Procedures
`function Triangle3Single(const T: TTriangle3Double): TTriangle3Single; overload;`
`function Triangle3Single(const p0, p1, p2: TVector3Single): TTriangle3Single; overload;`
`function Triangle3Double(const T: TTriangle3Single): TTriangle3Double; overload;`
`function Triangle3Double(const p0, p1, p2: TVector3Double): TTriangle3Double; overload;`
`function IsValidTriangle(const Tri: TTriangle3Single): boolean; overload;`
Check does the triangle define a correct plane in 3D space. That is, check does the triangle not degenerate to a point or line segment (which can happen when some points are at the same position, or are colinear).
`function IsValidTriangle(const Tri: TTriangle3Double): boolean; overload;`
`function TriangleDir(const Tri: TTriangle3Single): TVector3Single; overload;`
Normal vector of a triangle. Returns vector pointing our from CCW triangle side (for right-handed coordinate system), and orthogonal to triangle plane. The version "Dir" (TriangleDir) doesn't normalize the result (it may not have length equal 1). For degenerated triangles (when IsValidTriangle would return false), we return zero vector.
`function TriangleDir(const Tri: TTriangle3Double): TVector3Double; overload;`
`function TriangleDir(const p0, p1, p2: TVector3Single): TVector3Single; overload;`
`function TriangleDir(const p0, p1, p2: TVector3Double): TVector3Double; overload;`
`function TriangleNormal(const Tri: TTriangle3Single): TVector3Single; overload;`
`function TriangleNormal(const Tri: TTriangle3Double): TVector3Double; overload;`
`function TriangleNormal(const p0, p1, p2: TVector3Single): TVector3Single; overload;`
`function TriangleNormal(const p0, p1, p2: TVector3Double): TVector3Double; overload;`
`function TriangleTransform(const Tri: TTriangle3Single; const M: TMatrix4Single): TTriangle3Single; overload;`
Transform triangle by 4x4 matrix. This simply transforms each triangle point. ###### Exceptions raised ETransformedResultInvalid Raised when matrix will transform some point to a direction (vector with 4th component equal zero). In this case we just cannot interpret the result as a 3D point.
`function TriangleTransform(const Tri: TTriangle3Double; const M: TMatrix4Double): TTriangle3Double; overload;`
`function IndexedTriangleNormal(const Indexes: TVector3Cardinal; VerticesArray: PVector3Single; VerticesStride: integer): TVector3Single;`
Normal vector of a triangle defined as three indexes intro vertex array. VerticesStride is the shift between vertex values in the array, VerticesStride = 0 behaves like VerticesStride = SizeOf(TVector3Single).
`function TriangleArea(const Tri: TTriangle3Single): Single; overload;`
Surface area of 3D triangle. This works for degenerated (equal to line segment or even single point) triangles too: returns 0 for them.
`function TriangleArea(const Tri: TTriangle3Double): Double; overload;`
`function TriangleAreaSqr(const Tri: TTriangle3Single): Single; overload;`
`function TriangleAreaSqr(const Tri: TTriangle3Double): Double; overload;`
`function TrianglePlane(const Tri: TTriangle3Single): TVector4Single; overload;`
Plane of the triangle. Note that this has many possible solutions (plane representation as equation `Ax + By + Cz + D = 0` is not unambiguous), this just returns some solution deterministically. It's guaranteed that the direction of this plane (i.e. first 3 items of returned vector) will be in the same direction as calcualted by TriangleDir, which means that it points outward from CCW side of the triangle (assuming right-handed coord system). For TriangleNormPlane, this direction is also normalized (makes a vector with length 1). This way TrianglePlane calculates also TriangleNormal. For three points that do not define a plane, a plane with first three components = 0 is returned. In fact, the 4th component will be zero too in this case (for now), but don't depend on it.
`function TrianglePlane(const Tri: TTriangle3Double): TVector4Double; overload;`
`function TrianglePlane(const p0, p1, p2: TVector3Single): TVector4Single; overload;`
`function TrianglePlane(const p0, p1, p2: TVector3Double): TVector4Double; overload;`
`function TriangleNormPlane(const Tri: TTriangle3Single): TVector4Single; overload;`
`function TriangleNormPlane(const Tri: TTriangle3Double): TVector4Double; overload;`
`function IsPointWithinTriangle2d(const P: TVector2Single; const Tri: TTriangle2Single): boolean; overload;`
`function IsPointWithinTriangle2d(const P: TVector2Double; const Tri: TTriangle2Double): boolean; overload;`
`function IsPointOnTrianglePlaneWithinTriangle(const P: TVector3Single; const Tri: TTriangle3Single; const TriDir: TVector3Single): boolean; overload;`
Assuming a point lies on a triangle plane, check does it lie inside a triangle. Give first 3 components of triangle plane as TriDir.
`function IsPointOnTrianglePlaneWithinTriangle(const P: TVector3Double; const Tri: TTriangle3Double; const TriDir: TVector3Double): boolean; overload;`
`function IsTriangleSegmentCollision(const Tri: TTriangle3Single; const TriPlane: TVector4Single; const pos1, pos2: TVector3Single): boolean; overload;`
Check triangle with line segment collision. You can pass the triangle plane along with a triangle, this will speed calculation.
`function IsTriangleSegmentCollision(const Tri: TTriangle3Double; const TriPlane: TVector4Double; const pos1, pos2: TVector3Double): boolean; overload;`
`function IsTriangleSegmentCollision(const Tri: TTriangle3Single; const pos1, pos2: TVector3Single): boolean; overload;`
`function IsTriangleSegmentCollision(const Tri: TTriangle3Double; const pos1, pos2: TVector3Double): boolean; overload;`
`function IsTriangleSphereCollision(const Tri: TTriangle3Single; const TriPlane: TVector4Single; const SphereCenter: TVector3Single; SphereRadius: Single): boolean; overload;`
`function IsTriangleSphereCollision(const Tri: TTriangle3Double; const TriPlane: TVector4Double; const SphereCenter: TVector3Double; SphereRadius: Double): boolean; overload;`
`function IsTriangleSphereCollision(const Tri: TTriangle3Single; const SphereCenter: TVector3Single; SphereRadius: Single): boolean; overload;`
`function IsTriangleSphereCollision(const Tri: TTriangle3Double; const SphereCenter: TVector3Double; SphereRadius: Double): boolean; overload;`
`function TryTriangleSegmentCollision(var Intersection: TVector3Single; const Tri: TTriangle3Single; const TriPlane: TVector4Single; const Pos1, Pos2: TVector3Single): boolean; overload;`
Calculate triangle with line segment collision. You can pass the triangle plane along with a triangle, this will speed calculation. When there's no intersection, returns `False` and doesn't modify Intersection or T.
`function TryTriangleSegmentCollision(var Intersection: TVector3Double; const Tri: TTriangle3Double; const TriPlane: TVector4Double; const Pos1, Pos2: TVector3Double): boolean; overload;`
`function TryTriangleSegmentDirCollision(var Intersection: TVector3Single; const Tri: TTriangle3Single; const TriPlane: TVector4Single; const Segment0, SegmentVector: TVector3Single): boolean; overload;`
`function TryTriangleSegmentDirCollision(var Intersection: TVector3Double; const Tri: TTriangle3Double; const TriPlane: TVector4Double; const Segment0, SegmentVector: TVector3Double): boolean; overload;`
`function TryTriangleSegmentDirCollision(var Intersection: TVector3Single; var T: Single; const Tri: TTriangle3Single; const TriPlane: TVector4Single; const Segment0, SegmentVector: TVector3Single): boolean; overload;`
`function TryTriangleSegmentDirCollision(var Intersection: TVector3Double; var T: Double; const Tri: TTriangle3Double; const TriPlane: TVector4Double; const Segment0, SegmentVector: TVector3Double): boolean; overload;`
`function TryTriangleRayCollision(var Intersection: TVector3Single; const Tri: TTriangle3Single; const TriPlane: TVector4Single; const RayOrigin, RayDirection: TVector3Single): boolean; overload;`
Calculate triangle with ray collision. You can pass the triangle plane along with a triangle, this will speed calculation. When there's no intersection, returns `False` and doesn't modify Intersection or T.
`function TryTriangleRayCollision(var Intersection: TVector3Double; const Tri: TTriangle3Double; const TriPlane: TVector4Double; const RayOrigin, RayDirection: TVector3Double): boolean; overload;`
`function TryTriangleRayCollision(var Intersection: TVector3Single; var T: Single; const Tri: TTriangle3Single; const TriPlane: TVector4Single; const RayOrigin, RayDirection: TVector3Single): boolean; overload;`
`function TryTriangleRayCollision(var Intersection: TVector3Double; var T: Double; const Tri: TTriangle3Double; const TriPlane: TVector4Double; const RayOrigin, RayDirection: TVector3Double): boolean; overload;`
`function SampleTrianglePoint(const Tri: TTriangle3Single): TVector3Single;`
Random triangle point, chosen with a constant density for triangle area.
`function Barycentric(const Triangle: TTriangle3Single; const Point: TVector3Single): TVector3Single;`
For a given Point lying on a given Triangle, calculate it's barycentric coordinates. The resulting Barycentric coordinates can be used for linearly interpolating values along the triangle, as they satisfy the equation:
      Result[0] * Triangle[0] +
      Result[1] * Triangle[1] +
      Result[2] * Triangle[2] = Point
See also [http://en.wikipedia.org/wiki/Barycentric_coordinate_system_%28mathematics%29]
`function IndexedConvexPolygonNormal( Indices: PArray_Longint; IndicesCount: integer; Verts: PVector3Single; const VertsCount: Integer; const ResultForIncorrectPoly: TVector3Single): TVector3Single; overload;`
Calculates normalized normal vector for polygon composed from indexed vertices. Polygon is defines as vertices Verts[Indices[0]], Verts[Indices[1]] ... Verts[Indices[IndicesCount-1]]. Returns normal pointing from CCW. It's secured against invalid indexes on Indices list (that's the only reason why it takes VertsCount parameter, after all): they are ignored. If the polygon is degenerated, that is it doesn't determine a plane in 3D space (this includes, but is not limited, to cases when there are less than 3 valid points, like when IndicesCount < 3) then it returns ResultForIncorrectPoly.
`function IndexedConvexPolygonNormal( Indices: PArray_Longint; IndicesCount: integer; Verts: PVector3Single; const VertsCount: Integer; const VertsStride: PtrUInt; const ResultForIncorrectPoly: TVector3Single): TVector3Single; overload;`
`function IndexedConvexPolygonArea( Indices: PArray_Longint; IndicesCount: integer; Verts: PArray_Vector3Single; const VertsCount: Integer): Single; overload;`
Surface area of indexed convex polygon. Polygon is defines as vertices Verts[Indices[0]], Verts[Indices[1]] ... Verts[Indices[IndicesCount-1]]. It's secured against invalid indexes on Indices list (that's the only reason why it takes VertsCount parameter, after all): they are ignored.
`function IndexedConvexPolygonArea( Indices: PArray_Longint; IndicesCount: integer; Verts: PVector3Single; const VertsCount: Integer; const VertsStride: PtrUInt): Single; overload;`
`function IsPolygon2dCCW(Verts: PArray_Vector2Single; const VertsCount: Integer): Single; overload;`
Are the polygon points ordered CCW (counter-clockwise). When viewed with typical camera settings, that is +Y goes up and +X goes right. Polygon doesn't have to be convex. Polygon doesn't have to have all triangles valid, that is it's OK if some polygon triangles degenerate into points or line segments. Returns something > 0 if polygon is CCW, or < 0 when it's not. Returns zero when polygon has area 0.
`function IsPolygon2dCCW(const Verts: array of TVector2Single): Single; overload;`
`function Polygon2dArea(Verts: PArray_Vector2Single; const VertsCount: Integer): Single; overload;`
Calculate polygon area. Polygon doesn't have to be convex. Polygon doesn't have to have all triangles valid, that is it's OK if some polygon triangles degenerate into points or line segments.
`function Polygon2dArea(const Verts: array of TVector2Single): Single; overload;`
`function TriangleToNiceStr(const t: TTriangle2Single): string; overload;`
`function TriangleToNiceStr(const t: TTriangle2Double): string; overload;`
`function TriangleToNiceStr(const t: TTriangle3Single): string; overload;`
`function TriangleToNiceStr(const t: TTriangle3Double): string; overload;`
`function TriangleToRawStr(const t: TTriangle3Single): string; overload;`
`function TriangleToRawStr(const t: TTriangle3Double): string; overload;`
### Types
`TTriangle2Single = packed array[0..2]of TVector2Single;`
`PTriangle2Single = ˆTTriangle2Single;`
`TTriangle2Double = packed array[0..2]of TVector2Double;`
`PTriangle2Double = ˆTTriangle2Double;`
`TTriangle2Extended = packed array[0..2]of TVector2Extended;`
`PTriangle2Extended = ˆTTriangle2Extended;`
`TTriangle3Single = packed array[0..2]of TVector3Single;`
`PTriangle3Single = ˆTTriangle3Single;`
`TTriangle3Double = packed array[0..2]of TVector3Double;`
`PTriangle3Double = ˆTTriangle3Double;`
`TTriangle3Extended = packed array[0..2]of TVector3Extended;`
`PTriangle3Extended = ˆTTriangle3Extended;`
`TTriangle4Single = packed array[0..2]of TVector4Single;`
`PTriangle4Single = ˆTTriangle4Single;`
`P3DTriangle = ˆT3DTriangle;`
`T3DTriangleIgnoreFunc = function ( const Sender: TObject; const Triangle: P3DTriangle): boolean of object;`
Return for given Triangle do we want to ignore collisions with it. For now, Sender is always TTriangleOctree.
`TFaceIndexesList = specialize TGenericStructList<TFaceIndex>;`
### Constants
`UnknownFaceIndex: TFaceIndex = (IndexBegin: -1; IndexEnd: -1);`
Generated by PasDoc 0.13.0 on 2015-06-15 04:43:12