FreeCAD

Форк
0
/
FaceMakerBullseye.cpp 
196 строк · 7.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 <BRep_Builder.hxx>
26
# include <BRep_Tool.hxx>
27
# include <BRepAdaptor_Surface.hxx>
28
# include <BRepBuilderAPI_Copy.hxx>
29
# include <BRepBuilderAPI_MakeFace.hxx>
30
# include <BRepClass_FaceClassifier.hxx>
31
# include <BRepLib_FindSurface.hxx>
32
# include <Geom_Plane.hxx>
33
# include <GeomAPI_ProjectPointOnSurf.hxx>
34
# include <Precision.hxx>
35
# include <Standard_Failure.hxx>
36
# include <TopoDS.hxx>
37
# include <TopExp_Explorer.hxx>
38
# include <QtGlobal>
39
#endif
40

41
#include "FaceMakerBullseye.h"
42
#include "FaceMakerCheese.h"
43
#include "TopoShape.h"
44

45

46
using namespace Part;
47

48
TYPESYSTEM_SOURCE(Part::FaceMakerBullseye, Part::FaceMakerPublic)
49

50
void FaceMakerBullseye::setPlane(const gp_Pln &plane)
51
{
52
    this->myPlane = gp_Pln(plane);
53
    this->planeSupplied = true;
54
}
55

56
std::string FaceMakerBullseye::getUserFriendlyName() const
57
{
58
    return {tr("Bull's-eye facemaker").toStdString()};
59
}
60

61
std::string FaceMakerBullseye::getBriefExplanation() const
62
{
63
    return {tr("Supports making planar faces with holes with islands.").toStdString()};
64
}
65

66
void FaceMakerBullseye::Build_Essence()
67
{
68
    if (myWires.empty())
69
        return;
70

71
    //validity check
72
    for (TopoDS_Wire& w : myWires) {
73
        if (!BRep_Tool::IsClosed(w))
74
            throw Base::ValueError(QT_TRANSLATE_NOOP("Exception", "Wire is not closed."));
75
    }
76

77

78
    //find plane (at the same time, test that all wires are on the same plane)
79
    gp_Pln plane;
80
    if (this->planeSupplied) {
81
        plane = this->myPlane;
82
    }
83
    else {
84
        TopoDS_Builder builder;
85
        TopoDS_Compound comp;
86
        builder.MakeCompound(comp);
87
        for (TopoDS_Wire& w : myWires) {
88
            builder.Add(comp, BRepBuilderAPI_Copy(w).Shape());
89
        }
90
        BRepLib_FindSurface planeFinder(comp, -1, /*OnlyPlane=*/Standard_True);
91
        if (!planeFinder.Found())
92
            throw Base::ValueError("Wires are not coplanar.");
93
        plane = GeomAdaptor_Surface(planeFinder.Surface()).Plane();
94
    }
95

96
    //sort wires by length of diagonal of bounding box.
97
    std::vector<TopoDS_Wire> wires = this->myWires;
98
    std::stable_sort(wires.begin(), wires.end(), FaceMakerCheese::Wire_Compare());
99

100
    //add wires one by one to current set of faces.
101
    //We go from last to first, to make it so that outer wires come before inner wires.
102
    std::vector< std::unique_ptr<FaceDriller> > faces;
103
    for (int i = static_cast<int>(wires.size()) - 1; i >= 0; --i) {
104
        TopoDS_Wire& w = wires[i];
105

106
        //test if this wire is on any of existing faces (if yes, it's a hole;
107
        // if no, it's a beginning of a new face).
108
        //Since we are assuming the wires do not intersect, testing if one vertex of wire is in a face is enough.
109
        gp_Pnt p = BRep_Tool::Pnt(TopoDS::Vertex(TopExp_Explorer(w, TopAbs_VERTEX).Current()));
110
        FaceDriller* foundFace = nullptr;
111
        for (std::unique_ptr<FaceDriller>& ff : faces) {
112
            if (ff->hitTest(p)) {
113
                foundFace = &(*ff);
114
                break;
115
            }
116
        }
117

118
        if (foundFace) {
119
            //wire is on a face.
120
            foundFace->addHole(w);
121
        }
122
        else {
123
            //wire is not on a face. Start a new face.
124
            faces.push_back(std::make_unique<FaceDriller>(
125
                                plane, w
126
                           ));
127
        }
128
    }
129

130
    //and we are done!
131
    for (std::unique_ptr<FaceDriller>& ff : faces) {
132
        this->myShapesToReturn.push_back(ff->Face());
133
    }
134
}
135

136

137
FaceMakerBullseye::FaceDriller::FaceDriller(const gp_Pln& plane, TopoDS_Wire outerWire)
138
{
139
    this->myPlane = plane;
140
    this->myFace = TopoDS_Face();
141

142
    //Ensure correct orientation of the wire.
143
    if (getWireDirection(myPlane, outerWire) < 0)
144
        outerWire.Reverse();
145

146
    myHPlane = new Geom_Plane(this->myPlane);
147
    BRep_Builder builder;
148
    builder.MakeFace(this->myFace, myHPlane, Precision::Confusion());
149
    builder.Add(this->myFace, outerWire);
150
}
151

152
bool FaceMakerBullseye::FaceDriller::hitTest(const gp_Pnt& point) const
153
{
154
    double u, v;
155
    GeomAPI_ProjectPointOnSurf(point, myHPlane).LowerDistanceParameters(u, v);
156
    BRepClass_FaceClassifier cl(myFace, gp_Pnt2d(u, v), Precision::Confusion());
157
    TopAbs_State ret = cl.State();
158
    switch (ret) {
159
    case TopAbs_UNKNOWN:
160
        throw Base::ValueError("FaceMakerBullseye::FaceDriller::hitTest: result unknown.");
161
        break;
162
    default:
163
        return ret == TopAbs_IN || ret == TopAbs_ON;
164
    }
165

166
}
167

168
void FaceMakerBullseye::FaceDriller::addHole(TopoDS_Wire w)
169
{
170
    //Ensure correct orientation of the wire.
171
    if (getWireDirection(myPlane, w) > 0) //if wire is CCW..
172
        w.Reverse();   //.. we want CW!
173

174
    BRep_Builder builder;
175
    builder.Add(this->myFace, w);
176
}
177

178
int FaceMakerBullseye::FaceDriller::getWireDirection(const gp_Pln& plane, const TopoDS_Wire& wire)
179
{
180
    //make a test face
181
    BRepBuilderAPI_MakeFace mkFace(wire, /*onlyplane=*/Standard_True);
182
    TopoDS_Face tmpFace = mkFace.Face();
183
    if (tmpFace.IsNull()) {
184
        throw Standard_Failure("getWireDirection: Failed to create face from wire");
185
    }
186

187
    //compare face surface normal with our plane's one
188
    BRepAdaptor_Surface surf(tmpFace);
189
    bool normal_co = surf.Plane().Axis().Direction().Dot(plane.Axis().Direction()) > 0;
190

191
    //unlikely, but just in case OCC decided to reverse our wire for the face...  take that into account!
192
    TopoDS_Iterator it(tmpFace, /*CumOri=*/Standard_False);
193
    normal_co ^= it.Value().Orientation() != wire.Orientation();
194

195
    return normal_co ? 1 : -1;
196
}
197

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

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

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

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