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 functions

Box?

Returns the minimum bounding box of the PartitionedMesh.

android
@FloatRange(from = 0.0, to = 1.0) Float
computeCoverage(box: Box, boxToThis: AffineTransform)

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

android
@FloatRange(from = 0.0, to = 1.0) Float
computeCoverage(
    other: PartitionedMesh,
    otherShapeToThis: AffineTransform
)

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

android
@FloatRange(from = 0.0, to = 1.0) Float
computeCoverage(
    parallelogram: Parallelogram,
    parallelogramToThis: AffineTransform
)

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

android
@FloatRange(from = 0.0, to = 1.0) Float
computeCoverage(triangle: Triangle, triangleToThis: AffineTransform)

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

android
Boolean
computeCoverageIsGreaterThan(
    box: Box,
    coverageThreshold: Float,
    boxToThis: AffineTransform
)

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

android
Boolean
computeCoverageIsGreaterThan(
    other: PartitionedMesh,
    coverageThreshold: Float,
    otherShapeToThis: AffineTransform
)

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

android
Boolean
computeCoverageIsGreaterThan(
    parallelogram: Parallelogram,
    coverageThreshold: Float,
    parallelogramToThis: AffineTransform
)

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

android
Boolean
computeCoverageIsGreaterThan(
    triangle: Triangle,
    coverageThreshold: Float,
    triangleToThis: AffineTransform
)

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

android
@IntRange(from = 0) Int
getOutlineCount(groupIndex: @IntRange(from = 0) Int)

Returns the number of outlines of the mesh for the render group at groupIndex.

android
@IntRange(from = 0) Int
getOutlineVertexCount(
    groupIndex: @IntRange(from = 0) Int,
    outlineIndex: @IntRange(from = 0) Int
)

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

android
@IntRange(from = 0) Int

Returns the number of render groups in this mesh.

android
Unit

Initializes this MutableEnvelope's spatial index for geometry queries.

android
MutableVec
populateOutlinePosition(
    groupIndex: @IntRange(from = 0) Int,
    outlineIndex: @IntRange(from = 0) Int,
    outlineVertexIndex: @IntRange(from = 0) Int,
    outPosition: MutableVec
)

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.

android
open String
android

Protected functions

Unit
android

Extension functions

Path
PartitionedMesh.outlinesToPath(renderGroupIndex: @IntRange(from = 0) Int)

Returns a Path containing the outlines in the render group at renderGroupIndex.

android
Path
PartitionedMesh.populateOutlines(
    renderGroupIndex: @IntRange(from = 0) Int,
    out: Path
)

Replaces the contents of out with the outline of the render group at renderGroupIndex.

android

Public functions

computeBoundingBox

fun computeBoundingBox(): Box?

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

computeCoverage

fun computeCoverage(
    box: Box,
    boxToThis: AffineTransform = AffineTransform.IDENTITY
): @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. 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

fun computeCoverage(
    other: PartitionedMesh,
    otherShapeToThis: AffineTransform = AffineTransform.IDENTITY
): @FloatRange(from = 0.0, to = 1.0) Float

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

fun computeCoverage(
    parallelogram: Parallelogram,
    parallelogramToThis: AffineTransform = AffineTransform.IDENTITY
): @FloatRange(from = 0.0, to = 1.0) Float

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

fun computeCoverage(
    triangle: Triangle,
    triangleToThis: AffineTransform = AffineTransform.IDENTITY
): @FloatRange(from = 0.0, to = 1.0) Float

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

fun computeCoverageIsGreaterThan(
    box: Box,
    coverageThreshold: Float,
    boxToThis: AffineTransform = AffineTransform.IDENTITY
): Boolean

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

fun computeCoverageIsGreaterThan(
    other: PartitionedMesh,
    coverageThreshold: Float,
    otherShapeToThis: AffineTransform = AffineTransform.IDENTITY
): Boolean

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

fun computeCoverageIsGreaterThan(
    parallelogram: Parallelogram,
    coverageThreshold: Float,
    parallelogramToThis: AffineTransform = AffineTransform.IDENTITY
): Boolean

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

fun computeCoverageIsGreaterThan(
    triangle: Triangle,
    coverageThreshold: Float,
    triangleToThis: AffineTransform = AffineTransform.IDENTITY
): Boolean

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

fun getOutlineCount(groupIndex: @IntRange(from = 0) Int): @IntRange(from = 0) Int

Returns the number of outlines of the mesh for the render group at groupIndex.

Groups with discontinuous geometry will always have multiple outlines, but even continuous geometry may be drawn with multiple overlapping outlines when this improves rendering quality or performance.

getOutlineVertexCount

fun getOutlineVertexCount(
    groupIndex: @IntRange(from = 0) Int,
    outlineIndex: @IntRange(from = 0) Int
): @IntRange(from = 0) Int

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

getRenderGroupCount

fun getRenderGroupCount(): @IntRange(from = 0) Int

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

fun initializeSpatialIndex(): Unit

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

fun populateOutlinePosition(
    groupIndex: @IntRange(from = 0) Int,
    outlineIndex: @IntRange(from = 0) Int,
    outlineVertexIndex: @IntRange(from = 0) Int,
    outPosition: MutableVec
): MutableVec

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

open fun toString(): String

Protected functions

finalize

protected fun finalize(): Unit

Extension functions

outlinesToPath

fun PartitionedMesh.outlinesToPath(renderGroupIndex: @IntRange(from = 0) Int): Path

Returns a Path containing the outlines in the render group at renderGroupIndex.

populateOutlines

fun PartitionedMesh.populateOutlines(
    renderGroupIndex: @IntRange(from = 0) Int,
    out: Path
): Path

Replaces the contents of out with the outline of the render group at renderGroupIndex.

Returns the modified Path to allow chaining calls.

Returns
Path

out