FreeCAD

Форк
0
/
DimensionValidators.cpp 
737 строк · 27.2 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2022 WandererFan <wandererfan@gmail.com>                *
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 <BRepAdaptor_Curve.hxx>
26
#include <BRep_Tool.hxx>
27
#include <TopExp.hxx>
28
#endif//#ifndef _PreComp_
29

30
#include <App/DocumentObject.h>
31
#include <Base/Console.h>
32
#include <Gui/Selection.h>
33
#include <Mod/TechDraw/App/DrawViewPart.h>
34
#include <Mod/TechDraw/App/ShapeExtractor.h>
35

36
#include "DimensionValidators.h"
37

38

39
using namespace TechDraw;
40
using DU = DrawUtil;
41

42
TechDraw::DrawViewPart* TechDraw::getReferencesFromSelection(ReferenceVector& references2d,
43
                                                             ReferenceVector& references3d)
44
{
45
    TechDraw::DrawViewPart* dvp(nullptr);
46
    TechDraw::DrawViewDimension* dim(nullptr);
47
    std::vector<Gui::SelectionObject> selectionAll = Gui::Selection().getSelectionEx();
48
    for (auto& selItem : selectionAll) {
49
        if (selItem.getObject()->isDerivedFrom(TechDraw::DrawViewDimension::getClassTypeId())) {
50
            //we are probably repairing a dimension, but we will check later
51
            dim = static_cast<TechDraw::DrawViewDimension*>(selItem.getObject());
52
        } else if (selItem.getObject()->isDerivedFrom(TechDraw::DrawViewPart::getClassTypeId())) {
53
            //this could be a 2d geometry selection or just a DrawViewPart for context in
54
            //a 3d selection
55
            dvp = static_cast<TechDraw::DrawViewPart*>(selItem.getObject());
56
            if (selItem.getSubNames().empty()) {
57
                //there are no subNames, so we think this is a 3d case,
58
                //and we only need to select the view. We set the reference
59
                //subName to a null string to avoid later misunderstandings.
60
                ReferenceEntry ref(dvp, std::string());
61
                references2d.push_back(ref);
62
            }
63
            for (auto& sub : selItem.getSubNames()) {
64
                ReferenceEntry ref(dvp, sub);
65
                references2d.push_back(ref);
66
            }
67
        } else if (!selItem.getObject()->isDerivedFrom(TechDraw::DrawView::getClassTypeId())) {
68
            //this is not a TechDraw object, so we check to see if it has 3d geometry
69
            std::vector<App::DocumentObject*> links;
70
            links.push_back(selItem.getObject());
71
            if (!ShapeExtractor::getShapes(links).IsNull()) {
72
                //this item has 3d geometry so we are interested
73
                App::DocumentObject* obj3d = selItem.getObject();
74
                if (selItem.getSubNames().empty()) {
75
                    if (ShapeExtractor::isPointType(obj3d)) {
76
                        //a point object may not have a subName when selected,
77
                        //so we need to perform some special handling.
78
                        ReferenceEntry ref(obj3d, "Vertex1");
79
                        references3d.push_back(ref);
80
                        continue;
81
                    } else {
82
                        //this is a whole object reference, probably for an extent dimension
83
                        ReferenceEntry ref(obj3d, std::string());
84
                        references3d.push_back(ref);
85
                        continue;
86
                    }
87
                }
88
                //this is a regular reference in form obj+subelement
89
                for (auto& sub3d : selItem.getSubNames()) {
90
                    ReferenceEntry ref(obj3d, sub3d);
91
                    references3d.push_back(ref);
92
                }
93
            } else {
94
                Base::Console().Message("DV::getRefsFromSel - %s has no shape!\n",
95
                                        selItem.getObject()->getNameInDocument());
96
            }
97
        }
98
    }
99
    if (dim) {
100
        if (!dvp) {
101
            ReferenceEntry ref(dim->getViewPart(), std::string());
102
            references2d.push_back(ref);
103
            return dim->getViewPart();
104
        }
105
    }
106
    return dvp;
107
}
108

109
//! verify that the proposed references contains valid geometries from a 2d DrawViewPart.
110
DimensionGeometryType TechDraw::validateDimSelection(
111
    ReferenceVector references,     //[(dvp*, std::string),...,(dvp*, std::string)]
112
    StringVector acceptableGeometry,//"Edge", "Vertex", etc
113
    std::vector<int> minimumCounts, //how many of each geometry are needed for a good dimension
114
    std::vector<DimensionGeometryType> acceptableDimensionGeometrys)//isVertical, isHorizontal, ...
115
{
116
    StringVector subNames;
117
    TechDraw::DrawViewPart* dvpSave(nullptr);
118
    for (auto& ref : references) {
119
        TechDraw::DrawViewPart* dvp = dynamic_cast<TechDraw::DrawViewPart*>(ref.getObject());
120
        if (dvp) {
121
            dvpSave = dvp;
122
            if (!ref.getSubName().empty()) {
123
                subNames.push_back(ref.getSubName());
124
            }
125
        }
126
    }
127
    if (!dvpSave) {
128
        //must have 1 DVP in selection
129
        return isInvalid;
130
    }
131

132
    if (subNames.empty()) {
133
        //no geometry referenced. can not make a dim from this mess. We are being called to validate
134
        //a selection for a 3d reference
135
        return isViewReference;
136
    }
137

138
    if (subNames.front().empty()) {
139
        //can this still happen?
140
        return isViewReference;
141
    }
142

143
    //check for invalid geometry descriptors in the subNames
144
    std::unordered_set<std::string> acceptableGeometrySet(acceptableGeometry.begin(),
145
                                                          acceptableGeometry.end());
146
    if (!TechDraw::validateSubnameList(subNames, acceptableGeometrySet)) {
147
        //can not make a dimension from this
148
        return isInvalid;
149
    }
150

151
    //check for wrong number of geometry
152
    GeomCountVector foundCounts;
153
    GeomCountMap minimumCountMap = loadRequiredCounts(acceptableGeometry, minimumCounts);
154
    if (!checkGeometryOccurences(subNames, minimumCountMap)) {
155
        //too many or too few geometry descriptors.
156
        return isInvalid;
157
    }
158

159
    //we have a (potentially valid collection of 2d geometry
160
    ReferenceVector valid2dReferences;
161
    for (auto& sub : subNames) {
162
        ReferenceEntry validEntry(dvpSave, sub);
163
        valid2dReferences.push_back(validEntry);
164
    }
165

166
    DimensionGeometryType foundGeometry = getGeometryConfiguration(valid2dReferences);
167
    if (acceptableDimensionGeometrys.empty()) {
168
        //if the list is empty, we are accepting anything
169
        return foundGeometry;
170
    }
171
    for (auto& acceptable : acceptableDimensionGeometrys) {
172
        if (foundGeometry == acceptable) {
173
            return foundGeometry;
174
        }
175
    }
176

177
    return isInvalid;
178
}
179

180
//! verify that the proposed references contains valid geometries from non-TechDraw objects.
181
DimensionGeometryType TechDraw::validateDimSelection3d(
182
    TechDraw::DrawViewPart* dvp,
183
    ReferenceVector references,     //[(dvp*, std::string),...,(dvp*, std::string)]
184
    StringVector acceptableGeometry,//"Edge", "Vertex", etc
185
    std::vector<int> minimumCounts, //how many of each geometry are needed for a good dimension
186
    std::vector<DimensionGeometryType> acceptableDimensionGeometrys)//isVertical, isHorizontal, ...
187
{
188
    StringVector subNames;
189
    for (auto& ref : references) {
190
        if (!ref.getSubName().empty()) {
191
            subNames.push_back(ref.getSubName());
192
        }
193
    }
194

195

196
    //check for invalid geometry descriptors in the subNames
197
    std::unordered_set<std::string> acceptableGeometrySet(acceptableGeometry.begin(),
198
                                                          acceptableGeometry.end());
199
    if (!TechDraw::validateSubnameList(subNames, acceptableGeometrySet)) {
200
        //can not make a dimension from this
201
        return isInvalid;
202
    }
203

204
    //check for wrong number of geometry
205
    GeomCountMap minimumCountMap = loadRequiredCounts(acceptableGeometry, minimumCounts);
206
    if (!checkGeometryOccurences(subNames, minimumCountMap)) {
207
        //too many or too few geometry descriptors.
208
        return isInvalid;
209
    }
210

211
    //we have a (potentially valid collection of 3d geometry
212
    DimensionGeometryType foundGeometry = getGeometryConfiguration3d(dvp, references);
213
    if (acceptableDimensionGeometrys.empty()) {
214
        //if the list is empty, we are accepting anything
215
        return foundGeometry;
216
    }
217
    for (auto& acceptable : acceptableDimensionGeometrys) {
218
        if (foundGeometry == acceptable) {
219
            return foundGeometry;
220
        }
221
    }
222

223
    return isInvalid;
224
}
225
bool TechDraw::validateSubnameList(StringVector subNames, GeometrySet acceptableGeometrySet)
226
{
227
    for (auto& sub : subNames) {
228
        std::string geometryType = DrawUtil::getGeomTypeFromName(sub);
229
        if (acceptableGeometrySet.count(geometryType) == 0) {
230
            //this geometry type is not allowed
231
            return false;
232
        }
233
    }
234
    return true;
235
}
236

237
//count how many of each "Edge", "Vertex, etc and compare totals to required minimum
238
bool TechDraw::checkGeometryOccurences(StringVector subNames, GeomCountMap keyedMinimumCounts)
239
{
240
    //how many of each geometry descriptor are input
241
    GeomCountMap foundCounts;
242
    for (auto& sub : subNames) {
243
        std::string geometryType = DrawUtil::getGeomTypeFromName(sub);
244
        std::map<std::string, int>::iterator it0(foundCounts.find(geometryType));
245
        if (it0 == foundCounts.end()) {
246
            //first occurrence of this geometryType
247
            foundCounts[geometryType] = 1;
248
        } else {
249
            //already have this geometryType
250
            it0->second++;
251
        }
252
    }
253

254
    //hybrid dims (vertex-edge) can skip this check
255
    if (foundCounts.size() > 1) {
256
        //this is a hybrid dimension
257
        return true;
258
    }
259

260
    //check found geometry counts against required counts
261
    for (auto& foundItem : foundCounts) {
262
        std::string currentKey = foundItem.first;
263
        int foundCount = foundItem.second;
264
        auto itAccept = keyedMinimumCounts.find(currentKey);
265
        if (itAccept == keyedMinimumCounts.end()) {
266
            //not supposed to happen by this point
267
            throw Base::IndexError("Dimension validation counts and geometry do not match");
268
        }
269
        if (foundCount < keyedMinimumCounts[currentKey]) {
270
            //not enough of this type of geom to make a good dimension - ex 1 Vertex
271
            return false;
272
        }
273
    }
274
    //we have no complaints about the input
275
    return true;
276
}
277

278
//return the first valid configuration contained in the already validated references
279
DimensionGeometryType TechDraw::getGeometryConfiguration(ReferenceVector valid2dReferences)
280
{
281
    DimensionGeometryType config = isValidHybrid(valid2dReferences);
282
    if (config > isInvalid) {
283
        return config;
284
    }
285

286
    config = isValidMultiEdge(valid2dReferences);
287
    if (config > isInvalid) {
288
        return config;
289
    }
290
    config = isValidVertexes(valid2dReferences);
291
    if (config > isInvalid) {
292
        return config;
293
    }
294
    config = isValidSingleEdge(valid2dReferences.front());
295
    if (config > isInvalid) {
296
        return config;
297
    }
298

299
    // no valid configuration found
300
    return isInvalid;
301
}
302

303
//return the first valid configuration contained in the already validated references
304
DimensionGeometryType TechDraw::getGeometryConfiguration3d(DrawViewPart* dvp,
305
                                                           ReferenceVector valid3dReferences)
306
{
307
    //first we check for whole object references
308
    ReferenceVector wholeObjectRefs;
309
    ReferenceVector subElementRefs;
310
    for (auto& ref : valid3dReferences) {
311
        if (ref.isWholeObject()) {
312
            wholeObjectRefs.push_back(ref);
313
        } else {
314
            subElementRefs.push_back(ref);
315
        }
316
    }
317
    if (subElementRefs.empty()) {
318
        //only whole object references
319
        return isMultiEdge;
320
    }
321
    if (!wholeObjectRefs.empty()) {
322
        //mix of whole object and subelement refs
323
        return isMultiEdge;//??? correct ???
324
    }
325

326
    //only have subelement refs
327
    DimensionGeometryType config = isValidMultiEdge3d(dvp, valid3dReferences);
328
    if (config > isInvalid) {
329
        return config;
330
    }
331
    config = isValidVertexes3d(dvp, valid3dReferences);
332
    if (config > isInvalid) {
333
        return config;
334
    }
335
    config = isValidSingleEdge3d(dvp, valid3dReferences.front());
336
    if (config > isInvalid) {
337
        return config;
338
    }
339
    config = isValidHybrid3d(dvp, valid3dReferences);
340
    if (config > isInvalid) {
341
        return config;
342
    }
343

344
    // no valid configuration found
345
    return isInvalid;
346
}
347

348
//fill the GeomCountMap with pairs made from corresponding items in acceptableGeometry
349
//and minimumCounts
350
GeomCountMap TechDraw::loadRequiredCounts(StringVector& acceptableGeometry,
351
                                          std::vector<int>& minimumCounts)
352
{
353
    if (acceptableGeometry.size() != minimumCounts.size()) {
354
        throw Base::IndexError("acceptableGeometry and minimum counts have different sizes.");
355
    }
356

357
    GeomCountMap result;
358
    int iCount = 0;
359
    for (auto& acceptableItem : acceptableGeometry) {
360
        result[acceptableItem] = minimumCounts.at(iCount);
361
        iCount++;
362
    }
363
    return result;
364
}
365

366
//! verify that Selection contains a valid Geometry for a single Edge Dimension
367
DimensionGeometryType TechDraw::isValidSingleEdge(ReferenceEntry ref)
368
{
369
    auto objFeat(dynamic_cast<TechDraw::DrawViewPart*>(ref.getObject()));
370
    if (!objFeat) {
371
        return isInvalid;
372
    }
373

374
    //the Name starts with "Edge"
375
    std::string geomName = DrawUtil::getGeomTypeFromName(ref.getSubName());
376
    if (geomName != "Edge") {
377
        return isInvalid;
378
    }
379

380
    //the geometry exists (redundant?)
381
    int GeoId(TechDraw::DrawUtil::getIndexFromName(ref.getSubName()));
382
    TechDraw::BaseGeomPtr geom = objFeat->getGeomByIndex(GeoId);
383
    if (!geom) {
384
        return isInvalid;
385
    }
386

387
    if (geom->getGeomType() == TechDraw::GENERIC) {
388
        TechDraw::GenericPtr gen1 = std::static_pointer_cast<TechDraw::Generic>(geom);
389
        if (gen1->points.size() < 2) {
390
            return isInvalid;
391
        }
392
        Base::Vector3d line = gen1->points.at(1) - gen1->points.at(0);
393
        if (fabs(line.y) < FLT_EPSILON) {
394
            return TechDraw::isHorizontal;
395
        } else if (fabs(line.x) < FLT_EPSILON) {
396
            return TechDraw::isVertical;
397
        } else {
398
            return TechDraw::isDiagonal;
399
        }
400
    } else if (geom->getGeomType() == TechDraw::CIRCLE || geom->getGeomType() == TechDraw::ARCOFCIRCLE) {
401
        return isCircle;
402
    } else if (geom->getGeomType() == TechDraw::ELLIPSE || geom->getGeomType() == TechDraw::ARCOFELLIPSE) {
403
        return isEllipse;
404
    } else if (geom->getGeomType() == TechDraw::BSPLINE) {
405
        TechDraw::BSplinePtr spline = std::static_pointer_cast<TechDraw::BSpline>(geom);
406
        if (spline->isCircle()) {
407
            return isBSplineCircle;
408
        } else {
409
            return isBSpline;
410
        }
411
    }
412
    return isInvalid;
413
}
414

415
//! verify that Selection contains a valid Geometry for a single Edge Dimension
416
DimensionGeometryType TechDraw::isValidSingleEdge3d(DrawViewPart* dvp, ReferenceEntry ref)
417
{
418
    (void)dvp;
419
    //the Name starts with "Edge"
420
    std::string geomName = DrawUtil::getGeomTypeFromName(ref.getSubName());
421
    if (geomName != "Edge") {
422
        return isInvalid;
423
    }
424

425
    TopoDS_Shape refShape = ref.getGeometry();
426
    if (refShape.IsNull() || refShape.ShapeType() != TopAbs_EDGE) {
427
        throw Base::RuntimeError("Geometry for reference is not an edge.");
428
    }
429

430
    TopoDS_Edge occEdge = TopoDS::Edge(refShape);
431
    BRepAdaptor_Curve adapt(occEdge);
432
    if (adapt.GetType() == GeomAbs_Line) {
433
        Base::Vector3d point0 = DU::toVector3d(BRep_Tool::Pnt(TopExp::FirstVertex(occEdge)));
434
        point0 = dvp->projectPoint(point0);
435
        Base::Vector3d point1 = DU::toVector3d(BRep_Tool::Pnt(TopExp::LastVertex(occEdge)));
436
        point1 = dvp->projectPoint(point1);
437
        Base::Vector3d line = point1 - point0;
438
        if (fabs(line.y) < FLT_EPSILON) {
439
            return TechDraw::isHorizontal;
440
        } else if (fabs(line.x) < FLT_EPSILON) {
441
            return TechDraw::isVertical;
442
        }
443
        //        else if (fabs(line.z) < FLT_EPSILON) {
444
        //            return TechDraw::isZLimited;
445
        //        }
446
        else {
447
            return TechDraw::isDiagonal;
448
        }
449
    } else if (adapt.GetType() == GeomAbs_Circle) {
450
        return isCircle;
451
    } else if (adapt.GetType() == GeomAbs_Ellipse) {
452
        return isEllipse;
453
    } else if (adapt.GetType() == GeomAbs_BSplineCurve) {
454
        if (GeometryUtils::isCircle(occEdge)) {
455
            return isBSplineCircle;
456
        } else {
457
            return isBSpline;
458
        }
459
    }
460

461
    return isInvalid;
462
}
463

464
//! verify that the edge references can make a dimension. Currently only extent
465
//! dimensions support more than 2 edges
466
DimensionGeometryType TechDraw::isValidMultiEdge(ReferenceVector refs)
467
{
468
    //there has to be at least 2
469
    if (refs.size() < 2) {
470
        return isInvalid;
471
    }
472

473
    //they all must start with "Edge"
474
    const std::string matchToken{"Edge"};
475
    if (!refsMatchToken(refs, matchToken)) {
476
        return isInvalid;
477
    }
478

479
    auto objFeat0(dynamic_cast<TechDraw::DrawViewPart*>(refs.at(0).getObject()));
480
    if (!objFeat0) {
481
        //probably redundant
482
        throw Base::RuntimeError("Logic error in isValidMultiEdge");
483
    }
484

485
    if (refs.size() > 2) {
486
        //many edges, must be an extent?
487
        return isMultiEdge;
488
    }
489

490
    //exactly 2 edges. could be angle, could be distance
491
    int GeoId0(TechDraw::DrawUtil::getIndexFromName(refs.at(0).getSubName()));
492
    int GeoId1(TechDraw::DrawUtil::getIndexFromName(refs.at(1).getSubName()));
493
    TechDraw::BaseGeomPtr geom0 = objFeat0->getGeomByIndex(GeoId0);
494
    TechDraw::BaseGeomPtr geom1 = objFeat0->getGeomByIndex(GeoId1);
495

496
    if (geom0->getGeomType() == TechDraw::GENERIC && geom1->getGeomType() == TechDraw::GENERIC) {
497
        TechDraw::GenericPtr gen0 = std::static_pointer_cast<TechDraw::Generic>(geom0);
498
        TechDraw::GenericPtr gen1 = std::static_pointer_cast<TechDraw::Generic>(geom1);
499
        if (gen0->points.size() > 2 || gen1->points.size() > 2) {//the edge is a polyline
500
            return isInvalid;                                    //not supported yet
501
        }
502
        Base::Vector3d line0 = gen0->points.at(1) - gen0->points.at(0);
503
        Base::Vector3d line1 = gen1->points.at(1) - gen1->points.at(0);
504
        double xprod = fabs(line0.x * line1.y - line0.y * line1.x);
505
        if (xprod > FLT_EPSILON) {//edges are not parallel
506
            return isAngle;       //angle or distance
507
        } else {
508
            return isDiagonal;//distance || line
509
        }
510
    } else {
511
        return isDiagonal;//two edges, not both straight lines
512
    }
513

514
    return isInvalid;
515
}
516

517
//! verify that the edge references can make a dimension. Currently only extent
518
//! dimensions support more than 2 edges
519
DimensionGeometryType TechDraw::isValidMultiEdge3d(DrawViewPart* dvp, ReferenceVector refs)
520
{
521
    (void)dvp;
522
    //there has to be at least 2
523
    if (refs.size() < 2) {
524
        return isInvalid;
525
    }
526

527
    //they all must start with "Edge"
528
    const std::string matchToken{"Edge"};
529
    if (!refsMatchToken(refs, matchToken)) {
530
        return isInvalid;
531
    }
532

533
    std::vector<TopoDS_Edge> edges;
534
    for (auto& ref : refs) {
535
        std::vector<TopoDS_Shape> shapesAll = ShapeExtractor::getShapesFromObject(ref.getObject());
536
        if (shapesAll.empty()) {
537
            //reference has no geometry
538
            return isInvalid;
539
        }
540
    }
541
    std::vector<TopoDS_Edge> edgesAll;
542
    std::vector<int> typeAll;
543
    for (auto& ref : refs) {
544
        TopoDS_Shape geometry = ref.getGeometry();
545
        if (geometry.ShapeType() != TopAbs_EDGE) {
546
            return isInvalid;
547
        }
548
        TopoDS_Edge edge = TopoDS::Edge(geometry);
549
        BRepAdaptor_Curve adapt(edge);
550
        if (adapt.GetType() != GeomAbs_Line) {
551
            //not a line, so this must be an extent dim?
552
            return isMultiEdge;
553
        }
554
        edgesAll.push_back(edge);
555
    }
556
    if (edgesAll.size() > 2) {
557
        //must be an extent dimension of lines?
558
        return isMultiEdge;
559
    } else if (edgesAll.size() == 2) {
560
        Base::Vector3d first0 = DU::toVector3d(BRep_Tool::Pnt(TopExp::FirstVertex(edgesAll.at(0))));
561
        Base::Vector3d last0 = DU::toVector3d(BRep_Tool::Pnt(TopExp::LastVertex(edgesAll.at(1))));
562
        Base::Vector3d line0 = last0 - first0;
563
        Base::Vector3d first1 = DU::toVector3d(BRep_Tool::Pnt(TopExp::FirstVertex(edgesAll.at(0))));
564
        Base::Vector3d last1 = DU::toVector3d(BRep_Tool::Pnt(TopExp::LastVertex(edgesAll.at(1))));
565
        Base::Vector3d line1 = last1 - first1;
566
        if (DU::fpCompare(fabs(line0.Dot(line1)), 1)) {
567
            //lines are parallel, must be distance dim
568
            return isDiagonal;
569
        } else {
570
            //lines are skew, could be angle, could be distance?
571
            return isAngle;
572
        }
573
    }
574

575
    return isInvalid;
576
}
577

578
//! verify that the vertex references can make a dimension
579
DimensionGeometryType TechDraw::isValidVertexes(ReferenceVector refs)
580
{
581
    TechDraw::DrawViewPart* dvp(dynamic_cast<TechDraw::DrawViewPart*>(refs.front().getObject()));
582
    if (!dvp) {
583
        //probably redundant
584
        throw Base::RuntimeError("Logic error in isValidMultiEdge");
585
    }
586

587
    const std::string matchToken{"Vertex"};
588
    if (!refsMatchToken(refs, matchToken)) {
589
        return isInvalid;
590
    }
591

592
    if (refs.size() == 2) {
593
        //2 vertices can only make a distance dimension
594
        TechDraw::VertexPtr v0 = dvp->getVertex(refs.at(0).getSubName());
595
        TechDraw::VertexPtr v1 = dvp->getVertex(refs.at(1).getSubName());
596
        Base::Vector3d line = v1->point() - v0->point();
597
        if (fabs(line.y) < FLT_EPSILON) {
598
            return isHorizontal;
599
        } else if (fabs(line.x) < FLT_EPSILON) {
600
            return isVertical;
601
        } else {
602
            return isDiagonal;
603
        }
604
    } else if (refs.size() == 3) {
605
        //three vertices make an angle dimension
606
        return isAngle3Pt;
607
    }
608

609
    // did not find a valid configuration
610
    return isInvalid;
611
}
612

613
//! verify that the vertex references can make a dimension
614
DimensionGeometryType TechDraw::isValidVertexes3d(DrawViewPart* dvp, ReferenceVector refs)
615
{
616
    (void)dvp;
617
    const std::string matchToken{"Vertex"};
618
    if (!refsMatchToken(refs, matchToken)) {
619
        return isInvalid;
620
    }
621

622
    if (refs.size() == 2) {
623
        //2 vertices can only make a distance dimension
624
        TopoDS_Shape geometry0 = refs.at(0).getGeometry();
625
        TopoDS_Shape geometry1 = refs.at(1).getGeometry();
626
        if (geometry0.IsNull() || geometry1.IsNull() || geometry0.ShapeType() != TopAbs_VERTEX
627
            || geometry1.ShapeType() != TopAbs_VERTEX) {
628
            return isInvalid;
629
        }
630
        Base::Vector3d point0 = DU::toVector3d(BRep_Tool::Pnt(TopoDS::Vertex(geometry0)));
631
        point0 = dvp->projectPoint(point0);
632
        Base::Vector3d point1 = DU::toVector3d(BRep_Tool::Pnt(TopoDS::Vertex(geometry1)));
633
        point1 = dvp->projectPoint(point1);
634
        Base::Vector3d line = point1 - point0;
635
        if (fabs(line.y) < FLT_EPSILON) {
636
            return isHorizontal;
637
        } else if (fabs(line.x) < FLT_EPSILON) {
638
            return isVertical;
639
            //        } else if(fabs(line.z) < FLT_EPSILON) {
640
            //            return isZLimited;
641
        } else {
642
            return isDiagonal;
643
        }
644
    } else if (refs.size() == 3) {
645
        //three vertices make an angle dimension
646
        //we could check here that all the geometries are Vertex
647
        return isAngle3Pt;
648
    }
649

650
    // did not find a valid configuration
651
    return isInvalid;
652
}
653

654
//! verify that the mixed bag (ex Vertex-Edge) of references can make a dimension
655
DimensionGeometryType TechDraw::isValidHybrid(ReferenceVector refs)
656
{
657
    if (refs.empty()) {
658
        return isInvalid;
659
    }
660

661
    int vertexCount(0);
662
    int edgeCount(0);
663
    for (auto& ref : refs) {
664
        if (DU::getGeomTypeFromName(ref.getSubName()) == "Vertex") {
665
            vertexCount++;
666
        }
667
        if (DU::getGeomTypeFromName(ref.getSubName()) == "Edge") {
668
            edgeCount++;
669
        }
670
    }
671
    if (vertexCount > 0 && edgeCount > 0) {
672
        //must be a diagonal dim? could it be isHorizontal or isVertical?
673
        return isHybrid;
674
    }
675

676
    return isInvalid;
677
}
678

679
//! verify that the mixed bag (ex Vertex-Edge) of references can make a dimension
680
DimensionGeometryType TechDraw::isValidHybrid3d(DrawViewPart* dvp, ReferenceVector refs)
681
{
682
    (void)dvp;
683
    //we can reuse the 2d check here.
684
    return isValidHybrid(refs);
685
}
686

687
//handle situations where revised geometry type is valid but not suitable for existing dimType
688
long int TechDraw::mapGeometryTypeToDimType(long int dimType, DimensionGeometryType geometry2d,
689
                                            DimensionGeometryType geometry3d)
690
{
691
    if (geometry2d == isInvalid && geometry3d == isInvalid) {
692
        //probably an error, but we can't do anything with this
693
        return dimType;
694
    }
695

696
    if (geometry2d == isViewReference && geometry3d != isInvalid) {
697
        switch (geometry3d) {
698
            case isDiagonal:
699
                return DrawViewDimension::Distance;
700
            case isHorizontal:
701
                return DrawViewDimension::DistanceX;
702
            case isVertical:
703
                return DrawViewDimension::DistanceY;
704
            case isAngle:
705
                return DrawViewDimension::Angle;
706
            case isAngle3Pt:
707
                return DrawViewDimension::Angle3Pt;
708
        }
709
    } else if (geometry2d != isViewReference) {
710
        switch (geometry2d) {
711
            case isDiagonal:
712
                return DrawViewDimension::Distance;
713
            case isHorizontal:
714
                return DrawViewDimension::DistanceX;
715
            case isVertical:
716
                return DrawViewDimension::DistanceY;
717
            case isAngle:
718
                return DrawViewDimension::Angle;
719
            case isAngle3Pt:
720
                return DrawViewDimension::Angle3Pt;
721
        }
722
    }
723
    return dimType;
724
}
725

726
//! true if all the input references have subelements that match the geometry
727
//! type token.
728
bool  TechDraw::refsMatchToken(const ReferenceVector& refs, const std::string& matchToken)
729
{
730
    for (auto& entry : refs) {
731
        std::string entryToken = DU::getGeomTypeFromName(entry.getSubName(false));
732
        if (entryToken != matchToken) {
733
            return false;
734
        }
735
    }
736
    return true;
737
}
738

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

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

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

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