FreeCAD

Форк
0
/
FaceMaker.cpp 
292 строки · 10.0 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2016 Victor Titov (DeepSOIC) <vv.titov@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 <BRepBuilderAPI_MakeFace.hxx>
26
# include <BRepBuilderAPI_MakeWire.hxx>
27
# include <TopoDS.hxx>
28
# include <TopoDS_Builder.hxx>
29
# include <TopoDS_Iterator.hxx>
30
# include <QtGlobal>
31
#endif
32

33
#include <memory>
34

35
#include "FaceMaker.h"
36
#include <App/MappedElement.h>
37
#include "TopoShape.h"
38
#include "TopoShapeOpCode.h"
39

40

41
TYPESYSTEM_SOURCE_ABSTRACT(Part::FaceMaker, Base::BaseClass)
42
TYPESYSTEM_SOURCE_ABSTRACT(Part::FaceMakerPublic, Part::FaceMaker)
43

44
void Part::FaceMaker::addWire(const TopoDS_Wire& w)
45
{
46
    this->addShape(w);
47
}
48

49
void Part::FaceMaker::addShape(const TopoDS_Shape& sh)
50
{
51
    addTopoShape(sh);
52
}
53

54
void Part::FaceMaker::addTopoShape(const TopoShape& shape) {
55
    const TopoDS_Shape &sh = shape.getShape();
56
    if(sh.IsNull())
57
        throw Base::ValueError("Input shape is null.");
58
    switch(sh.ShapeType()){
59
        case TopAbs_COMPOUND:
60
            this->myCompounds.push_back(TopoDS::Compound(sh));
61
        break;
62
        case TopAbs_WIRE:
63
            this->myWires.push_back(TopoDS::Wire(sh));
64
            this->myTopoWires.push_back(shape);
65
        break;
66
        case TopAbs_EDGE:
67
            this->myWires.push_back(BRepBuilderAPI_MakeWire(TopoDS::Edge(sh)).Wire());
68
            this->myTopoWires.push_back(shape);
69
            this->myTopoWires.back().setShape(this->myWires.back(), false);
70
        break;
71
        case TopAbs_FACE:
72
            this->myInputFaces.push_back(sh);
73
        break;
74
        case TopAbs_VERTEX:
75
            // This is a special case, since this is generally a stand-alone point in a sketch.  We
76
            // need to ignore it rather than throw an error
77
        break;
78
        default:
79
            throw Base::TypeError(tr("Shape must be a wire, edge or compound. Something else was supplied.").toStdString());
80
        break;
81
    }
82
    this->mySourceShapes.push_back(shape);
83
}
84

85
void Part::FaceMaker::useCompound(const TopoDS_Compound& comp)
86
{
87
    TopoDS_Iterator it(comp);
88
    for(; it.More(); it.Next()){
89
        this->addShape(it.Value());
90
    }
91
}
92

93
void Part::FaceMaker::useTopoCompound(const TopoShape& comp)
94
{
95
    for(auto &s : comp.getSubTopoShapes())
96
        this->addTopoShape(s);
97
}
98

99
const TopoDS_Face& Part::FaceMaker::Face()
100
{
101
    return TopoDS::Face(TopoFace().getShape());
102
}
103

104
const Part::TopoShape &Part::FaceMaker::TopoFace() const{
105
    if(this->myTopoShape.isNull())
106
        throw NullShapeException("Part::FaceMaker: result shape is null.");
107
    if (this->myTopoShape.getShape().ShapeType() != TopAbs_FACE)
108
        throw Base::TypeError("Part::FaceMaker: return shape is not a single face.");
109
    return this->myTopoShape;
110
}
111

112
const Part::TopoShape &Part::FaceMaker::getTopoShape() const{
113
    if(this->myTopoShape.isNull())
114
        throw NullShapeException("Part::FaceMaker: result shape is null.");
115
    return this->myTopoShape;
116
}
117

118
#if OCC_VERSION_HEX >= 0x070600
119
void Part::FaceMaker::Build(const Message_ProgressRange&)
120
#else
121
void Part::FaceMaker::Build()
122
#endif
123
{
124
    this->NotDone();
125
    this->myShapesToReturn = this->myInputFaces;
126
    this->myGenerated.Clear();
127

128
    this->Build_Essence();//adds stuff to myShapesToReturn
129

130
    for(const TopoDS_Compound& cmp : this->myCompounds){
131
        std::unique_ptr<FaceMaker> facemaker = Part::FaceMaker::ConstructFromType(this->getTypeId());
132

133
        facemaker->useCompound(cmp);
134

135
        facemaker->Build();
136
        const TopoDS_Shape &subfaces = facemaker->Shape();
137
        if (subfaces.IsNull())
138
            continue;
139
        if (subfaces.ShapeType() == TopAbs_COMPOUND){
140
            this->myShapesToReturn.push_back(subfaces);
141
        } else {
142
            //result is not a compound (probably, a face)... but we want to follow compounding structure of input, so wrap it into compound.
143
            TopoDS_Builder builder;
144
            TopoDS_Compound cmp_res;
145
            builder.MakeCompound(cmp_res);
146
            builder.Add(cmp_res,subfaces);
147
            this->myShapesToReturn.push_back(cmp_res);
148
        }
149
    }
150

151
    if(this->myShapesToReturn.empty()){
152
        //nothing to do, null shape will be returned.
153
        this->myShape = TopoDS_Shape();
154
    } else if (this->myShapesToReturn.size() == 1){
155
        this->myShape = this->myShapesToReturn[0];
156
    } else {
157
        TopoDS_Builder builder;
158
        TopoDS_Compound cmp_res;
159
        builder.MakeCompound(cmp_res);
160
        for(TopoDS_Shape &sh: this->myShapesToReturn){
161
            builder.Add(cmp_res,sh);
162
        }
163
        this->myShape = cmp_res;
164
    }
165

166
    postBuild();
167
}
168

169
struct ElementName {
170
    long tag;
171
    Data::MappedName name;
172
    Data::ElementIDRefs sids;
173

174
    ElementName(long t, const Data::MappedName &n, const Data::ElementIDRefs &sids)
175
        :tag(t),name(n), sids(sids)
176
    {}
177

178
    inline bool operator<(const ElementName &other) const {
179
        if(tag<other.tag)
180
            return true;
181
        if(tag>other.tag)
182
            return false;
183
        return Data::ElementNameComparator()(name,other.name);
184
    }
185
};
186

187
void Part::FaceMaker::postBuild() {
188
    this->myTopoShape.setShape(this->myShape);
189
    this->myTopoShape.Hasher = this->MyHasher;
190
    this->myTopoShape.mapSubElement(this->mySourceShapes);
191
    int index = 0;
192
    const char *op = this->MyOp;
193
    if(!op)
194
        op = Part::OpCodes::Face;
195
    const auto &faces = this->myTopoShape.getSubTopoShapes(TopAbs_FACE);
196
    std::set<Data::MappedName> namesUsed;
197
    // name the face using the edges of its outer wire
198
    for(auto &face : faces) {
199
        ++index;
200
        TopoShape wire = face.splitWires();
201
        wire.mapSubElement(face);
202
        std::set<ElementName> edgeNames;
203
        int count = wire.countSubShapes(TopAbs_EDGE);
204
        for (int index2 = 1; index2 <= count; ++index2) {
205
            Data::ElementIDRefs sids;
206
            Data::MappedName name =
207
                face.getMappedName(Data::IndexedName::fromConst("Edge", index2), false, &sids);
208
            if (!name) {
209
                continue;
210
            }
211
            edgeNames.emplace(wire.getElementHistory(name), name, sids);
212
        }
213
        if (edgeNames.empty()) {
214
            continue;
215
        }
216

217
        std::vector<Data::MappedName> names;
218
        Data::ElementIDRefs sids;
219
        // To avoid name collision, we keep track of any used names to make sure
220
        // to use at least 'minElementNames' number of unused element names to
221
        // generate the face name.
222
        int nameCount = 0;
223
        for (const auto &e : edgeNames) {
224
            names.push_back(e.name);
225
            sids += e.sids;
226
            if (namesUsed.insert(e.name).second) {
227
                if (++nameCount >= minElementNames)
228
                    break;
229
            }
230
        }
231
        this->myTopoShape.setElementComboName(
232
                Data::IndexedName::fromConst("Face",index),names,op,nullptr,&sids);
233
    }
234
    this->myTopoShape.initCache(true);
235
    this->Done();
236
}
237

238
std::unique_ptr<Part::FaceMaker> Part::FaceMaker::ConstructFromType(const char* className)
239
{
240
    Base::Type fmType = Base::Type::fromName(className);
241
    if (fmType.isBad()){
242
        std::stringstream ss;
243
        ss << "Class '"<< className <<"' not found.";
244
        throw Base::TypeError(ss.str().c_str());
245
    }
246
    return Part::FaceMaker::ConstructFromType(fmType);
247
}
248

249
std::unique_ptr<Part::FaceMaker> Part::FaceMaker::ConstructFromType(Base::Type type)
250
{
251
    if (!type.isDerivedFrom(Part::FaceMaker::getClassTypeId())){
252
        std::stringstream ss;
253
        ss << "Class '" << type.getName() << "' is not derived from Part::FaceMaker.";
254
        throw Base::TypeError(ss.str().c_str());
255
    }
256
    std::unique_ptr<FaceMaker> instance(static_cast<Part::FaceMaker*>(type.createInstance()));
257
    if (!instance){
258
        std::stringstream ss;
259
        ss << "Cannot create FaceMaker from abstract type '" << type.getName() << "'";
260
        throw Base::TypeError(ss.str().c_str());
261
    }
262
    return instance;
263
}
264

265
void Part::FaceMaker::throwNotImplemented()
266
{
267
    throw Base::NotImplementedError("Not implemented yet...");
268
}
269

270

271
//----------------------------------------------------------------------------------------
272

273
TYPESYSTEM_SOURCE(Part::FaceMakerSimple, Part::FaceMakerPublic)
274

275

276
std::string Part::FaceMakerSimple::getUserFriendlyName() const
277
{
278
    return {tr("Simple").toStdString()};
279
}
280

281
std::string Part::FaceMakerSimple::getBriefExplanation() const
282
{
283
    return {tr("Makes separate plane face from every wire independently. No support for holes; wires can be on different planes.").toStdString()};
284

285
}
286

287
void Part::FaceMakerSimple::Build_Essence()
288
{
289
    for(TopoDS_Wire &w: myWires){
290
        this->myShapesToReturn.push_back(BRepBuilderAPI_MakeFace(w).Shape());
291
    }
292
}
293

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

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

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

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