PartitionedMesh


public final class PartitionedMesh


An immutable** complex shape expressed as a set of triangles. This is used to represent the shape of a stroke or other complex objects. The mesh may be divided into multiple partitions, which enables certain brush effects (e.g. "multi-coat"), and allows ink to create strokes using greater than 2^16 triangles (which must be rendered in multiple passes).

A PartitionedMesh may optionally have one or more "outlines", which are polylines that traverse some or all of the vertices in the mesh; these are used for path-based rendering of strokes. This supports disjoint meshes such as dashed lines.

PartitionedMesh provides fast intersection and coverage testing by use of an internal spatial index.

** PartitionedMesh is technically not immutable, as the spatial index is lazily instantiated; however, from the perspective of a caller, its properties do not change over the course of its lifetime. The entire object is thread-safe.

Summary

Public methods

final Box

Returns the minimum bounding box of the PartitionedMesh.

final @FloatRange(from = 0.0, to = 1.0) float

Computes an approximate measure of what portion of this PartitionedMesh is covered by or overlaps with box.

final @FloatRange(from = 0.0, to = 1.0) float
computeCoverage(
    @NonNull PartitionedMesh other,
    @NonNull AffineTransform otherShapeToThis
)

Computes an approximate measure of what portion of this PartitionedMesh is covered by or overlaps with the other.

final @FloatRange(from = 0.0, to = 1.0) float
computeCoverage(
    @NonNull Parallelogram parallelogram,
    @NonNull AffineTransform parallelogramToThis
)

Computes an approximate measure of what portion of this PartitionedMesh is covered by or overlaps with parallelogram.

final @FloatRange(from = 0.0, to = 1.0) float
computeCoverage(
    @NonNull Triangle triangle,
    @NonNull AffineTransform triangleToThis
)

Computes an approximate measure of what portion of this PartitionedMesh is covered by or overlaps with triangle.

final boolean
computeCoverageIsGreaterThan(
    @NonNull Box box,
    float coverageThreshold,
    @NonNull AffineTransform boxToThis
)

Returns true if the approximate portion of the PartitionedMesh covered by box is greater than coverageThreshold.

final boolean
computeCoverageIsGreaterThan(
    @NonNull PartitionedMesh other,
    float coverageThreshold,
    @NonNull AffineTransform otherShapeToThis
)

Returns true if the approximate portion of this PartitionedMesh covered by the other is greater than coverageThreshold.

final boolean
computeCoverageIsGreaterThan(
    @NonNull Parallelogram parallelogram,
    float coverageThreshold,
    @NonNull AffineTransform parallelogramToThis
)

Returns true if the approximate portion of the PartitionedMesh covered by parallelogram is greater than coverageThreshold.

final boolean
computeCoverageIsGreaterThan(
    @NonNull Triangle triangle,
    float coverageThreshold,
    @NonNull AffineTransform triangleToThis
)

Returns true if the approximate portion of the PartitionedMesh covered by triangle is greater than coverageThreshold.

final @IntRange(from = 0) int
getOutlineCount(@IntRange(from = 0) int groupIndex)

Returns the number of outlines that comprise the render group at groupIndex.

final @IntRange(from = 0) int
getOutlineVertexCount(
    @IntRange(from = 0) int groupIndex,
    @IntRange(from = 0) int outlineIndex
)

Returns the number of vertices that are in the outline at outlineIndex in the render group at groupIndex.

final @IntRange(from = 0) int

Returns the number of render groups in this mesh.

final void

Initializes this MutableEnvelope's spatial index for geometry queries.

final @NonNull MutableVec
populateOutlinePosition(
    @IntRange(from = 0) int groupIndex,
    @IntRange(from = 0) int outlineIndex,
    @IntRange(from = 0) int outlineVertexIndex,
    @NonNull MutableVec outPosition
)

Populates outPosition with the position of the outline vertex at outlineVertexIndex in the outline at outlineIndex in the render group at groupIndex, and returns outPosition.

@NonNull String

Protected methods

final void

Public methods

computeBoundingBox

Added in 1.0.0-alpha01
public final Box computeBoundingBox()

Returns the minimum bounding box of the PartitionedMesh. This will be null if the PartitionedMesh is empty.

computeCoverage

Added in 1.0.0-alpha01
public final @FloatRange(from = 0.0, to = 1.0) float computeCoverage(@NonNull Box box, @NonNull AffineTransform boxToThis)

Computes an approximate measure of what portion of this PartitionedMesh is covered by or overlaps with box. This is calculated by finding the sum of areas of the triangles that intersect the given box, and dividing that by the sum of the areas of all triangles in the PartitionedMesh, all in the PartitionedMesh's coordinate space. Triangles in the PartitionedMesh that overlap each other (e.g. in the case of a stroke that loops back over itself) are counted individually. Note that, if any triangles have negative area (due to winding, see Triangle.computeSignedArea), the absolute value of their area will be used instead.

On an empty PartitionedMesh, this will always return 0.

Optional argument boxToThis contains the transform that maps from box's coordinate space to this PartitionedMesh's coordinate space, which defaults to AffineTransform.IDENTITY.

computeCoverage

Added in 1.0.0-alpha01
public final @FloatRange(from = 0.0, to = 1.0) float computeCoverage(
    @NonNull PartitionedMesh other,
    @NonNull AffineTransform otherShapeToThis
)

Computes an approximate measure of what portion of this PartitionedMesh is covered by or overlaps with the other. This is calculated by finding the sum of areas of the triangles that intersect other, and dividing that by the sum of the areas of all triangles in the PartitionedMesh, all in the PartitionedMesh's coordinate space. Triangles in the PartitionedMesh that overlap each other (e.g. in the case of a stroke that loops back over itself) are counted individually. Note that, if any triangles have negative area (due to winding, see Triangle.computeSignedArea), the absolute value of their area will be used instead.

On an empty PartitionedMesh, this will always return 0.

Optional argument otherShapeToThis contains the transform that maps from other's coordinate space to this PartitionedMesh's coordinate space, which defaults to AffineTransform.IDENTITY.

computeCoverage

Added in 1.0.0-alpha01
public final @FloatRange(from = 0.0, to = 1.0) float computeCoverage(
    @NonNull Parallelogram parallelogram,
    @NonNull AffineTransform parallelogramToThis
)

Computes an approximate measure of what portion of this PartitionedMesh is covered by or overlaps with parallelogram. This is calculated by finding the sum of areas of the triangles that intersect the given parallelogram, and dividing that by the sum of the areas of all triangles in the PartitionedMesh, all in the PartitionedMesh's coordinate space. Triangles in the PartitionedMesh that overlap each other (e.g. in the case of a stroke that loops back over itself) are counted individually. Note that, if any triangles have negative area (due to winding, see Triangle.computeSignedArea), the absolute value of their area will be used instead.

On an empty PartitionedMesh, this will always return 0.

Optional argument parallelogramToThis contains the transform that maps from parallelogram's coordinate space to this PartitionedMesh's coordinate space, which defaults to AffineTransform.IDENTITY.

computeCoverage

Added in 1.0.0-alpha01
public final @FloatRange(from = 0.0, to = 1.0) float computeCoverage(
    @NonNull Triangle triangle,
    @NonNull AffineTransform triangleToThis
)

Computes an approximate measure of what portion of this PartitionedMesh is covered by or overlaps with triangle. This is calculated by finding the sum of areas of the triangles that intersect the given triangle, and dividing that by the sum of the areas of all triangles in the PartitionedMesh, all in the PartitionedMesh's coordinate space. Triangles in the PartitionedMesh that overlap each other (e.g. in the case of a stroke that loops back over itself) are counted individually. Note that, if any triangles have negative area (due to winding, see Triangle.computeSignedArea), the absolute value of their area will be used instead.

On an empty PartitionedMesh, this will always return 0.

Optional argument triangleToThis contains the transform that maps from triangle's coordinate space to this PartitionedMesh's coordinate space, which defaults to AffineTransform.IDENTITY.

computeCoverageIsGreaterThan

Added in 1.0.0-alpha01
public final boolean computeCoverageIsGreaterThan(
    @NonNull Box box,
    float coverageThreshold,
    @NonNull AffineTransform boxToThis
)

Returns true if the approximate portion of the PartitionedMesh covered by box is greater than coverageThreshold.

This is equivalent to:

computeCoverage(box, boxToThis) coverageThreshold

but may be faster.

On an empty PartitionedMesh, this will always return 0.

Optional argument boxToThis contains the transform that maps from box's coordinate space to this PartitionedMesh's coordinate space, which defaults to AffineTransform.IDENTITY.

computeCoverageIsGreaterThan

Added in 1.0.0-alpha01
public final boolean computeCoverageIsGreaterThan(
    @NonNull PartitionedMesh other,
    float coverageThreshold,
    @NonNull AffineTransform otherShapeToThis
)

Returns true if the approximate portion of this PartitionedMesh covered by the other is greater than coverageThreshold.

This is equivalent to:

computeCoverage(other, otherShapeToThis) coverageThreshold

but may be faster.

On an empty PartitionedMesh, this will always return 0.

Optional argument otherShapeToThis contains the transform that maps from other's coordinate space to this PartitionedMesh's coordinate space, which defaults to AffineTransform.IDENTITY.

computeCoverageIsGreaterThan

Added in 1.0.0-alpha01
public final boolean computeCoverageIsGreaterThan(
    @NonNull Parallelogram parallelogram,
    float coverageThreshold,
    @NonNull AffineTransform parallelogramToThis
)

Returns true if the approximate portion of the PartitionedMesh covered by parallelogram is greater than coverageThreshold.

This is equivalent to:

computeCoverage(parallelogram, parallelogramToThis) coverageThreshold

but may be faster.

On an empty PartitionedMesh, this will always return 0.

Optional argument parallelogramToThis contains the transform that maps from parallelogram's coordinate space to this PartitionedMesh's coordinate space, which defaults to AffineTransform.IDENTITY.

computeCoverageIsGreaterThan

Added in 1.0.0-alpha01
public final boolean computeCoverageIsGreaterThan(
    @NonNull Triangle triangle,
    float coverageThreshold,
    @NonNull AffineTransform triangleToThis
)

Returns true if the approximate portion of the PartitionedMesh covered by triangle is greater than coverageThreshold.

This is equivalent to:

computeCoverage(triangle, triangleToThis) coverageThreshold

but may be faster.

On an empty PartitionedMesh, this will always return 0.

Optional argument triangleToThis contains the transform that maps from triangle's coordinate space to this PartitionedMesh's coordinate space, which defaults to AffineTransform.IDENTITY.

getOutlineCount

Added in 1.0.0-alpha01
public final @IntRange(from = 0) int getOutlineCount(@IntRange(from = 0) int groupIndex)

Returns the number of outlines that comprise the render group at groupIndex.

getOutlineVertexCount

Added in 1.0.0-alpha01
public final @IntRange(from = 0) int getOutlineVertexCount(
    @IntRange(from = 0) int groupIndex,
    @IntRange(from = 0) int outlineIndex
)

Returns the number of vertices that are in the outline at outlineIndex in the render group at groupIndex.

getRenderGroupCount

Added in 1.0.0-alpha01
public final @IntRange(from = 0) int getRenderGroupCount()

Returns the number of render groups in this mesh. Each outline in the PartitionedMesh belongs to exactly one render group, which are numbered in z-order: the group with index zero should be rendered on bottom; the group with the highest index should be rendered on top.

initializeSpatialIndex

Added in 1.0.0-alpha01
public final void initializeSpatialIndex()

Initializes this MutableEnvelope's spatial index for geometry queries. If a geometry query is made with this shape and the spatial index is not currently initialized, it will be initialized in real time to satisfy that query.

populateOutlinePosition

Added in 1.0.0-alpha01
public final @NonNull MutableVec populateOutlinePosition(
    @IntRange(from = 0) int groupIndex,
    @IntRange(from = 0) int outlineIndex,
    @IntRange(from = 0) int outlineVertexIndex,
    @NonNull MutableVec outPosition
)

Populates outPosition with the position of the outline vertex at outlineVertexIndex in the outline at outlineIndex in the render group at groupIndex, and returns outPosition. groupIndex must be less than getRenderGroupCount, outlineIndex must be less getOutlineVertexCount for groupIndex, and outlineVertexIndex must be less than getOutlineVertexCount for groupIndex and outlineIndex.

toString

public @NonNull String toString()

Protected methods

finalize

Added in 1.0.0-alpha01
protected final void finalize()