FreeCAD

Форк
0
/
PartFeatures.cpp 
501 строка · 17.5 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2011 Werner Mayer <wmayer[at]users.sourceforge.net>     *
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 <memory>
26
#include <BRepAdaptor_CompCurve.hxx>
27
#include <BRepAdaptor_Curve.hxx>
28
#include <BRepBuilderAPI_Copy.hxx>
29
#include <BRepBuilderAPI_MakeWire.hxx>
30
#include <BRepFill.hxx>
31
#include <BRepLib_MakeWire.hxx>
32
#include <BRepOffsetAPI_MakePipeShell.hxx>
33
#include <Geom_BSplineSurface.hxx>
34
#include <Precision.hxx>
35
#include <ShapeAnalysis.hxx>
36
#include <ShapeAnalysis_FreeBounds.hxx>
37
#include <TopExp_Explorer.hxx>
38
#include <TopoDS.hxx>
39
#include <TopoDS_Face.hxx>
40
#include <TopoDS_Iterator.hxx>
41
#include <TopoDS_Shell.hxx>
42
#include <TopTools_HSequenceOfShape.hxx>
43
#include <TopTools_ListIteratorOfListOfShape.hxx>
44
#endif
45

46
#include <App/Link.h>
47

48
#include <App/Document.h>
49
#include "PartFeatures.h"
50
#include "TopoShapeOpCode.h"
51

52
using namespace Part;
53

54
PROPERTY_SOURCE(Part::RuledSurface, Part::Feature)
55

56
const char* RuledSurface::OrientationEnums[] = {"Automatic", "Forward", "Reversed", nullptr};
57

58
RuledSurface::RuledSurface()
59
{
60
    ADD_PROPERTY_TYPE(Curve1, (nullptr), "Ruled Surface", App::Prop_None, "Curve of ruled surface");
61
    ADD_PROPERTY_TYPE(Curve2, (nullptr), "Ruled Surface", App::Prop_None, "Curve of ruled surface");
62
    ADD_PROPERTY_TYPE(Orientation,
63
                      ((long)0),
64
                      "Ruled Surface",
65
                      App::Prop_None,
66
                      "Orientation of ruled surface");
67
    Orientation.setEnums(OrientationEnums);
68
}
69

70
short RuledSurface::mustExecute() const
71
{
72
    if (Curve1.isTouched()) {
73
        return 1;
74
    }
75
    if (Curve2.isTouched()) {
76
        return 1;
77
    }
78
    if (Orientation.isTouched()) {
79
        return 1;
80
    }
81
    return 0;
82
}
83

84
void RuledSurface::onChanged(const App::Property* prop)
85
{
86
    Part::Feature::onChanged(prop);
87
}
88

89
App::DocumentObjectExecReturn* RuledSurface::getShape(const App::PropertyLinkSub& link,
90
                                                      TopoDS_Shape& shape) const
91
{
92
    App::DocumentObject* obj = link.getValue();
93
    const Part::TopoShape part = Part::Feature::getTopoShape(obj);
94
    if (part.isNull()) {
95
        return new App::DocumentObjectExecReturn("No shape linked.");
96
    }
97

98
    // if no explicit sub-shape is selected use the whole part
99
    const std::vector<std::string>& element = link.getSubValues();
100
    if (element.empty()) {
101
        shape = part.getShape();
102
        return nullptr;
103
    }
104
    else if (element.size() != 1) {
105
        return new App::DocumentObjectExecReturn("Not exactly one sub-shape linked.");
106
    }
107

108
    if (!part.getShape().IsNull()) {
109
        if (!element[0].empty()) {
110
            // shape = Part::Feature::getTopoShape(obj, element[0].c_str(), true /*need
111
            // element*/).getShape();
112
            shape = part.getSubShape(element[0].c_str());
113
        }
114
        else {
115
            // the sub-element is an empty string, so use the whole part
116
            shape = part.getShape();
117
        }
118
    }
119

120
    return nullptr;
121
}
122

123
App::DocumentObjectExecReturn* RuledSurface::execute()
124
{
125
    try {
126
        std::vector<TopoShape> shapes;
127
        std::array<App::PropertyLinkSub*, 2> links = {&Curve1, &Curve2};
128
        for (auto link : links) {
129
            const auto& subs = link->getSubValues();
130
            if (subs.empty()) {
131
                shapes.push_back(getTopoShape(link->getValue()));
132
            }
133
            else if (subs.size() != 1) {
134
                return new App::DocumentObjectExecReturn("Not exactly one sub-shape linked.");
135
            }
136
            else {
137
                shapes.push_back(getTopoShape(link->getValue(), subs.front().c_str(), true));
138
            }
139
            if (shapes.back().isNull()) {
140
                return new App::DocumentObjectExecReturn("Invalid link.");
141
            }
142
        }
143
        TopoShape res(0);
144
        res.makeElementRuledSurface(shapes, Orientation.getValue());
145
        this->Shape.setValue(res);
146
        return Part::Feature::execute();
147

148
    }
149
    catch (Standard_Failure& e) {
150

151
        return new App::DocumentObjectExecReturn(e.GetMessageString());
152
    }
153
    catch (...) {
154
        return new App::DocumentObjectExecReturn("General error in RuledSurface::execute()");
155
    }
156
}
157

158
// ----------------------------------------------------------------------------
159

160
App::PropertyIntegerConstraint::Constraints Loft::Degrees = {2,
161
                                                             Geom_BSplineSurface::MaxDegree(),
162
                                                             1};
163

164
PROPERTY_SOURCE(Part::Loft, Part::Feature)
165

166
Loft::Loft()
167
{
168
    ADD_PROPERTY_TYPE(Sections, (nullptr), "Loft", App::Prop_None, "List of sections");
169
    Sections.setSize(0);
170
    ADD_PROPERTY_TYPE(Solid, (false), "Loft", App::Prop_None, "Create solid");
171
    ADD_PROPERTY_TYPE(Ruled, (false), "Loft", App::Prop_None, "Ruled surface");
172
    ADD_PROPERTY_TYPE(Closed, (false), "Loft", App::Prop_None, "Close Last to First Profile");
173
    ADD_PROPERTY_TYPE(MaxDegree, (5), "Loft", App::Prop_None, "Maximum Degree");
174
    ADD_PROPERTY_TYPE(Linearize,(false), "Loft", App::Prop_None,
175
                      "Linearize the result shape by simplifying linear edge and planar face into line and plane");
176
    MaxDegree.setConstraints(&Degrees);
177
}
178

179
short Loft::mustExecute() const
180
{
181
    if (Sections.isTouched()) {
182
        return 1;
183
    }
184
    if (Solid.isTouched()) {
185
        return 1;
186
    }
187
    if (Ruled.isTouched()) {
188
        return 1;
189
    }
190
    if (Closed.isTouched()) {
191
        return 1;
192
    }
193
    if (MaxDegree.isTouched()) {
194
        return 1;
195
    }
196
    return 0;
197
}
198

199
void Loft::onChanged(const App::Property* prop)
200
{
201
    Part::Feature::onChanged(prop);
202
}
203

204
App::DocumentObjectExecReturn* Loft::execute()
205
{
206
    if (Sections.getSize() == 0) {
207
        return new App::DocumentObjectExecReturn("No sections linked.");
208
    }
209

210
    try {
211
        std::vector<TopoShape> shapes;
212
        for (auto& obj : Sections.getValues()) {
213
            shapes.emplace_back(getTopoShape(obj));
214
            if (shapes.back().isNull()) {
215
                return new App::DocumentObjectExecReturn("Invalid section link");
216
            }
217
        }
218
        IsSolid isSolid = Solid.getValue() ? IsSolid::solid : IsSolid::notSolid;
219
        IsRuled isRuled = Ruled.getValue() ? IsRuled::ruled : IsRuled::notRuled;
220
        IsClosed isClosed = Closed.getValue() ? IsClosed::closed : IsClosed::notClosed;
221
        int degMax = MaxDegree.getValue();
222
        TopoShape result(0);
223
        result.makeElementLoft(shapes, isSolid, isRuled, isClosed, degMax);
224
        if (Linearize.getValue()) {
225
            result.linearize( LinearizeFace::linearizeFaces, LinearizeEdge::noEdges);
226
        }
227
        this->Shape.setValue(result);
228
        return Part::Feature::execute();
229
    }
230
    catch (Standard_Failure& e) {
231

232
        return new App::DocumentObjectExecReturn(e.GetMessageString());
233
    }
234
}
235

236
void Part::Loft::setupObject()
237
{
238
    Feature::setupObject();
239
//    Linearize.setValue(PartParams::getLinearizeExtrusionDraft()); // TODO: Resolve after PartParams
240
}
241

242
// ----------------------------------------------------------------------------
243

244
const char* Part::Sweep::TransitionEnums[] = {"Transformed",
245
                                              "Right corner",
246
                                              "Round corner",
247
                                              nullptr};
248

249
PROPERTY_SOURCE(Part::Sweep, Part::Feature)
250

251
Sweep::Sweep()
252
{
253
    ADD_PROPERTY_TYPE(Sections, (nullptr), "Sweep", App::Prop_None, "List of sections");
254
    Sections.setSize(0);
255
    ADD_PROPERTY_TYPE(Spine, (nullptr), "Sweep", App::Prop_None, "Path to sweep along");
256
    ADD_PROPERTY_TYPE(Solid, (false), "Sweep", App::Prop_None, "Create solid");
257
    ADD_PROPERTY_TYPE(Frenet, (true), "Sweep", App::Prop_None, "Frenet");
258
    ADD_PROPERTY_TYPE(Transition, (long(1)), "Sweep", App::Prop_None, "Transition mode");
259
    ADD_PROPERTY_TYPE(Linearize,(false), "Sweep", App::Prop_None,
260
                      "Linearize the result shape by simplifying linear edge and planar face into line and plane");
261
    Transition.setEnums(TransitionEnums);
262
}
263

264
short Sweep::mustExecute() const
265
{
266
    if (Sections.isTouched()) {
267
        return 1;
268
    }
269
    if (Spine.isTouched()) {
270
        return 1;
271
    }
272
    if (Solid.isTouched()) {
273
        return 1;
274
    }
275
    if (Frenet.isTouched()) {
276
        return 1;
277
    }
278
    if (Transition.isTouched()) {
279
        return 1;
280
    }
281
    return 0;
282
}
283

284
void Sweep::onChanged(const App::Property* prop)
285
{
286
    Part::Feature::onChanged(prop);
287
}
288

289
App::DocumentObjectExecReturn* Sweep::execute()
290
{
291
    if (Sections.getSize() == 0) {
292
        return new App::DocumentObjectExecReturn("No sections linked.");
293
    }
294
    if (!Spine.getValue()) {
295
        return new App::DocumentObjectExecReturn("No spine");
296
    }
297
    TopoShape spine = getTopoShape(Spine.getValue());
298
    const auto& subs = Spine.getSubValues();
299
    if (spine.isNull()) {
300
        return new App::DocumentObjectExecReturn("Invalid spine");
301
    }
302
    if (subs.size()) {
303
        std::vector<TopoShape> spineShapes;
304
        for (auto sub : subs) {
305
            auto shape = spine.getSubTopoShape(sub.c_str());
306
            if (shape.isNull()) {
307
                return new App::DocumentObjectExecReturn("Invalid spine");
308
            }
309
            spineShapes.push_back(shape);
310
        }
311
        spine = TopoShape().makeElementCompound(spineShapes, 0, TopoShape::SingleShapeCompoundCreationPolicy::returnShape);
312
    }
313
    std::vector<TopoShape> shapes;
314
    shapes.push_back(spine);
315
    for (auto& obj : Sections.getValues()) {
316
        shapes.emplace_back(getTopoShape(obj));
317
        if (shapes.back().isNull()) {
318
            return new App::DocumentObjectExecReturn("Invalid section link");
319
        }
320
    }
321
    MakeSolid isSolid = Solid.getValue() ? MakeSolid::makeSolid : MakeSolid::noSolid;
322
    Standard_Boolean isFrenet = Frenet.getValue() ? Standard_True : Standard_False;
323
    auto transMode = static_cast<TransitionMode>(Transition.getValue());
324
    try {
325
        TopoShape result(0);
326
        result.makeElementPipeShell(shapes, isSolid, isFrenet, transMode, Part::OpCodes::Sweep);
327
        if (Linearize.getValue()) {
328
            result.linearize(LinearizeFace::linearizeFaces, LinearizeEdge::noEdges);
329
        }
330
        this->Shape.setValue(result);
331
        return App::DocumentObject::StdReturn;
332
    }
333
    catch (Standard_Failure& e) {
334

335
        return new App::DocumentObjectExecReturn(e.GetMessageString());
336
    }
337
    catch (...) {
338
        return new App::DocumentObjectExecReturn("A fatal error occurred when making the sweep");
339
    }
340
}
341

342
void Part::Sweep::setupObject()
343
{
344
    Feature::setupObject();
345
//    Linearize.setValue(PartParams::getLinearizeExtrusionDraft()); // TODO: Resolve after PartParams
346
}
347

348
// ----------------------------------------------------------------------------
349

350
const char* Part::Thickness::ModeEnums[] = {"Skin", "Pipe", "RectoVerso", nullptr};
351
const char* Part::Thickness::JoinEnums[] = {"Arc", "Tangent", "Intersection", nullptr};
352

353
PROPERTY_SOURCE(Part::Thickness, Part::Feature)
354

355
Thickness::Thickness()
356
{
357
    ADD_PROPERTY_TYPE(Faces, (nullptr), "Thickness", App::Prop_None, "Faces to be removed");
358
    ADD_PROPERTY_TYPE(Value, (1.0), "Thickness", App::Prop_None, "Thickness value");
359
    ADD_PROPERTY_TYPE(Mode, (long(0)), "Thickness", App::Prop_None, "Mode");
360
    Mode.setEnums(ModeEnums);
361
    ADD_PROPERTY_TYPE(Join, (long(0)), "Thickness", App::Prop_None, "Join type");
362
    Join.setEnums(JoinEnums);
363
    ADD_PROPERTY_TYPE(Intersection, (false), "Thickness", App::Prop_None, "Intersection");
364
    ADD_PROPERTY_TYPE(SelfIntersection, (false), "Thickness", App::Prop_None, "Self Intersection");
365

366
    // Value should have length as unit
367
    Value.setUnit(Base::Unit::Length);
368
}
369

370
short Thickness::mustExecute() const
371
{
372
    if (Faces.isTouched()) {
373
        return 1;
374
    }
375
    if (Value.isTouched()) {
376
        return 1;
377
    }
378
    if (Mode.isTouched()) {
379
        return 1;
380
    }
381
    if (Join.isTouched()) {
382
        return 1;
383
    }
384
    if (Intersection.isTouched()) {
385
        return 1;
386
    }
387
    if (SelfIntersection.isTouched()) {
388
        return 1;
389
    }
390
    return 0;
391
}
392

393
void Thickness::handleChangedPropertyType(Base::XMLReader& reader,
394
                                          const char* TypeName,
395
                                          App::Property* prop)
396
{
397
    if (prop == &Value && strcmp(TypeName, "App::PropertyFloat") == 0) {
398
        App::PropertyFloat v;
399

400
        v.Restore(reader);
401

402
        Value.setValue(v.getValue());
403
    }
404
    else {
405
        Part::Feature::handleChangedPropertyType(reader, TypeName, prop);
406
    }
407
}
408

409
App::DocumentObjectExecReturn* Thickness::execute()
410
{
411
    std::vector<TopoShape> shapes;
412
    auto base = getTopoShape(Faces.getValue());
413
    if (base.isNull()) {
414
        return new App::DocumentObjectExecReturn("Invalid source shape");
415
    }
416
    if (base.countSubShapes(TopAbs_SOLID) != 1) {
417
        return new App::DocumentObjectExecReturn("Source shape is not single solid.");
418
    }
419
    for (auto& sub : Faces.getSubValues(true)) {
420
        shapes.push_back(base.getSubTopoShape(sub.c_str()));
421
        if (shapes.back().getShape().ShapeType() != TopAbs_FACE) {
422
            return new App::DocumentObjectExecReturn("Invalid face selection");
423
        }
424
    }
425
    double thickness = Value.getValue();
426
    double tol = Precision::Confusion();
427
    bool inter = Intersection.getValue();
428
    bool self = SelfIntersection.getValue();
429
    short mode = (short)Mode.getValue();
430
    short join = (short)Join.getValue();
431

432
    this->Shape.setValue(TopoShape(0,getDocument()->getStringHasher())
433
                             .makeElementThickSolid(base,
434
                                                    shapes,
435
                                                    thickness,
436
                                                    tol,
437
                                                    inter,
438
                                                    self,
439
                                                    mode,
440
                                                    static_cast<JoinType>(join)));
441
    return Part::Feature::execute();
442
}
443

444
// ----------------------------------------------------------------------------
445

446
PROPERTY_SOURCE(Part::Refine, Part::Feature)
447

448
Refine::Refine()
449
{
450
    ADD_PROPERTY_TYPE(Source, (nullptr), "Refine", App::Prop_None, "Source shape");
451
}
452

453
App::DocumentObjectExecReturn* Refine::execute()
454
{
455
    Part::Feature* source = Source.getValue<Part::Feature*>();
456
    if (!source) {
457
        return new App::DocumentObjectExecReturn("No part object linked.");
458
    }
459

460
    try {
461
        TopoShape myShape = source->Shape.getShape();
462
        this->Shape.setValue(myShape.removeSplitter());
463
        return App::DocumentObject::StdReturn;
464
    }
465
    catch (Standard_Failure& e) {
466
        return new App::DocumentObjectExecReturn(e.GetMessageString());
467
    }
468
}
469

470
// ----------------------------------------------------------------------------
471

472
PROPERTY_SOURCE(Part::Reverse, Part::Feature)
473

474
Reverse::Reverse()
475
{
476
    ADD_PROPERTY_TYPE(Source, (nullptr), "Reverse", App::Prop_None, "Source shape");
477
}
478

479
App::DocumentObjectExecReturn* Reverse::execute()
480
{
481
    App::DocumentObject* source = Source.getValue<App::DocumentObject*>();
482
    Part::TopoShape topoShape = Part::Feature::getTopoShape(source);
483
    if (topoShape.isNull()) {
484
        return new App::DocumentObjectExecReturn("No part object linked.");
485
    }
486

487
    try {
488
        TopoDS_Shape myShape = topoShape.getShape();
489
        if (!myShape.IsNull()) {
490
            this->Shape.setValue(myShape.Reversed());
491
            Base::Placement p;
492
            p.fromMatrix(topoShape.getTransform());
493
            this->Placement.setValue(p);
494
            return App::DocumentObject::StdReturn;
495
        }
496
        return new App::DocumentObjectExecReturn("Shape is null.");
497
    }
498
    catch (Standard_Failure& e) {
499
        return new App::DocumentObjectExecReturn(e.GetMessageString());
500
    }
501
}
502

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

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

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

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