FreeCAD

Форк
0
/
Measurement.cpp 
869 строк · 31.3 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2013 Luke Parry <l.parry@warwick.ac.uk>                 *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
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.      *
10
 *                                                                         *
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.                  *
15
 *                                                                         *
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                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23
#include "PreCompiled.h"
24
#ifndef _PreComp_
25
#include <BRep_Tool.hxx>
26
#include <BRepAdaptor_Curve.hxx>
27
#include <BRepAdaptor_Surface.hxx>
28
#include <BRepExtrema_DistShapeShape.hxx>
29
#include <BRepGProp.hxx>
30
#include <GCPnts_AbscissaPoint.hxx>
31
#include <gp_Pln.hxx>
32
#include <gp_Circ.hxx>
33
#include <gp_Torus.hxx>
34
#include <gp_Cylinder.hxx>
35
#include <gp_Sphere.hxx>
36
#include <gp_Lin.hxx>
37
#include <GProp_GProps.hxx>
38
#include <TopoDS.hxx>
39
#include <TopoDS_Shape.hxx>
40
#endif
41

42

43
#include <Base/Console.h>
44
#include <Base/Exception.h>
45
#include <Mod/Part/App/PartFeature.h>
46
#include <Mod/Part/App/TopoShape.h>
47

48
#include "Measurement.h"
49
#include "MeasurementPy.h"
50

51

52
#ifndef M_PI
53
#define M_PI 3.14159265358979323846
54
#endif
55

56
using namespace Measure;
57
using namespace Base;
58
using namespace Part;
59

60
TYPESYSTEM_SOURCE(Measure::Measurement, Base::BaseClass)
61

62
Measurement::Measurement()
63
{
64
    measureType = MeasureType::Invalid;
65
    References3D.setScope(App::LinkScope::Global);
66
}
67

68
Measurement::~Measurement() = default;
69

70
void Measurement::clear()
71
{
72
    std::vector<App::DocumentObject*> Objects;
73
    std::vector<std::string> SubElements;
74
    References3D.setValues(Objects, SubElements);
75
    measureType = MeasureType::Invalid;
76
}
77

78
bool Measurement::has3DReferences()
79
{
80
    return (References3D.getSize() > 0);
81
}
82

83
// add a 3D reference (obj+sub) to end of list
84
int Measurement::addReference3D(App::DocumentObject* obj, const std::string& subName)
85
{
86
    return addReference3D(obj, subName.c_str());
87
}
88

89
/// add a 3D reference (obj+sub) to end of list
90
int Measurement::addReference3D(App::DocumentObject* obj, const char* subName)
91
{
92
    std::vector<App::DocumentObject*> objects = References3D.getValues();
93
    std::vector<std::string> subElements = References3D.getSubValues();
94

95
    objects.push_back(obj);
96
    subElements.emplace_back(subName);
97

98
    References3D.setValues(objects, subElements);
99

100
    measureType = findType();
101
    return References3D.getSize();
102
}
103

104
MeasureType Measurement::findType()
105
{
106
    const std::vector<App::DocumentObject*>& objects = References3D.getValues();
107
    const std::vector<std::string>& subElements = References3D.getSubValues();
108

109
    std::vector<App::DocumentObject*>::const_iterator obj = objects.begin();
110
    std::vector<std::string>::const_iterator subEl = subElements.begin();
111

112
    MeasureType mode;
113

114
    int verts = 0;
115
    int edges = 0;
116
    int lines = 0;
117
    int circles = 0;
118
    int faces = 0;
119
    int planes = 0;
120
    int cylinders = 0;
121
    int cones = 0;
122
    int torus = 0;
123
    int spheres = 0;
124
    int vols = 0;
125

126
    for (; obj != objects.end(); ++obj, ++subEl) {
127

128
        // Check if solid object
129
        if (strcmp((*subEl).c_str(), "") == 0) {
130
            vols++;
131
        }
132
        else {
133

134
            TopoDS_Shape refSubShape;
135
            try {
136
                refSubShape = Part::Feature::getShape(*obj, (*subEl).c_str(), true);
137
                if (refSubShape.IsNull()) {
138
                    return MeasureType::Invalid;
139
                }
140
            }
141
            catch (Standard_Failure& e) {
142
                std::stringstream errorMsg;
143

144
                errorMsg << "Measurement - getType - " << e.GetMessageString() << std::endl;
145
                throw Base::CADKernelError(e.GetMessageString());
146
            }
147

148
            switch (refSubShape.ShapeType()) {
149
                case TopAbs_VERTEX: {
150
                    verts++;
151
                } break;
152
                case TopAbs_EDGE: {
153
                    edges++;
154
                    TopoDS_Edge edge = TopoDS::Edge(refSubShape);
155
                    BRepAdaptor_Curve sf(edge);
156

157
                    if (sf.GetType() == GeomAbs_Line) {
158
                        lines++;
159
                    }
160
                    else if (sf.GetType() == GeomAbs_Circle) {
161
                        circles++;
162
                    }
163
                } break;
164
                case TopAbs_FACE: {
165
                    faces++;
166
                    TopoDS_Face face = TopoDS::Face(refSubShape);
167
                    BRepAdaptor_Surface sf(face);
168

169
                    if (sf.GetType() == GeomAbs_Plane) {
170
                        planes++;
171
                    }
172
                    else if (sf.GetType() == GeomAbs_Cylinder) {
173
                        cylinders++;
174
                    }
175
                    else if (sf.GetType() == GeomAbs_Sphere) {
176
                        spheres++;
177
                    }
178
                    else if (sf.GetType() == GeomAbs_Cone) {
179
                        cones++;
180
                    }
181
                    else if (sf.GetType() == GeomAbs_Torus) {
182
                        torus++;
183
                    }
184
                } break;
185
                default:
186
                    break;
187
            }
188
        }
189
    }
190

191
    if (vols > 0) {
192
        if (verts > 0 || edges > 0 || faces > 0) {
193
            mode = MeasureType::Invalid;
194
        }
195
        else {
196
            mode = MeasureType::Volumes;
197
        }
198
    }
199
    else if (faces > 0) {
200
        if (verts > 0 || edges > 0) {
201
            if (faces == 1 && verts == 1) {
202
                mode = MeasureType::PointToSurface;
203
            }
204
            else {
205
                mode = MeasureType::Invalid;
206
            }
207
        }
208
        else {
209
            if (planes == 1 && faces == 1) {
210
                mode = MeasureType::Plane;
211
            }
212
            else if (planes == 2 && faces == 2) {
213
                if (planesAreParallel()) {
214
                    mode = MeasureType::TwoPlanes;
215
                }
216
                else {
217
                    mode = MeasureType::Surfaces;
218
                }
219
            }
220
            else if (cylinders == 1 && faces == 1) {
221
                mode = MeasureType::Cylinder;
222
            }
223
            else if (cones == 1 && faces == 1) {
224
                mode = MeasureType::Cone;
225
            }
226
            else if (spheres == 1 && faces == 1) {
227
                mode = MeasureType::Sphere;
228
            }
229
            else if (torus == 1 && faces == 1) {
230
                mode = MeasureType::Torus;
231
            }
232
            else {
233
                mode = MeasureType::Surfaces;
234
            }
235
        }
236
    }
237
    else if (edges > 0) {
238
        if (verts > 0) {
239
            if (verts > 1 && edges > 0) {
240
                mode = MeasureType::Invalid;
241
            }
242
            else {
243
                mode = MeasureType::PointToEdge;
244
            }
245
        }
246
        else if (lines == 1 && edges == 1) {
247
            mode = MeasureType::Line;
248
        }
249
        else if (lines == 2 && edges == 2) {
250
            if (linesAreParallel()) {
251
                mode = MeasureType::TwoParallelLines;
252
            }
253
            else {
254
                mode = MeasureType::TwoLines;
255
            }
256
        }
257
        else if (circles == 1 && edges == 1) {
258
            mode = MeasureType::Circle;
259
        }
260
        else {
261
            mode = MeasureType::Edges;
262
        }
263
    }
264
    else if (verts > 0) {
265
        if (verts == 2) {
266
            mode = MeasureType::PointToPoint;
267
        }
268
        else {
269
            mode = MeasureType::Points;
270
        }
271
    }
272
    else {
273
        mode = MeasureType::Invalid;
274
    }
275

276
    return mode;
277
}
278

279
MeasureType Measurement::getType()
280
{
281
    return measureType;
282
}
283

284
TopoDS_Shape Measurement::getShape(App::DocumentObject* obj, const char* subName) const
285
{
286
    // temporary fix to get "Vertex7" from "Body003.Pocket020.Vertex7"
287
    // when selected, Body features are provided as featureName and subNameAndIndex
288
    // other sources provide the full extended name with index
289
    if (strcmp(subName, "") == 0) {
290
        return Part::Feature::getShape(obj);
291
    }
292
    std::string workingSubName(subName);
293
    size_t lastDot = workingSubName.rfind('.');
294
    if (lastDot != std::string::npos) {
295
        workingSubName = workingSubName.substr(lastDot + 1);
296
    }
297

298
    try {
299
        Part::TopoShape partShape = Part::Feature::getTopoShape(obj);
300
        App::GeoFeature* geoFeat = dynamic_cast<App::GeoFeature*>(obj);
301
        if (geoFeat) {
302
            partShape.setPlacement(geoFeat->globalPlacement());
303
        }
304
        TopoDS_Shape shape = partShape.getSubShape(workingSubName.c_str());
305
        if (shape.IsNull()) {
306
            throw Part::NullShapeException("null shape in measurement");
307
        }
308
        return shape;
309
    }
310
    catch (const Base::Exception&) {
311
        // re-throw original exception
312
        throw;
313
    }
314
    catch (Standard_Failure& e) {
315
        throw Base::CADKernelError(e.GetMessageString());
316
    }
317
    catch (...) {
318
        throw Base::RuntimeError("Measurement: Unknown error retrieving shape");
319
    }
320
}
321

322
// TODO:: add lengthX, lengthY (and lengthZ??) support
323
//  Methods for distances (edge length, two points, edge and a point
324
double Measurement::length() const
325
{
326
    double result = 0.0;
327
    int numRefs = References3D.getSize();
328
    if (numRefs == 0) {
329
        Base::Console().Error("Measurement::length - No 3D references available\n");
330
    }
331
    else if (measureType == MeasureType::Invalid) {
332
        Base::Console().Error("Measurement::length - measureType is Invalid\n");
333
    }
334
    else {
335
        const std::vector<App::DocumentObject*>& objects = References3D.getValues();
336
        const std::vector<std::string>& subElements = References3D.getSubValues();
337

338
        if (measureType == MeasureType::Points || measureType == MeasureType::PointToPoint
339
            || measureType == MeasureType::PointToEdge
340
            || measureType == MeasureType::PointToSurface) {
341

342
            Base::Vector3d diff = this->delta();
343
            result = diff.Length();
344
        }
345
        else if (measureType == MeasureType::Edges || measureType == MeasureType::Line
346
                 || measureType == MeasureType::TwoLines || measureType == MeasureType::Circle) {
347

348
            // Iterate through edges and calculate each length
349
            std::vector<App::DocumentObject*>::const_iterator obj = objects.begin();
350
            std::vector<std::string>::const_iterator subEl = subElements.begin();
351

352
            for (; obj != objects.end(); ++obj, ++subEl) {
353

354
                //  Get the length of one edge
355
                TopoDS_Shape shape = getShape(*obj, (*subEl).c_str());
356
                const TopoDS_Edge& edge = TopoDS::Edge(shape);
357
                BRepAdaptor_Curve curve(edge);
358

359
                switch (curve.GetType()) {
360
                    case GeomAbs_Line: {
361
                        gp_Pnt P1 = curve.Value(curve.FirstParameter());
362
                        gp_Pnt P2 = curve.Value(curve.LastParameter());
363
                        gp_XYZ diff = P2.XYZ() - P1.XYZ();
364
                        result += diff.Modulus();
365
                        break;
366
                    }
367
                    case GeomAbs_Circle: {
368
                        double u = curve.FirstParameter();
369
                        double v = curve.LastParameter();
370
                        double radius = curve.Circle().Radius();
371
                        if (u > v) {  // if arc is reversed
372
                            std::swap(u, v);
373
                        }
374

375
                        double range = v - u;
376
                        result += radius * range;
377
                        break;
378
                    }
379
                    case GeomAbs_Ellipse:
380
                    case GeomAbs_BSplineCurve:
381
                    case GeomAbs_Hyperbola:
382
                    case GeomAbs_BezierCurve: {
383
                        result += GCPnts_AbscissaPoint::Length(curve);
384
                        break;
385
                    }
386
                    default: {
387
                        throw Base::RuntimeError(
388
                            "Measurement - length - Curve type not currently handled");
389
                    }
390
                }  // end switch
391
            }  // end for
392
        }
393
    }
394
    return result;
395
}
396

397
double Measurement::lineLineDistance() const
398
{
399
    // We don't use delta() because BRepExtrema_DistShapeShape return minimum length between line
400
    // segment. Here we get the nominal distance between the infinite lines.
401
    double distance = 0.0;
402

403
    if (measureType != MeasureType::TwoParallelLines || References3D.getSize() != 2) {
404
        return distance;
405
    }
406

407
    const std::vector<App::DocumentObject*>& objects = References3D.getValues();
408
    const std::vector<std::string>& subElements = References3D.getSubValues();
409

410
    // Get the first line
411
    TopoDS_Shape shape1 = getShape(objects[0], subElements[0].c_str());
412
    const TopoDS_Edge& edge1 = TopoDS::Edge(shape1);
413
    BRepAdaptor_Curve curve1(edge1);
414

415
    // Get the second line
416
    TopoDS_Shape shape2 = getShape(objects[1], subElements[1].c_str());
417
    const TopoDS_Edge& edge2 = TopoDS::Edge(shape2);
418
    BRepAdaptor_Curve curve2(edge2);
419

420
    if (curve1.GetType() == GeomAbs_Line && curve2.GetType() == GeomAbs_Line) {
421
        gp_Lin line1 = curve1.Line();
422
        gp_Lin line2 = curve2.Line();
423

424
        gp_Pnt p1 = line1.Location();
425
        gp_Pnt p2 = line2.Location();
426

427
        // Create a vector from a point on line1 to a point on line2
428
        gp_Vec lineVec(p1, p2);
429

430
        // The direction vector of one of the lines
431
        gp_Dir lineDir = line1.Direction();
432

433
        // Project lineVec onto lineDir
434
        gp_Vec parallelComponent = lineVec.Dot(lineDir) * lineDir;
435

436
        // Compute the perpendicular component
437
        gp_Vec perpendicularComponent = lineVec - parallelComponent;
438

439
        // Distance is the magnitude of the perpendicular component
440
        distance = perpendicularComponent.Magnitude();
441
    }
442
    else {
443
        Base::Console().Error("Measurement::length - TwoLines measureType requires two lines\n");
444
    }
445
    return distance;
446
}
447

448
double Measurement::planePlaneDistance() const
449
{
450
    if (measureType != MeasureType::TwoPlanes || References3D.getSize() != 2) {
451
        return 0.0;
452
    }
453

454
    const auto& objects = References3D.getValues();
455
    const auto& subElements = References3D.getSubValues();
456

457
    std::vector<gp_Pln> planes;
458

459
    // Get the first plane
460
    TopoDS_Shape shape1 = getShape(objects[0], subElements[0].c_str());
461
    const TopoDS_Face& face1 = TopoDS::Face(shape1);
462
    BRepAdaptor_Surface surface1(face1);
463
    const gp_Pln& plane1 = surface1.Plane();
464

465
    // Get the second plane
466
    TopoDS_Shape shape2 = getShape(objects[1], subElements[1].c_str());
467
    const TopoDS_Face& face2 = TopoDS::Face(shape2);
468
    BRepAdaptor_Surface surface2(face2);
469
    const gp_Pln& plane2 = surface2.Plane();
470

471
    // Distance between two parallel planes
472
    gp_Pnt pointOnPlane1 = plane1.Location();
473
    gp_Dir normalToPlane1 = plane1.Axis().Direction();
474

475
    gp_Pnt pointOnPlane2 = plane2.Location();
476

477
    // Create a vector from a point on plane1 to a point on plane2
478
    gp_Vec vectorBetweenPlanes(pointOnPlane1, pointOnPlane2);
479

480
    // Project this vector onto the plane normal
481
    double distance = Abs(vectorBetweenPlanes.Dot(normalToPlane1));
482

483
    return distance;
484
}
485

486
double Measurement::angle(const Base::Vector3d& /*param*/) const
487
{
488
    // TODO: do these references arrive as obj+sub pairs or as a struct of obj + [subs]?
489
    const std::vector<App::DocumentObject*>& objects = References3D.getValues();
490
    const std::vector<std::string>& subElements = References3D.getSubValues();
491
    int numRefs = objects.size();
492
    if (numRefs == 0) {
493
        throw Base::RuntimeError("No references available for angle measurement");
494
    }
495
    else if (measureType == MeasureType::Invalid) {
496
        throw Base::RuntimeError("MeasureType is Invalid for angle measurement");
497
    }
498
    else if (measureType == MeasureType::TwoLines) {
499
        // Only case that is supported is edge to edge
500
        // The angle between two skew lines is measured by the angle between one line (A)
501
        // and a line (B) with the direction of the second through a point on the first line.
502
        // Since we don't know if the directions of the lines point in the same general direction
503
        // we could get the angle we want or the supplementary angle.
504
        if (numRefs == 2) {
505
            TopoDS_Shape shape1 = getShape(objects.at(0), subElements.at(0).c_str());
506
            TopoDS_Shape shape2 = getShape(objects.at(1), subElements.at(1).c_str());
507

508
            BRepAdaptor_Curve curve1(TopoDS::Edge(shape1));
509
            BRepAdaptor_Curve curve2(TopoDS::Edge(shape2));
510

511
            if (curve1.GetType() == GeomAbs_Line && curve2.GetType() == GeomAbs_Line) {
512

513
                gp_Pnt pnt1First = curve1.Value(curve1.FirstParameter());
514
                gp_Dir dir1 = curve1.Line().Direction();
515
                gp_Dir dir2 = curve2.Line().Direction();
516
                gp_Dir dir2r = curve2.Line().Direction().Reversed();
517

518
                gp_Lin l1 = gp_Lin(pnt1First, dir1);    // (A)
519
                gp_Lin l2 = gp_Lin(pnt1First, dir2);    // (B)
520
                gp_Lin l2r = gp_Lin(pnt1First, dir2r);  // (B')
521
                Standard_Real aRad = l1.Angle(l2);
522
                double aRadr = l1.Angle(l2r);
523
                return std::min(aRad, aRadr) * 180 / M_PI;
524
            }
525
            else {
526
                throw Base::RuntimeError("Measurement references must both be lines");
527
            }
528
        }
529
        else {
530
            throw Base::RuntimeError("Can not compute angle measurement - too many references");
531
        }
532
    }
533
    else if (measureType == MeasureType::Points) {
534
        // NOTE: we are calculating the 3d angle here, not the projected angle
535
        // ASSUMPTION: the references are in end-apex-end order
536
        if (numRefs == 3) {
537
            TopoDS_Shape shape0 = getShape(objects.at(0), subElements.at(0).c_str());
538
            TopoDS_Shape shape1 = getShape(objects.at(1), subElements.at(1).c_str());
539
            TopoDS_Shape shape2 = getShape(objects.at(1), subElements.at(2).c_str());
540
            if (shape0.ShapeType() != TopAbs_VERTEX || shape1.ShapeType() != TopAbs_VERTEX
541
                || shape2.ShapeType() != TopAbs_VERTEX) {
542
                throw Base::RuntimeError("Measurement references for 3 point angle are not Vertex");
543
            }
544
            gp_Pnt gEnd0 = BRep_Tool::Pnt(TopoDS::Vertex(shape0));
545
            gp_Pnt gApex = BRep_Tool::Pnt(TopoDS::Vertex(shape1));
546
            gp_Pnt gEnd1 = BRep_Tool::Pnt(TopoDS::Vertex(shape2));
547
            gp_Dir gDir0 = gp_Dir(gEnd0.XYZ() - gApex.XYZ());
548
            gp_Dir gDir1 = gp_Dir(gEnd1.XYZ() - gApex.XYZ());
549
            gp_Lin line0 = gp_Lin(gEnd0, gDir0);
550
            gp_Lin line1 = gp_Lin(gEnd1, gDir1);
551
            double radians = line0.Angle(line1);
552
            return radians * 180 / M_PI;
553
        }
554
    }
555
    throw Base::RuntimeError("Unexpected error for angle measurement");
556
}
557

558
double Measurement::radius() const
559
{
560
    const std::vector<App::DocumentObject*>& objects = References3D.getValues();
561
    const std::vector<std::string>& subElements = References3D.getSubValues();
562

563
    int numRefs = References3D.getSize();
564
    if (numRefs == 0) {
565
        Base::Console().Error("Measurement::radius - No 3D references available\n");
566
    }
567
    else if (measureType == MeasureType::Circle) {
568
        TopoDS_Shape shape = getShape(objects.at(0), subElements.at(0).c_str());
569
        const TopoDS_Edge& edge = TopoDS::Edge(shape);
570

571
        BRepAdaptor_Curve curve(edge);
572
        if (curve.GetType() == GeomAbs_Circle) {
573
            return (double)curve.Circle().Radius();
574
        }
575
    }
576
    else if (measureType == MeasureType::Cylinder || measureType == MeasureType::Sphere
577
             || measureType == MeasureType::Torus) {
578
        TopoDS_Shape shape = getShape(objects.at(0), subElements.at(0).c_str());
579
        TopoDS_Face face = TopoDS::Face(shape);
580

581
        BRepAdaptor_Surface sf(face);
582
        if (sf.GetType() == GeomAbs_Cylinder) {
583
            return sf.Cylinder().Radius();
584
        }
585
        else if (sf.GetType() == GeomAbs_Sphere) {
586
            return sf.Sphere().Radius();
587
        }
588
        else if (sf.GetType() == GeomAbs_Torus) {
589
            return sf.Torus().MinorRadius();
590
        }
591
    }
592
    Base::Console().Error("Measurement::radius - Invalid References3D Provided\n");
593
    return 0.0;
594
}
595

596
Base::Vector3d Measurement::delta() const
597
{
598
    Base::Vector3d result;
599
    int numRefs = References3D.getSize();
600
    if (numRefs == 0) {
601
        Base::Console().Error("Measurement::delta - No 3D references available\n");
602
    }
603
    else if (measureType == MeasureType::Invalid) {
604
        Base::Console().Error("Measurement::delta - measureType is Invalid\n");
605
    }
606
    else {
607
        const std::vector<App::DocumentObject*>& objects = References3D.getValues();
608
        const std::vector<std::string>& subElements = References3D.getSubValues();
609

610
        if (measureType == MeasureType::PointToPoint) {
611
            if (numRefs == 2) {
612
                // Keep separate case for two points to reduce need for complex algorithm
613
                TopoDS_Shape shape1 = getShape(objects.at(0), subElements.at(0).c_str());
614
                TopoDS_Shape shape2 = getShape(objects.at(1), subElements.at(1).c_str());
615

616
                const TopoDS_Vertex& vert1 = TopoDS::Vertex(shape1);
617
                const TopoDS_Vertex& vert2 = TopoDS::Vertex(shape2);
618

619
                gp_Pnt P1 = BRep_Tool::Pnt(vert1);
620
                gp_Pnt P2 = BRep_Tool::Pnt(vert2);
621
                gp_XYZ diff = P2.XYZ() - P1.XYZ();
622
                return Base::Vector3d(diff.X(), diff.Y(), diff.Z());
623
            }
624
        }
625
        else if (measureType == MeasureType::PointToEdge
626
                 || measureType == MeasureType::PointToSurface) {
627
            // BrepExtema can calculate minimum distance between any set of topology sets.
628
            if (numRefs == 2) {
629
                TopoDS_Shape shape1 = getShape(objects.at(0), subElements.at(0).c_str());
630
                TopoDS_Shape shape2 = getShape(objects.at(1), subElements.at(1).c_str());
631

632
                BRepExtrema_DistShapeShape extrema(shape1, shape2);
633

634
                if (extrema.IsDone()) {
635
                    // Found the nearest point between point and curve
636
                    // NOTE we will assume there is only 1 solution (cyclic topology will create
637
                    // multiple solutions.
638
                    gp_Pnt P1 = extrema.PointOnShape1(1);
639
                    gp_Pnt P2 = extrema.PointOnShape2(1);
640
                    gp_XYZ diff = P2.XYZ() - P1.XYZ();
641
                    result = Base::Vector3d(diff.X(), diff.Y(), diff.Z());
642
                }
643
            }
644
        }
645
        else if (measureType == MeasureType::Edges) {
646
            // Only case that is supported is straight line edge
647
            if (numRefs == 1) {
648
                TopoDS_Shape shape = getShape(objects.at(0), subElements.at(0).c_str());
649
                const TopoDS_Edge& edge = TopoDS::Edge(shape);
650
                BRepAdaptor_Curve curve(edge);
651

652
                if (curve.GetType() == GeomAbs_Line) {
653
                    gp_Pnt P1 = curve.Value(curve.FirstParameter());
654
                    gp_Pnt P2 = curve.Value(curve.LastParameter());
655
                    gp_XYZ diff = P2.XYZ() - P1.XYZ();
656
                    result = Base::Vector3d(diff.X(), diff.Y(), diff.Z());
657
                }
658
            }
659
            else if (numRefs == 2) {
660
                TopoDS_Shape shape1 = getShape(objects.at(0), subElements.at(0).c_str());
661
                TopoDS_Shape shape2 = getShape(objects.at(1), subElements.at(1).c_str());
662

663
                BRepAdaptor_Curve curve1(TopoDS::Edge(shape1));
664
                BRepAdaptor_Curve curve2(TopoDS::Edge(shape2));
665

666
                // Only permit line to line distance
667
                if (curve1.GetType() == GeomAbs_Line && curve2.GetType() == GeomAbs_Line) {
668
                    BRepExtrema_DistShapeShape extrema(shape1, shape2);
669

670
                    if (extrema.IsDone()) {
671
                        // Found the nearest point between point and curve
672
                        // NOTE we will assume there is only 1 solution (cyclic topology will create
673
                        // multiple solutions.
674
                        gp_Pnt P1 = extrema.PointOnShape1(1);
675
                        gp_Pnt P2 = extrema.PointOnShape2(1);
676
                        gp_XYZ diff = P2.XYZ() - P1.XYZ();
677
                        result = Base::Vector3d(diff.X(), diff.Y(), diff.Z());
678
                    }
679
                }
680
            }
681
        }
682
        else {
683
            Base::Console().Error("Measurement::delta - measureType is not recognized\n");
684
        }
685
    }
686
    return result;
687
}
688

689
double Measurement::volume() const
690
{
691
    double result = 0.0;
692
    if (References3D.getSize() == 0) {
693
        Base::Console().Error("Measurement::volume - No 3D references available\n");
694
    }
695
    else if (measureType != MeasureType::Volumes) {
696
        Base::Console().Error("Measurement::volume - measureType is not Volumes\n");
697
    }
698
    else {
699
        const std::vector<App::DocumentObject*>& objects = References3D.getValues();
700
        const std::vector<std::string>& subElements = References3D.getSubValues();
701

702
        for (size_t i = 0; i < objects.size(); ++i) {
703
            GProp_GProps props = GProp_GProps();
704
            BRepGProp::VolumeProperties(getShape(objects[i], subElements[i].c_str()), props);
705
            result += props.Mass();
706
        }
707
    }
708
    return result;
709
}
710

711
double Measurement::area() const
712
{
713
    double result = 0.0;
714
    if (References3D.getSize() == 0) {
715
        Base::Console().Error("Measurement::area - No 3D references available\n");
716
    }
717
    else if (measureType == MeasureType::Volumes || measureType == MeasureType::Surfaces
718
             || measureType == MeasureType::Cylinder || measureType == MeasureType::Cone
719
             || measureType == MeasureType::Sphere || measureType == MeasureType::Torus
720
             || measureType == MeasureType::Plane) {
721

722
        const std::vector<App::DocumentObject*>& objects = References3D.getValues();
723
        const std::vector<std::string>& subElements = References3D.getSubValues();
724

725
        for (size_t i = 0; i < objects.size(); ++i) {
726
            GProp_GProps props;
727
            BRepGProp::SurfaceProperties(getShape(objects[i], subElements[i].c_str()), props);
728
            result += props.Mass();  // Area is obtained using Mass method for surface properties
729
        }
730
    }
731
    else {
732
        Base::Console().Error("Measurement::area - measureType is not valid\n");
733
    }
734
    return result;
735
}
736

737
Base::Vector3d Measurement::massCenter() const
738
{
739
    Base::Vector3d result;
740
    int numRefs = References3D.getSize();
741
    if (numRefs == 0) {
742
        Base::Console().Error("Measurement::massCenter - No 3D references available\n");
743
    }
744
    else if (measureType == MeasureType::Invalid) {
745
        Base::Console().Error("Measurement::massCenter - measureType is Invalid\n");
746
    }
747
    else {
748
        const std::vector<App::DocumentObject*>& objects = References3D.getValues();
749
        const std::vector<std::string>& subElements = References3D.getSubValues();
750
        GProp_GProps gprops = GProp_GProps();
751

752
        if (measureType == MeasureType::Volumes) {
753
            // Iterate through edges and calculate each length
754
            std::vector<App::DocumentObject*>::const_iterator obj = objects.begin();
755
            std::vector<std::string>::const_iterator subEl = subElements.begin();
756

757
            for (; obj != objects.end(); ++obj, ++subEl) {
758

759
                // Compute inertia properties
760

761
                GProp_GProps props = GProp_GProps();
762
                BRepGProp::VolumeProperties(getShape((*obj), ""), props);
763
                gprops.Add(props);
764
                // Get inertia properties
765
            }
766

767
            gp_Pnt cog = gprops.CentreOfMass();
768

769
            return Base::Vector3d(cog.X(), cog.Y(), cog.Z());
770
        }
771
        else {
772
            Base::Console().Error("Measurement::massCenter - measureType is not recognized\n");
773
        }
774
    }
775
    return result;
776
}
777

778
bool Measurement::planesAreParallel() const
779
{
780
    const std::vector<App::DocumentObject*>& objects = References3D.getValues();
781
    const std::vector<std::string>& subElements = References3D.getSubValues();
782

783
    std::vector<gp_Dir> planeNormals;
784

785
    for (size_t i = 0; i < objects.size(); ++i) {
786
        TopoDS_Shape refSubShape;
787
        try {
788
            refSubShape = Part::Feature::getShape(objects[i], subElements[i].c_str(), true);
789
            if (refSubShape.IsNull()) {
790
                return false;
791
            }
792
        }
793
        catch (Standard_Failure& e) {
794
            std::stringstream errorMsg;
795
            errorMsg << "Measurement - planesAreParallel - " << e.GetMessageString() << std::endl;
796
            throw Base::CADKernelError(e.GetMessageString());
797
        }
798

799
        if (refSubShape.ShapeType() == TopAbs_FACE) {
800
            TopoDS_Face face = TopoDS::Face(refSubShape);
801
            BRepAdaptor_Surface sf(face);
802

803
            if (sf.GetType() == GeomAbs_Plane) {
804
                gp_Pln plane = sf.Plane();
805
                gp_Dir normal = plane.Axis().Direction();
806
                planeNormals.push_back(normal);
807
            }
808
        }
809
    }
810

811
    if (planeNormals.size() != 2) {
812
        return false;  // Ensure exactly two planes are considered
813
    }
814

815
    // Check if normals are parallel (either identical or opposite)
816
    const gp_Dir& normal1 = planeNormals[0];
817
    const gp_Dir& normal2 = planeNormals[1];
818

819
    return normal1.IsParallel(normal2, Precision::Angular());
820
}
821

822
bool Measurement::linesAreParallel() const
823
{
824
    const std::vector<App::DocumentObject*>& objects = References3D.getValues();
825
    const std::vector<std::string>& subElements = References3D.getSubValues();
826

827
    if (References3D.getSize() != 2) {
828
        return false;
829
    }
830

831
    // Get the first line
832
    TopoDS_Shape shape1 = getShape(objects[0], subElements[0].c_str());
833
    const TopoDS_Edge& edge1 = TopoDS::Edge(shape1);
834
    BRepAdaptor_Curve curve1(edge1);
835

836
    // Get the second line
837
    TopoDS_Shape shape2 = getShape(objects[1], subElements[1].c_str());
838
    const TopoDS_Edge& edge2 = TopoDS::Edge(shape2);
839
    BRepAdaptor_Curve curve2(edge2);
840

841
    if (curve1.GetType() == GeomAbs_Line && curve2.GetType() == GeomAbs_Line) {
842
        gp_Lin line1 = curve1.Line();
843
        gp_Lin line2 = curve2.Line();
844

845
        gp_Dir dir1 = line1.Direction();
846
        gp_Dir dir2 = line2.Direction();
847

848
        // Check if lines are parallel
849
        if (dir1.IsParallel(dir2, Precision::Angular())) {
850
            return true;
851
        }
852
    }
853

854
    return false;
855
}
856

857
unsigned int Measurement::getMemSize() const
858
{
859
    return 0;
860
}
861

862
PyObject* Measurement::getPyObject()
863
{
864
    if (PythonObject.is(Py::_None())) {
865
        // ref counter is set to 1
866
        PythonObject = Py::Object(new MeasurementPy(this), true);
867
    }
868
    return Py::new_reference_to(PythonObject);
869
}
870

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.