/*************************************************************************** * Copyright (c) 2021 edi * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ #include "PreCompiled.h" #ifndef _PreComp_ # include # include # include # include # include # include #endif //#ifndef _PreComp_ #include # include # include #include #include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include #include #include "DrawGuiUtil.h" #include "MDIViewPage.h" #include "ViewProviderPage.h" #include "TaskLinkDim.h" using namespace TechDrawGui; using namespace TechDraw; using namespace std; //internal helper functions bool _circulation(Base::Vector3d A, Base::Vector3d B, Base::Vector3d C); void _createThreadCircle(std::string Name, TechDraw::DrawViewPart* objFeat, float factor); void _createThreadLines(std::vector SubNames, TechDraw::DrawViewPart* objFeat, float factor); void _setStyleAndWeight(TechDraw::CosmeticEdge* cosEdge, int style, float weight); //=========================================================================== // TechDraw_ExtensionCircleCenterLines //=========================================================================== DEF_STD_CMD_A(CmdTechDrawExtensionCircleCenterLines) CmdTechDrawExtensionCircleCenterLines::CmdTechDrawExtensionCircleCenterLines() : Command("TechDraw_ExtensionCircleCenterLines") { sAppModule = "TechDraw"; sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("Draw circle center lines"); sToolTipText = QT_TR_NOOP("Draw circle center line cross at circles\n\ - select many circles or arcs\n\ - click this button"); sWhatsThis = "TechDraw_ExtensionCircleCenterLines"; sStatusTip = sToolTipText; sPixmap = "TechDraw_ExtensionCircleCenterLines"; } void CmdTechDrawExtensionCircleCenterLines::activated(int iMsg) { Q_UNUSED(iMsg); auto selection = getSelection().getSelectionEx(); if( selection.empty() ) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("TechDraw Circle Centerlines"), QObject::tr("Selection is empty")); return; } auto objFeat = dynamic_cast(selection[0].getObject()); if( objFeat == nullptr ) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("TechDraw Circle Centerlines"), QObject::tr("No object selected")); return; } double scale = objFeat->getScale(); const std::vector SubNames = selection[0].getSubNames(); for (std::string Name : SubNames) { int GeoId = TechDraw::DrawUtil::getIndexFromName(Name); TechDraw::BaseGeom* geom = objFeat->getGeomByIndex(GeoId); std::string GeoType = TechDraw::DrawUtil::getGeomTypeFromName(Name); if (GeoType == "Edge"){ if (geom->geomType == TechDraw::CIRCLE || geom->geomType == TechDraw::ARCOFCIRCLE){ TechDraw::Circle* cgen = static_cast(geom); Base::Vector3d center = cgen->center; center.y = -center.y; float radius = cgen->radius; Base::Vector3d right(center.x+radius+2.0,center.y,0.0); Base::Vector3d top(center.x,center.y+radius+2.0,0.0); Base::Vector3d left(center.x-radius-2.0,center.y,0.0); Base::Vector3d bottom(center.x,center.y-radius-2.0,0.0); std::string line1tag = objFeat->addCosmeticEdge(right/scale, left/scale); std::string line2tag = objFeat->addCosmeticEdge(top/scale, bottom/scale); TechDraw::CosmeticEdge* horiz = objFeat->getCosmeticEdge(line1tag); _setStyleAndWeight(horiz,4,0.35); TechDraw::CosmeticEdge* vert = objFeat->getCosmeticEdge(line2tag); _setStyleAndWeight(vert,4,0.35); } } } getSelection().clearSelection(); objFeat->refreshCEGeoms(); objFeat->requestPaint(); } bool CmdTechDrawExtensionCircleCenterLines::isActive(void) { bool havePage = DrawGuiUtil::needPage(this); bool haveView = DrawGuiUtil::needView(this); return (havePage && haveView); } //=========================================================================== // TechDraw_ExtensionThreadHoleSide //=========================================================================== DEF_STD_CMD_A(CmdTechDrawExtensionThreadHoleSide) CmdTechDrawExtensionThreadHoleSide::CmdTechDrawExtensionThreadHoleSide() : Command("TechDraw_ExtensionThreadHoleSide") { sAppModule = "TechDraw"; sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("Cosmetic thread hole side view"); sToolTipText = QT_TR_NOOP("Draw cosmetic thread hole side view\n\ - select two parallel lines\n\ - click this button"); sWhatsThis = "TechDraw_ExtensionThreadHoleSide"; sStatusTip = sToolTipText; sPixmap = "TechDraw_ExtensionThreadHoleSide"; } void CmdTechDrawExtensionThreadHoleSide::activated(int iMsg) { Q_UNUSED(iMsg); auto selection = getSelection().getSelectionEx(); if( selection.empty() ) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("TechDraw Thread Hole Side"), QObject::tr("Selection is empty")); return; } TechDraw::DrawViewPart* objFeat = dynamic_cast(selection[0].getObject()); if( objFeat == nullptr ) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("TechDraw Thread Hole Side"), QObject::tr("No object selected")); return; } const std::vector SubNames = selection[0].getSubNames(); if (SubNames.size() >= 2) { _createThreadLines(SubNames, objFeat, 1.176); } getSelection().clearSelection(); objFeat->refreshCEGeoms(); objFeat->requestPaint(); } bool CmdTechDrawExtensionThreadHoleSide::isActive(void) { bool havePage = DrawGuiUtil::needPage(this); bool haveView = DrawGuiUtil::needView(this); return (havePage && haveView); } //=========================================================================== // TechDraw_ExtensionThreadBoltSide //=========================================================================== DEF_STD_CMD_A(CmdTechDrawExtensionThreadBoltSide) CmdTechDrawExtensionThreadBoltSide::CmdTechDrawExtensionThreadBoltSide() : Command("TechDraw_ExtensionThreadBoltSide") { sAppModule = "TechDraw"; sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("Cosmetic thread bolt side view"); sToolTipText = QT_TR_NOOP("Draw cosmetic screw thread side view\n\ - select two parallel lines\n\ - click this button"); sWhatsThis = "TechDraw_ExtensionThreadBoltSide"; sStatusTip = sToolTipText; sPixmap = "TechDraw_ExtensionThreadBoltSide"; } void CmdTechDrawExtensionThreadBoltSide::activated(int iMsg) { Q_UNUSED(iMsg); auto selection = getSelection().getSelectionEx(); if( selection.empty() ) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("TechDraw Thread Bolt Side"), QObject::tr("Selection is empty")); return; } TechDraw::DrawViewPart* objFeat = dynamic_cast(selection[0].getObject()); if( objFeat == nullptr ) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("TechDraw Thread Bolt Side"), QObject::tr("No object selected")); return; } const std::vector SubNames = selection[0].getSubNames(); if (SubNames.size() >= 2) { _createThreadLines(SubNames, objFeat, 0.85); } getSelection().clearSelection(); objFeat->refreshCEGeoms(); objFeat->requestPaint(); } bool CmdTechDrawExtensionThreadBoltSide::isActive(void) { bool havePage = DrawGuiUtil::needPage(this); bool haveView = DrawGuiUtil::needView(this); return (havePage && haveView); } //=========================================================================== // TechDraw_ExtensionThreadHoleBottom //=========================================================================== DEF_STD_CMD_A(CmdTechDrawExtensionThreadHoleBottom) CmdTechDrawExtensionThreadHoleBottom::CmdTechDrawExtensionThreadHoleBottom() : Command("TechDraw_ExtensionThreadHoleBottom") { sAppModule = "TechDraw"; sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("Cosmetic thread hole bottom view"); sToolTipText = QT_TR_NOOP("Draw cosmetic hole thread ground view\n\ - select many circles\n\ - click this button"); sWhatsThis = "TechDraw_ExtensionThreadHoleBottom"; sStatusTip = sToolTipText; sPixmap = "TechDraw_ExtensionThreadHoleBottom"; } void CmdTechDrawExtensionThreadHoleBottom::activated(int iMsg) { Q_UNUSED(iMsg); auto selection = getSelection().getSelectionEx(); if( selection.empty() ) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("TechDraw Thread Hole Bottom"), QObject::tr("Selection is empty")); return; } auto objFeat = dynamic_cast(selection[0].getObject()); if( objFeat == nullptr ) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("TechDraw Thread Hole Bottom"), QObject::tr("No object selected")); return; } const std::vector SubNames = selection[0].getSubNames(); for (std::string Name : SubNames) { _createThreadCircle(Name, objFeat, 1.177); } getSelection().clearSelection(); objFeat->refreshCEGeoms(); objFeat->requestPaint(); } bool CmdTechDrawExtensionThreadHoleBottom::isActive(void) { bool havePage = DrawGuiUtil::needPage(this); bool haveView = DrawGuiUtil::needView(this); return (havePage && haveView); } //=========================================================================== // TechDraw_ExtensionThreadBoltBottom //=========================================================================== DEF_STD_CMD_A(CmdTechDrawExtensionThreadBoltBottom) CmdTechDrawExtensionThreadBoltBottom::CmdTechDrawExtensionThreadBoltBottom() : Command("TechDraw_ExtensionThreadBoltBottom") { sAppModule = "TechDraw"; sGroup = QT_TR_NOOP("TechDraw"); sMenuText = QT_TR_NOOP("Cosmetic thread bolt bottom view"); sToolTipText = QT_TR_NOOP("Draw cosmetic screw thread ground view\n\ - select many circles\n\ - click this button"); sWhatsThis = "TechDraw_ExtensionThreadBoltBottom"; sStatusTip = sToolTipText; sPixmap = "TechDraw_ExtensionThreadBoltBottom"; } void CmdTechDrawExtensionThreadBoltBottom::activated(int iMsg) { Q_UNUSED(iMsg); auto selection = getSelection().getSelectionEx(); if( selection.empty() ) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("TechDraw Tread Bolt Bottom"), QObject::tr("Selection is empty")); return; } auto objFeat = dynamic_cast(selection[0].getObject()); if( objFeat == nullptr ) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("TechDraw Tread Bolt Bottom"), QObject::tr("No object selected")); return; } const std::vector SubNames = selection[0].getSubNames(); for (std::string Name : SubNames) { _createThreadCircle(Name, objFeat, 0.85); } getSelection().clearSelection(); objFeat->refreshCEGeoms(); objFeat->requestPaint(); } bool CmdTechDrawExtensionThreadBoltBottom::isActive(void) { bool havePage = DrawGuiUtil::needPage(this); bool haveView = DrawGuiUtil::needView(this); return (havePage && haveView); } //=========================================================================== // internal helper routines //=========================================================================== bool _circulation(Base::Vector3d A, Base::Vector3d B, Base::Vector3d C){ // test the circulation of the triangle A-B-C if (A.x*B.y+A.y*C.x+B.x*C.y-C.x*B.y-C.y*A.x-B.x*A.y > 0.0) return true; else return false; } void _createThreadCircle(std::string Name, TechDraw::DrawViewPart* objFeat, float factor){ // create the 3/4 arc symbolizing a thread from top seen double scale = objFeat->getScale(); int GeoId = TechDraw::DrawUtil::getIndexFromName(Name); TechDraw::BaseGeom* geom = objFeat->getGeomByIndex(GeoId); std::string GeoType = TechDraw::DrawUtil::getGeomTypeFromName(Name); if (GeoType == "Edge"){ if (geom->geomType == TechDraw::CIRCLE){ TechDraw::Circle* cgen = static_cast(geom); Base::Vector3d center = cgen->center; float radius = cgen->radius; TechDraw::BaseGeom* threadArc = new TechDraw::AOC(center/scale, radius*factor/scale, 255.0, 165.0); std::string arcTag = objFeat->addCosmeticEdge(threadArc); TechDraw::CosmeticEdge* arc = objFeat->getCosmeticEdge(arcTag); _setStyleAndWeight(arc,1,0.35); } } } void _createThreadLines(std::vector SubNames, TechDraw::DrawViewPart* objFeat, float factor){ // create symbolizing lines of a thread from the side seen double scale = objFeat->getScale(); std::string GeoType0 = TechDraw::DrawUtil::getGeomTypeFromName(SubNames[0]); std::string GeoType1 = TechDraw::DrawUtil::getGeomTypeFromName(SubNames[1]); if ((GeoType0 == "Edge") && (GeoType1 == "Edge")) { int GeoId0 = TechDraw::DrawUtil::getIndexFromName(SubNames[0]); int GeoId1 = TechDraw::DrawUtil::getIndexFromName(SubNames[1]); TechDraw::BaseGeom* geom0 = objFeat->getGeomByIndex(GeoId0); TechDraw::BaseGeom* geom1 = objFeat->getGeomByIndex(GeoId1); if ((geom0->geomType == TechDraw::GENERIC) && (geom1->geomType == TechDraw::GENERIC)) { TechDraw::Generic* line0 = static_cast(geom0); TechDraw::Generic* line1 = static_cast(geom1); Base::Vector3d start0 = line0->points.at(0); Base::Vector3d end0 = line0->points.at(1); Base::Vector3d start1 = line1->points.at(0); Base::Vector3d end1 = line1->points.at(1); if (_circulation(start0,end0,start1) != _circulation(end0,end1,start1)) { Base::Vector3d help1 = start1; Base::Vector3d help2 = end1; start1 = help2; end1 = help1; } start0.y = -start0.y; end0.y = -end0.y; start1.y = -start1.y; end1.y = -end1.y; float kernelDiam = (start1-start0).Length(); float kernelFactor = (kernelDiam*factor-kernelDiam)/2; Base::Vector3d delta = (start1-start0).Normalize()*kernelFactor; std::string line0Tag = objFeat->addCosmeticEdge((start0-delta)/scale, (end0-delta)/scale); std::string line1Tag = objFeat->addCosmeticEdge((start1+delta)/scale, (end1+delta)/scale); TechDraw::CosmeticEdge* cosTag0 = objFeat->getCosmeticEdge(line0Tag); TechDraw::CosmeticEdge* cosTag1 = objFeat->getCosmeticEdge(line1Tag); _setStyleAndWeight(cosTag0,1,0.35); _setStyleAndWeight(cosTag1,1,0.35); } else { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("TechDraw Thread Hole Side"), QObject::tr("Please select two straight lines")); return; } } } void _setStyleAndWeight(TechDraw::CosmeticEdge* cosEdge, int style, float weight) { // set style and weight of a cosmetic edge cosEdge->m_format.m_style = style; cosEdge->m_format.m_weight = weight; } //------------------------------------------------------------------------------ void CreateTechDrawCommandsExtensions(void) { Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); rcCmdMgr.addCommand(new CmdTechDrawExtensionCircleCenterLines()); rcCmdMgr.addCommand(new CmdTechDrawExtensionThreadHoleSide()); rcCmdMgr.addCommand(new CmdTechDrawExtensionThreadBoltSide()); rcCmdMgr.addCommand(new CmdTechDrawExtensionThreadHoleBottom()); rcCmdMgr.addCommand(new CmdTechDrawExtensionThreadBoltBottom()); }