add new feature "Projection on surface"

This commit is contained in:
MA-DEVELOP\apeltauer
2019-01-24 10:04:56 +01:00
committed by wmayer
parent d3351496d9
commit 1c5ee376e6
6 changed files with 1644 additions and 40 deletions

View File

@@ -2386,7 +2386,7 @@ CmdPartProjectionOnSurface::CmdPartProjectionOnSurface()
sToolTipText = QT_TR_NOOP("Create projection on surface...");
sWhatsThis = "Part_projectionOnSurface";
sStatusTip = sToolTipText;
sPixmap = "Part_Extrude";
sPixmap = "Part_ProjectionOnSurface";
}
void CmdPartProjectionOnSurface::activated(int iMsg)

View File

@@ -1,31 +1,965 @@
#include "PreCompiled.h"
/***************************************************************************
* Copyright (c) 2019 Manuel Apeltauer, direkt cnc-systeme GmbH *
* *
* 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"
#include "DlgProjectionOnSurface.h"
#include "ui_DlgProjectionOnSurface.h"
#include <Gui/BitmapFactory.h>
#include "Gui/MainWindow.h"
#include "Gui/MDIView.h"
#include "Gui/View3DInventor.h"
#include "Gui/View3DInventorViewer.h"
#include "Inventor/SbVec3d.h"
#include "Gui/Application.h"
#include "ViewProviderExt.h"
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <BRepProj_Projection.hxx>
#include <TopoDS_Builder.hxx>
#include <TopoDS_Edge.hxx>
#include <ShapeAnalysis.hxx>
#include <ShapeAnalysis_FreeBounds.hxx>
#include <ShapeFix_Wire.hxx>
#include <BRep_Tool.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <Geom_TrimmedCurve.hxx>
#include <GeomProjLib.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include "ShapeFix_Edge.hxx"
#include <BRepBuilderAPI_MakeFace.hxx>
#include <ShapeFix_Face.hxx>
#include <BRepCheck_Analyzer.hxx>
#include <ShapeFix_Wireframe.hxx>
#include <BRepPrimAPI_MakePrism.hxx>
using namespace PartGui;
//////////////////////////////////////////////////////////////////////////
class DlgProjectionOnSurface::EdgeSelection : public Gui::SelectionFilterGate
{
public:
bool canSelect;
EdgeSelection()
: Gui::SelectionFilterGate((Gui::SelectionFilter*)0)
{
canSelect = false;
}
~EdgeSelection() {}
bool allow(App::Document* /*pDoc*/, App::DocumentObject* iPObj, const char* sSubName)
{
Part::Feature* aPart = dynamic_cast<Part::Feature*>(iPObj);
if (!aPart) return false;
if (!sSubName) return false;
std::string subName(sSubName);
if (subName.empty()) return false;
auto subShape = aPart->Shape.getShape().getSubShape(sSubName);
if (subShape.IsNull()) return false;
auto type = subShape.ShapeType();
if (type != TopAbs_EDGE) return false;
return true;
}
};
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
class DlgProjectionOnSurface::FaceSelection : public Gui::SelectionFilterGate
{
public:
bool canSelect;
FaceSelection()
: Gui::SelectionFilterGate((Gui::SelectionFilter*)0)
{
canSelect = false;
}
~FaceSelection() {}
bool allow(App::Document* /*pDoc*/, App::DocumentObject* iPObj, const char* sSubName)
{
Part::Feature* aPart = dynamic_cast<Part::Feature*>(iPObj);
if (!aPart) return false;
if (!sSubName) return false;
std::string subName(sSubName);
if (subName.empty()) return false;
auto subShape = aPart->Shape.getShape().getSubShape(sSubName);
if (subShape.IsNull()) return false;
auto type = subShape.ShapeType();
if (type != TopAbs_FACE) return false;
return true;
}
};
//////////////////////////////////////////////////////////////////////////
using namespace PartGui;
DlgProjectionOnSurface::DlgProjectionOnSurface(QWidget *parent) :
QDialog(parent),
ui(new Ui::DlgProjectionOnSurface)
DlgProjectionOnSurface::DlgProjectionOnSurface(QWidget *parent)
: QWidget(parent)
, ui(new Ui::DlgProjectionOnSurface)
, m_projectionObjectName(tr("Projection Object"))
, filterEdge(nullptr)
, filterFace(nullptr)
{
ui->setupUi(this);
ui->pushButtonAddEdge->setCheckable(true);
ui->pushButtonAddFace->setCheckable(true);
ui->pushButtonAddProjFace->setCheckable(true);
ui->pushButtonAddWire->setCheckable(true);
m_guiObjectVec.push_back(ui->pushButtonAddEdge);
m_guiObjectVec.push_back(ui->pushButtonAddFace);
m_guiObjectVec.push_back(ui->pushButtonAddProjFace);
m_guiObjectVec.push_back(ui->pushButtonDirX);
m_guiObjectVec.push_back(ui->pushButtonDirY);
m_guiObjectVec.push_back(ui->pushButtonDirZ);
m_guiObjectVec.push_back(ui->pushButtonGetCurrentCamDir);
m_guiObjectVec.push_back(ui->radioButtonShowAll);
m_guiObjectVec.push_back(ui->radioButtonFaces);
m_guiObjectVec.push_back(ui->radioButtonEdges);
m_guiObjectVec.push_back(ui->pushButtonAddWire);
get_camera_direction();
disable_ui_elements(m_guiObjectVec, ui->pushButtonAddProjFace);
App::Document* activeDoc = App::GetApplication().getActiveDocument();
if (!activeDoc)
{
throw Base::ValueError(QString(tr("Have no active document!!!")).toUtf8());
return;
}
m_projectionObject = dynamic_cast<Part::Feature*>(activeDoc->addObject("Part::Feature", std::string(m_projectionObjectName.toUtf8()).c_str()));
if ( !m_projectionObject )
{
throw Base::ValueError(QString(tr("Can not create a projection object!!!")).toUtf8());
return;
}
on_radioButtonShowAll_clicked();
m_lastDepthVal = ui->doubleSpinBoxSolidDepth->value();
}
DlgProjectionOnSurface::~DlgProjectionOnSurface()
{
delete ui;
delete ui;
for ( auto it : m_projectionSurfaceVec)
{
higlight_object(it.partFeature, it.partName, false, 0);
PartGui::ViewProviderPartExt* vp = dynamic_cast<PartGui::ViewProviderPartExt*>(Gui::Application::Instance->getViewProvider(it.partFeature));
if (vp)
{
vp->Selectable.setValue(it.is_selectable);
vp->Transparency.setValue(it.transparency);
}
}
for (auto it : m_shapeVec)
{
higlight_object(it.partFeature, it.partName, false, 0);
}
Gui::Selection().rmvSelectionGate();
}
void PartGui::DlgProjectionOnSurface::apply(void)
{
}
void PartGui::DlgProjectionOnSurface::reject(void)
{
App::Document* activeDoc = App::GetApplication().getActiveDocument();
if (!activeDoc) return;
activeDoc->removeObject(m_projectionObject->getNameInDocument());
}
void PartGui::DlgProjectionOnSurface::on_pushButtonAddFace_clicked()
{
if ( ui->pushButtonAddFace->isChecked() )
{
m_currentSelection = "add_face";
disable_ui_elements(m_guiObjectVec, ui->pushButtonAddFace);
if (!filterFace)
{
filterFace = new FaceSelection();
Gui::Selection().addSelectionGate(filterFace);
}
}
else
{
m_currentSelection = "";
enable_ui_elements(m_guiObjectVec, nullptr);
Gui::Selection().rmvSelectionGate();
filterFace = nullptr;
}
}
void PartGui::DlgProjectionOnSurface::on_pushButtonAddEdge_clicked()
{
if (ui->pushButtonAddEdge->isChecked())
{
m_currentSelection = "add_edge";
disable_ui_elements(m_guiObjectVec, ui->pushButtonAddEdge);
if (!filterEdge)
{
filterEdge = new EdgeSelection();
Gui::Selection().addSelectionGate(filterEdge);
}
ui->radioButtonEdges->setChecked(true);
on_radioButtonEdges_clicked();
}
else
{
m_currentSelection = "";
enable_ui_elements(m_guiObjectVec, nullptr);
Gui::Selection().rmvSelectionGate();
filterEdge = nullptr;
}
}
void PartGui::DlgProjectionOnSurface::on_pushButtonGetCurrentCamDir_clicked()
{
get_camera_direction();
}
void PartGui::DlgProjectionOnSurface::on_pushButtonDirX_clicked()
{
set_xyz_dir_spinbox(ui->doubleSpinBoxDirX);
}
void PartGui::DlgProjectionOnSurface::on_pushButtonDirY_clicked()
{
set_xyz_dir_spinbox(ui->doubleSpinBoxDirY);
}
void PartGui::DlgProjectionOnSurface::on_pushButtonDirZ_clicked()
{
set_xyz_dir_spinbox(ui->doubleSpinBoxDirZ);
}
void PartGui::DlgProjectionOnSurface::onSelectionChanged(const Gui::SelectionChanges& msg)
{
if (msg.Type == Gui::SelectionChanges::AddSelection)
{
if ( m_currentSelection == "add_face" || m_currentSelection == "add_edge" || m_currentSelection == "add_wire")
{
store_current_selected_parts(m_shapeVec, 0xff00ff00);
create_projection_wire(m_shapeVec);
create_projection_face_from_wire(m_shapeVec);
create_face_extrude(m_shapeVec);
show_projected_shapes(m_shapeVec);
}
else if (m_currentSelection == "add_projection_surface")
{
m_projectionSurfaceVec.clear();
store_current_selected_parts(m_projectionSurfaceVec, 0xffff0000);
if (m_projectionSurfaceVec.size())
{
PartGui::ViewProviderPartExt* vp = dynamic_cast<PartGui::ViewProviderPartExt*>(Gui::Application::Instance->getViewProvider(m_projectionSurfaceVec.back().partFeature));
if (vp)
{
vp->Selectable.setValue(false);
vp->Transparency.setValue(90);
}
}
ui->pushButtonAddProjFace->setChecked(false);
on_pushButtonAddProjFace_clicked();
}
}
}
void PartGui::DlgProjectionOnSurface::get_camera_direction(void)
{
auto mainWindow = Gui::getMainWindow();
auto mdiObject = dynamic_cast<Gui::View3DInventor*>(mainWindow->activeWindow());
if (!mdiObject) return;
auto camerRotation = mdiObject->getViewer()->getCameraOrientation();
SbVec3f lookAt(0, 0, -1);
camerRotation.multVec(lookAt, lookAt);
float valX, valY, valZ;
lookAt.getValue(valX, valY, valZ);
ui->doubleSpinBoxDirX->setValue(valX);
ui->doubleSpinBoxDirY->setValue(valY);
ui->doubleSpinBoxDirZ->setValue(valZ);
}
void PartGui::DlgProjectionOnSurface::store_current_selected_parts(std::vector<SShapeStore>& iStoreVec, const unsigned int iColor)
{
App::Document* activeDoc = App::GetApplication().getActiveDocument();
if (!activeDoc) return;
std::vector<Gui::SelectionObject> selObj = Gui::Selection().getSelectionEx();
if (selObj.size())
{
for (auto it = selObj.begin(); it != selObj.end(); ++it)
{
auto aPart = dynamic_cast<Part::Feature*>(it->getObject());
if (!aPart) continue;
if (aPart)
{
SShapeStore currentShapeStore;
currentShapeStore.inputShape = aPart->Shape.getShape().getShape();
currentShapeStore.partFeature = aPart;
currentShapeStore.partName = aPart->getNameInDocument();
PartGui::ViewProviderPartExt* vp = dynamic_cast<PartGui::ViewProviderPartExt*>(Gui::Application::Instance->getViewProvider(aPart));
if (vp)
{
currentShapeStore.is_selectable = vp->Selectable.getValue();
currentShapeStore.transparency = vp->Transparency.getValue();
}
if (it->getSubNames().size() )
{
auto parentShape = currentShapeStore.inputShape;
for (auto itName = selObj.front().getSubNames().begin(); itName != selObj.front().getSubNames().end(); ++itName)
{
std::string parentName = aPart->getNameInDocument();
auto currentShape = aPart->Shape.getShape().getSubShape(itName->c_str());
currentShapeStore.inputShape = currentShape;
currentShapeStore.partName = *itName;
auto store = store_part_in_vector(currentShapeStore, iStoreVec);
higlight_object(aPart, *itName, store, iColor);
store_wire_in_vector(currentShapeStore, parentShape, iStoreVec, iColor);
}
}
else
{
auto store = store_part_in_vector(currentShapeStore, iStoreVec);
higlight_object(aPart, aPart->Shape.getName(), store, iColor);
}
Gui::Selection().clearSelection(activeDoc->getName());
Gui::Selection().rmvPreselect();
}
}
}
}
bool PartGui::DlgProjectionOnSurface::store_part_in_vector(SShapeStore& iCurrentShape, std::vector<SShapeStore>& iStoreVec)
{
if (iCurrentShape.inputShape.IsNull()) return false;
auto currentType = iCurrentShape.inputShape.ShapeType();
for ( auto it = iStoreVec.begin(); it != iStoreVec.end(); ++it)
{
if ( currentType == TopAbs_FACE )
{
if (it->aFace.IsSame(iCurrentShape.inputShape))
{
iStoreVec.erase(it);
return false;
}
}
else if ( currentType == TopAbs_EDGE )
{
if (it->aEdge.IsSame(iCurrentShape.inputShape))
{
iStoreVec.erase(it);
return false;
}
}
}
if (currentType == TopAbs_FACE)
{
iCurrentShape.aFace = TopoDS::Face(iCurrentShape.inputShape);
}
else if (currentType == TopAbs_EDGE)
{
iCurrentShape.aEdge = TopoDS::Edge(iCurrentShape.inputShape);
}
auto valX = ui->doubleSpinBoxDirX->value();
auto valY = ui->doubleSpinBoxDirY->value();
auto valZ = ui->doubleSpinBoxDirZ->value();
iCurrentShape.aProjectionDir = gp_Dir(valX, valY, valZ);
if ( m_projectionSurfaceVec.size() )
{
iCurrentShape.surfaceToProject = m_projectionSurfaceVec.front().aFace;
}
iStoreVec.push_back(iCurrentShape);
return true;
}
void PartGui::DlgProjectionOnSurface::create_projection_wire(std::vector<SShapeStore>& iCurrentShape)
{
try
{
if (iCurrentShape.empty()) return;
for ( auto &itCurrentShape : iCurrentShape )
{
if (m_projectionSurfaceVec.empty()) continue;;
if (itCurrentShape.aProjectedEdgeVec.size()) continue;;
if (!itCurrentShape.aProjectedFace.IsNull()) continue;;
if (itCurrentShape.aProjectedWireVec.size()) continue;;
if (!itCurrentShape.aFace.IsNull())
{
get_all_wire_from_face(itCurrentShape);
for (auto itWire : itCurrentShape.aWireVec)
{
BRepProj_Projection aProjection(itWire, itCurrentShape.surfaceToProject, itCurrentShape.aProjectionDir);
auto currentProjection = aProjection.Shape();
auto aWire = sort_and_heal_wire(currentProjection, itCurrentShape.surfaceToProject);
itCurrentShape.aProjectedWireVec.push_back(aWire);
}
}
else if (!itCurrentShape.aEdge.IsNull())
{
BRepProj_Projection aProjection(itCurrentShape.aEdge, itCurrentShape.surfaceToProject, itCurrentShape.aProjectionDir);
auto currentProjection = aProjection.Shape();
for (TopExp_Explorer aExplorer(currentProjection, TopAbs_EDGE); aExplorer.More(); aExplorer.Next())
{
itCurrentShape.aProjectedEdgeVec.push_back(TopoDS::Edge(aExplorer.Current()));
}
}
}
}
catch (Standard_Failure)
{
auto error = Standard_Failure::Caught();
std::stringstream ssOcc;
error->Print(ssOcc);
throw Base::ValueError(ssOcc.str().c_str());
}
}
TopoDS_Shape PartGui::DlgProjectionOnSurface::create_compound(const std::vector<SShapeStore>& iShapeVec)
{
if (iShapeVec.empty()) return TopoDS_Shape();
TopoDS_Compound aCompound;
TopoDS_Builder aBuilder;
aBuilder.MakeCompound(aCompound);
for (auto it : iShapeVec)
{
if ( m_currentShowType == "edges" )
{
for (auto it2 : it.aProjectedEdgeVec)
{
aBuilder.Add(aCompound, it2);
}
for (auto it2 : it.aProjectedWireVec)
{
aBuilder.Add(aCompound, it2);
}
continue;
}
else if ( m_currentShowType == "faces" )
{
if (it.aProjectedFace.IsNull())
{
for (auto it2 : it.aProjectedWireVec)
{
if (!it2.IsNull())
{
aBuilder.Add(aCompound, it2);
}
}
}
else aBuilder.Add(aCompound, it.aProjectedFace);
continue;
}
else if ( m_currentShowType == "all" )
{
if (!it.aProjectedSolid.IsNull())
{
aBuilder.Add(aCompound, it.aProjectedSolid);
}
else if ( !it.aProjectedFace.IsNull() )
{
aBuilder.Add(aCompound, it.aProjectedFace);
}
else if (it.aProjectedWireVec.size())
{
for ( auto itWire : it.aProjectedWireVec )
{
if ( itWire.IsNull() ) continue;
aBuilder.Add(aCompound, itWire);
}
}
else if (it.aProjectedEdgeVec.size())
{
for (auto itEdge : it.aProjectedEdgeVec)
{
if (itEdge.IsNull()) continue;
aBuilder.Add(aCompound, itEdge);
}
}
}
}
return aCompound;
}
void PartGui::DlgProjectionOnSurface::show_projected_shapes(const std::vector<SShapeStore>& iShapeStoreVec)
{
if (!m_projectionObject) return;
auto aCompound = create_compound(iShapeStoreVec);
if ( aCompound.IsNull() )
{
App::Document* activeDoc = App::GetApplication().getActiveDocument();
if (!activeDoc) return;
activeDoc->removeObject(m_projectionObject->getNameInDocument());
m_projectionObject = dynamic_cast<Part::Feature*>(activeDoc->addObject("Part::Feature", std::string(m_projectionObjectName.toUtf8()).c_str()));
return;
}
auto currentPlacement = m_projectionObject->Placement.getValue();
m_projectionObject->Shape.setValue(aCompound);
m_projectionObject->Placement.setValue(currentPlacement);
//set color
PartGui::ViewProviderPartExt* vp = dynamic_cast<PartGui::ViewProviderPartExt*>(Gui::Application::Instance->getViewProvider(m_projectionObject));
if (vp)
{
vp->LineColor.setValue(0x8ae23400);
vp->ShapeColor.setValue(0x8ae23400);
vp->PointColor.setValue(0x8ae23400);
}
}
void PartGui::DlgProjectionOnSurface::disable_ui_elements(const std::vector<QWidget*>& iObjectVec, QWidget* iExceptThis)
{
for ( auto it : iObjectVec )
{
if ( !it ) continue;
if ( it == iExceptThis ) continue;
it->setDisabled(true);
}
}
void PartGui::DlgProjectionOnSurface::enable_ui_elements(const std::vector<QWidget*>& iObjectVec, QWidget* iExceptThis)
{
for (auto it : iObjectVec)
{
if (!it) continue;
if (it == iExceptThis) continue;
it->setEnabled(true);
}
}
void PartGui::DlgProjectionOnSurface::higlight_object(Part::Feature* iCurrentObject, const std::string& iShapeName, bool iHighlight, const unsigned int iColor)
{
if (!iCurrentObject) return;
auto partenShape = iCurrentObject->Shape.getShape().getShape();
auto subShape = iCurrentObject->Shape.getShape().getSubShape(iShapeName.c_str());
TopoDS_Shape currentShape = subShape;
if (subShape.IsNull()) currentShape = partenShape;
auto currentShapeType = currentShape.ShapeType();
TopTools_IndexedMapOfShape anIndices;
TopExp::MapShapes(partenShape, currentShapeType, anIndices);
if (anIndices.IsEmpty()) return;
if (!anIndices.Contains(currentShape)) return;
auto index = anIndices.FindIndex(currentShape);
//set color
PartGui::ViewProviderPartExt* vp = dynamic_cast<PartGui::ViewProviderPartExt*>(Gui::Application::Instance->getViewProvider(iCurrentObject));
if (vp)
{
std::vector<App::Color> colors;
App::Color defaultColor;
if (currentShapeType == TopAbs_FACE)
{
colors = vp->DiffuseColor.getValues();
defaultColor = vp->ShapeColor.getValue();
}
else if ( currentShapeType == TopAbs_EDGE )
{
colors = vp->LineColorArray.getValues();
defaultColor = vp->LineColor.getValue();
}
if ( colors.size() != anIndices.Extent() )
{
colors.resize(anIndices.Extent(), defaultColor);
}
if ( iHighlight )
{
App::Color aColor;
aColor.setPackedValue(iColor);
colors.at(index - 1) = aColor;
}
else
{
colors.at(index - 1) = defaultColor;
}
if (currentShapeType == TopAbs_FACE)
{
vp->DiffuseColor.setValues(colors);
}
else if (currentShapeType == TopAbs_EDGE)
{
vp->LineColorArray.setValues(colors);
}
}
}
void PartGui::DlgProjectionOnSurface::get_all_wire_from_face(SShapeStore& ioCurrentSahpe)
{
auto outerWire = ShapeAnalysis::OuterWire(ioCurrentSahpe.aFace);
ioCurrentSahpe.aWireVec.push_back(outerWire);
for (TopExp_Explorer aExplorer(ioCurrentSahpe.aFace, TopAbs_WIRE); aExplorer.More(); aExplorer.Next())
{
auto currentWire = TopoDS::Wire(aExplorer.Current());
if (currentWire.IsSame(outerWire)) continue;
ioCurrentSahpe.aWireVec.push_back(currentWire);
}
}
void PartGui::DlgProjectionOnSurface::create_projection_face_from_wire(std::vector<SShapeStore>& iCurrentShape)
{
try
{
if (iCurrentShape.empty()) return;
for ( auto &itCurrentShape : iCurrentShape )
{
if (itCurrentShape.aFace.IsNull()) continue;;
if (itCurrentShape.aProjectedWireVec.empty()) continue;;
if (!itCurrentShape.aProjectedFace.IsNull()) continue;;
auto surface = BRep_Tool::Surface(itCurrentShape.surfaceToProject);
//create a wire of all edges in parametric space on the surface of the face to projected
// --> othwerwise BRepBuilderAPI_MakeFace can not make a face from the wire!
for (auto itWireVec : itCurrentShape.aProjectedWireVec)
{
std::vector<const TopoDS_Shape> edgeVec;
for (TopExp_Explorer aExplorer(itWireVec, TopAbs_EDGE); aExplorer.More(); aExplorer.Next())
{
auto currentEdge = TopoDS::Edge(aExplorer.Current());
edgeVec.push_back(currentEdge);
}
if (edgeVec.empty()) continue;
BRepBuilderAPI_MakeWire aWire;
for (auto itEdge : edgeVec)
{
Standard_Real first, last;
auto currentCurve = BRep_Tool::Curve(TopoDS::Edge(itEdge), first, last);
// trim the curve, otherwise it can be an infinite one
auto trimmedCurve = new Geom_TrimmedCurve(currentCurve, first, last);
// get parametric space curve
auto aCurve = GeomProjLib::Curve2d(trimmedCurve, surface);
auto edgeInParametricSpace = BRepBuilderAPI_MakeEdge(aCurve, surface).Edge();
ShapeFix_Edge aEdgeRepair;
aEdgeRepair.FixAddCurve3d(edgeInParametricSpace);
aWire.Add(edgeInParametricSpace);
}
if (!aWire.IsDone())
{
std::stringstream errmsg;
errmsg << "Cannot create wire in parametric space....: " << aWire.Error() << "\n";
Base::Console().Warning(errmsg.str().c_str());
continue;
}
ShapeFix_Wire aWireRepair(aWire.Wire(), itCurrentShape.surfaceToProject, 0.00001);
aWireRepair.FixAddCurve3dMode();
aWireRepair.FixAddPCurveMode();
aWireRepair.Perform();
itCurrentShape.aProjectedWireInParametricSpaceVec.push_back(aWireRepair.Wire());
}
// try to create a face from the wires
// the first wire is the outerwire
// the following wires are the inside wires
BRepBuilderAPI_MakeFace faceMaker;
bool first = true;
for (auto itWireVec : itCurrentShape.aProjectedWireInParametricSpaceVec)
{
if (first)
{
first = false;
// change the wire direction, othwerwise no face is created
auto currentWire = TopoDS::Wire(itWireVec.Reversed());
if (itCurrentShape.surfaceToProject.Orientation() == TopAbs_REVERSED) currentWire = itWireVec;
faceMaker = BRepBuilderAPI_MakeFace(surface, currentWire);
ShapeFix_Face fix(faceMaker.Face());
fix.Perform();
auto aFace = fix.Face();
BRepCheck_Analyzer aChecker(aFace);
if (!aChecker.IsValid())
{
faceMaker = BRepBuilderAPI_MakeFace(surface, itWireVec);
}
}
else
{
// make a copy of the current face maker
// if the face fails just try again with the copy
auto tempCopy = BRepBuilderAPI_MakeFace(faceMaker.Face());
faceMaker.Add(TopoDS::Wire(itWireVec.Reversed()));
ShapeFix_Face fix(faceMaker.Face());
fix.Perform();
auto aFace = fix.Face();
BRepCheck_Analyzer aChecker(aFace);
if (!aChecker.IsValid())
{
faceMaker = BRepBuilderAPI_MakeFace(tempCopy);
faceMaker.Add(TopoDS::Wire(itWireVec));
}
}
}
auto doneFlag = faceMaker.IsDone();
auto error = faceMaker.Error();
itCurrentShape.aProjectedFace = faceMaker.Face();
}
}
catch (Standard_Failure)
{
auto error = Standard_Failure::Caught();
std::stringstream ssOcc;
error->Print(ssOcc);
throw Base::ValueError(ssOcc.str().c_str());
}
}
TopoDS_Wire PartGui::DlgProjectionOnSurface::sort_and_heal_wire(const TopoDS_Shape& iShape, const TopoDS_Face& iFaceToProject)
{
// try to sort and heal all wires
// if the wires are not clean making a face will fail!
ShapeAnalysis_FreeBounds shapeAnalyzer;
Handle(TopTools_HSequenceOfShape) shapeList = new TopTools_HSequenceOfShape;
Handle(TopTools_HSequenceOfShape) aWireHandle;
Handle(TopTools_HSequenceOfShape) aWireWireHandle;
for (TopExp_Explorer aExplorer(iShape, TopAbs_EDGE); aExplorer.More(); aExplorer.Next())
{
auto anEdge = TopoDS::Edge(aExplorer.Current());
shapeList->Append(TopoDS::Edge(aExplorer.Current()));
}
shapeAnalyzer.ConnectEdgesToWires(shapeList, 0.0001, false, aWireHandle);
shapeAnalyzer.ConnectWiresToWires(aWireHandle, 0.0001, false, aWireWireHandle);
if (!aWireWireHandle) return TopoDS_Wire();
for (auto it = 1; it <= aWireWireHandle->Length(); ++it)
{
auto aShape = TopoDS::Wire(aWireWireHandle->Value(it));
ShapeFix_Wire aWireRepair(aShape, iFaceToProject, 0.0001);
aWireRepair.FixAddCurve3dMode();
aWireRepair.FixAddPCurveMode();
aWireRepair.Perform();
//return aWireRepair.Wire();
ShapeFix_Wireframe aWireFramFix(aWireRepair.Wire());
auto retVal = aWireFramFix.FixWireGaps();
retVal = aWireFramFix.FixSmallEdges();
return TopoDS::Wire(aWireFramFix.Shape());
}
return TopoDS_Wire();
}
void PartGui::DlgProjectionOnSurface::create_face_extrude(std::vector<SShapeStore>& iCurrentShape)
{
try
{
if (iCurrentShape.empty()) return;
for ( auto &itCurrentShape : iCurrentShape )
{
if (itCurrentShape.aProjectedFace.IsNull()) continue;;
auto height = ui->doubleSpinBoxExtrudeHeight->value();
if (itCurrentShape.exrudeValue == height) continue;;
gp_Vec directionToExtrude(itCurrentShape.aProjectionDir.XYZ());
directionToExtrude.Reverse();
if (height == 0) return;
directionToExtrude.Multiply(height);
BRepPrimAPI_MakePrism extrude(itCurrentShape.aProjectedFace, directionToExtrude);
itCurrentShape.aProjectedSolid = extrude.Shape();
itCurrentShape.exrudeValue = height;
}
}
catch (Standard_Failure)
{
auto error = Standard_Failure::Caught();
std::stringstream ssOcc;
error->Print(ssOcc);
throw Base::ValueError(ssOcc.str().c_str());
}
}
void PartGui::DlgProjectionOnSurface::store_wire_in_vector(const SShapeStore& iCurrentShape, const TopoDS_Shape& iParentShape, std::vector<SShapeStore>& iStoreVec, const unsigned int iColor)
{
if (m_currentSelection != "add_wire") return;
if (iParentShape.IsNull()) return;
if (iCurrentShape.inputShape.IsNull()) return;
auto currentType = iCurrentShape.inputShape.ShapeType();
if (currentType != TopAbs_EDGE) return;
std::vector<TopoDS_Wire> aWireVec;
for (TopExp_Explorer aExplorer(iParentShape, TopAbs_WIRE); aExplorer.More(); aExplorer.Next())
{
aWireVec.push_back(TopoDS::Wire(aExplorer.Current()));
}
std::vector<TopoDS_Edge> edgeVec;
for ( auto it : aWireVec )
{
bool edgeExists = false;
for (TopExp_Explorer aExplorer(it, TopAbs_EDGE); aExplorer.More(); aExplorer.Next())
{
auto currentEdge = TopoDS::Edge(aExplorer.Current());
edgeVec.push_back(currentEdge);
if (currentEdge.IsSame(iCurrentShape.inputShape)) edgeExists = true;
}
if (edgeExists) break;
edgeVec.clear();
}
if (edgeVec.empty()) return;
TopTools_IndexedMapOfShape indexMap;
TopExp::MapShapes(iParentShape, TopAbs_EDGE, indexMap);
if (indexMap.IsEmpty()) return;
for ( auto it : edgeVec )
{
if ( it.IsSame(iCurrentShape.inputShape)) continue;
if (!indexMap.Contains(it)) return;
auto index = indexMap.FindIndex(it);
auto newEdgeObject = iCurrentShape;
newEdgeObject.inputShape = it;
newEdgeObject.partName = "Edge" + std::to_string(index);
auto store = store_part_in_vector(newEdgeObject, iStoreVec);
higlight_object(newEdgeObject.partFeature, newEdgeObject.partName, store, iColor);
}
}
void PartGui::DlgProjectionOnSurface::set_xyz_dir_spinbox(QDoubleSpinBox* icurrentSpinBox)
{
auto currentVal = icurrentSpinBox->value();
auto newVal = 0.0;
if (currentVal != 1.0 && currentVal != -1.0)
{
newVal = -1;
}
else if (currentVal == 1.0)
{
newVal = -1;
}
else if (currentVal == -1.0)
{
newVal = 1;
}
ui->doubleSpinBoxDirX->setValue(0);
ui->doubleSpinBoxDirY->setValue(0);
ui->doubleSpinBoxDirZ->setValue(0);
icurrentSpinBox->setValue(newVal);
}
void PartGui::DlgProjectionOnSurface::on_pushButtonAddProjFace_clicked()
{
if (ui->pushButtonAddProjFace->isChecked())
{
m_currentSelection = "add_projection_surface";
disable_ui_elements(m_guiObjectVec, ui->pushButtonAddProjFace);
if (!filterFace)
{
filterFace = new FaceSelection();
Gui::Selection().addSelectionGate(filterFace);
}
}
else
{
m_currentSelection = "";
enable_ui_elements(m_guiObjectVec, nullptr);
Gui::Selection().rmvSelectionGate();
filterFace = nullptr;
}
}
void PartGui::DlgProjectionOnSurface::on_radioButtonShowAll_clicked()
{
m_currentShowType = "all";
show_projected_shapes(m_shapeVec);
}
void PartGui::DlgProjectionOnSurface::on_radioButtonFaces_clicked()
{
m_currentShowType = "faces";
show_projected_shapes(m_shapeVec);
}
void PartGui::DlgProjectionOnSurface::on_radioButtonEdges_clicked()
{
m_currentShowType = "edges";
show_projected_shapes(m_shapeVec);
}
void PartGui::DlgProjectionOnSurface::on_doubleSpinBoxExtrudeHeight_valueChanged(double arg1)
{
create_face_extrude(m_shapeVec);
show_projected_shapes(m_shapeVec);
}
void PartGui::DlgProjectionOnSurface::on_pushButtonAddWire_clicked()
{
if (ui->pushButtonAddWire->isChecked())
{
m_currentSelection = "add_wire";
disable_ui_elements(m_guiObjectVec, ui->pushButtonAddWire);
if (!filterEdge)
{
filterEdge = new EdgeSelection();
Gui::Selection().addSelectionGate(filterEdge);
}
ui->radioButtonEdges->setChecked(true);
on_radioButtonEdges_clicked();
}
else
{
m_currentSelection = "";
enable_ui_elements(m_guiObjectVec, nullptr);
Gui::Selection().rmvSelectionGate();
filterEdge = nullptr;
}
}
void PartGui::DlgProjectionOnSurface::on_doubleSpinBoxSolidDepth_valueChanged(double arg1)
{
auto valX = ui->doubleSpinBoxDirX->value();
auto valY = ui->doubleSpinBoxDirY->value();
auto valZ = ui->doubleSpinBoxDirZ->value();
auto valueToMove = arg1 - m_lastDepthVal;
Base::Vector3d vectorToMove(valX, valY, valZ);
vectorToMove *= valueToMove;
auto placment = m_projectionObject->Placement.getValue();
placment.move(vectorToMove);
m_projectionObject->Placement.setValue(placment);
m_lastDepthVal = ui->doubleSpinBoxSolidDepth->value();
}
// ---------------------------------------
TaskProjectionOnSurface::TaskProjectionOnSurface()
{
widget = new DlgProjectionOnSurface();
taskbox = new Gui::TaskView::TaskBox(
Gui::BitmapFactory().pixmap("Part_Extrude"),
Gui::BitmapFactory().pixmap("Part_ProjectionOnSurface"),
widget->windowTitle(), true, 0);
taskbox->groupLayout()->addWidget(widget);
Content.push_back(taskbox);
@@ -38,8 +972,9 @@ TaskProjectionOnSurface::~TaskProjectionOnSurface()
bool TaskProjectionOnSurface::accept()
{
widget->accept();
return (widget->result() == QDialog::Accepted);
return true;
widget->apply();
//return (widget->result() == QDialog::Accepted);
}
bool TaskProjectionOnSurface::reject()
@@ -52,7 +987,7 @@ void TaskProjectionOnSurface::clicked(int id)
{
if (id == QDialogButtonBox::Apply) {
try {
//widget->apply();
widget->apply();
}
catch (Base::AbortException&) {
@@ -60,3 +995,6 @@ void TaskProjectionOnSurface::clicked(int id)
}
}
#include "moc_DlgProjectionOnSurface.cpp"

View File

@@ -1,33 +1,141 @@
#ifndef DLGPROJECTIONONSURFACE_H
#define DLGPROJECTIONONSURFACE_H
/***************************************************************************
* Copyright (c) 2019 Manuel Apeltauer, direkt cnc-systeme GmbH *
* *
* 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 *
* *
***************************************************************************/
#ifndef PARTGUI_DLGPROJECTIONONSURFACE_H
#define PARTGUI_DLGPROJECTIONONSURFACE_H
#include <QDialog>
#include <QWidget>
#include <QDoubleSpinBox>
#include <Gui/TaskView/TaskDialog.h>
#include <Gui/TaskView/TaskView.h>
namespace Ui {
}
#include "../App/PartFeature.h"
#include "TopoDS_Shape.hxx"
#include "TopoDS_Edge.hxx"
#include "TopoDS_Face.hxx"
#include "TopoDS_Wire.hxx"
namespace PartGui {
class Ui_DlgProjectionOnSurface;
class DlgProjectionOnSurface : public QDialog
namespace Ui {
class DlgProjectionOnSurface;
}
class DlgProjectionOnSurface : public QWidget, public Gui::SelectionObserver
{
//Q_OBJECT
Q_OBJECT
public:
explicit DlgProjectionOnSurface(QWidget *parent = 0);
~DlgProjectionOnSurface();
void apply(void);
void reject(void);
private Q_SLOTS:
void on_pushButtonAddFace_clicked();
void on_pushButtonAddEdge_clicked();
void on_pushButtonGetCurrentCamDir_clicked();
void on_pushButtonDirX_clicked();
void on_pushButtonDirY_clicked();
void on_pushButtonDirZ_clicked();
void on_pushButtonAddProjFace_clicked();
void on_radioButtonShowAll_clicked();
void on_radioButtonFaces_clicked();
void on_radioButtonEdges_clicked();
void on_doubleSpinBoxExtrudeHeight_valueChanged(double arg1);
void on_pushButtonAddWire_clicked();
void on_doubleSpinBoxSolidDepth_valueChanged(double arg1);
private:
Ui_DlgProjectionOnSurface*ui;
struct SShapeStore
{
TopoDS_Shape inputShape;
TopoDS_Face surfaceToProject;
gp_Dir aProjectionDir;
TopoDS_Face aFace;
TopoDS_Edge aEdge;
std::vector<TopoDS_Wire> aWireVec;
std::vector<TopoDS_Wire> aProjectedWireVec;
std::vector<TopoDS_Edge> aProjectedEdgeVec;
std::vector<TopoDS_Wire> aProjectedWireInParametricSpaceVec;
TopoDS_Face aProjectedFace;
TopoDS_Shape aProjectedSolid;
Part::Feature* partFeature;
std::string partName;
bool is_selectable;
long transparency;
float exrudeValue;
};
//from Gui::SelectionObserver
virtual void onSelectionChanged(const Gui::SelectionChanges& msg);
void get_camera_direction(void);
void store_current_selected_parts(std::vector<SShapeStore>& iStoreVec, const unsigned int iColor);
bool store_part_in_vector(SShapeStore& iCurrentShape, std::vector<SShapeStore>& iStoreVec);
void create_projection_wire(std::vector<SShapeStore>& iCurrentShape);
TopoDS_Shape create_compound(const std::vector<SShapeStore>& iShapeVec);
void show_projected_shapes(const std::vector<SShapeStore>& iShapeStoreVec);
void disable_ui_elements(const std::vector<QWidget*>& iObjectVec, QWidget* iExceptThis);
void enable_ui_elements(const std::vector<QWidget*>& iObjectVec, QWidget* iExceptThis);
void higlight_object(Part::Feature* iCurrentObject, const std::string& iShapeName, bool iHighlight, const unsigned int iColor);
void get_all_wire_from_face(SShapeStore& ioCurrentSahpe);
void create_projection_face_from_wire(std::vector<SShapeStore>& iCurrentShape);
TopoDS_Wire sort_and_heal_wire(const TopoDS_Shape& iShape, const TopoDS_Face& iFaceToProject);
void create_face_extrude(std::vector<SShapeStore>& iCurrentShape);
void store_wire_in_vector(const SShapeStore& iCurrentShape, const TopoDS_Shape& iParentShape, std::vector<SShapeStore>& iStoreVec, const unsigned int iColor);
void set_xyz_dir_spinbox(QDoubleSpinBox* icurrentSpinBox);
private:
Ui::DlgProjectionOnSurface *ui;
std::vector<SShapeStore> m_shapeVec;
std::vector<SShapeStore> m_projectionSurfaceVec;
std::string m_currentSelection;
std::string m_currentShowType;
std::vector<QWidget*> m_guiObjectVec;
const QString m_projectionObjectName;
Part::Feature* m_projectionObject;
float m_lastDepthVal;
class EdgeSelection;
EdgeSelection* filterEdge;
class FaceSelection;
FaceSelection* filterFace;
};
class TaskProjectionOnSurface : public Gui::TaskView::TaskDialog
{
//Q_OBJECT
Q_OBJECT
public:
TaskProjectionOnSurface();
@@ -40,7 +148,7 @@ public:
virtual QDialogButtonBox::StandardButtons getStandardButtons() const
{
return QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Close;
return QDialogButtonBox::Ok | QDialogButtonBox::Close;
}
private:
@@ -48,5 +156,6 @@ private:
Gui::TaskView::TaskBox* taskbox;
};
} // namespace PartGui
#endif // DLGPROJECTIONONSURFACE_H
#endif // PARTGUI_DLGPROJECTIONONSURFACE_H

View File

@@ -1,31 +1,241 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DlgProjectionOnSurface</class>
<widget class="QDialog" name="DlgProjectionOnSurface">
<class>PartGui::DlgProjectionOnSurface</class>
<widget class="QWidget" name="PartGui::DlgProjectionOnSurface">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
<height>764</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
<string>Form</string>
</property>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>180</x>
<y>120</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="pushButtonAddProjFace">
<property name="text">
<string>Select projection surface</string>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="pushButtonAddFace">
<property name="text">
<string>Add face</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonAddWire">
<property name="text">
<string>Add wire</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonAddEdge">
<property name="text">
<string>Add edge</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QRadioButton" name="radioButtonShowAll">
<property name="text">
<string>Show all</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButtonFaces">
<property name="text">
<string>Show faces</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButtonEdges">
<property name="text">
<string>Show Edges</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="labelExtrudeHeigth">
<property name="text">
<string>Extrude height</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="doubleSpinBoxExtrudeHeight">
<property name="maximum">
<double>999.000000000000000</double>
</property>
<property name="value">
<double>10.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QLabel" name="labelDepth">
<property name="text">
<string>Solid depth</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="doubleSpinBoxSolidDepth">
<property name="minimum">
<double>-999.000000000000000</double>
</property>
<property name="maximum">
<double>999.000000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBoxDir">
<property name="title">
<string>Direction</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QPushButton" name="pushButtonGetCurrentCamDir">
<property name="text">
<string>Get current camera direction</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="pushButtonDirX">
<property name="text">
<string>X:</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="doubleSpinBoxDirX">
<property name="enabled">
<bool>false</bool>
</property>
<property name="readOnly">
<bool>false</bool>
</property>
<property name="minimum">
<double>-1.000000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QPushButton" name="pushButtonDirY">
<property name="text">
<string>Y:</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="doubleSpinBoxDirY">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<double>-1.000000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QPushButton" name="pushButtonDirZ">
<property name="text">
<string>Z:</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="doubleSpinBoxDirZ">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<double>-1.000000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>

View File

@@ -74,6 +74,7 @@
<file>icons/Part_JoinCutout.svg</file>
<file>icons/Part_JoinEmbed.svg</file>
<file>icons/PartWorkbench.svg</file>
<file>icons/Part_ProjectionOnSurface.svg</file>
<file>translations/Part_af.qm</file>
<file>translations/Part_de.qm</file>
<file>translations/Part_fi.qm</file>

View File

@@ -0,0 +1,346 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64"
height="64"
viewBox="0 0 16.933333 16.933334"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="Part_ProjectionOnSurface.svg"
inkscape:label="Gear Proj">
<defs
id="defs2">
<linearGradient
id="linearGradient3864-9">
<stop
style="stop-color:#204a87;stop-opacity:1"
offset="0"
id="stop6175" />
<stop
style="stop-color:#729fcf;stop-opacity:1"
offset="1"
id="stop6177" />
</linearGradient>
<linearGradient
id="linearGradient3864">
<stop
style="stop-color:#71b2f8;stop-opacity:1;"
offset="0"
id="stop3866" />
<stop
style="stop-color:#002795;stop-opacity:1;"
offset="1"
id="stop3868" />
</linearGradient>
<inkscape:perspective
id="perspective2988"
inkscape:persp3d-origin="32 : 21.333333 : 1"
inkscape:vp_z="64 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 32 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="40"
x2="20"
y1="55.717518"
x1="22.116516"
id="linearGradient3773"
xlink:href="#linearGradient3767"
inkscape:collect="always"
gradientTransform="matrix(1,0,0,0.80043488,-0.21205357,1.3620882)" />
<linearGradient
id="linearGradient3767"
inkscape:collect="always">
<stop
id="stop3769"
offset="0"
style="stop-color:#3465a4;stop-opacity:1" />
<stop
id="stop3771"
offset="1"
style="stop-color:#729fcf;stop-opacity:1" />
</linearGradient>
<linearGradient
gradientUnits="userSpaceOnUse"
y2="38"
x2="50"
y1="51.179787"
x1="53.896763"
id="linearGradient3783"
xlink:href="#linearGradient3777"
inkscape:collect="always"
gradientTransform="translate(-0.178571,-10.928571)" />
<linearGradient
id="linearGradient3777"
inkscape:collect="always">
<stop
id="stop3779"
offset="0"
style="stop-color:#204a87;stop-opacity:1" />
<stop
id="stop3781"
offset="1"
style="stop-color:#3465a4;stop-opacity:1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3767"
id="linearGradient5871"
x1="44.663254"
y1="66.59771"
x2="80.450974"
y2="66.59771"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-42.769166,-23.920078)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3777"
id="linearGradient5903"
x1="44.690838"
y1="39.061024"
x2="70.759598"
y2="39.061024"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-6.3392858,1.0267858)" />
<linearGradient
id="linearGradient3682">
<stop
id="stop3684"
offset="0"
style="stop-color:#ff6d0f;stop-opacity:1;" />
<stop
id="stop3686"
offset="1"
style="stop-color:#ff1000;stop-opacity:1;" />
</linearGradient>
<inkscape:perspective
id="perspective3148"
inkscape:persp3d-origin="32 : 21.333333 : 1"
inkscape:vp_z="64 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 32 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
id="linearGradient3864-9-4">
<stop
id="stop3866-1"
offset="0"
style="stop-color:#204a87;stop-opacity:1" />
<stop
id="stop3868-1"
offset="1"
style="stop-color:#729fcf;stop-opacity:1" />
</linearGradient>
<linearGradient
id="linearGradient3682-0">
<stop
style="stop-color:#a40000;stop-opacity:1"
offset="0"
id="stop3684-0" />
<stop
style="stop-color:#ef2929;stop-opacity:1"
offset="1"
id="stop3686-0" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="64 : 32 : 1"
inkscape:persp3d-origin="32 : 21.333333 : 1"
id="perspective3148-5" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3682-0-6"
id="radialGradient3817-5-3"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.2361257,0.30001695,-0.83232803,3.3883821,-499.9452,-167.33108)"
cx="270.58316"
cy="33.899986"
fx="270.58316"
fy="33.899986"
r="19.571428" />
<linearGradient
id="linearGradient3682-0-6">
<stop
style="stop-color:#ff390f;stop-opacity:1"
offset="0"
id="stop3684-0-7" />
<stop
style="stop-color:#ff1000;stop-opacity:1;"
offset="1"
id="stop3686-0-5" />
</linearGradient>
<linearGradient
gradientUnits="userSpaceOnUse"
y2="40"
x2="20"
y1="55.717518"
x1="22.116516"
id="linearGradient3773-8"
xlink:href="#linearGradient3767"
inkscape:collect="always"
gradientTransform="matrix(0.2719906,0,0,0.21771077,4.1098594,-0.60061144)" />
<inkscape:perspective
id="perspective2988-3"
inkscape:persp3d-origin="32 : 21.333333 : 1"
inkscape:vp_z="64 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 32 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="38"
x2="50"
y1="51.179787"
x1="53.896763"
id="linearGradient3783-0"
xlink:href="#linearGradient3777"
inkscape:collect="always"
gradientTransform="matrix(0.39506609,0,0,0.39506609,-0.01269431,-5.8114314)" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="40"
x2="20"
y1="55.717518"
x1="22.116516"
id="linearGradient3773-0"
xlink:href="#linearGradient3767"
inkscape:collect="always"
gradientTransform="matrix(0.39506609,0,0,0.39506609,-0.01269431,-5.8114314)" />
<inkscape:perspective
id="perspective3148-9"
inkscape:persp3d-origin="32 : 21.333333 : 1"
inkscape:vp_z="64 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 32 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="64 : 32 : 1"
inkscape:persp3d-origin="32 : 21.333333 : 1"
id="perspective3148-5-0" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3682-0-6"
id="radialGradient3817-5-3-3"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.2361257,0.30001695,-0.83232803,3.3883821,-499.9452,-167.33108)"
cx="270.58316"
cy="33.899986"
fx="270.58316"
fy="33.899986"
r="19.571428" />
<linearGradient
gradientTransform="matrix(0.21275462,0,0,0.16272468,50.684307,3.2886466)"
gradientUnits="userSpaceOnUse"
y2="7.7114096"
x2="-211.40184"
y1="68.841812"
x1="-206.69949"
id="linearGradient3806"
xlink:href="#linearGradient4066"
inkscape:collect="always" />
<linearGradient
inkscape:collect="always"
id="linearGradient4066">
<stop
style="stop-color:#4e9a06;stop-opacity:1"
offset="0"
id="stop4068" />
<stop
style="stop-color:#8ae234;stop-opacity:1"
offset="1"
id="stop4070" />
</linearGradient>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="7.919596"
inkscape:cx="-19.036936"
inkscape:cy="23.646719"
inkscape:document-units="mm"
inkscape:current-layer="layer8"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1096"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
units="px" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer7"
inkscape:label="Solid"
transform="matrix(1.1184437,-0.25664164,0.01996106,1.4775748,-1.0512274,-7.2671715)">
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path2993"
d="M 1.1725043,7.225752 14.604751,9.5961484 24.08634,6.4356185 12.234355,4.8553547 Z"
style="fill:#729fcf;stroke:#0b1521;stroke-width:0.79013211;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path2995"
d="m 24.08634,6.4356185 v 7.9013225 l -9.481589,3.95066 V 9.5961484 Z"
style="fill:url(#linearGradient3783-0);fill-opacity:1;stroke:#0b1521;stroke-width:0.79013211;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
<path
style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient3773-0);fill-opacity:1;fill-rule:evenodd;stroke:#0b1521;stroke-width:0.79013211;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="M 1.1725043,7.225752 14.604751,9.5961484 V 18.287601 L 1.1725043,15.917205 Z"
id="path3825"
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path3765"
d="m 1.9626367,8.1848616 0.00343,7.0792334 11.8554093,2.081525 -0.0034,-7.084964 z"
style="fill:none;stroke:#729fcf;stroke-width:0.79013211;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path3775"
d="m 15.399796,10.162606 -0.0049,6.927603 7.90176,-3.27944 1.44e-4,-6.2686576 z"
style="fill:none;stroke:#3465a4;stroke-width:0.79013211;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
<g
id="layer8"
inkscape:label="F">
<path
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccc"
id="rect3663-8"
d="m 4.4570351,3.9695931 2e-6,11.0952039 3.0013315,-1e-6 V 10.473678 H 10.4597 V 8.1781188 H 7.4583686 V 6.2651527 H 12.460589 V 3.9695931 Z"
style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient3806);fill-opacity:1;fill-rule:evenodd;stroke:#280000;stroke-width:0.43747175;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB