Skip to content

Commit 31b40ce

Browse files
authored
Merge pull request FreeCAD#12237 from bgbsww/bgbsww-toponamingMakeRefine
Toponaming: Transfer in makeElementRefine
2 parents 0dcfe94 + 46230c9 commit 31b40ce

9 files changed

+352
-11
lines changed

src/Mod/Part/App/TopoShape.cpp

+6-3
Original file line numberDiff line numberDiff line change
@@ -4042,22 +4042,25 @@ TopoShape &TopoShape::makeFace(const std::vector<TopoShape> &shapes, const char
40424042
return *this;
40434043
}
40444044

4045-
TopoShape &TopoShape::makeRefine(const TopoShape &shape, const char *op, bool no_fail)
4045+
TopoShape &TopoShape::makeRefine(const TopoShape &shape, const char *op, RefineFail no_fail)
40464046
{
40474047
(void)op;
40484048
_Shape.Nullify();
40494049

40504050
if(shape.isNull()) {
4051-
if(!no_fail)
4051+
if (no_fail == RefineFail::throwException) {
40524052
HANDLE_NULL_SHAPE;
4053+
}
40534054
return *this;
40544055
}
40554056
try {
40564057
BRepBuilderAPI_RefineModel mkRefine(shape.getShape());
40574058
_Shape = mkRefine.Shape();
40584059
return *this;
40594060
}catch (Standard_Failure &) {
4060-
if(!no_fail) throw;
4061+
if(no_fail == RefineFail::throwException ) {
4062+
throw;
4063+
}
40614064
}
40624065
*this = shape;
40634066
return *this;

src/Mod/Part/App/TopoShape.h

+48-2
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,13 @@ enum class HistoryTraceType
104104
followTypeChange
105105
};
106106

107+
/// Behavior of refines when a problem arises; either leave the shape untouched or throw an exception.
108+
/// This replaces a boolean parameter in the original Toponaming branch by realthunder..
109+
enum class RefineFail
110+
{
111+
shapeUntouched,
112+
throwException
113+
};
107114

108115
/** The representation for a CAD Shape
109116
*/
@@ -387,6 +394,7 @@ class PartExport TopoShape: public Data::ComplexGeoData
387394
TopoDS_Shape removeShape(const std::vector<TopoDS_Shape>& s) const;
388395
void sewShape(double tolerance = 1.0e-06);
389396
bool fix(double, double, double);
397+
bool fixSolidOrientation();
390398
bool removeInternalWires(double);
391399
TopoDS_Shape removeSplitter() const;
392400
TopoDS_Shape defeaturing(const std::vector<TopoDS_Shape>& s) const;
@@ -582,9 +590,47 @@ class PartExport TopoShape: public Data::ComplexGeoData
582590
{
583591
return TopoShape().makeGTransform(*this, mat, op, copy);
584592
}
593+
594+
/** Refine the input shape by merging faces/edges that share the same geometry
595+
*
596+
* @param source: input shape
597+
* @param op: optional string to be encoded into topo naming for indicating
598+
* the operation
599+
* @param no_fail: if throwException, throw exception if failed to refine. Or else,
600+
* if shapeUntouched the shape remains untouched if failed.
601+
*
602+
* @return The original content of this TopoShape is discarded and replaced
603+
* with the refined shape. The function returns the TopoShape
604+
* itself as a self reference so that multiple operations can be
605+
* carried out for the same shape in the same line of code.
606+
*/
607+
TopoShape& makeElementRefine(const TopoShape& source,
608+
const char* op = nullptr,
609+
RefineFail no_fail = RefineFail::throwException);
610+
611+
/** Refine the input shape by merging faces/edges that share the same geometry
612+
*
613+
* @param source: input shape
614+
* @param op: optional string to be encoded into topo naming for indicating
615+
* the operation
616+
* @param no_fail: if throwException, throw exception if failed to refine. Or else,
617+
* if shapeUntouched the shape remains untouched if failed.
618+
*
619+
* @return Return a refined shape. The shape itself is not modified
620+
*/
621+
TopoShape makeElementRefine(const char* op = nullptr,
622+
RefineFail no_fail = RefineFail::throwException) const
623+
{
624+
return TopoShape(Tag, Hasher).makeElementRefine(*this, op, no_fail);
625+
}
626+
627+
628+
TopoShape& makeRefine(const TopoShape& shape,
629+
const char* op = nullptr,
630+
RefineFail no_fail = RefineFail::throwException);
585631

586-
TopoShape& makeRefine(const TopoShape& shape, const char* op = nullptr, bool no_fail = true);
587-
TopoShape makeRefine(const char* op = nullptr, bool no_fail = true) const
632+
TopoShape makeRefine(const char* op = nullptr,
633+
RefineFail no_fail = RefineFail::throwException) const
588634
{
589635
return TopoShape().makeRefine(*this, op, no_fail);
590636
}

src/Mod/Part/App/TopoShapeExpansion.cpp

+110-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#ifndef _PreComp_
2828

2929
#include <BRepBuilderAPI_MakeWire.hxx>
30+
#include <modelRefine.h>
3031
#include <BRepCheck_Analyzer.hxx>
3132
#include <BRepFill_Generator.hxx>
3233
#include <BRepTools.hxx>
@@ -42,10 +43,12 @@
4243

4344
#include "TopoShape.h"
4445
#include "TopoShapeCache.h"
46+
#include "TopoShapeMapper.h"
4547
#include "FaceMaker.h"
4648

4749
#include "TopoShapeOpCode.h"
4850
#include <App/ElementNamingUtils.h>
51+
#include <BRepLib.hxx>
4952

5053
FC_LOG_LEVEL_INIT("TopoShape", true, true) // NOLINT
5154

@@ -751,7 +754,7 @@ TopoShape& TopoShape::makeShapeWithElementMap(const TopoDS_Shape& shape,
751754

752755
// First, collect names from other shapes that generates or modifies the
753756
// new shape
754-
for (auto& pinfo : infos) {
757+
for (auto& pinfo : infos) { // Walk Vertexes, then Edges, then Faces
755758
auto& info = *pinfo;
756759
for (const auto & incomingShape : shapes) {
757760
if (!canMapElement(incomingShape)) {
@@ -1511,6 +1514,57 @@ TopoShape& TopoShape::makeElementFace(const std::vector<TopoShape>& shapes,
15111514
return *this;
15121515
}
15131516

1517+
class MyRefineMaker : public BRepBuilderAPI_RefineModel
1518+
{
1519+
public:
1520+
explicit MyRefineMaker(const TopoDS_Shape &s)
1521+
:BRepBuilderAPI_RefineModel(s)
1522+
{}
1523+
1524+
void populate(ShapeMapper &mapper)
1525+
{
1526+
for (TopTools_DataMapIteratorOfDataMapOfShapeListOfShape it(this->myModified); it.More(); it.Next())
1527+
{
1528+
if (it.Key().IsNull()) continue;
1529+
mapper.populate(MappingStatus::Generated, it.Key(), it.Value());
1530+
}
1531+
}
1532+
};
1533+
1534+
TopoShape& TopoShape::makeElementRefine(const TopoShape& shape, const char* op, RefineFail no_fail)
1535+
{
1536+
if (shape.isNull()) {
1537+
if (no_fail == RefineFail::throwException) {
1538+
FC_THROWM(NullShapeException, "Null shape");
1539+
}
1540+
_Shape.Nullify();
1541+
return *this;
1542+
}
1543+
if (!op) {
1544+
op = Part::OpCodes::Refine;
1545+
}
1546+
bool closed = shape.isClosed();
1547+
try {
1548+
MyRefineMaker mkRefine(shape.getShape());
1549+
GenericShapeMapper mapper;
1550+
mkRefine.populate(mapper);
1551+
mapper.init(shape, mkRefine.Shape());
1552+
makeShapeWithElementMap(mkRefine.Shape(), mapper, {shape}, op);
1553+
// For some reason, refine operation may reverse the solid
1554+
fixSolidOrientation();
1555+
if (isClosed() == closed) {
1556+
return *this;
1557+
}
1558+
}
1559+
catch (Standard_Failure&) {
1560+
if (no_fail == RefineFail::throwException) {
1561+
throw;
1562+
}
1563+
}
1564+
*this = shape;
1565+
return *this;
1566+
}
1567+
15141568
/**
15151569
* Encode and set an element name in the elementMap. If a hasher is defined, apply it to the name.
15161570
*
@@ -1851,4 +1905,59 @@ TopoShape& TopoShape::makeElementShellFromWires(const std::vector<TopoShape>& wi
18511905
return *this;
18521906
}
18531907

1908+
bool TopoShape::fixSolidOrientation()
1909+
{
1910+
if (isNull()) {
1911+
return false;
1912+
}
1913+
1914+
if (shapeType() == TopAbs_SOLID) {
1915+
TopoDS_Solid solid = TopoDS::Solid(_Shape);
1916+
BRepLib::OrientClosedSolid(solid);
1917+
if (solid.IsEqual(_Shape)) {
1918+
return false;
1919+
}
1920+
setShape(solid, false);
1921+
return true;
1922+
}
1923+
1924+
if (shapeType() == TopAbs_COMPOUND || shapeType() == TopAbs_COMPSOLID) {
1925+
auto shapes = getSubTopoShapes();
1926+
bool touched = false;
1927+
for (auto& s : shapes) {
1928+
if (s.fixSolidOrientation()) {
1929+
touched = true;
1930+
}
1931+
}
1932+
if (!touched) {
1933+
return false;
1934+
}
1935+
1936+
BRep_Builder builder;
1937+
if (shapeType() == TopAbs_COMPOUND) {
1938+
TopoDS_Compound comp;
1939+
builder.MakeCompound(comp);
1940+
for (auto& s : shapes) {
1941+
if (!s.isNull()) {
1942+
builder.Add(comp, s.getShape());
1943+
}
1944+
}
1945+
setShape(comp, false);
1946+
}
1947+
else {
1948+
TopoDS_CompSolid comp;
1949+
builder.MakeCompSolid(comp);
1950+
for (auto& s : shapes) {
1951+
if (!s.isNull()) {
1952+
builder.Add(comp, s.getShape());
1953+
}
1954+
}
1955+
setShape(comp, false);
1956+
}
1957+
return true;
1958+
}
1959+
1960+
return false;
1961+
}
1962+
18541963
} // namespace Part

src/Mod/Part/App/TopoShapeMapper.cpp

+101-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,31 @@
1-
#include "PreCompiled.h"
1+
// SPDX-License-Identifier: LGPL-2.1-or-later
2+
/****************************************************************************
3+
* *
4+
* Copyright (c) 2002 Jürgen Riegel <[email protected]> *
5+
* *
6+
* This file is part of FreeCAD. *
7+
* *
8+
* FreeCAD is free software: you can redistribute it and/or modify it *
9+
* under the terms of the GNU Lesser General Public License as *
10+
* published by the Free Software Foundation, either version 2.1 of the *
11+
* License, or (at your option) any later version. *
12+
* *
13+
* FreeCAD is distributed in the hope that it will be useful, but *
14+
* WITHOUT ANY WARRANTY; without even the implied warranty of *
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16+
* Lesser General Public License for more details. *
17+
* *
18+
* You should have received a copy of the GNU Lesser General Public *
19+
* License along with FreeCAD. If not, see *
20+
* <https://www.gnu.org/licenses/>. *
21+
* *
22+
***************************************************************************/
23+
24+
#include <BRep_Tool.hxx>
25+
#include <TopoDS_Edge.hxx>
226

327
#include "TopoShapeMapper.h"
28+
#include "Geometry.h"
429

530
namespace Part
631
{
@@ -96,4 +121,79 @@ void ShapeMapper::insert(MappingStatus status,
96121
}
97122
};
98123

124+
void GenericShapeMapper::init(const TopoShape& src, const TopoDS_Shape& dst)
125+
{
126+
for (TopExp_Explorer exp(dst, TopAbs_FACE); exp.More(); exp.Next()) {
127+
const TopoDS_Shape& dstFace = exp.Current();
128+
if (src.findShape(dstFace)) {
129+
continue;
130+
}
131+
#if OCC_VERSION_HEX < 0x070800
132+
struct TopoDS_ShapeHasher
133+
{
134+
std::size_t operator()(const TopoDS_Shape& key) const
135+
{
136+
return key.HashCode(IntegerLast());
137+
}
138+
};
139+
std::unordered_map<TopoDS_Shape, int, TopoDS_ShapeHasher> map;
140+
#else
141+
std::unordered_map<TopoDS_Shape, int> map;
142+
#endif
143+
bool found = false;
144+
145+
// Try to find a face in the src that shares at least two edges (or one
146+
// closed edge) with dstFace.
147+
// TODO: consider degenerative cases of two or more edges on the same line.
148+
for (TopExp_Explorer it(dstFace, TopAbs_EDGE); it.More(); it.Next()) {
149+
int idx = src.findShape(it.Current());
150+
if (!idx) {
151+
continue;
152+
}
153+
TopoDS_Edge e = TopoDS::Edge(it.Current());
154+
if (BRep_Tool::IsClosed(e)) {
155+
// closed edge, one face is enough
156+
TopoDS_Shape face =
157+
src.findAncestorShape(src.getSubShape(TopAbs_EDGE, idx), TopAbs_FACE);
158+
if (!face.IsNull()) {
159+
this->insert(MappingStatus::Generated, face, dstFace);
160+
found = true;
161+
break;
162+
}
163+
continue;
164+
}
165+
for (auto& face :
166+
src.findAncestorsShapes(src.getSubShape(TopAbs_EDGE, idx), TopAbs_FACE)) {
167+
int& cnt = map[face];
168+
if (++cnt == 2) {
169+
this->insert(MappingStatus::Generated, face, dstFace);
170+
found = true;
171+
break;
172+
}
173+
if (found) {
174+
break;
175+
}
176+
}
177+
}
178+
179+
if (found) {
180+
continue;
181+
}
182+
183+
// if no face matches, try search by geometry surface
184+
std::unique_ptr<Geometry> g(Geometry::fromShape(dstFace));
185+
if (!g) {
186+
continue;
187+
}
188+
189+
for (auto& v : map) {
190+
std::unique_ptr<Geometry> g2(Geometry::fromShape(v.first));
191+
if (g2 && g2->isSame(*g, 1e-7, 1e-12)) {
192+
this->insert(MappingStatus::Generated, v.first, dstFace);
193+
break;
194+
}
195+
}
196+
}
197+
}
198+
99199
} // namespace Part

0 commit comments

Comments
 (0)