• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

google / vector_math.dart / 17181727464

04 Aug 2025 07:19PM UTC coverage: 26.702% (+0.3%) from 26.388%
17181727464

push

github

web-flow
Bump min SDK to 3.7, update dependencies, reformat (#348)

496 of 1182 new or added lines in 55 files covered. (41.96%)

18 existing lines in 8 files now uncovered.

4463 of 16714 relevant lines covered (26.7%)

1.18 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

67.43
/lib/src/vector_math/aabb3.dart
1
// Copyright (c) 2015, Google Inc. Please see the AUTHORS file for details.
2
// All rights reserved. Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
4

5
part of '../../vector_math.dart';
6

7
/// Defines a 3-dimensional axis-aligned bounding box between a [min] and a
8
/// [max] position.
9
class Aabb3 {
10
  final Vector3 _min;
11
  final Vector3 _max;
12

13
  Vector3 get min => _min;
6✔
14
  Vector3 get max => _max;
6✔
15

16
  /// The center of the AABB.
17
  Vector3 get center =>
1✔
18
      _min.clone()
2✔
19
        ..add(_max)
2✔
20
        ..scale(0.5);
1✔
21

22
  /// Create a new AABB with [min] and [max] set to the origin.
23
  Aabb3() : _min = Vector3.zero(), _max = Vector3.zero();
6✔
24

25
  /// Create a new AABB as a copy of [other].
26
  Aabb3.copy(Aabb3 other)
×
NEW
27
    : _min = Vector3.copy(other._min),
×
NEW
28
      _max = Vector3.copy(other._max);
×
29

30
  /// Create a new AABB with a [min] and [max].
31
  Aabb3.minMax(Vector3 min, Vector3 max)
3✔
32
    : _min = Vector3.copy(min),
3✔
33
      _max = Vector3.copy(max);
3✔
34

35
  /// Create a new AABB that encloses a [sphere].
36
  factory Aabb3.fromSphere(Sphere sphere) => Aabb3()..setSphere(sphere);
3✔
37

38
  /// Create a new AABB that encloses a [triangle].
39
  factory Aabb3.fromTriangle(Triangle triangle) =>
1✔
40
      Aabb3()..setTriangle(triangle);
2✔
41

42
  /// Create a new AABB that encloses a [quad].
43
  factory Aabb3.fromQuad(Quad quad) => Aabb3()..setQuad(quad);
3✔
44

45
  /// Create a new AABB that encloses a [obb].
46
  factory Aabb3.fromObb3(Obb3 obb) => Aabb3()..setObb3(obb);
×
47

48
  /// Create a new AABB that encloses a limited [ray] (or line segment) that has
49
  /// a minLimit and maxLimit.
50
  factory Aabb3.fromRay(Ray ray, double limitMin, double limitMax) =>
1✔
51
      Aabb3()..setRay(ray, limitMin, limitMax);
2✔
52

53
  /// Create a new AABB with a [center] and [halfExtents].
54
  factory Aabb3.centerAndHalfExtents(Vector3 center, Vector3 halfExtents) =>
1✔
55
      Aabb3()..setCenterAndHalfExtents(center, halfExtents);
2✔
56

57
  /// Constructs [Aabb3] with a min/max storage that views given [buffer]
58
  /// starting at [offset]. [offset] has to be multiple of
59
  /// [Float32List.bytesPerElement].
60
  Aabb3.fromBuffer(ByteBuffer buffer, int offset)
1✔
61
    : _min = Vector3.fromBuffer(buffer, offset),
1✔
62
      _max = Vector3.fromBuffer(
1✔
63
        buffer,
64
        offset + Float32List.bytesPerElement * 3,
2✔
65
      );
66

67
  /// Set the AABB by a [center] and [halfExtents].
68
  void setCenterAndHalfExtents(Vector3 center, Vector3 halfExtents) {
2✔
69
    _min
2✔
70
      ..setFrom(center)
2✔
71
      ..sub(halfExtents);
2✔
72
    _max
2✔
73
      ..setFrom(center)
2✔
74
      ..add(halfExtents);
2✔
75
  }
76

77
  /// Set the AABB to enclose a [sphere].
78
  void setSphere(Sphere sphere) {
1✔
79
    _min
1✔
80
      ..splat(-sphere.radius)
3✔
81
      ..add(sphere._center);
2✔
82
    _max
1✔
83
      ..splat(sphere.radius)
2✔
84
      ..add(sphere._center);
2✔
85
  }
86

87
  /// Set the AABB to enclose a [triangle].
88
  void setTriangle(Triangle triangle) {
1✔
89
    _min.setValues(
2✔
90
      math.min(
1✔
91
        triangle._point0.x,
2✔
92
        math.min(triangle._point1.x, triangle._point2.x),
5✔
93
      ),
94
      math.min(
1✔
95
        triangle._point0.y,
2✔
96
        math.min(triangle._point1.y, triangle._point2.y),
5✔
97
      ),
98
      math.min(
1✔
99
        triangle._point0.z,
2✔
100
        math.min(triangle._point1.z, triangle._point2.z),
5✔
101
      ),
102
    );
103
    _max.setValues(
2✔
104
      math.max(
1✔
105
        triangle._point0.x,
2✔
106
        math.max(triangle._point1.x, triangle._point2.x),
5✔
107
      ),
108
      math.max(
1✔
109
        triangle._point0.y,
2✔
110
        math.max(triangle._point1.y, triangle._point2.y),
5✔
111
      ),
112
      math.max(
1✔
113
        triangle._point0.z,
2✔
114
        math.max(triangle._point1.z, triangle._point2.z),
5✔
115
      ),
116
    );
117
  }
118

119
  /// Set the AABB to enclose a [quad].
120
  void setQuad(Quad quad) {
1✔
121
    _min.setValues(
2✔
122
      math.min(
1✔
123
        quad._point0.x,
2✔
124
        math.min(quad._point1.x, math.min(quad._point2.x, quad._point3.x)),
8✔
125
      ),
126
      math.min(
1✔
127
        quad._point0.y,
2✔
128
        math.min(quad._point1.y, math.min(quad._point2.y, quad._point3.y)),
8✔
129
      ),
130
      math.min(
1✔
131
        quad._point0.z,
2✔
132
        math.min(quad._point1.z, math.min(quad._point2.z, quad._point3.z)),
8✔
133
      ),
134
    );
135
    _max.setValues(
2✔
136
      math.max(
1✔
137
        quad._point0.x,
2✔
138
        math.max(quad._point1.x, math.max(quad._point2.x, quad._point3.x)),
8✔
139
      ),
140
      math.max(
1✔
141
        quad._point0.y,
2✔
142
        math.max(quad._point1.y, math.max(quad._point2.y, quad._point3.y)),
8✔
143
      ),
144
      math.max(
1✔
145
        quad._point0.z,
2✔
146
        math.max(quad._point1.z, math.max(quad._point2.z, quad._point3.z)),
8✔
147
      ),
148
    );
149
  }
150

151
  /// Set the AABB to enclose a [obb].
152
  void setObb3(Obb3 obb) {
×
153
    final corner = Vector3.zero();
×
154

155
    obb.copyCorner(0, corner);
×
156
    _min.setFrom(corner);
×
157
    _max.setFrom(corner);
×
158

159
    obb.copyCorner(1, corner);
×
160
    hullPoint(corner);
×
161

162
    obb.copyCorner(2, corner);
×
163
    hullPoint(corner);
×
164

165
    obb.copyCorner(3, corner);
×
166
    hullPoint(corner);
×
167

168
    obb.copyCorner(4, corner);
×
169
    hullPoint(corner);
×
170

171
    obb.copyCorner(5, corner);
×
172
    hullPoint(corner);
×
173

174
    obb.copyCorner(6, corner);
×
175
    hullPoint(corner);
×
176

177
    obb.copyCorner(7, corner);
×
178
    hullPoint(corner);
×
179
  }
180

181
  /// Set the AABB to enclose a limited [ray] (or line segment) that is limited
182
  /// by [limitMin] and [limitMax].
183
  void setRay(Ray ray, double limitMin, double limitMax) {
1✔
184
    ray
185
      ..copyAt(_min, limitMin)
2✔
186
      ..copyAt(_max, limitMax);
2✔
187

188
    if (_max.x < _min.x) {
5✔
189
      final temp = _max.x;
×
190
      _max.x = _min.x;
×
191
      _min.x = temp;
×
192
    }
193

194
    if (_max.y < _min.y) {
5✔
195
      final temp = _max.y;
×
196
      _max.y = _min.y;
×
197
      _min.y = temp;
×
198
    }
199

200
    if (_max.z < _min.z) {
5✔
201
      final temp = _max.z;
2✔
202
      _max.z = _min.z;
4✔
203
      _min.z = temp;
2✔
204
    }
205
  }
206

207
  /// Copy the [center] and the [halfExtents] of this.
208
  void copyCenterAndHalfExtents(Vector3 center, Vector3 halfExtents) {
2✔
209
    center
210
      ..setFrom(_min)
4✔
211
      ..add(_max)
4✔
212
      ..scale(0.5);
2✔
213
    halfExtents
214
      ..setFrom(_max)
4✔
215
      ..sub(_min)
4✔
216
      ..scale(0.5);
2✔
217
  }
218

219
  /// Copy the [center] of this.
220
  void copyCenter(Vector3 center) {
×
221
    center
222
      ..setFrom(_min)
×
223
      ..add(_max)
×
224
      ..scale(0.5);
×
225
  }
226

227
  /// Copy the [min] and [max] from [other] into this.
228
  void copyFrom(Aabb3 other) {
×
229
    _min.setFrom(other._min);
×
230
    _max.setFrom(other._max);
×
231
  }
232

233
  static final _center = Vector3.zero();
×
234
  static final _halfExtents = Vector3.zero();
×
235
  void _updateCenterAndHalfExtents() =>
×
236
      copyCenterAndHalfExtents(_center, _halfExtents);
×
237

238
  /// Transform this by the transform [t].
239
  void transform(Matrix4 t) {
×
240
    _updateCenterAndHalfExtents();
×
241
    t
242
      ..transform3(_center)
×
243
      ..absoluteRotate(_halfExtents);
×
244
    _min
×
245
      ..setFrom(_center)
×
246
      ..sub(_halfExtents);
×
247
    _max
×
248
      ..setFrom(_center)
×
249
      ..add(_halfExtents);
×
250
  }
251

252
  /// Rotate this by the rotation matrix [t].
253
  void rotate(Matrix4 t) {
×
254
    _updateCenterAndHalfExtents();
×
255
    t.absoluteRotate(_halfExtents);
×
256
    _min
×
257
      ..setFrom(_center)
×
258
      ..sub(_halfExtents);
×
259
    _max
×
260
      ..setFrom(_center)
×
261
      ..add(_halfExtents);
×
262
  }
263

264
  /// Create a copy of this that is transformed by the transform [t] and store
265
  /// it in [out].
NEW
266
  Aabb3 transformed(Matrix4 t, Aabb3 out) =>
×
267
      out
NEW
268
        ..copyFrom(this)
×
NEW
269
        ..transform(t);
×
270

271
  /// Create a copy of this that is rotated by the rotation matrix [t] and
272
  /// store it in [out].
NEW
273
  Aabb3 rotated(Matrix4 t, Aabb3 out) =>
×
274
      out
NEW
275
        ..copyFrom(this)
×
NEW
276
        ..rotate(t);
×
277

278
  void getPN(Vector3 planeNormal, Vector3 outP, Vector3 outN) {
×
279
    if (planeNormal.x < 0.0) {
×
280
      outP.x = _min.x;
×
281
      outN.x = _max.x;
×
282
    } else {
283
      outP.x = _max.x;
×
284
      outN.x = _min.x;
×
285
    }
286

287
    if (planeNormal.y < 0.0) {
×
288
      outP.y = _min.y;
×
289
      outN.y = _max.y;
×
290
    } else {
291
      outP.y = _max.y;
×
292
      outN.y = _min.y;
×
293
    }
294

295
    if (planeNormal.z < 0.0) {
×
296
      outP.z = _min.z;
×
297
      outN.z = _max.z;
×
298
    } else {
299
      outP.z = _max.z;
×
300
      outN.z = _min.z;
×
301
    }
302
  }
303

304
  /// Set the min and max of this so that this is a hull of this and
305
  /// [other].
306
  void hull(Aabb3 other) {
1✔
307
    Vector3.min(_min, other._min, _min);
4✔
308
    Vector3.max(_max, other._max, _max);
4✔
309
  }
310

311
  /// Set the min and max of this so that this contains [point].
312
  void hullPoint(Vector3 point) {
1✔
313
    Vector3.min(_min, point, _min);
3✔
314
    Vector3.max(_max, point, _max);
3✔
315
  }
316

317
  /// Return if this contains [other].
318
  bool containsAabb3(Aabb3 other) {
1✔
319
    final otherMax = other._max;
1✔
320
    final otherMin = other._min;
1✔
321

322
    return (_min.x < otherMin.x) &&
4✔
323
        (_min.y < otherMin.y) &&
4✔
324
        (_min.z < otherMin.z) &&
4✔
325
        (_max.x > otherMax.x) &&
4✔
326
        (_max.y > otherMax.y) &&
4✔
327
        (_max.z > otherMax.z);
4✔
328
  }
329

330
  /// Return if this contains [other].
331
  bool containsSphere(Sphere other) {
1✔
332
    final boxExtends = Vector3.all(other.radius);
2✔
333
    final sphereBox = Aabb3.centerAndHalfExtents(other._center, boxExtends);
2✔
334

335
    return containsAabb3(sphereBox);
1✔
336
  }
337

338
  /// Return if this contains [other].
339
  bool containsVector3(Vector3 other) =>
1✔
340
      (_min.x < other.x) &&
4✔
341
      (_min.y < other.y) &&
4✔
342
      (_min.z < other.z) &&
4✔
343
      (_max.x > other.x) &&
4✔
344
      (_max.y > other.y) &&
4✔
345
      (_max.z > other.z);
4✔
346

347
  /// Return if this contains [other].
348
  bool containsTriangle(Triangle other) =>
1✔
349
      containsVector3(other._point0) &&
2✔
350
      containsVector3(other._point1) &&
2✔
351
      containsVector3(other._point2);
2✔
352

353
  /// Return if this intersects with [other].
354
  bool intersectsWithAabb3(Aabb3 other) {
1✔
355
    final otherMax = other._max;
1✔
356
    final otherMin = other._min;
1✔
357

358
    return (_min.x <= otherMax.x) &&
4✔
359
        (_min.y <= otherMax.y) &&
4✔
360
        (_min.z <= otherMax.z) &&
4✔
361
        (_max.x >= otherMin.x) &&
4✔
362
        (_max.y >= otherMin.y) &&
4✔
363
        (_max.z >= otherMin.z);
4✔
364
  }
365

366
  /// Return if this intersects with [other].
367
  bool intersectsWithSphere(Sphere other) {
1✔
368
    final center = other._center;
1✔
369
    final radius = other.radius;
1✔
370
    var d = 0.0;
371
    var e = 0.0;
372

373
    for (var i = 0; i < 3; ++i) {
2✔
374
      if ((e = center[i] - _min[i]) < 0.0) {
5✔
375
        if (e < -radius) {
2✔
376
          return false;
377
        }
378

379
        d = d + e * e;
2✔
380
      } else {
381
        if ((e = center[i] - _max[i]) > 0.0) {
5✔
382
          if (e > radius) {
×
383
            return false;
384
          }
385

386
          d = d + e * e;
×
387
        }
388
      }
389
    }
390

391
    return d <= radius * radius;
2✔
392
  }
393

394
  /// Return if this intersects with [other].
395
  bool intersectsWithVector3(Vector3 other) =>
2✔
396
      (_min.x <= other.x) &&
8✔
397
      (_min.y <= other.y) &&
8✔
398
      (_min.z <= other.z) &&
8✔
399
      (_max.x >= other.x) &&
8✔
400
      (_max.y >= other.y) &&
8✔
401
      (_max.z >= other.z);
8✔
402

403
  // Avoid allocating these instance on every call to intersectsWithTriangle
404
  static final _aabbCenter = Vector3.zero();
6✔
405
  static final _aabbHalfExtents = Vector3.zero();
6✔
406
  static final _v0 = Vector3.zero();
6✔
407
  static final _v1 = Vector3.zero();
6✔
408
  static final _v2 = Vector3.zero();
6✔
409
  static final _f0 = Vector3.zero();
6✔
410
  static final _f1 = Vector3.zero();
6✔
411
  static final _f2 = Vector3.zero();
6✔
412
  static final _trianglePlane = Plane();
6✔
413

414
  static final _u0 = Vector3(1.0, 0.0, 0.0);
×
415
  static final _u1 = Vector3(0.0, 1.0, 0.0);
×
416
  static final _u2 = Vector3(0.0, 0.0, 1.0);
×
417

418
  /// Return if this intersects with [other].
419
  /// [epsilon] allows the caller to specify a custum eplsilon value that should
420
  /// be used for the test. If [result] is specified and an intersection is
421
  /// found, result is modified to contain more details about the type of
422
  /// intersection.
423
  bool intersectsWithTriangle(
2✔
424
    Triangle other, {
425
    double epsilon = 1e-3,
426
    IntersectionResult? result,
427
  }) {
428
    double p0, p1, p2, r, len;
429
    double a;
430

431
    // This line isn't required if we are using center and half extents to
432
    // define a aabb
433
    copyCenterAndHalfExtents(_aabbCenter, _aabbHalfExtents);
6✔
434

435
    // Translate triangle as conceptually moving AABB to origin
436
    _v0
2✔
437
      ..setFrom(other.point0)
4✔
438
      ..sub(_aabbCenter);
4✔
439
    _v1
2✔
440
      ..setFrom(other.point1)
4✔
441
      ..sub(_aabbCenter);
4✔
442
    _v2
2✔
443
      ..setFrom(other.point2)
4✔
444
      ..sub(_aabbCenter);
4✔
445

446
    // Translate triangle as conceptually moving AABB to origin
447
    _f0
2✔
448
      ..setFrom(_v1)
4✔
449
      ..sub(_v0);
4✔
450
    _f1
2✔
451
      ..setFrom(_v2)
4✔
452
      ..sub(_v1);
4✔
453
    _f2
2✔
454
      ..setFrom(_v0)
4✔
455
      ..sub(_v2);
4✔
456

457
    // Test axes a00..a22 (category 3)
458
    // Test axis a00
459
    len = _f0.y * _f0.y + _f0.z * _f0.z;
22✔
460
    if (len > epsilon) {
2✔
461
      // Ignore tests on degenerate axes.
462
      p0 = _v0.z * _f0.y - _v0.y * _f0.z;
22✔
463
      p2 = _v2.z * _f0.y - _v2.y * _f0.z;
22✔
464
      r = _aabbHalfExtents[1] * _f0.z.abs() + _aabbHalfExtents[2] * _f0.y.abs();
26✔
465
      if (math.max(-math.max(p0, p2), math.min(p0, p2)) > r + epsilon) {
12✔
466
        return false; // Axis is a separating axis
467
      }
468

469
      a = math.min(p0, p2) - r;
4✔
470
      if (result != null && (result._depth == null || (result._depth!) < a)) {
×
471
        result._depth = a;
×
472
        _u0.crossInto(_f0, result.axis);
×
473
      }
474
    }
475

476
    // Test axis a01
477
    len = _f1.y * _f1.y + _f1.z * _f1.z;
22✔
478
    if (len > epsilon) {
2✔
479
      // Ignore tests on degenerate axes.
480
      p0 = _v0.z * _f1.y - _v0.y * _f1.z;
22✔
481
      p1 = _v1.z * _f1.y - _v1.y * _f1.z;
22✔
482
      r = _aabbHalfExtents[1] * _f1.z.abs() + _aabbHalfExtents[2] * _f1.y.abs();
26✔
483
      if (math.max(-math.max(p0, p1), math.min(p0, p1)) > r + epsilon) {
12✔
484
        return false; // Axis is a separating axis
485
      }
486

487
      a = math.min(p0, p1) - r;
4✔
488
      if (result != null && (result._depth == null || (result._depth!) < a)) {
×
489
        result._depth = a;
×
490
        _u0.crossInto(_f1, result.axis);
×
491
      }
492
    }
493

494
    // Test axis a02
495
    len = _f2.y * _f2.y + _f2.z * _f2.z;
22✔
496
    if (len > epsilon) {
2✔
497
      // Ignore tests on degenerate axes.
498
      p0 = _v0.z * _f2.y - _v0.y * _f2.z;
22✔
499
      p1 = _v1.z * _f2.y - _v1.y * _f2.z;
22✔
500
      r = _aabbHalfExtents[1] * _f2.z.abs() + _aabbHalfExtents[2] * _f2.y.abs();
26✔
501
      if (math.max(-math.max(p0, p1), math.min(p0, p1)) > r + epsilon) {
12✔
502
        return false; // Axis is a separating axis
503
      }
504

505
      a = math.min(p0, p1) - r;
4✔
506
      if (result != null && (result._depth == null || (result._depth!) < a)) {
×
507
        result._depth = a;
×
508
        _u0.crossInto(_f2, result.axis);
×
509
      }
510
    }
511

512
    // Test axis a10
513
    len = _f0.x * _f0.x + _f0.z * _f0.z;
22✔
514
    if (len > epsilon) {
2✔
515
      // Ignore tests on degenerate axes.
516
      p0 = _v0.x * _f0.z - _v0.z * _f0.x;
22✔
517
      p2 = _v2.x * _f0.z - _v2.z * _f0.x;
22✔
518
      r = _aabbHalfExtents[0] * _f0.z.abs() + _aabbHalfExtents[2] * _f0.x.abs();
26✔
519
      if (math.max(-math.max(p0, p2), math.min(p0, p2)) > r + epsilon) {
12✔
520
        return false; // Axis is a separating axis
521
      }
522

523
      a = math.min(p0, p2) - r;
4✔
524
      if (result != null && (result._depth == null || (result._depth!) < a)) {
×
525
        result._depth = a;
×
526
        _u1.crossInto(_f0, result.axis);
×
527
      }
528
    }
529

530
    // Test axis a11
531
    len = _f1.x * _f1.x + _f1.z * _f1.z;
22✔
532
    if (len > epsilon) {
2✔
533
      // Ignore tests on degenerate axes.
534
      p0 = _v0.x * _f1.z - _v0.z * _f1.x;
22✔
535
      p1 = _v1.x * _f1.z - _v1.z * _f1.x;
22✔
536
      r = _aabbHalfExtents[0] * _f1.z.abs() + _aabbHalfExtents[2] * _f1.x.abs();
26✔
537
      if (math.max(-math.max(p0, p1), math.min(p0, p1)) > r + epsilon) {
12✔
538
        return false; // Axis is a separating axis
539
      }
540

541
      a = math.min(p0, p1) - r;
4✔
542
      if (result != null && (result._depth == null || (result._depth!) < a)) {
×
543
        result._depth = a;
×
544
        _u1.crossInto(_f1, result.axis);
×
545
      }
546
    }
547

548
    // Test axis a12
549
    len = _f2.x * _f2.x + _f2.z * _f2.z;
22✔
550
    if (len > epsilon) {
2✔
551
      // Ignore tests on degenerate axes.
552
      p0 = _v0.x * _f2.z - _v0.z * _f2.x;
22✔
553
      p1 = _v1.x * _f2.z - _v1.z * _f2.x;
22✔
554
      r = _aabbHalfExtents[0] * _f2.z.abs() + _aabbHalfExtents[2] * _f2.x.abs();
26✔
555
      if (math.max(-math.max(p0, p1), math.min(p0, p1)) > r + epsilon) {
12✔
556
        return false; // Axis is a separating axis
557
      }
558

559
      a = math.min(p0, p1) - r;
4✔
560
      if (result != null && (result._depth == null || (result._depth!) < a)) {
×
561
        result._depth = a;
×
562
        _u1.crossInto(_f2, result.axis);
×
563
      }
564
    }
565

566
    // Test axis a20
567
    len = _f0.x * _f0.x + _f0.y * _f0.y;
22✔
568
    if (len > epsilon) {
2✔
569
      // Ignore tests on degenerate axes.
570
      p0 = _v0.y * _f0.x - _v0.x * _f0.y;
22✔
571
      p2 = _v2.y * _f0.x - _v2.x * _f0.y;
22✔
572
      r = _aabbHalfExtents[0] * _f0.y.abs() + _aabbHalfExtents[1] * _f0.x.abs();
26✔
573
      if (math.max(-math.max(p0, p2), math.min(p0, p2)) > r + epsilon) {
12✔
574
        return false; // Axis is a separating axis
575
      }
576

577
      a = math.min(p0, p2) - r;
4✔
578
      if (result != null && (result._depth == null || (result._depth!) < a)) {
×
579
        result._depth = a;
×
580
        _u2.crossInto(_f0, result.axis);
×
581
      }
582
    }
583

584
    // Test axis a21
585
    len = _f1.x * _f1.x + _f1.y * _f1.y;
22✔
586
    if (len > epsilon) {
2✔
587
      // Ignore tests on degenerate axes.
588
      p0 = _v0.y * _f1.x - _v0.x * _f1.y;
22✔
589
      p1 = _v1.y * _f1.x - _v1.x * _f1.y;
22✔
590
      r = _aabbHalfExtents[0] * _f1.y.abs() + _aabbHalfExtents[1] * _f1.x.abs();
26✔
591
      if (math.max(-math.max(p0, p1), math.min(p0, p1)) > r + epsilon) {
12✔
592
        return false; // Axis is a separating axis
593
      }
594

595
      a = math.min(p0, p1) - r;
4✔
596
      if (result != null && (result._depth == null || (result._depth!) < a)) {
×
597
        result._depth = a;
×
598
        _u2.crossInto(_f1, result.axis);
×
599
      }
600
    }
601

602
    // Test axis a22
603
    len = _f2.x * _f2.x + _f2.y * _f2.y;
22✔
604
    if (len > epsilon) {
2✔
605
      // Ignore tests on degenerate axes.
606
      p0 = _v0.y * _f2.x - _v0.x * _f2.y;
22✔
607
      p1 = _v1.y * _f2.x - _v1.x * _f2.y;
22✔
608
      r = _aabbHalfExtents[0] * _f2.y.abs() + _aabbHalfExtents[1] * _f2.x.abs();
26✔
609
      if (math.max(-math.max(p0, p1), math.min(p0, p1)) > r + epsilon) {
12✔
610
        return false; // Axis is a separating axis
611
      }
612

613
      a = math.min(p0, p1) - r;
4✔
614
      if (result != null && (result._depth == null || (result._depth!) < a)) {
×
615
        result._depth = a;
×
616
        _u2.crossInto(_f2, result.axis);
×
617
      }
618
    }
619

620
    // Test the three axes corresponding to the face normals of AABB b
621
    // (category 1).
622
    // Exit if [-e0, e0] and [min(v0.x,v1.x,v2.x), max(v0.x,v1.x,v2.x)] do not
623
    // overlap
624
    if (math.max(_v0.x, math.max(_v1.x, _v2.x)) < -_aabbHalfExtents[0] ||
24✔
625
        math.min(_v0.x, math.min(_v1.x, _v2.x)) > _aabbHalfExtents[0]) {
22✔
626
      return false;
627
    }
628
    a = math.min(_v0.x, math.min(_v1.x, _v2.x)) - _aabbHalfExtents[0];
22✔
629
    if (result != null && (result._depth == null || (result._depth!) < a)) {
×
630
      result._depth = a;
×
631
      result.axis.setFrom(_u0);
×
632
    }
633
    // ... [-e1, e1] and [min(v0.y,v1.y,v2.y), max(v0.y,v1.y,v2.y)] do not
634
    // overlap
635
    if (math.max(_v0.y, math.max(_v1.y, _v2.y)) < -_aabbHalfExtents[1] ||
24✔
636
        math.min(_v0.y, math.min(_v1.y, _v2.y)) > _aabbHalfExtents[1]) {
22✔
637
      return false;
638
    }
639
    a = math.min(_v0.y, math.min(_v1.y, _v2.y)) - _aabbHalfExtents[1];
22✔
640
    if (result != null && (result._depth == null || (result._depth!) < a)) {
×
641
      result._depth = a;
×
642
      result.axis.setFrom(_u1);
×
643
    }
644
    // ... [-e2, e2] and [min(v0.z,v1.z,v2.z), max(v0.z,v1.z,v2.z)] do not
645
    // overlap
646
    if (math.max(_v0.z, math.max(_v1.z, _v2.z)) < -_aabbHalfExtents[2] ||
24✔
647
        math.min(_v0.z, math.min(_v1.z, _v2.z)) > _aabbHalfExtents[2]) {
22✔
648
      return false;
649
    }
650
    a = math.min(_v0.z, math.min(_v1.z, _v2.z)) - _aabbHalfExtents[2];
22✔
651
    if (result != null && (result._depth == null || (result._depth!) < a)) {
×
652
      result._depth = a;
×
653
      result.axis.setFrom(_u2);
×
654
    }
655

656
    // It seems like that wee need to move the edges before creating the
657
    // plane
658
    _v0.add(_aabbCenter);
6✔
659

660
    // Test separating axis corresponding to triangle face normal (category 2)
661
    _f0.crossInto(_f1, _trianglePlane.normal);
10✔
662
    _trianglePlane.constant = _trianglePlane.normal.dot(_v0);
12✔
663
    return intersectsWithPlane(_trianglePlane, result: result);
4✔
664
  }
665

666
  /// Return if this intersects with [other]
667
  bool intersectsWithPlane(Plane other, {IntersectionResult? result}) {
2✔
668
    // This line is not necessary with a (center, extents) AABB representation
669
    copyCenterAndHalfExtents(_aabbCenter, _aabbHalfExtents);
6✔
670

671
    // Compute the projection interval radius of b onto L(t) = b.c + t * p.n
672
    final r =
673
        _aabbHalfExtents[0] * other.normal[0].abs() +
14✔
674
        _aabbHalfExtents[1] * other.normal[1].abs() +
14✔
675
        _aabbHalfExtents[2] * other.normal[2].abs();
12✔
676
    // Compute distance of box center from plane
677
    final s = other.normal.dot(_aabbCenter) - other.constant;
10✔
678
    // Intersection occurs when distance s falls within [-r,+r] interval
679
    if (s.abs() <= r) {
4✔
680
      final a = s - r;
2✔
681
      if (result != null && (result._depth == null || (result._depth!) < a)) {
1✔
682
        result._depth = a;
1✔
683
        result.axis.setFrom(other.normal);
3✔
684
      }
685
      return true;
686
    }
687

688
    return false;
689
  }
690

691
  // Avoid allocating these instance on every call to intersectsWithTriangle
692
  static final _quadTriangle0 = Triangle();
×
693
  static final _quadTriangle1 = Triangle();
×
694

695
  /// Return `true` if this intersects with [other].
696
  ///
697
  /// If [result] is specified and an intersection is
698
  /// found, result is modified to contain more details about the type of
699
  /// intersection.
700
  bool intersectsWithQuad(Quad other, {IntersectionResult? result}) {
×
701
    other.copyTriangles(_quadTriangle0, _quadTriangle1);
×
702

703
    return intersectsWithTriangle(_quadTriangle0, result: result) ||
×
704
        intersectsWithTriangle(_quadTriangle1, result: result);
×
705
  }
706
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc