1
/***************************************************************************
2
* Copyright (c) 2005 Imetric 3D GmbH *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
23
#include "PreCompiled.h"
25
#include <Mod/Mesh/App/WildMagic4/Wm4DistSegment3Triangle3.h>
26
#include <Mod/Mesh/App/WildMagic4/Wm4DistVector3Triangle3.h>
27
#include <Mod/Mesh/App/WildMagic4/Wm4IntrSegment3Box3.h>
28
#include <Mod/Mesh/App/WildMagic4/Wm4IntrSegment3Plane3.h>
33
#include "tritritest.h"
36
using namespace MeshCore;
39
MeshPointArray::MeshPointArray(const MeshPointArray& ary) = default;
41
MeshPointArray::MeshPointArray(MeshPointArray&& ary) = default;
43
PointIndex MeshPointArray::Get(const MeshPoint& rclPoint)
47
clIter = std::find(begin(), end(), rclPoint);
48
if (clIter != end()) {
49
return clIter - begin();
52
return POINT_INDEX_MAX;
56
PointIndex MeshPointArray::GetOrAddIndex(const MeshPoint& rclPoint)
58
PointIndex ulIndex {};
60
if ((ulIndex = Get(rclPoint)) == POINT_INDEX_MAX) {
62
return static_cast<PointIndex>(size() - 1);
69
void MeshPointArray::SetFlag(MeshPoint::TFlagType tF) const
71
for (MeshPointArray::_TConstIterator i = begin(); i < end(); ++i) {
76
void MeshPointArray::ResetFlag(MeshPoint::TFlagType tF) const
78
for (MeshPointArray::_TConstIterator i = begin(); i < end(); ++i) {
83
void MeshPointArray::SetProperty(unsigned long ulVal) const
85
for (const auto& pP : *this) {
86
pP.SetProperty(ulVal);
90
void MeshPointArray::ResetInvalid() const
92
for (const auto& pP : *this) {
97
MeshPointArray& MeshPointArray::operator=(const MeshPointArray& rclPAry) = default;
99
MeshPointArray& MeshPointArray::operator=(MeshPointArray&& rclPAry) = default;
101
void MeshPointArray::Transform(const Base::Matrix4D& mat)
103
for (auto& pP : *this) {
108
MeshFacetArray::MeshFacetArray(const MeshFacetArray& ary) = default;
110
MeshFacetArray::MeshFacetArray(MeshFacetArray&& ary) = default;
112
void MeshFacetArray::Erase(_TIterator pIter)
114
FacetIndex i {}, *pulN {};
115
_TIterator pPass, pEnd;
116
FacetIndex ulInd = pIter - begin();
120
while (pPass < pEnd) {
121
for (i = 0; i < 3; i++) {
122
pulN = &pPass->_aulNeighbours[i];
123
if ((*pulN > ulInd) && (*pulN != FACET_INDEX_MAX)) {
131
void MeshFacetArray::TransposeIndices(PointIndex ulOrig, PointIndex ulNew)
133
_TIterator pIter = begin(), pEnd = end();
135
while (pIter < pEnd) {
136
pIter->Transpose(ulOrig, ulNew);
141
void MeshFacetArray::DecrementIndices(PointIndex ulIndex)
143
_TIterator pIter = begin(), pEnd = end();
145
while (pIter < pEnd) {
146
pIter->Decrement(ulIndex);
151
void MeshFacetArray::SetFlag(MeshFacet::TFlagType tF) const
153
for (MeshFacetArray::_TConstIterator i = begin(); i < end(); ++i) {
158
void MeshFacetArray::ResetFlag(MeshFacet::TFlagType tF) const
160
for (MeshFacetArray::_TConstIterator i = begin(); i < end(); ++i) {
165
void MeshFacetArray::SetProperty(unsigned long ulVal) const
167
for (const auto& pF : *this) {
168
pF.SetProperty(ulVal);
172
void MeshFacetArray::ResetInvalid() const
174
for (const auto& pF : *this) {
179
MeshFacetArray& MeshFacetArray::operator=(const MeshFacetArray& rclFAry) = default;
181
MeshFacetArray& MeshFacetArray::operator=(MeshFacetArray&& rclFAry) = default;
183
// -----------------------------------------------------------------
185
bool MeshGeomEdge::ContainedByOrIntersectBoundingBox(const Base::BoundBox3f& rclBB) const
187
// Test whether all corner points of the Edge are on one of the 6 sides of the BB
188
if (!(GetBoundBox() && rclBB)) {
192
// Test whether Edge-BB is completely in BB
193
if (rclBB.IsInBox(GetBoundBox())) {
197
// Test whether one of the corner points is in BB
198
for (const auto& pnt : _aclPoints) {
199
if (rclBB.IsInBox(pnt)) {
204
// "real" test for cut
205
if (IntersectBoundingBox(rclBB)) {
212
Base::BoundBox3f MeshGeomEdge::GetBoundBox() const
214
return {_aclPoints, 2};
217
bool MeshGeomEdge::IntersectBoundingBox(const Base::BoundBox3f& rclBB) const
219
const Base::Vector3f& rclP0 = _aclPoints[0];
220
const Base::Vector3f& rclP1 = _aclPoints[1];
222
Vector3<float> A(rclP0.x, rclP0.y, rclP0.z);
223
Vector3<float> B(rclP1.x, rclP1.y, rclP1.z);
225
Vector3<float> n = B - A;
226
float len = n.Length();
228
Vector3<float> p = 0.5f * (A + B);
230
Segment3<float> akSeg(p, n, 0.5f * len);
232
Base::Vector3f clCenter = rclBB.GetCenter();
233
Vector3<float> center(clCenter.x, clCenter.y, clCenter.z);
234
Vector3<float> axis0(1.0f, 0.0f, 0.0f);
235
Vector3<float> axis1(0.0f, 1.0f, 0.0f);
236
Vector3<float> axis2(0.0f, 0.0f, 1.0f);
237
float extent0 = 0.5f * rclBB.LengthX();
238
float extent1 = 0.5f * rclBB.LengthY();
239
float extent2 = 0.5f * rclBB.LengthZ();
241
Box3<float> kBox(center, axis0, axis1, axis2, extent0, extent1, extent2);
243
IntrSegment3Box3<float> intrsectbox(akSeg, kBox, false);
244
return intrsectbox.Test();
247
bool MeshGeomEdge::IntersectWithLine(const Base::Vector3f& rclPt,
248
const Base::Vector3f& rclDir,
249
Base::Vector3f& rclRes) const
251
const float eps = 1e-06f;
252
Base::Vector3f n = _aclPoints[1] - _aclPoints[0];
254
// check angle between edge and the line direction, FLOAT_MAX is
255
// returned for degenerated edges
256
float fAngle = rclDir.GetAngle(n);
259
float distance = _aclPoints[0].DistanceToLine(rclPt, rclDir);
260
if (distance < eps) {
262
rclRes = _aclPoints[0];
266
return false; // no intersection possible
269
// that's the normal of a helper plane and its base at _aclPoints
270
Base::Vector3f normal = n.Cross(rclDir);
272
// if the distance of rclPt to the plane is higher than eps then the
273
// two lines are warped and there is no intersection possible
274
if (fabs(rclPt.DistanceToPlane(_aclPoints[0], normal)) > eps) {
278
// get a second helper plane and get the intersection with the line
279
Base::Vector3f normal2 = normal.Cross(n);
281
float s = ((_aclPoints[0] - rclPt) * normal2) / (rclDir * normal2);
282
rclRes = rclPt + s * rclDir;
284
float dist1 = Base::Distance(_aclPoints[0], _aclPoints[1]);
285
float dist2 = Base::Distance(_aclPoints[0], rclRes);
286
float dist3 = Base::Distance(_aclPoints[1], rclRes);
288
return dist2 + dist3 <= dist1 + eps;
291
bool MeshGeomEdge::IsParallel(const MeshGeomEdge& edge) const
293
Base::Vector3f r(_aclPoints[1] - _aclPoints[0]);
294
Base::Vector3f s(edge._aclPoints[1] - edge._aclPoints[0]);
295
Base::Vector3f n = r.Cross(s);
299
bool MeshGeomEdge::IsCollinear(const MeshGeomEdge& edge) const
301
if (IsParallel(edge)) {
302
Base::Vector3f r(_aclPoints[1] - _aclPoints[0]);
303
Base::Vector3f d = edge._aclPoints[0] - _aclPoints[0];
304
return d.Cross(r).IsNull();
310
bool MeshGeomEdge::IntersectWithEdge(const MeshGeomEdge& edge, Base::Vector3f& res) const
312
const float eps = 1e-06f;
313
Base::Vector3f p(_aclPoints[0]);
314
Base::Vector3f r(_aclPoints[1] - _aclPoints[0]);
315
Base::Vector3f q(edge._aclPoints[0]);
316
Base::Vector3f s(edge._aclPoints[1] - edge._aclPoints[0]);
317
Base::Vector3f n = r.Cross(s);
318
Base::Vector3f d = q - p;
320
// lines are collinear or parallel
322
if (d.Cross(r).IsNull()) {
324
if (IsProjectionPointOf(edge._aclPoints[0])) {
325
res = edge._aclPoints[0];
328
if (IsProjectionPointOf(edge._aclPoints[1])) {
329
res = edge._aclPoints[1];
341
// Get the distance of q to the plane defined by p and n
342
float distance = q.DistanceToPlane(p, n);
345
if (fabs(distance) > eps) {
349
float t = d.Cross(s).Dot(n) / n.Sqr();
350
float u = d.Cross(r).Dot(n) / n.Sqr();
352
auto is_in_range = [](float v) {
353
return v >= 0.0f && v <= 1.0f;
356
if (is_in_range(t) && is_in_range(u)) {
357
res = p + t * r; // equal to q + u * s
365
bool MeshGeomEdge::IntersectWithPlane(const Base::Vector3f& rclPt,
366
const Base::Vector3f& rclDir,
367
Base::Vector3f& rclRes) const
369
float dist1 = _aclPoints[0].DistanceToPlane(rclPt, rclDir);
370
float dist2 = _aclPoints[1].DistanceToPlane(rclPt, rclDir);
372
// either both points are below or above the plane
373
if (dist1 * dist2 >= 0.0f) {
377
Base::Vector3f u = _aclPoints[1] - _aclPoints[0];
378
Base::Vector3f b = rclPt - _aclPoints[0];
379
float t = b.Dot(rclDir) / u.Dot(rclDir);
380
rclRes = _aclPoints[0] + t * u;
385
void MeshGeomEdge::ProjectPointToLine(const Base::Vector3f& rclPoint, Base::Vector3f& rclProj) const
387
Base::Vector3f pt1 = rclPoint - _aclPoints[0];
388
Base::Vector3f dir = _aclPoints[1] - _aclPoints[0];
390
vec.ProjectToLine(pt1, dir);
391
rclProj = rclPoint + vec;
394
void MeshGeomEdge::ClosestPointsToLine(const Base::Vector3f& linePt,
395
const Base::Vector3f& lineDir,
396
Base::Vector3f& rclPnt1,
397
Base::Vector3f& rclPnt2) const
399
const float eps = 1e-06f;
400
Base::Vector3f edgeDir = _aclPoints[1] - _aclPoints[0];
402
// check angle between edge and the line direction, FLOAT_MAX is
403
// returned for degenerated edges
404
float fAngle = lineDir.GetAngle(edgeDir);
407
float distance = _aclPoints[0].DistanceToLine(linePt, lineDir);
408
if (distance < eps) {
410
rclPnt1 = _aclPoints[0];
411
rclPnt2 = _aclPoints[0];
414
rclPnt1 = _aclPoints[0];
416
edge._aclPoints[0] = linePt;
417
edge._aclPoints[1] = linePt + lineDir;
418
edge.ProjectPointToLine(rclPnt1, rclPnt2);
422
// that's the normal of a helper plane
423
Base::Vector3f normal = edgeDir.Cross(lineDir);
425
// get a second helper plane and get the intersection with the line
426
Base::Vector3f normal2 = normal.Cross(edgeDir);
427
float s = ((_aclPoints[0] - linePt) * normal2) / (lineDir * normal2);
428
rclPnt2 = linePt + s * lineDir;
430
// get a third helper plane and get the intersection with the line
431
Base::Vector3f normal3 = normal.Cross(lineDir);
432
float t = ((linePt - _aclPoints[0]) * normal3) / (edgeDir * normal3);
433
rclPnt1 = _aclPoints[0] + t * edgeDir;
437
bool MeshGeomEdge::IsPointOf(const Base::Vector3f& rclPoint, float fDistance) const
439
float len2 = Base::DistanceP2(_aclPoints[0], _aclPoints[1]);
441
return _aclPoints[0].IsEqual(rclPoint, 0.0f);
444
Base::Vector3f p2p1 = _aclPoints[1] - _aclPoints[0];
445
Base::Vector3f pXp1 = rclPoint - _aclPoints[0];
447
float dot = pXp1 * p2p1;
448
float t = dot / len2;
449
if (t < 0.0f || t > 1.0f) {
454
Base::Vector3f ptEdge = t * p2p1 + _aclPoints[0];
455
return Base::Distance(ptEdge, rclPoint) <= fDistance;
458
bool MeshGeomEdge::IsProjectionPointOf(const Base::Vector3f& point) const
460
Base::Vector3f fromStartToPoint = point - _aclPoints[0];
461
Base::Vector3f fromPointToEnd = _aclPoints[1] - point;
462
float dot = fromStartToPoint * fromPointToEnd;
466
// -----------------------------------------------------------------
468
MeshGeomFacet::MeshGeomFacet()
469
: _bNormalCalculated(false)
475
MeshGeomFacet::MeshGeomFacet(const Base::Vector3f& v1,
476
const Base::Vector3f& v2,
477
const Base::Vector3f& v3)
478
: _bNormalCalculated(false)
488
bool MeshGeomFacet::IsPointOf(const Base::Vector3f& rclPoint, float fDistance) const
490
if (DistancePlaneToPoint(rclPoint) > fDistance) {
494
// force internal normal to be computed if not done yet
495
Base::Vector3f clNorm(GetNormal()), clProjPt(rclPoint), clEdge;
496
Base::Vector3f clP0(_aclPoints[0]), clP1(_aclPoints[1]), clP2(_aclPoints[2]);
497
float fLP {}, fLE {};
500
clProjPt.ProjectToPlane(_aclPoints[0], clNorm);
504
clEdge = clP1 - clP0;
505
fLP = clProjPt.DistanceToLine(clP0, clEdge);
507
fLE = clP2.DistanceToLine(clP0, clEdge);
509
if (clProjPt.DistanceToLine(clP2, clEdge) > fLE) {
519
clEdge = clP2 - clP0;
520
fLP = clProjPt.DistanceToLine(clP0, clEdge);
522
fLE = clP1.DistanceToLine(clP0, clEdge);
524
if (clProjPt.DistanceToLine(clP1, clEdge) > fLE) {
534
clEdge = clP2 - clP1;
535
fLP = clProjPt.DistanceToLine(clP1, clEdge);
537
fLE = clP0.DistanceToLine(clP1, clEdge);
539
if (clProjPt.DistanceToLine(clP0, clEdge) > fLE) {
551
bool MeshGeomFacet::IsPointOfFace(const Base::Vector3f& rclP, float fDistance) const
553
// more effective implementation than in MeshGeomFacet::IsPointOf
555
Base::Vector3f a(_aclPoints[0].x, _aclPoints[0].y, _aclPoints[0].z);
556
Base::Vector3f b(_aclPoints[1].x, _aclPoints[1].y, _aclPoints[1].z);
557
Base::Vector3f c(_aclPoints[2].x, _aclPoints[2].y, _aclPoints[2].z);
558
Base::Vector3f p(rclP);
560
Base::Vector3f n = (b - a) % (c - a);
561
Base::Vector3f n1 = (a - p) % (b - p);
562
Base::Vector3f n2 = (c - p) % (a - p);
563
Base::Vector3f n3 = (b - p) % (c - p);
565
if (n * (p - a) > fDistance * n.Length()) {
569
if (n * (a - p) > fDistance * n.Length()) {
573
if (n * n1 <= 0.0f) {
577
if (n * n2 <= 0.0f) {
581
if (n * n3 <= 0.0f) {
588
bool MeshGeomFacet::Weights(const Base::Vector3f& rclP, float& w0, float& w1, float& w2) const
590
float fAreaABC = Area();
591
float fAreaPBC = MeshGeomFacet(rclP, _aclPoints[1], _aclPoints[2]).Area();
592
float fAreaPCA = MeshGeomFacet(rclP, _aclPoints[2], _aclPoints[0]).Area();
593
float fAreaPAB = MeshGeomFacet(rclP, _aclPoints[0], _aclPoints[1]).Area();
595
w0 = fAreaPBC / fAreaABC;
596
w1 = fAreaPCA / fAreaABC;
597
w2 = fAreaPAB / fAreaABC;
599
return fabs(w0 + w1 + w2 - 1.0f) < 0.001f;
602
void MeshGeomFacet::ProjectPointToPlane(const Base::Vector3f& rclPoint,
603
Base::Vector3f& rclProj) const
605
rclPoint.ProjectToPlane(_aclPoints[0], GetNormal(), rclProj);
608
void MeshGeomFacet::ProjectFacetToPlane(MeshGeomFacet& rclFacet) const
610
// project facet 2 onto facet 1
611
IntersectPlaneWithLine(rclFacet._aclPoints[0], GetNormal(), rclFacet._aclPoints[0]);
612
IntersectPlaneWithLine(rclFacet._aclPoints[1], GetNormal(), rclFacet._aclPoints[1]);
613
IntersectPlaneWithLine(rclFacet._aclPoints[2], GetNormal(), rclFacet._aclPoints[2]);
616
void MeshGeomFacet::Enlarge(float fDist)
618
Base::Vector3f clM, clU, clV, clPNew[3];
620
PointIndex i {}, ulP1 {}, ulP2 {}, ulP3 {};
622
for (i = 0; i < 3; i++) {
626
clU = _aclPoints[ulP2] - _aclPoints[ulP1];
627
clV = _aclPoints[ulP3] - _aclPoints[ulP1];
629
fA = clM.GetAngle(-clU);
630
fD = fDist / float(sin(fA));
632
clM.Scale(fD, fD, fD);
633
clPNew[ulP1] = _aclPoints[ulP1] + clM;
636
_aclPoints[0] = clPNew[0];
637
_aclPoints[1] = clPNew[1];
638
_aclPoints[2] = clPNew[2];
641
bool MeshGeomFacet::IsDegenerated(float epsilon) const
643
// The triangle has the points A,B,C where we can define the vector u and v
644
// u = b-a and v = c-a. Then we define the line g: r = a+t*u and the plane
645
// E: (x-c)*u=0. The intersection point of g and E is S.
646
// The vector to S can be computed with a+(uv)/(uu)*u. The difference of
647
// C and S then is v-(u*v)/(u*u)*u. The square distance leads to the formula
648
// (v-(u*v)/(u*u)*u)^2 < eps which means that C and S is considered equal if
649
// the square distance is less than an epsilon and thus the triangle is de-
651
// After a few calculation step we get the formula:
652
// (u*u)*(v*v)-(u*v)*(u*v) < eps*(u*u)
653
// So, if we do the same except that we define a line h which goes through
654
// A and C and a plane going through B we get a similar formula:
655
// (u*u)*(v*v)-(u*v)*(u*v) < eps*(v*v).
656
// As end formula we can write then:
657
// (u*u)*(v*v)-(u*v)*(u*v) < max(eps*(u*u),eps*(v*v)).
659
// BTW (u*u)*(v*v)-(u*v)*(u*v) is the same as (uxv)*(uxv).
660
Base::Vector3d p1 = Base::convertTo<Base::Vector3d>(this->_aclPoints[0]);
661
Base::Vector3d p2 = Base::convertTo<Base::Vector3d>(this->_aclPoints[1]);
662
Base::Vector3d p3 = Base::convertTo<Base::Vector3d>(this->_aclPoints[2]);
664
Base::Vector3d u = p2 - p1;
665
Base::Vector3d v = p3 - p1;
667
double eps = static_cast<double>(epsilon);
677
double crosssqr = uu * vv - uv * uv;
678
if (crosssqr <= eps * std::max<double>(uu, vv)) {
684
bool MeshGeomFacet::IsDeformed(float fCosOfMinAngle, float fCosOfMaxAngle) const
689
for (int i = 0; i < 3; i++) {
690
u = _aclPoints[(i + 1) % 3] - _aclPoints[i];
691
v = _aclPoints[(i + 2) % 3] - _aclPoints[i];
697
if (fCosAngle > fCosOfMinAngle || fCosAngle < fCosOfMaxAngle) {
705
bool MeshGeomFacet::IntersectBoundingBox(const Base::BoundBox3f& rclBB) const
707
// the triangle's corner points
708
const Base::Vector3f& v0 = _aclPoints[0];
709
const Base::Vector3f& v1 = _aclPoints[1];
710
const Base::Vector3f& v2 = _aclPoints[2];
712
// first check if at least one point is inside the box
713
if (rclBB.IsInBox(v0) || rclBB.IsInBox(v1) || rclBB.IsInBox(v2)) {
718
float len0 = (v0 - v1).Length();
719
float len1 = (v1 - v2).Length();
720
float len2 = (v2 - v0).Length();
722
// Build up the line segments
723
Vector3<float> p0(0.5f * (v0.x + v1.x), 0.5f * (v0.y + v1.y), 0.5f * (v0.z + v1.z));
724
Vector3<float> p1(0.5f * (v1.x + v2.x), 0.5f * (v1.y + v2.y), 0.5f * (v1.z + v2.z));
725
Vector3<float> p2(0.5f * (v2.x + v0.x), 0.5f * (v2.y + v0.y), 0.5f * (v2.z + v0.z));
727
Vector3<float> d0(v1.x - v0.x, v1.y - v0.y, v1.z - v0.z);
729
Vector3<float> d1(v2.x - v1.x, v2.y - v1.y, v2.z - v1.z);
731
Vector3<float> d2(v0.x - v2.x, v0.y - v2.y, v0.z - v2.z);
734
Segment3<float> akSeg0(p0, d0, len0 / 2.0f);
735
Segment3<float> akSeg1(p1, d1, len1 / 2.0f);
736
Segment3<float> akSeg2(p2, d2, len2 / 2.0f);
739
Base::Vector3f clCenter = rclBB.GetCenter();
740
Vector3<float> center(clCenter.x, clCenter.y, clCenter.z);
741
Vector3<float> axis0(1.0f, 0.0f, 0.0f);
742
Vector3<float> axis1(0.0f, 1.0f, 0.0f);
743
Vector3<float> axis2(0.0f, 0.0f, 1.0f);
744
float extent0 = 0.5f * rclBB.LengthX();
745
float extent1 = 0.5f * rclBB.LengthY();
746
float extent2 = 0.5f * rclBB.LengthZ();
748
Box3<float> akBox(center, axis0, axis1, axis2, extent0, extent1, extent2);
750
// Check for intersection of line segments and box
751
IntrSegment3Box3<float> akSec0(akSeg0, akBox, false);
755
IntrSegment3Box3<float> akSec1(akSeg1, akBox, false);
759
IntrSegment3Box3<float> akSec2(akSeg2, akBox, false);
768
bool MeshGeomFacet::IntersectWithPlane(const Base::Vector3f& rclBase,
769
const Base::Vector3f& rclNormal,
770
Base::Vector3f& rclP1,
771
Base::Vector3f& rclP2) const
773
const float eps = 1e-06f;
775
// the triangle's corner points
776
const Base::Vector3f& v0 = _aclPoints[0];
777
const Base::Vector3f& v1 = _aclPoints[1];
778
const Base::Vector3f& v2 = _aclPoints[2];
780
// first check if a triangle's edge lies on the plane
781
float dist0 = fabs(v0.DistanceToPlane(rclBase, rclNormal));
782
float dist1 = fabs(v1.DistanceToPlane(rclBase, rclNormal));
783
float dist2 = fabs(v2.DistanceToPlane(rclBase, rclNormal));
784
if (dist0 < eps && dist1 < eps) {
789
if (dist1 < eps && dist2 < eps) {
794
if (dist2 < eps && dist0 < eps) {
801
float len0 = (v0 - v1).Length();
802
float len1 = (v1 - v2).Length();
803
float len2 = (v2 - v0).Length();
805
// Build up the line segments
806
Vector3<float> p0(0.5f * (v0.x + v1.x), 0.5f * (v0.y + v1.y), 0.5f * (v0.z + v1.z));
807
Vector3<float> p1(0.5f * (v1.x + v2.x), 0.5f * (v1.y + v2.y), 0.5f * (v1.z + v2.z));
808
Vector3<float> p2(0.5f * (v2.x + v0.x), 0.5f * (v2.y + v0.y), 0.5f * (v2.z + v0.z));
810
Vector3<float> d0(v1.x - v0.x, v1.y - v0.y, v1.z - v0.z);
812
Vector3<float> d1(v2.x - v1.x, v2.y - v1.y, v2.z - v1.z);
814
Vector3<float> d2(v0.x - v2.x, v0.y - v2.y, v0.z - v2.z);
817
Segment3<float> akSeg0(p0, d0, len0 / 2.0f);
818
Segment3<float> akSeg1(p1, d1, len1 / 2.0f);
819
Segment3<float> akSeg2(p2, d2, len2 / 2.0f);
821
// Build up the plane
822
Vector3<float> p(rclBase.x, rclBase.y, rclBase.z);
823
Vector3<float> n(rclNormal.x, rclNormal.y, rclNormal.z);
824
Plane3<float> akPln(n, p);
826
// Check for intersection with plane for each line segment
827
IntrSegment3Plane3<float> test0(akSeg0, akPln);
828
IntrSegment3Plane3<float> test1(akSeg1, akPln);
829
IntrSegment3Plane3<float> test2(akSeg2, akPln);
833
// now check if a triangle's corner lies on the plane
838
intr = p1 + test1.GetSegmentT() * d1;
839
rclP2.Set(intr[0], intr[1], intr[2]);
843
else if (dist1 < eps) {
847
intr = p2 + test2.GetSegmentT() * d2;
848
rclP2.Set(intr[0], intr[1], intr[2]);
852
else if (dist2 < eps) {
856
intr = p0 + test0.GetSegmentT() * d0;
857
rclP2.Set(intr[0], intr[1], intr[2]);
862
// check for arbitrary intersections
864
intr = p0 + test0.GetSegmentT() * d0;
865
rclP1.Set(intr[0], intr[1], intr[2]);
868
intr = p1 + test1.GetSegmentT() * d1;
869
rclP2.Set(intr[0], intr[1], intr[2]);
872
else if (test2.Find()) {
873
intr = p2 + test2.GetSegmentT() * d2;
874
rclP2.Set(intr[0], intr[1], intr[2]);
878
else if (test1.Find()) {
879
intr = p1 + test1.GetSegmentT() * d1;
880
rclP1.Set(intr[0], intr[1], intr[2]);
883
intr = p2 + test2.GetSegmentT() * d2;
884
rclP2.Set(intr[0], intr[1], intr[2]);
892
bool MeshGeomFacet::Foraminate(const Base::Vector3f& P,
893
const Base::Vector3f& dir,
895
float fMaxAngle) const
897
const float eps = 1e-06f;
898
Base::Vector3f n = this->GetNormal();
900
// check angle between facet normal and the line direction, FLOAT_MAX is
901
// returned for degenerated facets
902
float fAngle = dir.GetAngle(n);
903
if (fAngle > fMaxAngle) {
909
float dd = dir * dir;
911
// the line mustn't be parallel to the triangle
912
if ((nd * nd) <= (eps * dd * nn)) {
916
Base::Vector3f u = this->_aclPoints[1] - this->_aclPoints[0];
917
Base::Vector3f v = this->_aclPoints[2] - this->_aclPoints[0];
919
Base::Vector3f w0 = P - this->_aclPoints[0];
920
float r = -(n * w0) / nd;
921
Base::Vector3f w = w0 + r * dir;
928
float det = float(fabs((uu * vv) - (uv * uv)));
930
float s = (vv * wu) - (uv * wv);
931
float t = (uu * wv) - (uv * wu);
933
// is the intersection point inside the triangle?
934
if ((s >= 0.0f) && (t >= 0.0f) && ((s + t) <= det)) {
935
I = w + this->_aclPoints[0];
942
bool MeshGeomFacet::IntersectPlaneWithLine(const Base::Vector3f& rclPt,
943
const Base::Vector3f& rclDir,
944
Base::Vector3f& rclRes) const
946
// calculate the intersection of the straight line <-> plane
947
if (fabs(rclDir * GetNormal()) < 1e-3f) {
948
return false; // line and plane are parallel
951
float s = ((GetGravityPoint() - rclPt) * GetNormal()) / (rclDir * GetNormal());
952
rclRes = rclPt + s * rclDir;
957
bool MeshGeomFacet::IntersectWithLine(const Base::Vector3f& rclPt,
958
const Base::Vector3f& rclDir,
959
Base::Vector3f& rclRes) const
961
if (!IntersectPlaneWithLine(rclPt, rclDir, rclRes)) {
962
return false; // line and plane are parallel
964
// Check if the intersection point is inside the facet
965
return IsPointOfFace(rclRes, 1e-03f);
968
float MeshGeomFacet::DistanceToLineSegment(const Base::Vector3f& rclP1,
969
const Base::Vector3f& rclP2) const
972
Vector3<float> A(rclP1.x, rclP1.y, rclP1.z);
973
Vector3<float> B(rclP2.x, rclP2.y, rclP2.z);
975
Vector3<float> n = B - A;
976
float len = n.Length();
978
Vector3<float> p = 0.5f * (A + B);
980
Segment3<float> akSeg(p, n, 0.5f * len);
983
Vector3<float> akF0(_aclPoints[0].x, _aclPoints[0].y, _aclPoints[0].z);
984
Vector3<float> akF1(_aclPoints[1].x, _aclPoints[1].y, _aclPoints[1].z);
985
Vector3<float> akF2(_aclPoints[2].x, _aclPoints[2].y, _aclPoints[2].z);
987
Triangle3<float> akTria(akF0, akF1, akF2);
989
DistSegment3Triangle3<float> akDistSegTria(akSeg, akTria);
990
return akDistSegTria.Get();
993
float MeshGeomFacet::DistanceToPoint(const Base::Vector3f& rclPt, Base::Vector3f& rclNt) const
995
Vector3<float> akPt(rclPt.x, rclPt.y, rclPt.z);
996
Vector3<float> akF0(_aclPoints[0].x, _aclPoints[0].y, _aclPoints[0].z);
997
Vector3<float> akF1(_aclPoints[1].x, _aclPoints[1].y, _aclPoints[1].z);
998
Vector3<float> akF2(_aclPoints[2].x, _aclPoints[2].y, _aclPoints[2].z);
1000
Triangle3<float> akTria(akF0, akF1, akF2);
1001
DistVector3Triangle3<float> akDistPtTria(akPt, akTria);
1003
float fDist = akDistPtTria.Get();
1005
// get nearest point of the facet
1006
Vector3<float> akNt = akDistPtTria.GetClosestPoint1();
1007
rclNt.Set(akNt.X(), akNt.Y(), akNt.Z());
1012
void MeshGeomFacet::SubSample(float fStep, std::vector<Base::Vector3f>& rclPoints) const
1014
std::vector<Base::Vector3f> clPoints;
1015
Base::Vector3f A = _aclPoints[0];
1016
Base::Vector3f B = _aclPoints[1];
1017
Base::Vector3f C = _aclPoints[2];
1018
Base::Vector3f clVecAB(B - A);
1019
Base::Vector3f clVecAC(C - A);
1020
Base::Vector3f clVecBC(C - B);
1022
// longest axis corresponds to AB
1023
float fLenAB = clVecAB.Length();
1024
float fLenAC = clVecAC.Length();
1025
float fLenBC = clVecBC.Length();
1027
if (fLenAC > fLenAB) {
1029
std::swap(fLenAB, fLenAC);
1031
if (fLenBC > fLenAB) {
1033
std::swap(fLenBC, fLenAB);
1039
Base::Vector3f clVecABNorm(clVecAB);
1040
Base::Vector3f clVecHNorm((clVecAB % clVecAC) % clVecAB);
1041
clVecABNorm.Normalize();
1042
clVecHNorm.Normalize();
1045
float cy = float(sin(clVecAB.GetAngle(clVecAC)) * fLenAC);
1046
float cx = float(sqrt(fabs(fLenAC * fLenAC - cy * cy)));
1048
float fDetABC = bx * cy;
1050
for (float px = (fStep / 2.0f); px < fLenAB; px += fStep) // NOLINT
1052
for (float py = (fStep / 2.0f); py < cy; py += fStep) // NOLINT
1054
float u = (bx * cy + cx * py - px * cy - bx * py) / fDetABC;
1055
float v = (px * cy - cx * py) / fDetABC;
1056
float w = (bx * py) / fDetABC;
1058
if ((u >= 0.0f) && (v >= 0.0f) && (w >= 0.0f) && ((u + v) < 1.0f)) {
1059
// rclPoints.push_back(CBase::Vector3f(u*A + v*B + w*C));
1060
Base::Vector3f clV = A + (px * clVecABNorm) + (py * clVecHNorm);
1061
clPoints.push_back(clV);
1069
// if couldn't subsample the facet take gravity center
1070
if (clPoints.empty()) {
1071
clPoints.push_back(this->GetGravityPoint());
1074
rclPoints.insert(rclPoints.end(), clPoints.begin(), clPoints.end());
1077
bool MeshGeomFacet::IsCoplanar(const MeshGeomFacet& facet) const
1079
const float eps = 1e-06f;
1080
const float unit = 0.9995f;
1081
float mult = fabs(this->GetNormal() * facet.GetNormal());
1082
float dist = fabs(DistancePlaneToPoint(facet._aclPoints[0]));
1083
return (mult >= unit) && (dist <= eps);
1087
* Fast Triangle-Triangle Intersection Test by Tomas Moeller
1088
* http://www.acm.org/jgt/papers/Moller97/tritri.html
1089
* http://www.cs.lth.se/home/Tomas_Akenine_Moller/code/
1091
bool MeshGeomFacet::IntersectWithFacet(const MeshGeomFacet& rclFacet) const
1093
float V[3][3], U[3][3];
1094
for (int i = 0; i < 3; i++) {
1095
V[i][0] = _aclPoints[i].x;
1096
V[i][1] = _aclPoints[i].y;
1097
V[i][2] = _aclPoints[i].z;
1098
U[i][0] = rclFacet._aclPoints[i].x;
1099
U[i][1] = rclFacet._aclPoints[i].y;
1100
U[i][2] = rclFacet._aclPoints[i].z;
1103
if (tri_tri_intersect(V[0], V[1], V[2], U[0], U[1], U[2]) == 0) {
1104
return false; // no intersections
1110
* Fast Triangle-Triangle Intersection Test by Tomas Moeller
1111
* http://www.acm.org/jgt/papers/Moller97/tritri.html
1112
* http://www.cs.lth.se/home/Tomas_Akenine_Moller/code/
1114
int MeshGeomFacet::IntersectWithFacet(const MeshGeomFacet& rclFacet,
1115
Base::Vector3f& rclPt0,
1116
Base::Vector3f& rclPt1) const
1118
// Note: tri_tri_intersect_with_isection() does not return line of
1119
// intersection when triangles are coplanar. See tritritest.h:18 and 658.
1120
if (IsCoplanar(rclFacet)) {
1121
// Since tri_tri_intersect_with_isection may return garbage values try to get
1122
// sensible values with edge/edge intersections
1123
std::vector<Base::Vector3f> intersections;
1124
for (short i = 0; i < 3; i++) {
1125
MeshGeomEdge edge1 = GetEdge(i);
1126
for (short j = 0; j < 3; j++) {
1127
MeshGeomEdge edge2 = rclFacet.GetEdge(j);
1128
Base::Vector3f point;
1129
if (edge1.IntersectWithEdge(edge2, point)) {
1130
intersections.push_back(point);
1135
// If triangles overlap there can be more than two intersection points
1136
// In that case use any two of them.
1137
if (intersections.size() >= 2) {
1138
rclPt0 = intersections[0];
1139
rclPt1 = intersections[1];
1142
else if (intersections.size() == 1) {
1143
rclPt0 = intersections[0];
1144
rclPt1 = intersections[0];
1151
float V[3][3] {}, U[3][3] {};
1153
float isectpt1[3] {}, isectpt2[3] {};
1155
for (int i = 0; i < 3; i++) {
1156
V[i][0] = _aclPoints[i].x;
1157
V[i][1] = _aclPoints[i].y;
1158
V[i][2] = _aclPoints[i].z;
1159
U[i][0] = rclFacet._aclPoints[i].x;
1160
U[i][1] = rclFacet._aclPoints[i].y;
1161
U[i][2] = rclFacet._aclPoints[i].z;
1164
if (tri_tri_intersect_with_isectline(V[0],
1174
return 0; // no intersections
1177
rclPt0.x = isectpt1[0];
1178
rclPt0.y = isectpt1[1];
1179
rclPt0.z = isectpt1[2];
1180
rclPt1.x = isectpt2[0];
1181
rclPt1.y = isectpt2[1];
1182
rclPt1.z = isectpt2[2];
1184
// With extremely acute-angled triangles it may happen that the algorithm
1185
// claims an intersection but the intersection points are far outside the
1186
// model. So, a plausibility check is to verify that the intersection points
1187
// are inside the bounding boxes of both triangles.
1188
Base::BoundBox3f box1 = this->GetBoundBox();
1189
box1.Enlarge(0.001f);
1190
if (!box1.IsInBox(rclPt0) || !box1.IsInBox(rclPt1)) {
1194
Base::BoundBox3f box2 = rclFacet.GetBoundBox();
1195
box2.Enlarge(0.001f);
1196
if (!box2.IsInBox(rclPt0) || !box2.IsInBox(rclPt1)) {
1200
// Note: The algorithm delivers sometimes false-positives, i.e. it claims
1201
// that the two triangles intersect but they don't. It seems that this bad
1202
// behaviour occurs if the triangles are nearly co-planar
1203
float mult = fabs(this->GetNormal() * rclFacet.GetNormal());
1204
if (rclPt0 == rclPt1) {
1205
if (mult < 0.995f) { // not co-planar, thus no test needed
1208
if (this->IsPointOf(rclPt0) && rclFacet.IsPointOf(rclPt0)) {
1213
if (mult < 0.995f) { // not co-planar, thus no test needed
1216
if (this->IsPointOf(rclPt0) && rclFacet.IsPointOf(rclPt0) && this->IsPointOf(rclPt1)
1217
&& rclFacet.IsPointOf(rclPt1)) {
1222
// the intersection algorithm delivered a false-positive
1226
bool MeshGeomFacet::IsPointOf(const Base::Vector3f& P) const
1228
Base::Vector3d p1 = Base::convertTo<Base::Vector3d>(this->_aclPoints[0]);
1229
Base::Vector3d p2 = Base::convertTo<Base::Vector3d>(this->_aclPoints[1]);
1230
Base::Vector3d p3 = Base::convertTo<Base::Vector3d>(this->_aclPoints[2]);
1231
Base::Vector3d p4 = Base::convertTo<Base::Vector3d>(P);
1233
Base::Vector3d u = p2 - p1;
1234
Base::Vector3d v = p3 - p1;
1235
Base::Vector3d w = p4 - p1;
1242
double det = fabs((uu * vv) - (uv * uv));
1244
// Note: Due to roundoff errors it can happen that we get very small
1245
// negative values for s or t. This e.g. can happen if the point lies
1246
// at the border of the facet. And as det could also become very small
1247
// we need an adaptive tolerance.
1248
const double eps = std::min<double>(1.0e-6, det * det);
1250
double s = (vv * wu) - (uv * wv);
1251
double t = (uu * wv) - (uv * wu);
1253
// is the point inside the triangle?
1254
if ((s >= -eps) && (t >= -eps) && ((s + t) <= det + eps)) {
1261
float MeshGeomFacet::CenterOfInscribedCircle(Base::Vector3f& rclCenter) const
1263
const Base::Vector3f& p0 = _aclPoints[0];
1264
const Base::Vector3f& p1 = _aclPoints[1];
1265
const Base::Vector3f& p2 = _aclPoints[2];
1267
float a = Base::Distance(p1, p2);
1268
float b = Base::Distance(p2, p0);
1269
float c = Base::Distance(p0, p1);
1271
// radius of the circle
1272
float fRadius = Area();
1273
fRadius *= 2.0f / (a + b + c);
1275
// center of the circle
1276
float w = a + b + c;
1277
rclCenter.x = (a * p0.x + b * p1.x + c * p2.x) / w;
1278
rclCenter.y = (a * p0.y + b * p1.y + c * p2.y) / w;
1279
rclCenter.z = (a * p0.z + b * p1.z + c * p2.z) / w;
1284
float MeshGeomFacet::CenterOfCircumCircle(Base::Vector3f& rclCenter) const
1286
const Base::Vector3f& p0 = _aclPoints[0];
1287
const Base::Vector3f& p1 = _aclPoints[1];
1288
const Base::Vector3f& p2 = _aclPoints[2];
1290
Base::Vector3f u = (p1 - p0);
1291
Base::Vector3f v = (p2 - p1);
1292
Base::Vector3f w = (p0 - p2);
1294
double uu = (u * u);
1295
double vv = (v * v);
1296
double ww = (w * w);
1297
double uv = -(u * v);
1298
double vw = -(v * w);
1299
double uw = -(w * u);
1301
double w0 = (2 * sqrt(uu * ww - uw * uw) * uw / (uu * ww));
1302
double w1 = (2 * sqrt(uu * vv - uv * uv) * uv / (uu * vv));
1303
double w2 = (2 * sqrt(vv * ww - vw * vw) * vw / (vv * ww));
1305
// center of the circle
1306
double wx = w0 + w1 + w2;
1307
rclCenter.x = static_cast<float>((w0 * p0.x + w1 * p1.x + w2 * p2.x) / wx);
1308
rclCenter.y = static_cast<float>((w0 * p0.y + w1 * p1.y + w2 * p2.y) / wx);
1309
rclCenter.z = static_cast<float>((w0 * p0.z + w1 * p1.z + w2 * p2.z) / wx);
1311
// radius of the circle
1312
float fRadius = static_cast<float>(sqrt(uu * vv * ww) / (4 * Area()));
1316
unsigned short MeshGeomFacet::NearestEdgeToPoint(const Base::Vector3f& rclPt) const
1318
unsigned short usSide {};
1320
const Base::Vector3f& rcP1 = _aclPoints[0];
1321
const Base::Vector3f& rcP2 = _aclPoints[1];
1322
const Base::Vector3f& rcP3 = _aclPoints[2];
1324
float fD1 = FLOAT_MAX;
1325
float fD2 = FLOAT_MAX;
1326
float fD3 = FLOAT_MAX;
1329
Base::Vector3f clDir = rcP2 - rcP1;
1330
float fLen = Base::Distance(rcP2, rcP1);
1331
float t = ((rclPt - rcP1) * clDir) / (fLen * fLen);
1333
fD1 = Base::Distance(rclPt, rcP1);
1335
else if (t > 1.0f) {
1336
fD1 = Base::Distance(rclPt, rcP2);
1339
fD1 = (((rclPt - rcP1) % clDir).Length()) / fLen;
1343
clDir = rcP3 - rcP2;
1344
fLen = Base::Distance(rcP3, rcP2);
1345
t = ((rclPt - rcP2) * clDir) / (fLen * fLen);
1347
fD2 = Base::Distance(rclPt, rcP2);
1349
else if (t > 1.0f) {
1350
fD2 = Base::Distance(rclPt, rcP3);
1353
fD2 = (((rclPt - rcP2) % clDir).Length()) / fLen;
1357
clDir = rcP1 - rcP3;
1358
fLen = Base::Distance(rcP1, rcP3);
1359
t = ((rclPt - rcP3) * clDir) / (fLen * fLen);
1361
fD3 = Base::Distance(rclPt, rcP3);
1363
else if (t > 1.0f) {
1364
fD3 = Base::Distance(rclPt, rcP1);
1367
fD3 = (((rclPt - rcP3) % clDir).Length()) / fLen;
1390
void MeshGeomFacet::NearestEdgeToPoint(const Base::Vector3f& rclPt,
1392
unsigned short& usSide) const
1394
const Base::Vector3f& rcP1 = _aclPoints[0];
1395
const Base::Vector3f& rcP2 = _aclPoints[1];
1396
const Base::Vector3f& rcP3 = _aclPoints[2];
1398
float fD1 = FLOAT_MAX;
1399
float fD2 = FLOAT_MAX;
1400
float fD3 = FLOAT_MAX;
1403
Base::Vector3f clDir = rcP2 - rcP1;
1404
float fLen = Base::Distance(rcP2, rcP1);
1405
float t = ((rclPt - rcP1) * clDir) / (fLen * fLen);
1407
fD1 = Base::Distance(rclPt, rcP1);
1409
else if (t > 1.0f) {
1410
fD1 = Base::Distance(rclPt, rcP2);
1413
fD1 = (((rclPt - rcP1) % clDir).Length()) / fLen;
1417
clDir = rcP3 - rcP2;
1418
fLen = Base::Distance(rcP3, rcP2);
1419
t = ((rclPt - rcP2) * clDir) / (fLen * fLen);
1421
fD2 = Base::Distance(rclPt, rcP2);
1423
else if (t > 1.0f) {
1424
fD2 = Base::Distance(rclPt, rcP3);
1427
fD2 = (((rclPt - rcP2) % clDir).Length()) / fLen;
1431
clDir = rcP1 - rcP3;
1432
fLen = Base::Distance(rcP1, rcP3);
1433
t = ((rclPt - rcP3) * clDir) / (fLen * fLen);
1435
fD3 = Base::Distance(rclPt, rcP3);
1437
else if (t > 1.0f) {
1438
fD3 = Base::Distance(rclPt, rcP1);
1441
fD3 = (((rclPt - rcP3) % clDir).Length()) / fLen;
1466
MeshGeomEdge MeshGeomFacet::GetEdge(short side) const
1469
edge._aclPoints[0] = this->_aclPoints[side % 3];
1470
edge._aclPoints[1] = this->_aclPoints[(side + 1) % 3];
1474
float MeshGeomFacet::VolumeOfPrism(const MeshGeomFacet& rclF1) const
1476
Base::Vector3f P1 = this->_aclPoints[0];
1477
Base::Vector3f P2 = this->_aclPoints[1];
1478
Base::Vector3f P3 = this->_aclPoints[2];
1479
Base::Vector3f Q1 = rclF1._aclPoints[0];
1480
Base::Vector3f Q2 = rclF1._aclPoints[1];
1481
Base::Vector3f Q3 = rclF1._aclPoints[2];
1483
if ((P1 - Q2).Length() < (P1 - Q1).Length()) {
1484
Base::Vector3f tmp = Q1;
1488
if ((P1 - Q3).Length() < (P1 - Q1).Length()) {
1489
Base::Vector3f tmp = Q1;
1493
if ((P2 - Q3).Length() < (P2 - Q2).Length()) {
1494
Base::Vector3f tmp = Q2;
1499
Base::Vector3f N1 = (P2 - P1) % (P3 - P1);
1500
Base::Vector3f N2 = (P2 - P1) % (Q2 - P1);
1501
Base::Vector3f N3 = (Q2 - P1) % (Q1 - P1);
1504
fVol += float(fabs((Q3 - P1) * N1));
1505
fVol += float(fabs((Q3 - P1) * N2));
1506
fVol += float(fabs((Q3 - P1) * N3));
1514
float MeshGeomFacet::MaximumAngle() const
1516
float fMaxAngle = 0.0f;
1518
for (int i = 0; i < 3; i++) {
1519
Base::Vector3f dir1(_aclPoints[(i + 1) % 3] - _aclPoints[i]);
1520
Base::Vector3f dir2(_aclPoints[(i + 2) % 3] - _aclPoints[i]);
1521
float fAngle = dir1.GetAngle(dir2);
1522
if (fAngle > fMaxAngle) {
1530
float MeshGeomFacet::MinimumAngle() const
1532
float fMinAngle = Mathf::PI;
1534
for (int i = 0; i < 3; i++) {
1535
Base::Vector3f dir1(_aclPoints[(i + 1) % 3] - _aclPoints[i]);
1536
Base::Vector3f dir2(_aclPoints[(i + 2) % 3] - _aclPoints[i]);
1537
float fAngle = dir1.GetAngle(dir2);
1538
if (fAngle < fMinAngle) {
1546
bool MeshGeomFacet::IsPointOfSphere(const Base::Vector3f& rP) const
1549
Base::Vector3f center;
1550
radius = CenterOfCircumCircle(center);
1553
float dist = Base::DistanceP2(rP, center);
1554
return dist < radius;
1557
bool MeshGeomFacet::IsPointOfSphere(const MeshGeomFacet& rFacet) const
1560
Base::Vector3f center;
1561
radius = CenterOfCircumCircle(center);
1564
for (const auto& pnt : rFacet._aclPoints) {
1565
float dist = Base::DistanceP2(pnt, center);
1566
if (dist < radius) {
1574
float MeshGeomFacet::AspectRatio() const
1576
Base::Vector3f d0 = _aclPoints[0] - _aclPoints[1];
1577
Base::Vector3f d1 = _aclPoints[1] - _aclPoints[2];
1578
Base::Vector3f d2 = _aclPoints[2] - _aclPoints[0];
1580
float l2 {}, maxl2 = d0.Sqr();
1581
if ((l2 = d1.Sqr()) > maxl2) {
1586
if ((l2 = d1.Sqr()) > maxl2) {
1590
// squared area of the parallelogram spanned by d0 and d1
1591
float a2 = (d0 % d1).Sqr();
1592
return float(sqrt((maxl2 * maxl2) / a2));
1595
float MeshGeomFacet::AspectRatio2() const
1597
const Base::Vector3f& rcP1 = _aclPoints[0];
1598
const Base::Vector3f& rcP2 = _aclPoints[1];
1599
const Base::Vector3f& rcP3 = _aclPoints[2];
1601
float a = Base::Distance(rcP1, rcP2);
1602
float b = Base::Distance(rcP2, rcP3);
1603
float c = Base::Distance(rcP3, rcP1);
1605
// https://stackoverflow.com/questions/10289752/aspect-ratio-of-a-triangle-of-a-meshed-surface
1606
return a * b * c / ((b + c - a) * (c + a - b) * (a + b - c));
1609
float MeshGeomFacet::Roundness() const
1611
const double FOUR_ROOT3 = 6.928203230275509;
1612
double area = static_cast<double>(Area());
1613
Base::Vector3f d0 = _aclPoints[0] - _aclPoints[1];
1614
Base::Vector3f d1 = _aclPoints[1] - _aclPoints[2];
1615
Base::Vector3f d2 = _aclPoints[2] - _aclPoints[0];
1617
double sum = static_cast<double>(d0.Sqr() + d1.Sqr() + d2.Sqr());
1618
return static_cast<float>(FOUR_ROOT3 * area / sum);
1621
void MeshGeomFacet::Transform(const Base::Matrix4D& mat)
1623
mat.multVec(_aclPoints[0], _aclPoints[0]);
1624
mat.multVec(_aclPoints[1], _aclPoints[1]);
1625
mat.multVec(_aclPoints[2], _aclPoints[2]);