Assembly: Initial implementation (#10427)

* Assembly: Initial implementation.
* Disable Assembly wb as it's WIP.
* Stub code for handling assembly import.

Co-authored-by: sliptonic <shopinthewoods@gmail.com>
Co-authored-by: Paddle <PaddleStroke@users.noreply.github.com>
This commit is contained in:
PaddleStroke
2023-08-31 19:30:10 +02:00
committed by GitHub
parent f3463fe5a7
commit b7a6558c72
26 changed files with 2494 additions and 3 deletions

View File

@@ -118,6 +118,7 @@ macro(InitializeFreeCADBuildOptions)
option(BUILD_PART "Build the FreeCAD part module" ON)
option(BUILD_PART_DESIGN "Build the FreeCAD part design module" ON)
option(BUILD_PATH "Build the FreeCAD path module" ON)
option(BUILD_ASSEMBLY "Build the FreeCAD Assembly module" ON)
option(BUILD_PLOT "Build the FreeCAD plot module" ON)
option(BUILD_POINTS "Build the FreeCAD points module" ON)
option(BUILD_REVERSEENGINEERING "Build the FreeCAD reverse engineering module" ON)

View File

@@ -433,7 +433,7 @@ QStringList DlgSettingsWorkbenchesImp::getDisabledWorkbenches()
ParameterGrp::handle hGrp;
hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Workbenches");
disabled_wbs = QString::fromStdString(hGrp->GetASCII("Disabled", "NoneWorkbench,TestWorkbench"));
disabled_wbs = QString::fromStdString(hGrp->GetASCII("Disabled", "NoneWorkbench,TestWorkbench,AssemblyWorkbench"));
#if QT_VERSION >= QT_VERSION_CHECK(5,15,0)
unfiltered_disabled_wbs_list = disabled_wbs.split(QLatin1String(","), Qt::SkipEmptyParts);
#else

View File

@@ -610,7 +610,7 @@ class Addon:
wbName = self.get_workbench_name()
# Add the wb to the list of disabled if it was not already
disabled_wbs = pref.GetString("Disabled", "NoneWorkbench,TestWorkbench")
disabled_wbs = pref.GetString("Disabled", "NoneWorkbench,TestWorkbench,AssemblyWorkbench")
# print(f"start disabling {disabled_wbs}")
disabled_wbs_list = disabled_wbs.split(",")
if not (wbName in disabled_wbs_list):
@@ -641,7 +641,7 @@ class Addon:
def remove_from_disabled_wbs(self, wbName: str):
pref = fci.ParamGet("User parameter:BaseApp/Preferences/Workbenches")
disabled_wbs = pref.GetString("Disabled", "NoneWorkbench,TestWorkbench")
disabled_wbs = pref.GetString("Disabled", "NoneWorkbench,TestWorkbench,AssemblyWorkbench")
# print(f"start enabling : {disabled_wbs}")
disabled_wbs_list = disabled_wbs.split(",")
disabled_wbs = ""

View File

View File

View File

@@ -0,0 +1,48 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/****************************************************************************
* *
* Copyright (c) 2023 Ondsel <development@ondsel.com> *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* FreeCAD 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 *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
#include <FCGlobal.h>
#ifndef ASSEMBLY_GLOBAL_H
#define ASSEMBLY_GLOBAL_H
// Assembly
#ifndef AssemblyExport
#ifdef Assembly_EXPORTS
# define AssemblyExport FREECAD_DECL_EXPORT
#else
# define AssemblyExport FREECAD_DECL_IMPORT
#endif
#endif
// AssemblyGui
#ifndef AssemblyGuiExport
#ifdef AssemblyGui_EXPORTS
# define AssemblyGuiExport FREECAD_DECL_EXPORT
#else
# define AssemblyGuiExport FREECAD_DECL_IMPORT
#endif
#endif
#endif //ASSEMBLY_GLOBAL_H

View File

@@ -0,0 +1,32 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# /****************************************************************************
# *
# Copyright (c) 2023 Ondsel <development@ondsel.com> *
# *
# This file is part of FreeCAD. *
# *
# FreeCAD is free software: you can redistribute it and/or modify it *
# under the terms of the GNU Lesser General Public License as *
# published by the Free Software Foundation, either version 2.1 of the *
# License, or (at your option) any later version. *
# *
# FreeCAD 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 *
# Lesser General Public License for more details. *
# *
# You should have received a copy of the GNU Lesser General Public *
# License along with FreeCAD. If not, see *
# <https://www.gnu.org/licenses/>. *
# *
# ***************************************************************************/
def open(filename):
doc = App.activeDocument()
# here you do all what is needed with filename, read, classify data, create corresponding FreeCAD objects
doc.recompute()
def insert(filename, docname):
print("Inserting file: " + filename + " into document: " + docname)

View File

@@ -0,0 +1,74 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# /****************************************************************************
# *
# Copyright (c) 2023 Ondsel <development@ondsel.com> *
# *
# This file is part of FreeCAD. *
# *
# FreeCAD is free software: you can redistribute it and/or modify it *
# under the terms of the GNU Lesser General Public License as *
# published by the Free Software Foundation, either version 2.1 of the *
# License, or (at your option) any later version. *
# *
# FreeCAD 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 *
# Lesser General Public License for more details. *
# *
# You should have received a copy of the GNU Lesser General Public *
# License along with FreeCAD. If not, see *
# <https://www.gnu.org/licenses/>. *
# *
# ***************************************************************************/
import FreeCAD
import Part
import unittest
class TestCore(unittest.TestCase):
@classmethod
def setUpClass(cls):
"""setUpClass()...
This method is called upon instantiation of this test class. Add code and objects here
that are needed for the duration of the test() methods in this class. In other words,
set up the 'global' test environment here; use the `setUp()` method to set up a 'local'
test environment.
This method does not have access to the class `self` reference, but it
is able to call static methods within this same class.
"""
pass
@classmethod
def tearDownClass(cls):
"""tearDownClass()...
This method is called prior to destruction of this test class. Add code and objects here
that cleanup the test environment after the test() methods in this class have been executed.
This method does not have access to the class `self` reference. This method
is able to call static methods within this same class.
"""
pass
# Close geometry document without saving
# FreeCAD.closeDocument(FreeCAD.ActiveDocument.Name)
# Setup and tear down methods called before and after each unit test
def setUp(self):
"""setUp()...
This method is called prior to each `test()` method. Add code and objects here
that are needed for multiple `test()` methods.
"""
self.doc = FreeCAD.ActiveDocument
self.con = FreeCAD.Console
def tearDown(self):
"""tearDown()...
This method is called after each test() method. Add cleanup instructions here.
Such cleanup instructions will likely undo those in the setUp() method.
"""
pass
def test00(self):
pass
self.assertTrue(True)

View File

@@ -0,0 +1,74 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# /****************************************************************************
# *
# Copyright (c) 2023 Ondsel <development@ondsel.com> *
# *
# This file is part of FreeCAD. *
# *
# FreeCAD is free software: you can redistribute it and/or modify it *
# under the terms of the GNU Lesser General Public License as *
# published by the Free Software Foundation, either version 2.1 of the *
# License, or (at your option) any later version. *
# *
# FreeCAD 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 *
# Lesser General Public License for more details. *
# *
# You should have received a copy of the GNU Lesser General Public *
# License along with FreeCAD. If not, see *
# <https://www.gnu.org/licenses/>. *
# *
# ***************************************************************************/
import FreeCAD
import Part
import unittest
class TestTEMPLATE(unittest.TestCase):
@classmethod
def setUpClass(cls):
"""setUpClass()...
This method is called upon instantiation of this test class. Add code and objects here
that are needed for the duration of the test() methods in this class. In other words,
set up the 'global' test environment here; use the `setUp()` method to set up a 'local'
test environment.
This method does not have access to the class `self` reference, but it
is able to call static methods within this same class.
"""
pass
@classmethod
def tearDownClass(cls):
"""tearDownClass()...
This method is called prior to destruction of this test class. Add code and objects here
that cleanup the test environment after the test() methods in this class have been executed.
This method does not have access to the class `self` reference. This method
is able to call static methods within this same class.
"""
pass
# Close geometry document without saving
# FreeCAD.closeDocument(FreeCAD.ActiveDocument.Name)
# Setup and tear down methods called before and after each unit test
def setUp(self):
"""setUp()...
This method is called prior to each `test()` method. Add code and objects here
that are needed for multiple `test()` methods.
"""
self.doc = FreeCAD.ActiveDocument
self.con = FreeCAD.Console
def tearDown(self):
"""tearDown()...
This method is called after each test() method. Add cleanup instructions here.
Such cleanup instructions will likely undo those in the setUp() method.
"""
pass
def test00(self):
pass
self.assertTrue(True)

View File

@@ -0,0 +1,63 @@
add_subdirectory(App)
if(BUILD_GUI)
add_subdirectory(Gui)
endif(BUILD_GUI)
set(Assembly_Scripts
Init.py
Commands.py
TestAssemblyWorkbench.py
Preferences.py
AssemblyImport.py
)
if(BUILD_GUI)
list (APPEND Assembly_Scripts InitGui.py)
endif(BUILD_GUI)
INSTALL(
FILES
${Assembly_Scripts}
DESTINATION
Mod/Assembly
)
SET(AssemblyScripts_SRCS
Assembly/__init__.py
)
SET(AssemblyTests_SRCS
AssemblyTests/__init__.py
AssemblyTests/TestCore.py
)
SET(all_files
${AssemblyTests_SRCS}
${AssemblyScripts_SRCS}
)
ADD_CUSTOM_TARGET(AssemblyScripts ALL
SOURCES ${all_files}
)
SET(test_files
${Assembly_Scripts}
${AssemblyTests_SRCS}
)
ADD_CUSTOM_TARGET(AssemblyTests ALL
SOURCES ${test_files}
)
fc_copy_sources(AssemblyScripts "${CMAKE_BINARY_DIR}/Mod/Assembly" ${all_files})
fc_copy_sources(AssemblyTests "${CMAKE_BINARY_DIR}/Mod/Assembly" ${test_files})
INSTALL(
FILES
${AssemblyTests_SRCS}
DESTINATION
Mod/Assembly/AssemblyTests
)

View File

@@ -0,0 +1,345 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# /****************************************************************************
# *
# Copyright (c) 2023 Ondsel <development@ondsel.com> *
# *
# This file is part of FreeCAD. *
# *
# FreeCAD is free software: you can redistribute it and/or modify it *
# under the terms of the GNU Lesser General Public License as *
# published by the Free Software Foundation, either version 2.1 of the *
# License, or (at your option) any later version. *
# *
# FreeCAD 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 *
# Lesser General Public License for more details. *
# *
# You should have received a copy of the GNU Lesser General Public *
# License along with FreeCAD. If not, see *
# <https://www.gnu.org/licenses/>. *
# *
# ***************************************************************************/
import os, re
import FreeCAD as App
from PySide.QtCore import QT_TRANSLATE_NOOP
if App.GuiUp:
import FreeCADGui as Gui
from PySide import QtCore, QtGui, QtWidgets
# translate = App.Qt.translate
__title__ = "Assembly Commands"
__author__ = "Ondsel"
__url__ = "https://www.freecad.org"
def activeAssembly():
doc = Gui.ActiveDocument
if doc is None or doc.ActiveView is None:
return None
active_part = doc.ActiveView.getActiveObject("part")
if active_part is not None and active_part.Type == "Assembly":
return active_part
return None
def isDocTemporary(doc):
# Guard against older versions of FreeCad which don't have the Temporary attribute
try:
docTemporary = doc.Temporary
except AttributeError:
docTemporary = False
return docTemporary
def labelName(obj):
if obj:
if obj.Name == obj.Label:
txt = obj.Label
else:
txt = obj.Label + " (" + obj.Name + ")"
return txt
else:
return None
class CommandCreateAssembly:
def __init__(self):
pass
def GetResources(self):
return {
"Pixmap": "Geoassembly",
"MenuText": QT_TRANSLATE_NOOP("Assembly_CreateAssembly", "Create Assembly"),
"Accel": "A",
"ToolTip": QT_TRANSLATE_NOOP(
"Assembly_CreateAssembly",
"Create an assembly object in the current document.",
),
"CmdType": "ForEdit",
}
def IsActive(self):
return App.ActiveDocument is not None
def Activated(self):
App.setActiveTransaction("Create assembly")
assembly = App.ActiveDocument.addObject("App::Part", "Assembly")
assembly.Type = "Assembly"
Gui.ActiveDocument.ActiveView.setActiveObject("part", assembly)
App.closeActiveTransaction()
class CommandInsertLink:
def __init__(self):
pass
def GetResources(self):
tooltip = "<p>Insert a Link into the assembly. "
tooltip += (
"This will create dynamic links to parts/bodies/primitives/assemblies, "
)
tooltip += "which can be in this document or in another document "
tooltip += "that is <b>open in the current session</b></p>"
tooltip += "<p>Press shift to add several links while clicking on the view."
return {
"Pixmap": "Assembly_InsertLink",
"MenuText": QT_TRANSLATE_NOOP("Assembly_InsertLink", "Insert Link"),
"Accel": "I",
"ToolTip": QT_TRANSLATE_NOOP("Assembly_InsertLink", tooltip),
"CmdType": "ForEdit",
}
def IsActive(self):
return activeAssembly() is not None
def Activated(self):
assembly = activeAssembly()
if not assembly:
return
view = Gui.activeDocument().activeView()
self.panel = TaskAssemblyInsertLink(assembly, view)
Gui.Control.showDialog(self.panel)
class TaskAssemblyInsertLink(QtCore.QObject):
def __init__(self, assembly, view):
super().__init__()
self.assembly = assembly
self.view = view
self.doc = App.ActiveDocument
self.form = Gui.PySideUic.loadUi(":/panels/TaskAssemblyInsertLink.ui")
self.form.installEventFilter(self)
# Actions
self.form.openFileButton.clicked.connect(self.openFile)
self.form.partList.itemClicked.connect(self.onItemClicked)
self.form.filterPartList.textChanged.connect(self.onFilterChange)
self.allParts = []
self.partsDoc = []
self.numberOfAddedParts = 0
self.translation = 0
self.partMoving = False
self.buildPartList()
App.setActiveTransaction("Insert Link")
def accept(self):
App.closeActiveTransaction()
self.deactivated()
return True
def reject(self):
App.closeActiveTransaction(True)
self.deactivated()
return True
def deactivated(self):
if self.partMoving:
self.endMove()
def buildPartList(self):
self.allParts.clear()
self.partsDoc.clear()
docList = App.listDocuments().values()
for doc in docList:
if isDocTemporary(doc):
continue
for obj in doc.findObjects("App::Part"):
# we don't want to link to itself
if obj != self.assembly:
self.allParts.append(obj)
self.partsDoc.append(doc)
for obj in doc.findObjects("PartDesign::Body"):
# but only those at top level (not nested inside other containers)
if obj.getParentGeoFeatureGroup() is None:
self.allParts.append(obj)
self.partsDoc.append(doc)
self.form.partList.clear()
for part in self.allParts:
newItem = QtGui.QListWidgetItem()
newItem.setText(part.Document.Name + "#" + labelName(part))
newItem.setIcon(part.ViewObject.Icon)
self.form.partList.addItem(newItem)
def onFilterChange(self):
filterStr = self.form.filterPartList.text().strip()
for x in range(self.form.partList.count()):
item = self.form.partList.item(x)
# check the items's text match the filter ignoring the case
matchStr = re.search(filterStr, item.text(), flags=re.IGNORECASE)
if filterStr and not matchStr:
item.setHidden(True)
else:
item.setHidden(False)
def openFile(self):
filename = None
importDoc = None
importDocIsOpen = False
dialog = QtGui.QFileDialog(
QtGui.QApplication.activeWindow(),
"Select FreeCAD document to import part from",
)
dialog.setNameFilter(
"Supported Formats *.FCStd *.fcstd (*.FCStd *.fcstd);;All files (*.*)"
)
if dialog.exec_():
filename = str(dialog.selectedFiles()[0])
# look only for filenames, not paths, as there are problems on WIN10 (Address-translation??)
requestedFile = os.path.split(filename)[1]
# see whether the file is already open
for d in App.listDocuments().values():
recentFile = os.path.split(d.FileName)[1]
if requestedFile == recentFile:
importDocIsOpen = True
break
# if not, open it
if not importDocIsOpen:
if filename.lower().endswith(".fcstd"):
App.openDocument(filename)
App.setActiveDocument(self.doc.Name)
self.buildPartList()
return
def onItemClicked(self, item):
for selected in self.form.partList.selectedIndexes():
selectedPart = self.allParts[selected.row()]
if not selectedPart:
return
if self.partMoving:
self.endMove()
# check that the current document had been saved or that it's the same document as that of the selected part
if not self.doc.FileName != "" and not self.doc == selectedPart.Document:
print(
"The current document must be saved before inserting an external part"
)
return
self.createdLink = self.assembly.newObject("App::Link", selectedPart.Name)
self.createdLink.LinkedObject = selectedPart
self.createdLink.Placement.Base = self.getTranslationVec(selectedPart)
self.createdLink.recompute()
self.numberOfAddedParts += 1
# highlight the link
Gui.Selection.clearSelection()
Gui.Selection.addSelection(
self.doc.Name, self.assembly.Name, self.createdLink.Name + "."
)
# Start moving the part if user brings mouse on view
self.initMove()
def initMove(self):
self.callbackMove = self.view.addEventCallback(
"SoLocation2Event", self.moveMouse
)
self.callbackClick = self.view.addEventCallback(
"SoMouseButtonEvent", self.clickMouse
)
self.callbackKey = self.view.addEventCallback(
"SoKeyboardEvent", self.KeyboardEvent
)
self.partMoving = True
# Selection filter to avoid selecting the part while it's moving
# filter = Gui.Selection.Filter('SELECT ???')
# Gui.Selection.addSelectionGate(filter)
def endMove(self):
self.view.removeEventCallback("SoLocation2Event", self.callbackMove)
self.view.removeEventCallback("SoMouseButtonEvent", self.callbackClick)
self.view.removeEventCallback("SoKeyboardEvent", self.callbackKey)
self.partMoving = False
self.doc.recompute()
# Gui.Selection.removeSelectionGate()
def moveMouse(self, info):
newPos = self.view.getPoint(*info["Position"])
self.createdLink.Placement.Base = newPos
def clickMouse(self, info):
if info["Button"] == "BUTTON1" and info["State"] == "DOWN":
if info["ShiftDown"]:
# Create a new link and moves this one now
currentPos = self.createdLink.Placement.Base
selectedPart = self.createdLink.LinkedObject
self.createdLink = self.assembly.newObject(
"App::Link", selectedPart.Name
)
self.createdLink.LinkedObject = selectedPart
self.createdLink.Placement.Base = currentPos
else:
self.endMove()
# 3D view keyboard handler
def KeyboardEvent(self, info):
if info["State"] == "UP" and info["Key"] == "ESCAPE":
self.endMove()
self.doc.removeObject(self.createdLink.Name)
# Taskbox keyboard event handler
def eventFilter(self, watched, event):
if watched == self.form and event.type() == QtCore.QEvent.KeyPress:
if event.key() == QtCore.Qt.Key_Escape and self.partMoving:
self.endMove()
self.doc.removeObject(self.createdLink.Name)
return True # Consume the event
return super().eventFilter(watched, event)
def getTranslationVec(self, part):
bb = part.Shape.BoundBox
if bb:
self.translation += (bb.XMax + bb.YMax + bb.ZMax) * 0.15
else:
self.translation += 10
return App.Vector(self.translation, self.translation, self.translation)
if App.GuiUp:
Gui.addCommand("Assembly_CreateAssembly", CommandCreateAssembly())
Gui.addCommand("Assembly_InsertLink", CommandInsertLink())

View File

@@ -0,0 +1,52 @@
include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}
)
set(AssemblyGui_LIBS
FreeCADGui
)
PYSIDE_WRAP_RC(Assembly_QRC_SRCS Resources/Assembly.qrc)
set (Assembly_TR_QRC ${CMAKE_CURRENT_BINARY_DIR}/Resources/Assembly_translation.qrc)
qt_find_and_add_translation(QM_SRCS "Resources/translations/*_*.ts"
${CMAKE_CURRENT_BINARY_DIR}/Resources/translations)
qt_create_resource_file(${Assembly_TR_QRC} ${QM_SRCS})
qt_add_resources(AssemblyResource_SRCS Resources/Assembly.qrc ${Assembly_TR_QRC})
SOURCE_GROUP("Resources" FILES ${AssemblyResource_SRCS})
SET(AssemblyGui_SRCS_Module
${Assembly_QRC_SRCS}
)
SOURCE_GROUP("Module" FILES ${AssemblyGui_SRCS_Module})
SET(AssemblyGui_SRCS
${AssemblyResource_SRCS}
${AssemblyGui_UIC_HDRS}
${AssemblyGui_SRCS_Module}
)
SET(AssemblyGuiIcon_SVG
Resources/icons/AssemblyWorkbench.svg
)
add_library(AssemblyGui SHARED ${AssemblyGui_SRCS} ${AssemblyGuiIcon_SVG})
target_link_libraries(AssemblyGui ${AssemblyGui_LIBS})
SET_BIN_DIR(AssemblyGui AssemblyGui /Mod/Assembly)
SET_PYTHON_PREFIX_SUFFIX(AssemblyGui)
fc_copy_sources(AssemblyGui "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/Assembly" ${AssemblyGuiIcon_SVG})
fc_target_copy_resource(AssemblyGui
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_BINARY_DIR}/Mod/Assembly
Assembly_rc.py)
INSTALL(TARGETS AssemblyGui DESTINATION ${CMAKE_INSTALL_LIBDIR})
INSTALL(FILES ${AssemblyGuiIcon_SVG} DESTINATION "${CMAKE_INSTALL_DATADIR}/Mod/Assembly/Resources/icons")

View File

@@ -0,0 +1,8 @@
<RCC>
<qresource>
<file>icons/Assembly_InsertLink.svg</file>
<file>icons/preferences-assembly.svg</file>
<file>panels/TaskAssemblyInsertLink.ui</file>
<file>preferences/Assembly.ui</file>
</qresource>
</RCC>

View File

@@ -0,0 +1,343 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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"
version="1.1"
viewBox="0 0 64 64"
id="svg96"
sodipodi:docname="Geofeaturegroup.svg"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1255"
inkscape:window-height="930"
id="namedview98"
showgrid="false"
inkscape:zoom="3.6875"
inkscape:cx="32"
inkscape:cy="32"
inkscape:window-x="67"
inkscape:window-y="23"
inkscape:window-maximized="0"
inkscape:current-layer="svg96" />
<defs
id="defs26">
<linearGradient
id="linearGradient4383">
<stop
stop-color="#3465a4"
offset="0"
id="stop2" />
<stop
stop-color="#729fcf"
offset="1"
id="stop4" />
</linearGradient>
<linearGradient
id="linearGradient4389"
x1="20.244"
x2="17.244"
y1="37.588"
y2="27.588"
gradientTransform="translate(-1.2435,-2.5881)"
gradientUnits="userSpaceOnUse"
xlink:href="#linearGradient3774" />
<linearGradient
id="linearGradient4399"
x1="48.714"
x2="44.714"
y1="45.586"
y2="34.586"
gradientTransform="translate(1.2856,1.4142)"
gradientUnits="userSpaceOnUse">
<stop
stop-color="#c4a000"
offset="0"
id="stop8" />
<stop
stop-color="#edd400"
offset="1"
id="stop10" />
</linearGradient>
<linearGradient
id="linearGradient69042"
x1="48.714"
x2="44.714"
y1="45.586"
y2="34.586"
gradientTransform="translate(-12.714,-17.586)"
gradientUnits="userSpaceOnUse"
xlink:href="#linearGradient3774" />
<linearGradient
id="linearGradient69056"
x1="27.244"
x2="22.244"
y1="54.588"
y2="40.588"
gradientTransform="translate(-1.2435,-2.5881)"
gradientUnits="userSpaceOnUse">
<stop
stop-color="#c4a000"
offset="0"
id="stop14" />
<stop
stop-color="#fce94f"
offset="1"
id="stop16" />
</linearGradient>
<linearGradient
id="linearGradient69709"
x1="20.244"
x2="17.244"
y1="37.588"
y2="27.588"
gradientTransform="matrix(1,-0.026667,0,1,81.696,-5.3735)"
gradientUnits="userSpaceOnUse"
xlink:href="#linearGradient4383" />
<linearGradient
id="linearGradient69717"
x1="50.714"
x2="48.714"
y1="25.586"
y2="20.586"
gradientTransform="translate(61.2256,1.0356)"
gradientUnits="userSpaceOnUse"
xlink:href="#linearGradient4383" />
<linearGradient
id="linearGradient3774">
<stop
stop-color="#4e9a06"
offset="0"
id="stop21" />
<stop
stop-color="#8ae234"
offset="1"
id="stop23" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient69056"
id="linearGradient920"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-41.2435,-2.5881)"
x1="20.243999"
y1="37.588001"
x2="17.243999"
y2="27.587999" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4399"
id="linearGradient922"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-52.714,-17.586)"
x1="48.714001"
y1="45.585999"
x2="44.714001"
y2="34.585999" />
</defs>
<metadata
id="metadata28">
<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 />
<dc:title>Path-Stock</dc:title>
<dc:date>2015-07-04</dc:date>
<dc:relation>http://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
<dc:publisher>
<cc:Agent>
<dc:title>FreeCAD</dc:title>
</cc:Agent>
</dc:publisher>
<dc:identifier>FreeCAD/src/Mod/Path/Gui/Resources/icons/Path-Stock.svg</dc:identifier>
<dc:rights>
<cc:Agent>
<dc:title>FreeCAD LGPL2+</dc:title>
</cc:Agent>
</dc:rights>
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
<dc:contributor>
<cc:Agent>
<dc:title>[agryson] Alexander Gryson</dc:title>
</cc:Agent>
</dc:contributor>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="g40"
style="stroke-width:2">
<path
d="M 9,49 V 35 l 28,10 v 14 z"
id="path30"
style="fill:url(#linearGradient69056);stroke:#302b00;stroke-linejoin:round"
inkscape:connector-curvature="0" />
<path
d="M 37,59 V 45 L 55,28 v 13 z"
id="path32"
style="fill:url(#linearGradient4399);stroke:#302b00;stroke-linejoin:round"
inkscape:connector-curvature="0" />
<path
d="M 11.008,47.606 11,37.9997 l 24,8 0.0081,10.185 z"
id="path34"
inkscape:connector-curvature="0"
style="fill:none;stroke:#fce94f" />
<path
d="M 39.005,54.168 39,45.9998 l 14,-13 0.0021,7.1768 z"
id="path36"
inkscape:connector-curvature="0"
style="fill:none;stroke:#edd400" />
<path
d="M 23,40 42,23 55,28 37,45 Z"
id="path38"
inkscape:connector-curvature="0"
style="fill:#fce94f;stroke:#302b00;stroke-linejoin:round" />
</g>
<g
id="g943"
transform="translate(-60)">
<path
d="m 91,33.5 -0.02739,-14.214 12.967,4.3352 v 14.5 z"
id="path54"
style="fill:url(#linearGradient69709);stroke:#0b1521;stroke-width:2;stroke-linejoin:round"
inkscape:connector-curvature="0" />
<path
d="m 92.927,32.029 0.04731,-10.141 8.9272,3.29 0.0781,10.042 z"
id="path56"
inkscape:connector-curvature="0"
style="fill:none;stroke:#729fcf;stroke-width:2" />
<path
d="m 103.94,38.121 v -14.5 l 11,-9 L 115,28 Z"
id="path58"
style="fill:url(#linearGradient69717);stroke:#0b1521;stroke-width:2;stroke-linejoin:round"
inkscape:connector-curvature="0" />
<path
d="m 105.94,33.621 v -9 l 7,-6 -0.0122,8.5816 z"
id="path60"
inkscape:connector-curvature="0"
style="fill:none;stroke:#729fcf;stroke-width:2" />
<path
d="M 90.973,19.286 102,9.9998 l 12.94,4.6214 -11,9 z"
id="path62"
inkscape:connector-curvature="0"
style="fill:#729fcf;stroke:#0b1521;stroke-width:2;stroke-linejoin:round" />
</g>
<g
display="none"
fill="#ef2929"
fill-rule="evenodd"
opacity=".588"
stroke="#ef2929"
stroke-width="1px"
id="g94">
<path
d="m9 35v14"
id="path66" />
<path
d="m9 35 28 10"
id="path68" />
<path
d="m55 28v13"
id="path70" />
<path
d="m37 45 18-17"
id="path72" />
<path
d="m23 40v-14"
id="path74" />
<path
d="m29 5 13 5"
id="path76" />
<path
d="m23 26 19-16"
id="path78" />
<path
d="m19 13 10-8"
id="path80" />
<path
d="m55 15-9 8"
id="path82" />
<path
d="m42 23v-13"
id="path84" />
<path
d="m42 23 14 5"
id="path86" />
<path
d="m23 40 19-17"
id="path88" />
<path
d="m23 10h19"
id="path90" />
<path
d="m34 17v13"
id="path92" />
</g>
<g
id="g963"
transform="translate(40)">
<g
style="stroke:#172a04;stroke-width:2;stroke-linejoin:round"
transform="translate(-40)"
id="g48">
<path
inkscape:connector-curvature="0"
style="fill:url(#linearGradient4389)"
id="path42"
d="M 9,35 V 21 l 14,5 v 14 z" />
<path
style="fill:#8ae234"
inkscape:connector-curvature="0"
id="path44"
d="M 9,21 28.585,5.209 42,10.0001 l -19,16 z" />
<path
inkscape:connector-curvature="0"
style="fill:url(#linearGradient69042)"
id="path46"
d="M 23,40 V 26 l 7.9726,-6.7138 0.02739,13.714 z" />
</g>
<path
inkscape:connector-curvature="0"
style="fill:url(#linearGradient920);fill-opacity:1;stroke:#172a04;stroke-width:2;stroke-linejoin:round"
id="path912"
d="M -31,35 V 21 l 14,5 v 14 z" />
<path
style="fill:#fce94f;fill-opacity:1;stroke:#172a04;stroke-width:2;stroke-linejoin:round;stroke-opacity:1"
inkscape:connector-curvature="0"
id="path914"
d="M -31,21 -11.415,5.209 2,10.0001 l -19,16 z" />
<path
inkscape:connector-curvature="0"
style="fill:url(#linearGradient922);fill-opacity:1;stroke:#172a04;stroke-width:2;stroke-linejoin:round"
id="path916"
d="M -17,40 V 26 l 7.9726,-6.7138 0.02739,13.714 z" />
<path
d="m -15,36 v -9 l 4,-3.5 v 9 z"
id="path50"
inkscape:connector-curvature="0"
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-opacity:1" />
<path
d="m -29.049,33.746 0.08695,-9.9796 9.9568,3.5229 -0.02105,9.9613 z"
id="path52"
inkscape:connector-curvature="0"
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

@@ -0,0 +1,424 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="64"
height="64"
id="svg3559"
version="1.1"
inkscape:version="1.1-beta1 (77e7b44db3, 2021-03-28)"
sodipodi:docname="AssemblyWorkbench.svg"
viewBox="0 0 64 64"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs3561">
<linearGradient
inkscape:collect="always"
id="linearGradient1083">
<stop
style="stop-color:#a50000;stop-opacity:1"
offset="0"
id="stop1079" />
<stop
style="stop-color:#ef2929;stop-opacity:1"
offset="1"
id="stop1081" />
</linearGradient>
<linearGradient
id="linearGradient4383-1"
inkscape:collect="always">
<stop
id="stop69725"
offset="0"
style="stop-color:#c4a000;stop-opacity:1" />
<stop
id="stop69727"
offset="1"
style="stop-color:#fce94f;stop-opacity:1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient4383">
<stop
style="stop-color:#3465a4;stop-opacity:1"
offset="0"
id="stop4385" />
<stop
style="stop-color:#729fcf;stop-opacity:1"
offset="1"
id="stop4387" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4383-1"
id="linearGradient4389"
x1="20.243532"
y1="37.588112"
x2="17.243532"
y2="27.588112"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-1.243533,-2.588112)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4383"
id="linearGradient4399"
x1="48.714352"
y1="45.585785"
x2="44.714352"
y2="34.585785"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(1.2856487,1.4142136)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4383-3"
id="linearGradient4389-0"
x1="27.243532"
y1="54.588112"
x2="21.243532"
y2="30.588112"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-1.243533,-2.588112)" />
<linearGradient
inkscape:collect="always"
id="linearGradient4383-3">
<stop
style="stop-color:#3465a4;stop-opacity:1"
offset="0"
id="stop4385-1" />
<stop
style="stop-color:#729fcf;stop-opacity:1"
offset="1"
id="stop4387-2" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4393-9"
id="linearGradient4399-7"
x1="48.714352"
y1="45.585785"
x2="40.714352"
y2="24.585787"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(1.2856487,1.4142136)" />
<linearGradient
inkscape:collect="always"
id="linearGradient4393-9">
<stop
style="stop-color:#204a87;stop-opacity:1"
offset="0"
id="stop4395-8" />
<stop
style="stop-color:#3465a4;stop-opacity:1"
offset="1"
id="stop4397-1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient73208"
id="linearGradient69042"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-12.714351,-17.585786)"
x1="48.714352"
y1="45.585785"
x2="44.714352"
y2="34.585785" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4383"
id="linearGradient69056"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-1.243533,-2.588112)"
x1="27.243532"
y1="54.588112"
x2="22.243532"
y2="40.588112" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1083"
id="linearGradient69709"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(21.756467,-5.588112)"
x1="20.243532"
y1="37.588112"
x2="17.243532"
y2="27.588112" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1083"
id="linearGradient69717"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(1.2856487,1.4142136)"
x1="50.714352"
y1="25.585787"
x2="48.714352"
y2="20.585787" />
<linearGradient
inkscape:collect="always"
id="linearGradient73208">
<stop
style="stop-color:#c4a000;stop-opacity:1"
offset="0"
id="stop73210" />
<stop
style="stop-color:#edd400;stop-opacity:1"
offset="1"
id="stop73212" />
</linearGradient>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="3.5355339"
inkscape:cx="-6.2225397"
inkscape:cy="75.519004"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1857"
inkscape:window-height="1104"
inkscape:window-x="486"
inkscape:window-y="243"
inkscape:window-maximized="0"
inkscape:snap-global="true"
objecttolerance="10.0"
gridtolerance="10.0"
guidetolerance="10.0"
inkscape:pagecheckerboard="0">
<inkscape:grid
type="xygrid"
id="grid3007"
empspacing="4"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true"
spacingx="0.5"
spacingy="0.5" />
</sodipodi:namedview>
<metadata
id="metadata3564">
<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>Path-Stock</dc:title>
<dc:date>2015-07-04</dc:date>
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
<dc:publisher>
<cc:Agent>
<dc:title>FreeCAD</dc:title>
</cc:Agent>
</dc:publisher>
<dc:identifier>FreeCAD/src/Mod/Path/Gui/Resources/icons/Path-Stock.svg</dc:identifier>
<dc:rights>
<cc:Agent>
<dc:title>FreeCAD LGPL2+</dc:title>
</cc:Agent>
</dc:rights>
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
<dc:contributor>
<cc:Agent>
<dc:title>[agryson] Alexander Gryson</dc:title>
</cc:Agent>
</dc:contributor>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer"
style="display:inline">
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path69052"
d="m 9,35 0,-14 14,5 0,14 z"
style="fill:url(#linearGradient4389);fill-opacity:1.0;fill-rule:nonzero;stroke:#0b1521;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<path
style="fill:url(#linearGradient69056);fill-opacity:1.0;fill-rule:nonzero;stroke:#0b1521;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
d="M 9,49 9,35 37,45 37,59 Z"
id="path4381"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:url(#linearGradient4399);fill-opacity:1.0;fill-rule:nonzero;stroke:#0b1521;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
d="M 37,59 37,45 55,28 55,41 Z"
id="path4391"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:#fce94f;fill-opacity:1;fill-rule:nonzero;stroke:#0b1521;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
d="M 9,21 29,5 42,10 23,26 Z"
id="path4403"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 11.008035,47.60627 11,38 l 24,8 0.0081,10.184812 z"
id="path4381-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 39.005041,54.16825 39,46 53,33 l 0.0021,7.176847 z"
id="path4391-0"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path69038"
d="M 23,40 42,23 55,28 37,45 Z"
style="fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:#0b1521;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path69040"
d="m 23,40 0,-14 8,-7 0,14 z"
style="fill:url(#linearGradient69042);fill-opacity:1.0;fill-rule:nonzero;stroke:#0b1521;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path69044"
d="m 25,36 0,-9 4,-3.5 0,9 z"
style="fill:none;stroke:#edd400;stroke-width:2;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path69048"
d="M 11.008,33.60627 11,24 l 10,3 0,10 z"
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:url(#linearGradient69709);fill-opacity:1.0;fill-rule:nonzero;stroke:#302b00;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
d="m 31,33 0,-14 13,5 0,14.5 z"
id="path69705"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:none;stroke:#ef2929;stroke-width:2;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 33,32 0,-10 9,3 0,10.5 z"
id="path69707"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path69715"
d="M 44,38.5 44,24 55,15 55,28 Z"
style="fill:url(#linearGradient69717);fill-opacity:1.0;fill-rule:nonzero;stroke:#302b00;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path69719"
d="m 46,34 0,-9 7,-6 0,8 z"
style="fill:none;stroke:#ef2929;stroke-width:2;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path69721"
d="m 31,19 11,-9 13,5 -11,9 z"
style="fill:#ef2929;fill-opacity:1;fill-rule:nonzero;stroke:#302b00;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="temporal"
style="display:none;opacity:0.58800001"
sodipodi:insensitive="true">
<path
inkscape:connector-curvature="0"
id="path68967"
d="M 9,35 9,49"
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
sodipodi:nodetypes="cc" />
<path
inkscape:connector-curvature="0"
id="path68971"
d="M 9,35 37,45"
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="cc"
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 55,28 0,13"
id="path68973"
inkscape:connector-curvature="0" />
<path
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 37,45 55,28"
id="path68977"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path68983"
d="M 23,40 23,26"
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path68985"
d="m 29,5 13,5"
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 23,26 42,10"
id="path68989"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 19,13 29,5"
id="path68993"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 55,15 -9,8"
id="path68997"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path69030"
d="M 42,23 42,10"
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 42,23 14,5"
id="path69034"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path69036"
d="M 23,40 42,23"
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path69711"
d="m 23,10 19,0"
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="fill:#ef2929;fill-rule:evenodd;stroke:#ef2929;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 34,17 0,13"
id="path69713"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -0,0 +1,343 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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"
version="1.1"
viewBox="0 0 64 64"
id="svg96"
sodipodi:docname="Geofeaturegroup.svg"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1255"
inkscape:window-height="930"
id="namedview98"
showgrid="false"
inkscape:zoom="3.6875"
inkscape:cx="32"
inkscape:cy="32"
inkscape:window-x="67"
inkscape:window-y="23"
inkscape:window-maximized="0"
inkscape:current-layer="svg96" />
<defs
id="defs26">
<linearGradient
id="linearGradient4383">
<stop
stop-color="#3465a4"
offset="0"
id="stop2" />
<stop
stop-color="#729fcf"
offset="1"
id="stop4" />
</linearGradient>
<linearGradient
id="linearGradient4389"
x1="20.244"
x2="17.244"
y1="37.588"
y2="27.588"
gradientTransform="translate(-1.2435,-2.5881)"
gradientUnits="userSpaceOnUse"
xlink:href="#linearGradient3774" />
<linearGradient
id="linearGradient4399"
x1="48.714"
x2="44.714"
y1="45.586"
y2="34.586"
gradientTransform="translate(1.2856,1.4142)"
gradientUnits="userSpaceOnUse">
<stop
stop-color="#c4a000"
offset="0"
id="stop8" />
<stop
stop-color="#edd400"
offset="1"
id="stop10" />
</linearGradient>
<linearGradient
id="linearGradient69042"
x1="48.714"
x2="44.714"
y1="45.586"
y2="34.586"
gradientTransform="translate(-12.714,-17.586)"
gradientUnits="userSpaceOnUse"
xlink:href="#linearGradient3774" />
<linearGradient
id="linearGradient69056"
x1="27.244"
x2="22.244"
y1="54.588"
y2="40.588"
gradientTransform="translate(-1.2435,-2.5881)"
gradientUnits="userSpaceOnUse">
<stop
stop-color="#c4a000"
offset="0"
id="stop14" />
<stop
stop-color="#fce94f"
offset="1"
id="stop16" />
</linearGradient>
<linearGradient
id="linearGradient69709"
x1="20.244"
x2="17.244"
y1="37.588"
y2="27.588"
gradientTransform="matrix(1,-0.026667,0,1,81.696,-5.3735)"
gradientUnits="userSpaceOnUse"
xlink:href="#linearGradient4383" />
<linearGradient
id="linearGradient69717"
x1="50.714"
x2="48.714"
y1="25.586"
y2="20.586"
gradientTransform="translate(61.2256,1.0356)"
gradientUnits="userSpaceOnUse"
xlink:href="#linearGradient4383" />
<linearGradient
id="linearGradient3774">
<stop
stop-color="#4e9a06"
offset="0"
id="stop21" />
<stop
stop-color="#8ae234"
offset="1"
id="stop23" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient69056"
id="linearGradient920"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-41.2435,-2.5881)"
x1="20.243999"
y1="37.588001"
x2="17.243999"
y2="27.587999" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4399"
id="linearGradient922"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-52.714,-17.586)"
x1="48.714001"
y1="45.585999"
x2="44.714001"
y2="34.585999" />
</defs>
<metadata
id="metadata28">
<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 />
<dc:title>Path-Stock</dc:title>
<dc:date>2015-07-04</dc:date>
<dc:relation>http://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
<dc:publisher>
<cc:Agent>
<dc:title>FreeCAD</dc:title>
</cc:Agent>
</dc:publisher>
<dc:identifier>FreeCAD/src/Mod/Path/Gui/Resources/icons/Path-Stock.svg</dc:identifier>
<dc:rights>
<cc:Agent>
<dc:title>FreeCAD LGPL2+</dc:title>
</cc:Agent>
</dc:rights>
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
<dc:contributor>
<cc:Agent>
<dc:title>[agryson] Alexander Gryson</dc:title>
</cc:Agent>
</dc:contributor>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="g40"
style="stroke-width:2">
<path
d="M 9,49 V 35 l 28,10 v 14 z"
id="path30"
style="fill:url(#linearGradient69056);stroke:#302b00;stroke-linejoin:round"
inkscape:connector-curvature="0" />
<path
d="M 37,59 V 45 L 55,28 v 13 z"
id="path32"
style="fill:url(#linearGradient4399);stroke:#302b00;stroke-linejoin:round"
inkscape:connector-curvature="0" />
<path
d="M 11.008,47.606 11,37.9997 l 24,8 0.0081,10.185 z"
id="path34"
inkscape:connector-curvature="0"
style="fill:none;stroke:#fce94f" />
<path
d="M 39.005,54.168 39,45.9998 l 14,-13 0.0021,7.1768 z"
id="path36"
inkscape:connector-curvature="0"
style="fill:none;stroke:#edd400" />
<path
d="M 23,40 42,23 55,28 37,45 Z"
id="path38"
inkscape:connector-curvature="0"
style="fill:#fce94f;stroke:#302b00;stroke-linejoin:round" />
</g>
<g
id="g943"
transform="translate(-60)">
<path
d="m 91,33.5 -0.02739,-14.214 12.967,4.3352 v 14.5 z"
id="path54"
style="fill:url(#linearGradient69709);stroke:#0b1521;stroke-width:2;stroke-linejoin:round"
inkscape:connector-curvature="0" />
<path
d="m 92.927,32.029 0.04731,-10.141 8.9272,3.29 0.0781,10.042 z"
id="path56"
inkscape:connector-curvature="0"
style="fill:none;stroke:#729fcf;stroke-width:2" />
<path
d="m 103.94,38.121 v -14.5 l 11,-9 L 115,28 Z"
id="path58"
style="fill:url(#linearGradient69717);stroke:#0b1521;stroke-width:2;stroke-linejoin:round"
inkscape:connector-curvature="0" />
<path
d="m 105.94,33.621 v -9 l 7,-6 -0.0122,8.5816 z"
id="path60"
inkscape:connector-curvature="0"
style="fill:none;stroke:#729fcf;stroke-width:2" />
<path
d="M 90.973,19.286 102,9.9998 l 12.94,4.6214 -11,9 z"
id="path62"
inkscape:connector-curvature="0"
style="fill:#729fcf;stroke:#0b1521;stroke-width:2;stroke-linejoin:round" />
</g>
<g
display="none"
fill="#ef2929"
fill-rule="evenodd"
opacity=".588"
stroke="#ef2929"
stroke-width="1px"
id="g94">
<path
d="m9 35v14"
id="path66" />
<path
d="m9 35 28 10"
id="path68" />
<path
d="m55 28v13"
id="path70" />
<path
d="m37 45 18-17"
id="path72" />
<path
d="m23 40v-14"
id="path74" />
<path
d="m29 5 13 5"
id="path76" />
<path
d="m23 26 19-16"
id="path78" />
<path
d="m19 13 10-8"
id="path80" />
<path
d="m55 15-9 8"
id="path82" />
<path
d="m42 23v-13"
id="path84" />
<path
d="m42 23 14 5"
id="path86" />
<path
d="m23 40 19-17"
id="path88" />
<path
d="m23 10h19"
id="path90" />
<path
d="m34 17v13"
id="path92" />
</g>
<g
id="g963"
transform="translate(40)">
<g
style="stroke:#172a04;stroke-width:2;stroke-linejoin:round"
transform="translate(-40)"
id="g48">
<path
inkscape:connector-curvature="0"
style="fill:url(#linearGradient4389)"
id="path42"
d="M 9,35 V 21 l 14,5 v 14 z" />
<path
style="fill:#8ae234"
inkscape:connector-curvature="0"
id="path44"
d="M 9,21 28.585,5.209 42,10.0001 l -19,16 z" />
<path
inkscape:connector-curvature="0"
style="fill:url(#linearGradient69042)"
id="path46"
d="M 23,40 V 26 l 7.9726,-6.7138 0.02739,13.714 z" />
</g>
<path
inkscape:connector-curvature="0"
style="fill:url(#linearGradient920);fill-opacity:1;stroke:#172a04;stroke-width:2;stroke-linejoin:round"
id="path912"
d="M -31,35 V 21 l 14,5 v 14 z" />
<path
style="fill:#fce94f;fill-opacity:1;stroke:#172a04;stroke-width:2;stroke-linejoin:round;stroke-opacity:1"
inkscape:connector-curvature="0"
id="path914"
d="M -31,21 -11.415,5.209 2,10.0001 l -19,16 z" />
<path
inkscape:connector-curvature="0"
style="fill:url(#linearGradient922);fill-opacity:1;stroke:#172a04;stroke-width:2;stroke-linejoin:round"
id="path916"
d="M -17,40 V 26 l 7.9726,-6.7138 0.02739,13.714 z" />
<path
d="m -15,36 v -9 l 4,-3.5 v 9 z"
id="path50"
inkscape:connector-curvature="0"
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-opacity:1" />
<path
d="m -29.049,33.746 0.08695,-9.9796 9.9568,3.5229 -0.02105,9.9613 z"
id="path52"
inkscape:connector-curvature="0"
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TaskAssemblyInsertLink</class>
<widget class="QWidget" name="TaskAssemblyInsertLink">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>376</width>
<height>387</height>
</rect>
</property>
<property name="windowTitle">
<string>Insert Link</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLineEdit" name="filterPartList">
<property name="placeholderText">
<string>Search parts...</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QListWidget" name="partList"/>
</item>
<item row="2" column="0">
<layout class="QHBoxLayout" name="hLayout">
<item>
<widget class="QLabel" name="label1">
<property name="text">
<string>Don't find your part? </string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="openFileButton">
<property name="text">
<string>Open file</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AssemblyGui::DlgSettingsAssembly</class>
<widget class="QWidget" name="AssemblyGui::DlgSettingsAssembly">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>487</width>
<height>691</height>
</rect>
</property>
<property name="windowTitle">
<string>General</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>217</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

37
src/Mod/Assembly/Init.py Normal file
View File

@@ -0,0 +1,37 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# /****************************************************************************
# *
# Copyright (c) 2023 Ondsel <development@ondsel.com> *
# *
# This file is part of FreeCAD. *
# *
# FreeCAD is free software: you can redistribute it and/or modify it *
# under the terms of the GNU Lesser General Public License as *
# published by the Free Software Foundation, either version 2.1 of the *
# License, or (at your option) any later version. *
# *
# FreeCAD 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 *
# Lesser General Public License for more details. *
# *
# You should have received a copy of the GNU Lesser General Public *
# License along with FreeCAD. If not, see *
# <https://www.gnu.org/licenses/>. *
# *
# ***************************************************************************/
# Get the Parameter Group of this module
ParGrp = App.ParamGet("System parameter:Modules").GetGroup("Assembly")
# Set the needed information
ParGrp.SetString("HelpIndex", "Assembly/Help/index.html")
ParGrp.SetString("WorkBenchName", "Assembly")
ParGrp.SetString("WorkBenchModule", "AssemblyWorkbench.py")
FreeCAD.__unit_test__ += ["TestAssemblyWorkbench"]
# This adds a custom import type to the FreeCAD import dialog.
# The correct format for assembly interoperability is a research topic. ASMT is a placeholder.
FreeCAD.addImportType("Assembly Format (*.asmt)", "AssemblyImport")
# FreeCAD.addExportType()

104
src/Mod/Assembly/InitGui.py Normal file
View File

@@ -0,0 +1,104 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# /****************************************************************************
# *
# Copyright (c) 2023 Ondsel <development@ondsel.com> *
# *
# This file is part of FreeCAD. *
# *
# FreeCAD is free software: you can redistribute it and/or modify it *
# under the terms of the GNU Lesser General Public License as *
# published by the Free Software Foundation, either version 2.1 of the *
# License, or (at your option) any later version. *
# *
# FreeCAD 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 *
# Lesser General Public License for more details. *
# *
# You should have received a copy of the GNU Lesser General Public *
# License along with FreeCAD. If not, see *
# <https://www.gnu.org/licenses/>. *
# *
# ***************************************************************************/
import Assembly_rc
class AssemblyCommandGroup:
def __init__(self, cmdlist, menu, tooltip=None):
self.cmdlist = cmdlist
self.menu = menu
if tooltip is None:
self.tooltip = menu
else:
self.tooltip = tooltip
def GetCommands(self):
return tuple(self.cmdlist)
def GetResources(self):
return {"MenuText": self.menu, "ToolTip": self.tooltip}
def IsActive(self):
if FreeCAD.ActiveDocument is not None:
return True
return False
class AssemblyWorkbench(Workbench):
"Assembly workbench"
def __init__(self):
print("Loading Assembly workbench...")
self.__class__.Icon = (
FreeCAD.getResourceDir()
+ "Mod/Assembly/Resources/icons/AssemblyWorkbench.svg"
)
self.__class__.MenuText = "Assembly"
self.__class__.ToolTip = "Assembly workbench"
def Initialize(self):
print("Initializing Assembly workbench...")
global AssemblyCommandGroup
translate = FreeCAD.Qt.translate
# load the builtin modules
from PySide import QtCore, QtGui
from PySide.QtCore import QT_TRANSLATE_NOOP
import Commands
from Preferences import PreferencesPage
# from Preferences import preferences
FreeCADGui.addLanguagePath(":/translations")
FreeCADGui.addIconPath(":/icons")
FreeCADGui.addPreferencePage(
PreferencesPage, QT_TRANSLATE_NOOP("QObject", "Assembly")
)
# build commands list
cmdlist = ["Assembly_CreateAssembly", "Assembly_InsertLink"]
self.appendToolbar(QT_TRANSLATE_NOOP("Workbench", "Assembly"), cmdlist)
self.appendMenu(
[QT_TRANSLATE_NOOP("Workbench", "&Assembly")],
cmdlist + ["Separator"],
)
print("Assembly workbench loaded")
def Activated(self):
# update the translation engine
FreeCADGui.updateLocale()
def Deactivated(self):
pass
def ContextMenu(self, recipient):
pass
Gui.addWorkbench(AssemblyWorkbench())

View File

@@ -0,0 +1,40 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# /****************************************************************************
# *
# Copyright (c) 2023 Ondsel <development@ondsel.com> *
# *
# This file is part of FreeCAD. *
# *
# FreeCAD is free software: you can redistribute it and/or modify it *
# under the terms of the GNU Lesser General Public License as *
# published by the Free Software Foundation, either version 2.1 of the *
# License, or (at your option) any later version. *
# *
# FreeCAD 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 *
# Lesser General Public License for more details. *
# *
# You should have received a copy of the GNU Lesser General Public *
# License along with FreeCAD. If not, see *
# <https://www.gnu.org/licenses/>. *
# *
# ***************************************************************************/
import FreeCAD
import FreeCADGui
def preferences():
return FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Assembly")
class PreferencesPage:
def __init__(self, parent=None):
self.form = FreeCADGui.PySideUic.loadUi(":preferences/Assembly.ui")
def saveSettings(self):
pass
def loadSettings(self):
pass

View File

@@ -0,0 +1,31 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
# /****************************************************************************
# *
# Copyright (c) 2023 Ondsel <development@ondsel.com> *
# *
# This file is part of FreeCAD. *
# *
# FreeCAD is free software: you can redistribute it and/or modify it *
# under the terms of the GNU Lesser General Public License as *
# published by the Free Software Foundation, either version 2.1 of the *
# License, or (at your option) any later version. *
# *
# FreeCAD 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 *
# Lesser General Public License for more details. *
# *
# You should have received a copy of the GNU Lesser General Public *
# License along with FreeCAD. If not, see *
# <https://www.gnu.org/licenses/>. *
# *
# ***************************************************************************/
import TestApp
from AssemblyTests.TestCore import TestCore
# dummy usage to get flake8 and lgtm quiet
False if TestCore.__name__ else True
False if TestApp.__name__ else True

View File

@@ -0,0 +1,4 @@
/** \defgroup ASSEMBLY Assembly
* \ingroup PYTHONWORKBENCHES
* \brief Tools to build assemblies
*/

View File

@@ -6,6 +6,10 @@ if(BUILD_ARCH)
add_subdirectory(Arch)
endif(BUILD_ARCH)
if(BUILD_ASSEMBLY)
add_subdirectory(Assembly)
endif(BUILD_ASSEMBLY)
if(BUILD_CLOUD)
add_subdirectory(Cloud)
endif(BUILD_CLOUD)