#include "FITKOCCModelSolid.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "FITKOCCVirtualTopoCreator.h" #include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h" #include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h" #include "FITK_Interface/FITKInterfaceGeometry/FITKGeoCommandList.h" #include "FITK_Interface/FITKInterfaceGeometry/FITKGeoInterfaceFactory.h" #include "FITK_Interface/FITKInterfaceGeometry/FITKAbsGeoModelSurface.h" #include namespace { struct CWire { Bnd_Box Bound; BRepBuilderAPI_MakeWire MakeWire{}; gp_Pnt Start{}; gp_Pnt End{}; bool isNull() { return MakeWire.Edge().IsNull(); } bool isClosed() { return MakeWire.Shape().Closed(); } }; } namespace OCC { FITKOCCModelClosedSurfaceSolid::FITKOCCModelClosedSurfaceSolid() : OCCShapeAgent(this) { _shapeAgent = _occShapeAgent; } bool FITKOCCModelClosedSurfaceSolid::update() { if (m_Faces.isEmpty()) return false; auto geoCmdList = FITKGLODATA->getGeometryData(); BRepBuilderAPI_Sewing sewing; for (int i = 0; i < m_Faces.size(); ++i) { auto face = m_Faces.at(i); if (face.isNull()) continue; auto cmd = geoCmdList->getDataByID(face.CmdId); if (cmd == nullptr) { printLog(tr("Failed to get geometry command."), 3); return false; } auto vshape = cmd->getShapeT(Interface::FITKGeoEnum::VTopoShapeType::VSFace, face.VirtualTopoId); if (vshape == nullptr) { printLog(tr("Failed to get face from virtual topo."), 3); return false; } auto topoShape = vshape->getTopoShape(); if (topoShape.ShapeType() == TopAbs_ShapeEnum::TopAbs_FACE) { TopoDS_Face f = TopoDS::Face(topoShape); if (f.IsNull()) continue; if (f.Orientation() == TopAbs_Orientation::TopAbs_REVERSED) { f.Reverse(); } sewing.Add(f); } else { printLog(tr("Error topo shape type for make wire."), 3); return false; } } sewing.Perform(); auto type = sewing.SewedShape().ShapeType(); /*if (type == TopAbs_COMPOUND) { TopoDS_Builder aShellBuilder; TopoDS_Shell aShell; aShellBuilder.MakeShell(aShell); int faceCount = 0; int edgeCount = 0; for (TopoDS_Iterator anExp(sewing.SewedShape()); anExp.More(); anExp.Next()) { const TopoDS_Shape &curShape1 = anExp.Value(); TopAbs_ShapeEnum type1 = curShape1.ShapeType(); if (type1 == TopAbs_SHELL) { for (TopExp_Explorer anExp(curShape1, TopAbs_FACE); anExp.More(); anExp.Next()) { const TopoDS_Shape &curShape2 = anExp.Current(); aShellBuilder.Add(aShell, curShape2); faceCount++; } } } }*/ if (type != TopAbs_SHELL) { printLog(tr("Error topo shape type for make wire."), 3); return false; } try { TopoDS_Shell shell = TopoDS::Shell(sewing.SewedShape()); if (shell.IsNull() || !shell.Closed()) { printLog(tr("Must be closed shell."), 3); return false; } BRepBuilderAPI_MakeSolid solid(shell); if (!solid.IsDone()) { printLog(tr("Error topo shape type for make wire."), 3); return false; } _occShapeAgent->updateShape(solid.Shape()); } catch (...) { printLog(tr("Failed to make solid!"), 3); return false; } return true; } FITKOCCModelExtrudeSolid::FITKOCCModelExtrudeSolid() : OCCShapeAgent(this) { _shapeAgent = _occShapeAgent; } bool FITKOCCModelExtrudeSolid::update() { auto geoCmdList = FITKGLODATA->getGeometryData(); auto cmd = geoCmdList->getDataByID(m_SourceSurface.CmdId); if (cmd == nullptr) return false; Interface::FITKGeoEnum::VTopoShapeType type = cmd->getGeometryCommandType() == Interface::FITKGeoEnum::FITKGeometryComType::FGTSketch2D ? Interface::FITKGeoEnum::VTopoShapeType::VSAssembly : Interface::FITKGeoEnum::VTopoShapeType::VSFace; auto shape = cmd->getShapeT(type, m_SourceSurface.VirtualTopoId); if (shape == nullptr) return false; auto topoShape = shape->getTopoShape(); gp_Vec dir(m_Direction[0], m_Direction[1], m_Direction[2]); auto mag = dir.Magnitude(); if (mag <= Precision::Confusion()) { printLog(tr("The direction cannot be a zero vector!"), 3); return false; } dir = dir * m_Length / mag; try { // 如果是草绘则返回的是线的组合体,需要合并面 if (topoShape.ShapeType() == TopAbs_ShapeEnum::TopAbs_COMPOUND) { TopoDS_Compound compound = TopoDS::Compound(topoShape); TopExp_Explorer exp; QList wiresList{}; // 按封闭曲线分组 for (exp.Init(compound, TopAbs_EDGE); exp.More(); exp.Next()) { TopoDS_Edge edge = TopoDS::Edge(exp.Current()); if (edge.IsNull()) continue; Standard_Real first; Standard_Real last; Handle(Geom_Curve) curve = BRep_Tool::Curve(edge, first, last); gp_Pnt start = curve->Value(first); gp_Pnt end = curve->Value(last); /* 自成封闭的曲线 */ /* @{ */ if (start.Distance(end) < Precision::Confusion()) { CWire w; w.MakeWire.Add(edge); w.Start = start; w.End = end; wiresList.push_back(w); continue; } /* @} */ /* 是否能拼接到已有曲线 */ /* @{ */ bool isSep{ true }; for (auto& wire : wiresList) { // 已经闭合的曲线不参与比较 if (wire.isClosed()) continue; if (wire.Start.Distance(start) < Precision::Confusion()) { wire.MakeWire.Add(edge); wire.Start = end; isSep = false; break; } else if (wire.Start.Distance(end) < Precision::Confusion()) { wire.MakeWire.Add(edge); wire.Start = start; isSep = false; break; } else if (wire.End.Distance(start) < Precision::Confusion()) { wire.MakeWire.Add(edge); wire.End = end; isSep = false; break; } else if (wire.End.Distance(end) < Precision::Confusion()) { wire.MakeWire.Add(edge); wire.End = start; isSep = false; break; } else { printLog(QString("wire.Start: [%1, %2, %3]; wire.End: [%4, %5, %6]").arg(wire.Start.X()).arg(wire.Start.Y()).arg(wire.Start.Z()).arg(wire.End.X()).arg(wire.End.Y()).arg(wire.End.Z()), 2); printLog(QString("Start: [%1, %2, %3]; End: [%4, %5, %6]").arg(start.X()).arg(start.Y()).arg(start.Z()).arg(end.X()).arg(end.Y()).arg(end.Z()), 2); } } /* @} */ // 如果能连接到已有曲线,则分析下一条边 if (!isSep) continue; // 如果不能连接到已有曲线,则自成一条新的曲线 else { CWire w; w.MakeWire.Add(edge); w.Start = start; w.End = end; wiresList.push_back(w); continue; } } // 检测封闭性,计算包围盒 for (auto wire : wiresList) { if (!wire.isClosed()) { printLog(tr("The selected sketch contains several open profile."), 3); return false; } else { BRepBndLib::Add(wire.MakeWire.Shape(), wire.Bound); } } /* 按包围盒大小排序 */ /* @{ */ for (int i = 0; i < wiresList.size() - 1; ++i) { int n = i; while (n >= 0 && wiresList.at(n).Bound.IsOut(wiresList.at(n + 1).Bound)) { auto temp = wiresList.at(n); wiresList[n] = wiresList[n + 1]; wiresList[n + 1] = temp; n--; } } /* @} */ // 初始化组合对象。 BRep_Builder builder; TopoDS_Compound compoundSolid; builder.MakeCompound(compoundSolid); auto count = wiresList.size(); for (int i = 0; i < count; ++i) { auto wire = wiresList.at(i); BRepBuilderAPI_MakeFace face(wire.MakeWire, true); if (count > i + 1) { CWire cwire = wiresList.at(i + 1); TopoDS_Shape innerShape = cwire.MakeWire.Shape(); if (innerShape.ShapeType() != TopAbs_WIRE) return false; TopoDS_Wire innerWire = TopoDS::Wire(innerShape); if (innerWire.IsNull()) return false; innerWire.Reverse(); face.Add(innerWire); ++i; } face.Build(); if (!face.IsDone()) return false; builder.Add(compoundSolid, BRepPrimAPI_MakePrism(face, dir).Shape()); } _occShapeAgent->updateShape(compoundSolid); } else { _occShapeAgent->updateShape(BRepPrimAPI_MakePrism(topoShape, dir).Shape()); } } catch (...) { printLog(tr("Failed to make solid!"), 3); return false; } return true; } FITKOCCModelRevolSolid::FITKOCCModelRevolSolid() : OCCShapeAgent(this) { _shapeAgent = _occShapeAgent; } bool FITKOCCModelRevolSolid::update() { auto geoCmdList = FITKGLODATA->getGeometryData(); auto cmd = geoCmdList->getDataByID(m_SourceSurface.CmdId); if (cmd == nullptr) return false; Interface::FITKGeoEnum::VTopoShapeType type = cmd->getGeometryCommandType() == Interface::FITKGeoEnum::FITKGeometryComType::FGTSketch2D ? Interface::FITKGeoEnum::VTopoShapeType::VSAssembly : Interface::FITKGeoEnum::VTopoShapeType::VSFace; auto vshape = cmd->getShapeT(type, m_SourceSurface.VirtualTopoId); if (vshape == nullptr) return false; auto topoShape = vshape->getTopoShape(); //m_OriginId; gp_Ax1 ax1( gp_Pnt(m_RotateAxisPoint1[0], m_RotateAxisPoint1[1], m_RotateAxisPoint1[2]), gp_Dir(m_RotateAxisPoint2[0] - m_RotateAxisPoint1[0], m_RotateAxisPoint2[1] - m_RotateAxisPoint1[1], m_RotateAxisPoint2[2] - m_RotateAxisPoint1[2])); try { // 如果是草绘则返回的是线的组合体,需要合并面 if (topoShape.ShapeType() == TopAbs_ShapeEnum::TopAbs_COMPOUND) { TopoDS_Compound compound = TopoDS::Compound(topoShape); TopExp_Explorer exp; QList wiresList{}; // 按封闭曲线分组 for (exp.Init(compound, TopAbs_EDGE); exp.More(); exp.Next()) { TopoDS_Edge edge = TopoDS::Edge(exp.Current()); if (edge.IsNull()) continue; Standard_Real first; Standard_Real last; Handle(Geom_Curve) curve = BRep_Tool::Curve(edge, first, last); gp_Pnt start = curve->Value(first); gp_Pnt end = curve->Value(last); /* 自成封闭的曲线 */ /* @{ */ if (start.Distance(end) < Precision::Confusion()) { CWire w; w.MakeWire.Add(edge); w.Start = start; w.End = end; wiresList.push_back(w); continue; } /* @} */ /* 是否能拼接到已有曲线 */ /* @{ */ bool isSep{ true }; for (auto& wire : wiresList) { // 已经闭合的曲线不参与比较 if (wire.isClosed()) continue; if (wire.Start.Distance(start) < Precision::Confusion()) { wire.MakeWire.Add(edge); wire.Start = end; isSep = false; break; } else if (wire.Start.Distance(end) < Precision::Confusion()) { wire.MakeWire.Add(edge); wire.Start = start; isSep = false; break; } else if (wire.End.Distance(start) < Precision::Confusion()) { wire.MakeWire.Add(edge); wire.End = end; isSep = false; break; } else if (wire.End.Distance(end) < Precision::Confusion()) { wire.MakeWire.Add(edge); wire.End = start; isSep = false; break; } else { printLog(QString("wire.Start: [%1, %2, %3]; wire.End: [%4, %5, %6]").arg(wire.Start.X()).arg(wire.Start.Y()).arg(wire.Start.Z()).arg(wire.End.X()).arg(wire.End.Y()).arg(wire.End.Z()), 2); printLog(QString("Start: [%1, %2, %3]; End: [%4, %5, %6]").arg(start.X()).arg(start.Y()).arg(start.Z()).arg(end.X()).arg(end.Y()).arg(end.Z()), 2); } } /* @} */ // 如果能连接到已有曲线,则分析下一条边 if (!isSep) continue; // 如果不能连接到已有曲线,则自成一条新的曲线 else { CWire w; w.MakeWire.Add(edge); w.Start = start; w.End = end; wiresList.push_back(w); continue; } } // 检测封闭性,计算包围盒 for (auto wire : wiresList) { if (!wire.isClosed()) { printLog(tr("The selected sketch contains several open profile."), 3); return false; } else { BRepBndLib::Add(wire.MakeWire.Shape(), wire.Bound); } } /* 按包围盒大小排序 */ /* @{ */ for (int i = 0; i < wiresList.size() - 1; ++i) { int n = i; while (n >= 0 && wiresList.at(n).Bound.IsOut(wiresList.at(n + 1).Bound)) { auto temp = wiresList.at(n); wiresList[n] = wiresList[n + 1]; wiresList[n + 1] = temp; n--; } } /* @} */ // 初始化组合对象。 BRep_Builder builder; TopoDS_Compound compoundSolid; builder.MakeCompound(compoundSolid); auto count = wiresList.size(); for (int i = 0; i < count; ++i) { auto wire = wiresList.at(i); BRepBuilderAPI_MakeFace face(wire.MakeWire, true); if (count > i + 1) { CWire cwire = wiresList.at(i + 1); TopoDS_Shape innerShape = cwire.MakeWire.Shape(); if (innerShape.ShapeType() != TopAbs_WIRE) return false; TopoDS_Wire innerWire = TopoDS::Wire(innerShape); if (innerWire.IsNull()) return false; innerWire.Reverse(); face.Add(innerWire); ++i; } face.Build(); if (!face.IsDone()) return false; builder.Add(compoundSolid, BRepPrimAPI_MakeRevol(face, ax1, m_Angle * M_PI / 180).Shape()); } _occShapeAgent->updateShape(compoundSolid); } else { _occShapeAgent->updateShape(BRepPrimAPI_MakeRevol(topoShape, ax1, m_Angle * M_PI / 180).Shape()); } } catch (...) { printLog(tr("Failed to make solid!"), 3); return false; } return true; } FITKOCCModelSweepSolid::FITKOCCModelSweepSolid() : OCCShapeAgent(this) { _shapeAgent = _occShapeAgent; } bool FITKOCCModelSweepSolid::update() { auto geoCmdList = FITKGLODATA->getGeometryData(); auto profileCmd = geoCmdList->getDataByID(m_Profile.CmdId); auto curveCmd = geoCmdList->getDataByID(m_Curve.CmdId); if (profileCmd == nullptr || curveCmd == nullptr) return false; Interface::FITKGeoEnum::VTopoShapeType profileType = profileCmd->getGeometryCommandType() == Interface::FITKGeoEnum::FITKGeometryComType::FGTSketch2D ? Interface::FITKGeoEnum::VTopoShapeType::VSAssembly : Interface::FITKGeoEnum::VTopoShapeType::VSFace; auto profileShape = profileCmd->getShapeT(profileType, m_Profile.VirtualTopoId); Interface::FITKGeoEnum::VTopoShapeType curveType = curveCmd->getGeometryCommandType() == Interface::FITKGeoEnum::FITKGeometryComType::FGTSketch2D ? Interface::FITKGeoEnum::VTopoShapeType::VSAssembly : Interface::FITKGeoEnum::VTopoShapeType::VSEdge; auto curveShape = curveCmd->getShapeT(curveType, m_Curve.VirtualTopoId); if (profileShape == nullptr || curveShape == nullptr) return false; auto profileTopoShape = profileShape->getTopoShape(); auto curveTopoShape = curveShape->getTopoShape(); try { /* 分析扫略线 */ /*@{*/ TopoDS_Wire sweepWire; auto type = curveTopoShape.ShapeType(); if (type == TopAbs_ShapeEnum::TopAbs_WIRE) { sweepWire = TopoDS::Wire(curveTopoShape); } else if (type == TopAbs_ShapeEnum::TopAbs_EDGE) { sweepWire = BRepBuilderAPI_MakeWire(TopoDS::Edge(curveTopoShape)); } else if (type == TopAbs_ShapeEnum::TopAbs_COMPOUND) { TopoDS_Compound compound = TopoDS::Compound(curveTopoShape); TopExp_Explorer exp; BRepBuilderAPI_MakeWire makeWire; for (exp.Init(compound, TopAbs_EDGE); exp.More(); exp.Next()) { TopoDS_Edge edge = TopoDS::Edge(exp.Current()); if (edge.IsNull()) continue; makeWire.Add(edge); } makeWire.Build(); if (!makeWire.IsDone()) return false; sweepWire = TopoDS::Wire(makeWire.Shape()); } else return false; /*@}*/ // 如果是草绘则返回的是线的组合体,需要合并面 if (profileTopoShape.ShapeType() == TopAbs_ShapeEnum::TopAbs_COMPOUND) { TopoDS_Compound compound = TopoDS::Compound(profileTopoShape); TopExp_Explorer exp; QList wiresList{}; // 按封闭曲线分组 for (exp.Init(compound, TopAbs_EDGE); exp.More(); exp.Next()) { TopoDS_Edge edge = TopoDS::Edge(exp.Current()); if (edge.IsNull()) continue; Standard_Real first; Standard_Real last; Handle(Geom_Curve) curve = BRep_Tool::Curve(edge, first, last); gp_Pnt start = curve->Value(first); gp_Pnt end = curve->Value(last); /* 自成封闭的曲线 */ /* @{ */ if (start.Distance(end) < Precision::Confusion()) { CWire w; w.MakeWire.Add(edge); w.Start = start; w.End = end; wiresList.push_back(w); continue; } /* @} */ /* 是否能拼接到已有曲线 */ /* @{ */ bool isSep{ true }; for (auto& wire : wiresList) { // 已经闭合的曲线不参与比较 if (wire.isClosed()) continue; if (wire.Start.Distance(start) < Precision::Confusion()) { wire.MakeWire.Add(edge); wire.Start = end; isSep = false; break; } else if (wire.Start.Distance(end) < Precision::Confusion()) { wire.MakeWire.Add(edge); wire.Start = start; isSep = false; break; } else if (wire.End.Distance(start) < Precision::Confusion()) { wire.MakeWire.Add(edge); wire.End = end; isSep = false; break; } else if (wire.End.Distance(end) < Precision::Confusion()) { wire.MakeWire.Add(edge); wire.End = start; isSep = false; break; } else { printLog(QString("wire.Start: [%1, %2, %3]; wire.End: [%4, %5, %6]").arg(wire.Start.X()).arg(wire.Start.Y()).arg(wire.Start.Z()).arg(wire.End.X()).arg(wire.End.Y()).arg(wire.End.Z()), 2); printLog(QString("Start: [%1, %2, %3]; End: [%4, %5, %6]").arg(start.X()).arg(start.Y()).arg(start.Z()).arg(end.X()).arg(end.Y()).arg(end.Z()), 2); } } /* @} */ // 如果能连接到已有曲线,则分析下一条边 if (!isSep) continue; // 如果不能连接到已有曲线,则自成一条新的曲线 else { CWire w; w.MakeWire.Add(edge); w.Start = start; w.End = end; wiresList.push_back(w); continue; } } // 检测封闭性,计算包围盒 for (auto wire : wiresList) { if (!wire.isClosed()) { printLog(tr("The selected sketch contains several open profile."), 3); return false; } else { BRepBndLib::Add(wire.MakeWire.Shape(), wire.Bound); } } /* 按包围盒大小排序 */ /* @{ */ for (int i = 0; i < wiresList.size() - 1; ++i) { int n = i; while (n >= 0 && wiresList.at(n).Bound.IsOut(wiresList.at(n + 1).Bound)) { auto temp = wiresList.at(n); wiresList[n] = wiresList[n + 1]; wiresList[n + 1] = temp; n--; } } /* @} */ // 初始化组合对象。 BRep_Builder builder; TopoDS_Compound compoundSolid; builder.MakeCompound(compoundSolid); auto count = wiresList.size(); for (int i = 0; i < count; ++i) { auto wire = wiresList.at(i); BRepBuilderAPI_MakeFace face(wire.MakeWire, true); if (count > i + 1) { CWire cwire = wiresList.at(i + 1); TopoDS_Shape innerShape = cwire.MakeWire.Shape(); if (innerShape.ShapeType() != TopAbs_WIRE) return false; TopoDS_Wire innerWire = TopoDS::Wire(innerShape); if (innerWire.IsNull()) return false; innerWire.Reverse(); face.Add(innerWire); ++i; } face.Build(); if (!face.IsDone()) return false; builder.Add(compoundSolid, BRepOffsetAPI_MakePipe(sweepWire, face).Shape()); } _occShapeAgent->updateShape(compoundSolid); } else { BRepOffsetAPI_MakePipe pipe(sweepWire, profileTopoShape); pipe.Build(); if (!pipe.IsDone()) return false; _occShapeAgent->updateShape(pipe.Shape()); } return true; } catch (...) { printLog(tr("Failed to make solid!"), 3); return false; } } FITKOCCModelMultiSectionSolid::FITKOCCModelMultiSectionSolid() : OCCShapeAgent(this) { _shapeAgent = _occShapeAgent; } bool FITKOCCModelMultiSectionSolid::update() { if (m_Sections.size() < 2) return false; auto geoCmdList = FITKGLODATA->getGeometryData(); BRepOffsetAPI_ThruSections thruSection(true); for (auto section : m_Sections) { auto cmd = geoCmdList->getDataByID(section.CmdId); if (cmd == nullptr) return false; Interface::FITKGeoEnum::VTopoShapeType type = cmd->getGeometryCommandType() == Interface::FITKGeoEnum::FITKGeometryComType::FGTSketch2D ? Interface::FITKGeoEnum::VTopoShapeType::VSAssembly : Interface::FITKGeoEnum::VTopoShapeType::VSEdge; auto vshape = cmd->getShapeT(type, section.VirtualTopoId); if (vshape == nullptr) return false; auto topoShape = vshape->getTopoShape(); if (topoShape.ShapeType() == TopAbs_ShapeEnum::TopAbs_EDGE) { BRepLib_MakeWire wire(TopoDS::Edge(topoShape)); thruSection.AddWire(wire.Wire()); } else if (topoShape.ShapeType() == TopAbs_ShapeEnum::TopAbs_WIRE) { thruSection.AddWire(TopoDS::Wire(topoShape)); } else if (topoShape.ShapeType() == TopAbs_ShapeEnum::TopAbs_COMPOUND) { TopExp_Explorer exp; BRepLib_MakeWire wire; // 按封闭曲线分组 for (exp.Init(topoShape, TopAbs_EDGE); exp.More(); exp.Next()) { TopoDS_Edge edge = TopoDS::Edge(exp.Current()); if (edge.IsNull()) continue; wire.Add(edge); } try { wire.Build(); if (!wire.IsDone()) return false; thruSection.AddWire(wire.Wire()); } catch (...) { printLog(tr("Failed to make wire!"), 3); return false; } } } try { thruSection.Build(); if (!thruSection.IsDone()) return false; _occShapeAgent->updateShape(thruSection.Shape()); } catch (...) { printLog(tr("Failed to make solid!"), 3); return false; } return true; } }