1 /* <lambda>null2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.ink.geometry 18 19 import androidx.annotation.FloatRange 20 import androidx.annotation.IntRange 21 import androidx.annotation.RestrictTo 22 import androidx.annotation.VisibleForTesting 23 import androidx.ink.geometry.internal.threadLocal 24 import androidx.ink.nativeloader.NativeLoader 25 import androidx.ink.nativeloader.UsedByNative 26 27 /** 28 * An immutable** complex shape expressed as a set of triangles. This is used to represent the shape 29 * of a stroke or other complex objects. The mesh may be divided into multiple partitions, which 30 * enables certain brush effects (e.g. "multi-coat"), and allows ink to create strokes using greater 31 * than 2^16 triangles (which must be rendered in multiple passes). 32 * 33 * A [PartitionedMesh] may optionally have one or more "outlines", which are polylines that traverse 34 * some or all of the vertices in the mesh; these are used for path-based rendering of strokes. This 35 * supports disjoint meshes such as dashed lines. 36 * 37 * [PartitionedMesh] provides fast intersection and coverage testing by use of an internal spatial 38 * index. 39 * 40 * ** [PartitionedMesh] is technically not immutable, as the spatial index is lazily instantiated; 41 * however, from the perspective of a caller, its properties do not change over the course of its 42 * lifetime. The entire object is thread-safe. 43 */ 44 @Suppress("NotCloseable") // Finalize is only used to free the native peer. 45 public class PartitionedMesh 46 private constructor( 47 /** 48 * This is the raw pointer address of an `ink::PartitionedMesh` that has been heap allocated to 49 * be owned solely by this JVM [PartitionedMesh] object. Although the `ink::PartitionedMesh` is 50 * owned exclusively by this [PartitionedMesh] object, it may be a copy of another 51 * `ink::PartitionedMesh`, where it has a copy of fairly lightweight metadata but shares 52 * ownership of the more heavyweight `ink::Mesh` objects. This class is responsible for freeing 53 * the `ink::PartitionedMesh` through its [finalize] method. 54 */ 55 @get:RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public val nativePointer: Long 56 ) { 57 58 private val scratchIntArray by threadLocal { IntArray(2) } 59 60 /** 61 * Only for tests - creates a new empty [PartitionedMesh]. Since a [PartitionedMesh] is 62 * immutable, this serves no practical purpose outside of tests. 63 */ 64 @VisibleForTesting internal constructor() : this(PartitionedMeshNative.create()) 65 66 /** 67 * Returns the number of render groups in this mesh. Each outline in the [PartitionedMesh] 68 * belongs to exactly one render group, which are numbered in z-order: the group with index zero 69 * should be rendered on bottom; the group with the highest index should be rendered on top. 70 */ 71 @IntRange(from = 0) 72 public fun getRenderGroupCount(): Int = 73 PartitionedMeshNative.getRenderGroupCount(nativePointer).also { check(it >= 0) } 74 75 /** The [Mesh] objects that make up this shape. */ 76 private val meshesByGroup: List<List<Mesh>> = 77 (0 until getRenderGroupCount()).map { groupIndex -> 78 PartitionedMeshNative.newCopiesOfMeshes(nativePointer, groupIndex).map(Mesh::wrapNative) 79 } 80 81 private var _bounds: Box? = null 82 83 /** 84 * Returns the minimum bounding box of the [PartitionedMesh]. This will be null if the 85 * [PartitionedMesh] is empty. 86 */ 87 public fun computeBoundingBox(): Box? { 88 // If we've already computed the bounding box, re-use it -- it won't change over the 89 // lifetime of 90 // this object. 91 if (_bounds != null) return _bounds 92 93 // If we have no meshes, then the bounding box is null. 94 if (meshesByGroup.isEmpty()) return null 95 96 val envelope = BoxAccumulator() 97 for (meshes in meshesByGroup) { 98 for (mesh in meshes) { 99 envelope.add(mesh.bounds) 100 } 101 } 102 _bounds = envelope.box 103 return envelope.box 104 } 105 106 /** Returns the [MeshFormat] used for each [Mesh] in the specified render group. */ 107 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // NonPublicApi 108 public fun renderGroupFormat(@IntRange(from = 0) groupIndex: Int): MeshFormat { 109 require(groupIndex >= 0 && groupIndex < getRenderGroupCount()) { 110 "groupIndex=$groupIndex must be between 0 and getRenderGroupCount()=${getRenderGroupCount()}" 111 } 112 return MeshFormat(PartitionedMeshNative.getRenderGroupFormat(nativePointer, groupIndex)) 113 } 114 115 /** 116 * Returns the meshes that make up render group [groupIndex], listed in z-order (the first mesh 117 * in the span should be rendered on bottom; the last mesh should be rendered on top). 118 */ 119 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // NonPublicApi 120 public fun renderGroupMeshes(@IntRange(from = 0) groupIndex: Int): List<Mesh> { 121 require(groupIndex >= 0 && groupIndex < getRenderGroupCount()) { 122 "groupIndex=$groupIndex must be between 0 and getRenderGroupCount()=${getRenderGroupCount()}" 123 } 124 return meshesByGroup[groupIndex] 125 } 126 127 /** 128 * Returns the number of outlines of the mesh for the render group at [groupIndex]. 129 * 130 * Groups with discontinuous geometry will always have multiple outlines, but even continuous 131 * geometry may be drawn with multiple overlapping outlines when this improves rendering quality 132 * or performance. 133 */ 134 @IntRange(from = 0) 135 public fun getOutlineCount(@IntRange(from = 0) groupIndex: Int): Int { 136 require(groupIndex >= 0 && groupIndex < getRenderGroupCount()) { 137 "groupIndex=$groupIndex must be between 0 and getRenderGroupCount()=${getRenderGroupCount()}" 138 } 139 return PartitionedMeshNative.getOutlineCount(nativePointer, groupIndex).also { 140 check(it >= 0) 141 } 142 } 143 144 /** 145 * Returns the number of vertices that are in the outline at [outlineIndex] in the render group 146 * at [groupIndex]. 147 */ 148 @IntRange(from = 0) 149 public fun getOutlineVertexCount( 150 @IntRange(from = 0) groupIndex: Int, 151 @IntRange(from = 0) outlineIndex: Int, 152 ): Int { 153 require(outlineIndex >= 0 && outlineIndex < getOutlineCount(groupIndex)) { 154 "outlineIndex=$outlineIndex must be between 0 and getOutlineCount=${getOutlineCount(groupIndex)}" 155 } 156 return PartitionedMeshNative.getOutlineVertexCount(nativePointer, groupIndex, outlineIndex) 157 .also { check(it >= 0) } 158 } 159 160 /** 161 * Populates [outPosition] with the position of the outline vertex at [outlineVertexIndex] in 162 * the outline at [outlineIndex] in the render group at [groupIndex], and returns [outPosition]. 163 * [groupIndex] must be less than [getRenderGroupCount], [outlineIndex] must be less 164 * [getOutlineVertexCount] for [groupIndex], and [outlineVertexIndex] must be less than 165 * [getOutlineVertexCount] for [groupIndex] and [outlineIndex]. 166 */ 167 public fun populateOutlinePosition( 168 @IntRange(from = 0) groupIndex: Int, 169 @IntRange(from = 0) outlineIndex: Int, 170 @IntRange(from = 0) outlineVertexIndex: Int, 171 outPosition: MutableVec, 172 ): MutableVec { 173 val outlineVertexCount = getOutlineVertexCount(groupIndex, outlineIndex) 174 require(outlineVertexIndex >= 0 && outlineVertexIndex < outlineVertexCount) { 175 "outlineVertexIndex=$outlineVertexIndex must be between 0 and " + 176 "outlineVertexCount($outlineVertexIndex)=$outlineVertexCount" 177 } 178 PartitionedMeshNative.fillOutlineMeshIndexAndMeshVertexIndex( 179 nativePointer, 180 groupIndex, 181 outlineIndex, 182 outlineVertexIndex, 183 scratchIntArray, 184 ) 185 val (meshIndex, meshVertexIndex) = scratchIntArray 186 val mesh = meshesByGroup[groupIndex][meshIndex] 187 mesh.fillPosition(meshVertexIndex, outPosition) 188 return outPosition 189 } 190 191 /** 192 * Computes an approximate measure of what portion of this [PartitionedMesh] is covered by or 193 * overlaps with [triangle]. This is calculated by finding the sum of areas of the triangles 194 * that intersect the given [triangle], and dividing that by the sum of the areas of all 195 * triangles in the [PartitionedMesh], all in the [PartitionedMesh]'s coordinate space. 196 * Triangles in the [PartitionedMesh] that overlap each other (e.g. in the case of a stroke that 197 * loops back over itself) are counted individually. Note that, if any triangles have negative 198 * area (due to winding, see [Triangle.computeSignedArea]), the absolute value of their area 199 * will be used instead. 200 * 201 * On an empty [PartitionedMesh], this will always return 0. 202 * 203 * Optional argument [triangleToThis] contains the transform that maps from [triangle]'s 204 * coordinate space to this [PartitionedMesh]'s coordinate space, which defaults to 205 * [AffineTransform.IDENTITY]. 206 */ 207 @JvmOverloads 208 @FloatRange(from = 0.0, to = 1.0) 209 public fun computeCoverage( 210 triangle: Triangle, 211 triangleToThis: AffineTransform = AffineTransform.IDENTITY, 212 ): Float = 213 PartitionedMeshNative.partitionedMeshTriangleCoverage( 214 nativePointer = nativePointer, 215 triangleP0X = triangle.p0.x, 216 triangleP0Y = triangle.p0.y, 217 triangleP1X = triangle.p1.x, 218 triangleP1Y = triangle.p1.y, 219 triangleP2X = triangle.p2.x, 220 triangleP2Y = triangle.p2.y, 221 triangleToThisTransformA = triangleToThis.m00, 222 triangleToThisTransformB = triangleToThis.m10, 223 triangleToThisTransformC = triangleToThis.m20, 224 triangleToThisTransformD = triangleToThis.m01, 225 triangleToThisTransformE = triangleToThis.m11, 226 triangleToThisTransformF = triangleToThis.m21, 227 ) 228 229 /** 230 * Computes an approximate measure of what portion of this [PartitionedMesh] is covered by or 231 * overlaps with [box]. This is calculated by finding the sum of areas of the triangles that 232 * intersect the given [box], and dividing that by the sum of the areas of all triangles in the 233 * [PartitionedMesh], all in the [PartitionedMesh]'s coordinate space. Triangles in the 234 * [PartitionedMesh] that overlap each other (e.g. in the case of a stroke that loops back over 235 * itself) are counted individually. Note that, if any triangles have negative area (due to 236 * winding, see [Triangle.computeSignedArea]), the absolute value of their area will be used 237 * instead. 238 * 239 * On an empty [PartitionedMesh], this will always return 0. 240 * 241 * Optional argument [boxToThis] contains the transform that maps from [box]'s coordinate space 242 * to this [PartitionedMesh]'s coordinate space, which defaults to [AffineTransform.IDENTITY]. 243 */ 244 @JvmOverloads 245 @FloatRange(from = 0.0, to = 1.0) 246 public fun computeCoverage( 247 box: Box, 248 boxToThis: AffineTransform = AffineTransform.IDENTITY, 249 ): Float = 250 PartitionedMeshNative.partitionedMeshBoxCoverage( 251 nativePointer = nativePointer, 252 boxXMin = box.xMin, 253 boxYMin = box.yMin, 254 boxXMax = box.xMax, 255 boxYMax = box.yMax, 256 boxToThisTransformA = boxToThis.m00, 257 boxToThisTransformB = boxToThis.m10, 258 boxToThisTransformC = boxToThis.m20, 259 boxToThisTransformD = boxToThis.m01, 260 boxToThisTransformE = boxToThis.m11, 261 boxToThisTransformF = boxToThis.m21, 262 ) 263 264 /** 265 * Computes an approximate measure of what portion of this [PartitionedMesh] is covered by or 266 * overlaps with [parallelogram]. This is calculated by finding the sum of areas of the 267 * triangles that intersect the given [parallelogram], and dividing that by the sum of the areas 268 * of all triangles in the [PartitionedMesh], all in the [PartitionedMesh]'s coordinate space. 269 * Triangles in the [PartitionedMesh] that overlap each other (e.g. in the case of a stroke that 270 * loops back over itself) are counted individually. Note that, if any triangles have negative 271 * area (due to winding, see [Triangle.computeSignedArea]), the absolute value of their area 272 * will be used instead. 273 * 274 * On an empty [PartitionedMesh], this will always return 0. 275 * 276 * Optional argument [parallelogramToThis] contains the transform that maps from 277 * [parallelogram]'s coordinate space to this [PartitionedMesh]'s coordinate space, which 278 * defaults to [AffineTransform.IDENTITY]. 279 */ 280 @JvmOverloads 281 @FloatRange(from = 0.0, to = 1.0) 282 public fun computeCoverage( 283 parallelogram: Parallelogram, 284 parallelogramToThis: AffineTransform = AffineTransform.IDENTITY, 285 ): Float = 286 PartitionedMeshNative.partitionedMeshParallelogramCoverage( 287 nativePointer = nativePointer, 288 parallelogramCenterX = parallelogram.center.x, 289 parallelogramCenterY = parallelogram.center.y, 290 parallelogramWidth = parallelogram.width, 291 parallelogramHeight = parallelogram.height, 292 parallelogramAngleInRadian = parallelogram.rotation, 293 parallelogramShearFactor = parallelogram.shearFactor, 294 parallelogramToThisTransformA = parallelogramToThis.m00, 295 parallelogramToThisTransformB = parallelogramToThis.m10, 296 parallelogramToThisTransformC = parallelogramToThis.m20, 297 parallelogramToThisTransformD = parallelogramToThis.m01, 298 parallelogramToThisTransformE = parallelogramToThis.m11, 299 parallelogramToThisTransformF = parallelogramToThis.m21, 300 ) 301 302 /** 303 * Computes an approximate measure of what portion of this [PartitionedMesh] is covered by or 304 * overlaps with the [other] [PartitionedMesh]. This is calculated by finding the sum of areas 305 * of the triangles that intersect [other], and dividing that by the sum of the areas of all 306 * triangles in the [PartitionedMesh], all in the [PartitionedMesh]'s coordinate space. 307 * Triangles in the [PartitionedMesh] that overlap each other (e.g. in the case of a stroke that 308 * loops back over itself) are counted individually. Note that, if any triangles have negative 309 * area (due to winding, see [Triangle.computeSignedArea]), the absolute value of their area 310 * will be used instead. 311 * 312 * On an empty [PartitionedMesh], this will always return 0. 313 * 314 * Optional argument [otherShapeToThis] contains the transform that maps from [other]'s 315 * coordinate space to this [PartitionedMesh]'s coordinate space, which defaults to 316 * [AffineTransform.IDENTITY]. 317 */ 318 @JvmOverloads 319 @FloatRange(from = 0.0, to = 1.0) 320 public fun computeCoverage( 321 other: PartitionedMesh, 322 otherShapeToThis: AffineTransform = AffineTransform.IDENTITY, 323 ): Float = 324 PartitionedMeshNative.partitionedMeshPartitionedMeshCoverage( 325 nativePointer = nativePointer, 326 otherShapeNativePointer = other.nativePointer, 327 otherShapeToThisTransformA = otherShapeToThis.m00, 328 otherShapeToThisTransformB = otherShapeToThis.m10, 329 otherShapeToThisTransformC = otherShapeToThis.m20, 330 otherShapeToThisTransformD = otherShapeToThis.m01, 331 otherShapeToThisTransformE = otherShapeToThis.m11, 332 otherShapeToThisTransformF = otherShapeToThis.m21, 333 ) 334 335 /** 336 * Returns true if the approximate portion of the [PartitionedMesh] covered by [triangle] is 337 * greater than [coverageThreshold]. 338 * 339 * This is equivalent to: 340 * ``` 341 * computeCoverage(triangle, triangleToThis) > coverageThreshold 342 * ``` 343 * 344 * but may be faster. 345 * 346 * On an empty [PartitionedMesh], this will always return 0. 347 * 348 * Optional argument [triangleToThis] contains the transform that maps from [triangle]'s 349 * coordinate space to this [PartitionedMesh]'s coordinate space, which defaults to 350 * [AffineTransform.IDENTITY]. 351 */ 352 @JvmOverloads 353 public fun computeCoverageIsGreaterThan( 354 triangle: Triangle, 355 coverageThreshold: Float, 356 triangleToThis: AffineTransform = AffineTransform.IDENTITY, 357 ): Boolean = 358 PartitionedMeshNative.partitionedMeshTriangleCoverageIsGreaterThan( 359 nativePointer = nativePointer, 360 triangleP0X = triangle.p0.x, 361 triangleP0Y = triangle.p0.y, 362 triangleP1X = triangle.p1.x, 363 triangleP1Y = triangle.p1.y, 364 triangleP2X = triangle.p2.x, 365 triangleP2Y = triangle.p2.y, 366 coverageThreshold = coverageThreshold, 367 triangleToThisTransformA = triangleToThis.m00, 368 triangleToThisTransformB = triangleToThis.m10, 369 triangleToThisTransformC = triangleToThis.m20, 370 triangleToThisTransformD = triangleToThis.m01, 371 triangleToThisTransformE = triangleToThis.m11, 372 triangleToThisTransformF = triangleToThis.m21, 373 ) 374 375 /** 376 * Returns true if the approximate portion of the [PartitionedMesh] covered by [box] is greater 377 * than [coverageThreshold]. 378 * 379 * This is equivalent to: 380 * ``` 381 * computeCoverage(box, boxToThis) > coverageThreshold 382 * ``` 383 * 384 * but may be faster. 385 * 386 * On an empty [PartitionedMesh], this will always return 0. 387 * 388 * Optional argument [boxToThis] contains the transform that maps from [box]'s coordinate space 389 * to this [PartitionedMesh]'s coordinate space, which defaults to [AffineTransform.IDENTITY]. 390 */ 391 @JvmOverloads 392 public fun computeCoverageIsGreaterThan( 393 box: Box, 394 coverageThreshold: Float, 395 boxToThis: AffineTransform = AffineTransform.IDENTITY, 396 ): Boolean = 397 PartitionedMeshNative.partitionedMeshBoxCoverageIsGreaterThan( 398 nativePointer = nativePointer, 399 boxXMin = box.xMin, 400 boxYMin = box.yMin, 401 boxXMax = box.xMax, 402 boxYMax = box.yMax, 403 coverageThreshold = coverageThreshold, 404 boxToThisTransformA = boxToThis.m00, 405 boxToThisTransformB = boxToThis.m10, 406 boxToThisTransformC = boxToThis.m20, 407 boxToThisTransformD = boxToThis.m01, 408 boxToThisTransformE = boxToThis.m11, 409 boxToThisTransformF = boxToThis.m21, 410 ) 411 412 /** 413 * Returns true if the approximate portion of the [PartitionedMesh] covered by [parallelogram] 414 * is greater than [coverageThreshold]. 415 * 416 * This is equivalent to: 417 * ``` 418 * computeCoverage(parallelogram, parallelogramToThis) > coverageThreshold 419 * ``` 420 * 421 * but may be faster. 422 * 423 * On an empty [PartitionedMesh], this will always return 0. 424 * 425 * Optional argument [parallelogramToThis] contains the transform that maps from 426 * [parallelogram]'s coordinate space to this [PartitionedMesh]'s coordinate space, which 427 * defaults to [AffineTransform.IDENTITY]. 428 */ 429 @JvmOverloads 430 public fun computeCoverageIsGreaterThan( 431 parallelogram: Parallelogram, 432 coverageThreshold: Float, 433 parallelogramToThis: AffineTransform = AffineTransform.IDENTITY, 434 ): Boolean = 435 PartitionedMeshNative.partitionedMeshParallelogramCoverageIsGreaterThan( 436 nativePointer = nativePointer, 437 parallelogramCenterX = parallelogram.center.x, 438 parallelogramCenterY = parallelogram.center.y, 439 parallelogramWidth = parallelogram.width, 440 parallelogramHeight = parallelogram.height, 441 parallelogramAngleInRadian = parallelogram.rotation, 442 parallelogramShearFactor = parallelogram.shearFactor, 443 coverageThreshold = coverageThreshold, 444 parallelogramToThisTransformA = parallelogramToThis.m00, 445 parallelogramToThisTransformB = parallelogramToThis.m10, 446 parallelogramToThisTransformC = parallelogramToThis.m20, 447 parallelogramToThisTransformD = parallelogramToThis.m01, 448 parallelogramToThisTransformE = parallelogramToThis.m11, 449 parallelogramToThisTransformF = parallelogramToThis.m21, 450 ) 451 452 /** 453 * Returns true if the approximate portion of this [PartitionedMesh] covered by the [other] 454 * [PartitionedMesh] is greater than [coverageThreshold]. 455 * 456 * This is equivalent to: 457 * ``` 458 * computeCoverage(other, otherShapeToThis) > coverageThreshold 459 * ``` 460 * 461 * but may be faster. 462 * 463 * On an empty [PartitionedMesh], this will always return 0. 464 * 465 * Optional argument [otherShapeToThis] contains the transform that maps from [other]'s 466 * coordinate space to this [PartitionedMesh]'s coordinate space, which defaults to 467 * [AffineTransform.IDENTITY]. 468 */ 469 @JvmOverloads 470 public fun computeCoverageIsGreaterThan( 471 other: PartitionedMesh, 472 coverageThreshold: Float, 473 otherShapeToThis: AffineTransform = AffineTransform.IDENTITY, 474 ): Boolean = 475 PartitionedMeshNative.partitionedMeshPartitionedMeshCoverageIsGreaterThan( 476 nativePointer = nativePointer, 477 otherShapeNativePointer = other.nativePointer, 478 coverageThreshold = coverageThreshold, 479 otherShapeToThisTransformA = otherShapeToThis.m00, 480 otherShapeToThisTransformB = otherShapeToThis.m10, 481 otherShapeToThisTransformC = otherShapeToThis.m20, 482 otherShapeToThisTransformD = otherShapeToThis.m01, 483 otherShapeToThisTransformE = otherShapeToThis.m11, 484 otherShapeToThisTransformF = otherShapeToThis.m21, 485 ) 486 487 /** 488 * Initializes this MutableEnvelope's spatial index for geometry queries. If a geometry query is 489 * made with this shape and the spatial index is not currently initialized, it will be 490 * initialized in real time to satisfy that query. 491 */ 492 public fun initializeSpatialIndex(): Unit = 493 PartitionedMeshNative.initializeSpatialIndex(nativePointer) 494 495 /** Returns true if this MutableEnvelope's spatial index has been initialized. */ 496 @VisibleForTesting 497 internal fun isSpatialIndexInitialized(): Boolean = 498 PartitionedMeshNative.isSpatialIndexInitialized(nativePointer) 499 500 override fun toString(): String { 501 val address = java.lang.Long.toHexString(nativePointer) 502 return "PartitionedMesh(bounds=${computeBoundingBox()}, meshesByGroup=$meshesByGroup, " + 503 "nativePointer=$address)" 504 } 505 506 protected fun finalize() { 507 // NOMUTANTS--Not tested post garbage collection. 508 PartitionedMeshNative.free(nativePointer) 509 } 510 511 /** Declared as a target for extension functions. */ 512 public companion object { 513 /** 514 * Construct a [PartitionedMesh] from an unowned heap-allocated native pointer to a C++ 515 * `PartitionedMesh`. 516 */ 517 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 518 public fun wrapNative(unownedNativePointer: Long): PartitionedMesh = 519 PartitionedMesh(unownedNativePointer) 520 } 521 } 522 523 /** Helper object to contain native JNI calls. */ 524 @UsedByNative 525 private object PartitionedMeshNative { 526 527 init { 528 NativeLoader.load() 529 } 530 createnull531 @UsedByNative external fun create(): Long 532 533 @UsedByNative external fun free(nativePointer: Long) 534 535 @UsedByNative external fun newCopiesOfMeshes(nativePointer: Long, groupIndex: Int): LongArray 536 537 @UsedByNative external fun getRenderGroupCount(nativePointer: Long): Int 538 539 @UsedByNative external fun getRenderGroupFormat(nativePointer: Long, groupIndex: Int): Long 540 541 @UsedByNative external fun getOutlineCount(nativePointer: Long, groupIndex: Int): Int 542 543 @UsedByNative 544 external fun getOutlineVertexCount(nativePointer: Long, groupIndex: Int, outlineIndex: Int): Int 545 546 @UsedByNative 547 external fun fillOutlineMeshIndexAndMeshVertexIndex( 548 nativePointer: Long, 549 groupIndex: Int, 550 outlineIndex: Int, 551 outlineVertexIndex: Int, 552 outMeshIndexAndMeshVertexIndex: IntArray, 553 ) 554 555 /** 556 * JNI method to construct C++ `PartitionedMesh` and `Triangle` objects and calculate coverage 557 * using them. 558 */ 559 @UsedByNative 560 external fun partitionedMeshTriangleCoverage( 561 nativePointer: Long, 562 triangleP0X: Float, 563 triangleP0Y: Float, 564 triangleP1X: Float, 565 triangleP1Y: Float, 566 triangleP2X: Float, 567 triangleP2Y: Float, 568 triangleToThisTransformA: Float, 569 triangleToThisTransformB: Float, 570 triangleToThisTransformC: Float, 571 triangleToThisTransformD: Float, 572 triangleToThisTransformE: Float, 573 triangleToThisTransformF: Float, 574 ): Float 575 576 /** 577 * JNI method to construct C++ `PartitionedMesh` and `Triangle` objects and calculate coverage 578 * using them. 579 */ 580 @UsedByNative 581 external fun partitionedMeshBoxCoverage( 582 nativePointer: Long, 583 boxXMin: Float, 584 boxYMin: Float, 585 boxXMax: Float, 586 boxYMax: Float, 587 boxToThisTransformA: Float, 588 boxToThisTransformB: Float, 589 boxToThisTransformC: Float, 590 boxToThisTransformD: Float, 591 boxToThisTransformE: Float, 592 boxToThisTransformF: Float, 593 ): Float 594 595 /** 596 * JNI method to construct C++ `PartitionedMesh` and `Quad` objects and calculate coverage using 597 * them. 598 */ 599 @UsedByNative 600 external fun partitionedMeshParallelogramCoverage( 601 nativePointer: Long, 602 parallelogramCenterX: Float, 603 parallelogramCenterY: Float, 604 parallelogramWidth: Float, 605 parallelogramHeight: Float, 606 parallelogramAngleInRadian: Float, 607 parallelogramShearFactor: Float, 608 parallelogramToThisTransformA: Float, 609 parallelogramToThisTransformB: Float, 610 parallelogramToThisTransformC: Float, 611 parallelogramToThisTransformD: Float, 612 parallelogramToThisTransformE: Float, 613 parallelogramToThisTransformF: Float, 614 ): Float 615 616 /** 617 * JNI method to construct C++ two `PartitionedMesh` objects and calculate coverage using them. 618 */ 619 @UsedByNative 620 external fun partitionedMeshPartitionedMeshCoverage( 621 nativePointer: Long, 622 otherShapeNativePointer: Long, 623 otherShapeToThisTransformA: Float, 624 otherShapeToThisTransformB: Float, 625 otherShapeToThisTransformC: Float, 626 otherShapeToThisTransformD: Float, 627 otherShapeToThisTransformE: Float, 628 otherShapeToThisTransformF: Float, 629 ): Float 630 631 /** 632 * JNI method to construct C++ `PartitionedMesh` and `Triangle` objects and call native 633 * `CoverageIsGreaterThan` on them. 634 */ 635 @UsedByNative 636 external fun partitionedMeshTriangleCoverageIsGreaterThan( 637 nativePointer: Long, 638 triangleP0X: Float, 639 triangleP0Y: Float, 640 triangleP1X: Float, 641 triangleP1Y: Float, 642 triangleP2X: Float, 643 triangleP2Y: Float, 644 coverageThreshold: Float, 645 triangleToThisTransformA: Float, 646 triangleToThisTransformB: Float, 647 triangleToThisTransformC: Float, 648 triangleToThisTransformD: Float, 649 triangleToThisTransformE: Float, 650 triangleToThisTransformF: Float, 651 ): Boolean 652 653 /** 654 * JNI method to construct C++ `PartitionedMesh` and `Rect` objects and call native 655 * `CoverageIsGreaterThan` on them. 656 */ 657 @UsedByNative 658 external fun partitionedMeshBoxCoverageIsGreaterThan( 659 nativePointer: Long, 660 boxXMin: Float, 661 boxYMin: Float, 662 boxXMax: Float, 663 boxYMax: Float, 664 coverageThreshold: Float, 665 boxToThisTransformA: Float, 666 boxToThisTransformB: Float, 667 boxToThisTransformC: Float, 668 boxToThisTransformD: Float, 669 boxToThisTransformE: Float, 670 boxToThisTransformF: Float, 671 ): Boolean 672 673 /** 674 * JNI method to construct C++ `PartitionedMesh` and `Quad` objects and call native 675 * `CoverageIsGreaterThan` on them. 676 */ 677 @UsedByNative 678 external fun partitionedMeshParallelogramCoverageIsGreaterThan( 679 nativePointer: Long, 680 parallelogramCenterX: Float, 681 parallelogramCenterY: Float, 682 parallelogramWidth: Float, 683 parallelogramHeight: Float, 684 parallelogramAngleInRadian: Float, 685 parallelogramShearFactor: Float, 686 coverageThreshold: Float, 687 parallelogramToThisTransformA: Float, 688 parallelogramToThisTransformB: Float, 689 parallelogramToThisTransformC: Float, 690 parallelogramToThisTransformD: Float, 691 parallelogramToThisTransformE: Float, 692 parallelogramToThisTransformF: Float, 693 ): Boolean 694 695 /** 696 * JNI method to construct two C++ `PartitionedMesh` objects and call native 697 * `CoverageIsGreaterThan` on them. 698 */ 699 @UsedByNative 700 external fun partitionedMeshPartitionedMeshCoverageIsGreaterThan( 701 nativePointer: Long, 702 otherShapeNativePointer: Long, 703 coverageThreshold: Float, 704 otherShapeToThisTransformA: Float, 705 otherShapeToThisTransformB: Float, 706 otherShapeToThisTransformC: Float, 707 otherShapeToThisTransformD: Float, 708 otherShapeToThisTransformE: Float, 709 otherShapeToThisTransformF: Float, 710 ): Boolean 711 712 @UsedByNative external fun initializeSpatialIndex(nativePointer: Long) 713 714 @UsedByNative external fun isSpatialIndexInitialized(nativePointer: Long): Boolean 715 } 716