|
27 | 27 | #ifndef _PreComp_
|
28 | 28 | #include <cmath>
|
29 | 29 |
|
| 30 | +#include <BRepAdaptor_Curve.hxx> |
| 31 | +#include <BRepAdaptor_CompCurve.hxx> |
| 32 | +# if OCC_VERSION_HEX < 0x070600 |
| 33 | +# include <BRepAdaptor_HCurve.hxx> |
| 34 | +# include <BRepAdaptor_HCompCurve.hxx> |
| 35 | +# endif |
30 | 36 |
|
31 | 37 | #include <BRepBuilderAPI_MakeWire.hxx>
|
32 | 38 | #include <BRepCheck_Analyzer.hxx>
|
| 39 | +#include <BRepFill.hxx> |
33 | 40 | #include <BRepFill_Generator.hxx>
|
34 | 41 | #include <BRepTools.hxx>
|
35 | 42 | #include <BRep_Builder.hxx>
|
|
77 | 84 |
|
78 | 85 | FC_LOG_LEVEL_INIT("TopoShape", true, true) // NOLINT
|
79 | 86 |
|
| 87 | +#if OCC_VERSION_HEX >= 0x070600 |
| 88 | +using Adaptor3d_HCurve = Adaptor3d_Curve; |
| 89 | +using BRepAdaptor_HCurve = BRepAdaptor_Curve; |
| 90 | +using BRepAdaptor_HCompCurve = BRepAdaptor_CompCurve; |
| 91 | +#endif |
| 92 | + |
80 | 93 | namespace Part
|
81 | 94 | {
|
82 | 95 |
|
@@ -1653,6 +1666,154 @@ TopoShape TopoShape::getSubTopoShape(TopAbs_ShapeEnum type, int idx, bool silent
|
1653 | 1666 | return shapeMap.getTopoShape(*this, idx);
|
1654 | 1667 | }
|
1655 | 1668 |
|
| 1669 | +TopoShape& TopoShape::makeElementRuledSurface(const std::vector<TopoShape>& shapes, |
| 1670 | + int orientation, |
| 1671 | + const char* op) |
| 1672 | +{ |
| 1673 | + if (!op) { |
| 1674 | + op = Part::OpCodes::RuledSurface; |
| 1675 | + } |
| 1676 | + |
| 1677 | + if (shapes.size() != 2) { |
| 1678 | + FC_THROWM(Base::CADKernelError, "Wrong number of input shapes"); |
| 1679 | + } |
| 1680 | + |
| 1681 | + std::vector<TopoShape> curves(2); |
| 1682 | + int i = 0; |
| 1683 | + for (auto& s : shapes) { |
| 1684 | + if (s.isNull()) { |
| 1685 | + FC_THROWM(NullShapeException, "Null input shape"); |
| 1686 | + } |
| 1687 | + auto type = s.shapeType(); |
| 1688 | + if (type == TopAbs_WIRE || type == TopAbs_EDGE) { |
| 1689 | + curves[i++] = s; |
| 1690 | + continue; |
| 1691 | + } |
| 1692 | + auto countOfWires = s.countSubShapes(TopAbs_WIRE); |
| 1693 | + if (countOfWires > 1) { |
| 1694 | + FC_THROWM(Base::CADKernelError, "Input shape has more than one wire"); |
| 1695 | + } |
| 1696 | + if (countOfWires == 1) { |
| 1697 | + curves[i++] = s.getSubTopoShape(TopAbs_WIRE, 1); |
| 1698 | + continue; |
| 1699 | + } |
| 1700 | + auto countOfEdges = s.countSubShapes(TopAbs_EDGE); |
| 1701 | + if (countOfEdges == 0) { |
| 1702 | + FC_THROWM(Base::CADKernelError, "Input shape has no edge"); |
| 1703 | + } |
| 1704 | + if (countOfEdges == 1) { |
| 1705 | + curves[i++] = s.getSubTopoShape(TopAbs_EDGE, 1); |
| 1706 | + continue; |
| 1707 | + } |
| 1708 | + curves[i] = s.makeElementWires(); |
| 1709 | + if (curves[i].isNull()) { |
| 1710 | + FC_THROWM(NullShapeException, "Null input shape"); |
| 1711 | + } |
| 1712 | + if (curves[i].shapeType() != TopAbs_WIRE) { |
| 1713 | + FC_THROWM(Base::CADKernelError, "Input shape forms more than one wire"); |
| 1714 | + } |
| 1715 | + ++i; |
| 1716 | + } |
| 1717 | + |
| 1718 | + if (curves[0].shapeType() != curves[1].shapeType()) { |
| 1719 | + for (auto& curve : curves) { |
| 1720 | + if (curve.shapeType() == TopAbs_EDGE) { |
| 1721 | + curve = curve.makeElementWires(); |
| 1722 | + } |
| 1723 | + } |
| 1724 | + } |
| 1725 | + |
| 1726 | + auto& S1 = curves[0]; |
| 1727 | + auto& S2 = curves[1]; |
| 1728 | + bool isWire = S1.shapeType() == TopAbs_WIRE; |
| 1729 | + |
| 1730 | + // https://forum.freecadweb.org/viewtopic.php?f=8&t=24052 |
| 1731 | + // |
| 1732 | + // if both shapes are sub-elements of one common shape then the fill |
| 1733 | + // algorithm leads to problems if the shape has set a placement. The |
| 1734 | + // workaround is to copy the sub-shape |
| 1735 | + S1 = S1.makeElementCopy(); |
| 1736 | + S2 = S2.makeElementCopy(); |
| 1737 | + |
| 1738 | + if (orientation == 0) { |
| 1739 | + // Automatic |
| 1740 | + Handle(Adaptor3d_HCurve) a1; |
| 1741 | + Handle(Adaptor3d_HCurve) a2; |
| 1742 | + if (!isWire) { |
| 1743 | + BRepAdaptor_HCurve adapt1(TopoDS::Edge(S1.getShape())); |
| 1744 | + BRepAdaptor_HCurve adapt2(TopoDS::Edge(S2.getShape())); |
| 1745 | + a1 = new BRepAdaptor_HCurve(adapt1); |
| 1746 | + a2 = new BRepAdaptor_HCurve(adapt2); |
| 1747 | + } |
| 1748 | + else { |
| 1749 | + BRepAdaptor_HCompCurve adapt1(TopoDS::Wire(S1.getShape())); |
| 1750 | + BRepAdaptor_HCompCurve adapt2(TopoDS::Wire(S2.getShape())); |
| 1751 | + a1 = new BRepAdaptor_HCompCurve(adapt1); |
| 1752 | + a2 = new BRepAdaptor_HCompCurve(adapt2); |
| 1753 | + } |
| 1754 | + |
| 1755 | + if (!a1.IsNull() && !a2.IsNull()) { |
| 1756 | + // get end points of 1st curve |
| 1757 | + gp_Pnt p1 = a1->Value(a1->FirstParameter()); |
| 1758 | + gp_Pnt p2 = a1->Value(a1->LastParameter()); |
| 1759 | + if (S1.getShape().Orientation() == TopAbs_REVERSED) { |
| 1760 | + std::swap(p1, p2); |
| 1761 | + } |
| 1762 | + |
| 1763 | + // get end points of 2nd curve |
| 1764 | + gp_Pnt p3 = a2->Value(a2->FirstParameter()); |
| 1765 | + gp_Pnt p4 = a2->Value(a2->LastParameter()); |
| 1766 | + if (S2.getShape().Orientation() == TopAbs_REVERSED) { |
| 1767 | + std::swap(p3, p4); |
| 1768 | + } |
| 1769 | + |
| 1770 | + // Form two triangles (P1,P2,P3) and (P4,P3,P2) and check their normals. |
| 1771 | + // If the dot product is negative then it's assumed that the resulting face |
| 1772 | + // is twisted, hence the 2nd edge is reversed. |
| 1773 | + gp_Vec v1(p1, p2); |
| 1774 | + gp_Vec v2(p1, p3); |
| 1775 | + gp_Vec n1 = v1.Crossed(v2); |
| 1776 | + |
| 1777 | + gp_Vec v3(p4, p3); |
| 1778 | + gp_Vec v4(p4, p2); |
| 1779 | + gp_Vec n2 = v3.Crossed(v4); |
| 1780 | + |
| 1781 | + if (n1.Dot(n2) < 0) { |
| 1782 | + S2.setShape(S2.getShape().Reversed(), false); |
| 1783 | + } |
| 1784 | + } |
| 1785 | + } |
| 1786 | + else if (orientation == 2) { |
| 1787 | + // Reverse |
| 1788 | + S2.setShape(S2.getShape().Reversed(), false); |
| 1789 | + } |
| 1790 | + |
| 1791 | + TopoDS_Shape ruledShape; |
| 1792 | + if (!isWire) { |
| 1793 | + ruledShape = BRepFill::Face(TopoDS::Edge(S1.getShape()), TopoDS::Edge(S2.getShape())); |
| 1794 | + } |
| 1795 | + else { |
| 1796 | + ruledShape = BRepFill::Shell(TopoDS::Wire(S1.getShape()), TopoDS::Wire(S2.getShape())); |
| 1797 | + } |
| 1798 | + |
| 1799 | + // Both BRepFill::Face() and Shell() modifies the original input edges |
| 1800 | + // without any API to provide relationship to the output edges. So we have |
| 1801 | + // to use searchSubShape() to build the relationship by ourselves. |
| 1802 | + |
| 1803 | + TopoShape res(ruledShape.Located(TopLoc_Location())); |
| 1804 | + std::vector<TopoShape> edges; |
| 1805 | + for (const auto& c : curves) { |
| 1806 | + for (const auto& e : c.getSubTopoShapes(TopAbs_EDGE)) { |
| 1807 | + auto found = res.findSubShapesWithSharedVertex(e); |
| 1808 | + if (found.size() > 0) { |
| 1809 | + found.front().resetElementMap(e.elementMap()); |
| 1810 | + edges.push_back(found.front()); |
| 1811 | + } |
| 1812 | + } |
| 1813 | + } |
| 1814 | + // Use empty mapper and let makeShapeWithElementMap name the created surface with lower elements. |
| 1815 | + return makeShapeWithElementMap(res.getShape(), Mapper(), edges, op); |
| 1816 | +} |
1656 | 1817 |
|
1657 | 1818 | TopoShape& TopoShape::makeElementCompound(const std::vector<TopoShape>& shapes,
|
1658 | 1819 | const char* op,
|
|
0 commit comments