Merge branch 'master' into DraftModifiersAppPart

This commit is contained in:
Yorik van Havre
2020-01-21 11:19:37 +01:00
committed by GitHub
47 changed files with 82455 additions and 720 deletions

View File

@@ -130,13 +130,13 @@
using namespace App;
using namespace std;
using namespace boost;
using namespace boost::program_options;
// scriptings (scripts are built-in but can be overridden by command line option)
#include <App/InitScript.h>
#include <App/TestScript.h>
#include <App/CMakeScript.h>
using namespace boost::program_options;
// scriptings (scripts are built-in but can be overridden by command line option)
#include <App/InitScript.h>
#include <App/TestScript.h>
#include <App/CMakeScript.h>
#ifdef _MSC_VER // New handler for Microsoft Visual C++ compiler
# pragma warning( disable : 4535 )
@@ -1082,6 +1082,16 @@ void Application::addImportType(const char* Type, const char* ModuleName)
}
}
void Application::changeImportModule(const char* Type, const char* OldModuleName, const char* NewModuleName)
{
for (auto& it : _mImportTypes) {
if (it.filter == Type && it.module == OldModuleName) {
it.module = NewModuleName;
break;
}
}
}
std::vector<std::string> Application::getImportModules(const char* Type) const
{
std::vector<std::string> modules;
@@ -1195,6 +1205,16 @@ void Application::addExportType(const char* Type, const char* ModuleName)
}
}
void Application::changeExportModule(const char* Type, const char* OldModuleName, const char* NewModuleName)
{
for (auto& it : _mExportTypes) {
if (it.filter == Type && it.module == OldModuleName) {
it.module = NewModuleName;
break;
}
}
}
std::vector<std::string> Application::getExportModules(const char* Type) const
{
std::vector<std::string> modules;
@@ -2256,7 +2276,7 @@ void Application::LoadParameters(void)
#if defined(_MSC_VER)
// fix weird error while linking boost (all versions of VC)
// VS2010: https://forum.freecadweb.org/viewtopic.php?f=4&t=1886&p=12553&hilit=boost%3A%3Afilesystem%3A%3Aget#p12553
// VS2010: https://forum.freecadweb.org/viewtopic.php?f=4&t=1886&p=12553&hilit=boost%3A%3Afilesystem%3A%3Aget#p12553
namespace boost { namespace program_options { std::string arg="arg"; } }
#if (defined (BOOST_VERSION) && (BOOST_VERSION >= 104100))
namespace boost { namespace program_options {
@@ -2946,7 +2966,7 @@ std::string Application::FindHomePath(const char* sCall)
binPath += L"bin";
SetDllDirectoryW(binPath.c_str());
// https://stackoverflow.com/questions/5625884/conversion-of-stdwstring-to-qstring-throws-linker-error
// https://stackoverflow.com/questions/5625884/conversion-of-stdwstring-to-qstring-throws-linker-error
#ifdef _MSC_VER
QString str = QString::fromUtf16(reinterpret_cast<const ushort *>(homePath.c_str()));
#else

View File

@@ -300,6 +300,8 @@ public:
//@{
/// Register an import filetype and a module name
void addImportType(const char* Type, const char* ModuleName);
/// Change the module name of a registered filetype
void changeImportModule(const char* Type, const char* OldModuleName, const char* NewModuleName);
/// Return a list of modules that support the given filetype.
std::vector<std::string> getImportModules(const char* Type) const;
/// Return a list of all modules.
@@ -316,6 +318,8 @@ public:
//@{
/// Register an export filetype and a module name
void addExportType(const char* Type, const char* ModuleName);
/// Change the module name of a registered filetype
void changeExportModule(const char* Type, const char* OldModuleName, const char* NewModuleName);
/// Return a list of modules that support the given filetype.
std::vector<std::string> getExportModules(const char* Type) const;
/// Return a list of all modules.
@@ -458,8 +462,10 @@ private:
static PyObject* sSetConfig (PyObject *self,PyObject *args);
static PyObject* sDumpConfig (PyObject *self,PyObject *args);
static PyObject* sAddImportType (PyObject *self,PyObject *args);
static PyObject* sChangeImportModule(PyObject *self,PyObject *args);
static PyObject* sGetImportType (PyObject *self,PyObject *args);
static PyObject* sAddExportType (PyObject *self,PyObject *args);
static PyObject* sChangeExportModule(PyObject *self,PyObject *args);
static PyObject* sGetExportType (PyObject *self,PyObject *args);
static PyObject* sGetResourceDir (PyObject *self,PyObject *args);
static PyObject* sGetUserAppDataDir (PyObject *self,PyObject *args);

View File

@@ -72,6 +72,8 @@ PyMethodDef Application::Methods[] = {
"Dump the configuration to the output."},
{"addImportType", (PyCFunction) Application::sAddImportType, METH_VARARGS,
"Register filetype for import"},
{"changeImportModule", (PyCFunction) Application::sChangeImportModule, METH_VARARGS,
"Change the import module name of a registered filetype"},
{"getImportType", (PyCFunction) Application::sGetImportType, METH_VARARGS,
"Get the name of the module that can import the filetype"},
{"EndingAdd", (PyCFunction) Application::sAddImportType, METH_VARARGS, // deprecated
@@ -80,6 +82,8 @@ PyMethodDef Application::Methods[] = {
"deprecated -- use getImportType"},
{"addExportType", (PyCFunction) Application::sAddExportType, METH_VARARGS,
"Register filetype for export"},
{"changeExportModule", (PyCFunction) Application::sChangeExportModule, METH_VARARGS,
"Change the export module name of a registered filetype"},
{"getExportType", (PyCFunction) Application::sGetExportType, METH_VARARGS,
"Get the name of the module that can export the filetype"},
{"getResourceDir", (PyCFunction) Application::sGetResourceDir, METH_VARARGS,
@@ -526,6 +530,18 @@ PyObject* Application::sAddImportType(PyObject * /*self*/, PyObject *args)
Py_Return;
}
PyObject* Application::sChangeImportModule(PyObject * /*self*/, PyObject *args)
{
char *key,*oldMod,*newMod;
if (!PyArg_ParseTuple(args, "sss", &key,&oldMod,&newMod))
return nullptr;
GetApplication().changeImportModule(key,oldMod,newMod);
Py_Return;
}
PyObject* Application::sGetImportType(PyObject * /*self*/, PyObject *args)
{
char* psKey=0;
@@ -578,6 +594,18 @@ PyObject* Application::sAddExportType(PyObject * /*self*/, PyObject *args)
Py_Return;
}
PyObject* Application::sChangeExportModule(PyObject * /*self*/, PyObject *args)
{
char *key,*oldMod,*newMod;
if (!PyArg_ParseTuple(args, "sss", &key,&oldMod,&newMod))
return nullptr;
GetApplication().changeExportModule(key,oldMod,newMod);
Py_Return;
}
PyObject* Application::sGetExportType(PyObject * /*self*/, PyObject *args)
{
char* psKey=0;

View File

@@ -247,6 +247,12 @@ except ImportError:
FreeCAD.Console.PrintError("\n\nSeems the python standard libs are not installed, bailing out!\n\n")
raise
# Backward compatibility to Py2
import sys
if sys.version_info.major < 3:
import time
time.process_time = time.clock
class FCADLogger(object):
'''Convenient class for tagged logging.

View File

@@ -223,6 +223,7 @@ void DlgGeneralImp::loadSettings()
int index = 1;
TStringMap list = Translator::instance()->supportedLocales();
ui->Languages->clear();
ui->Languages->addItem(QString::fromLatin1("English"), QByteArray("English"));
for (TStringMap::iterator it = list.begin(); it != list.end(); ++it, index++) {
QByteArray lang = it->first.c_str();

View File

@@ -324,16 +324,16 @@ public:
bool press = (kbev->getState() == SoKeyboardEvent::DOWN);
switch (kbev->getKey()) {
case SoKeyboardEvent::H:
if (press)
if (!press)
ns.onSetRotationCenter(kbev->getPosition());
break;
case SoKeyboardEvent::PAGE_UP:
if(press){
if(!press){
ns.doZoom(ns.viewer->getSoRenderManager()->getCamera(), true, posn);
}
break;
case SoKeyboardEvent::PAGE_DOWN:
if(press){
if(!press){
ns.doZoom(ns.viewer->getSoRenderManager()->getCamera(), false, posn);
}
break;

View File

@@ -244,6 +244,21 @@ int AlignmentGroup::count() const
return this->_views.size();
}
Base::BoundBox3d AlignmentGroup::getBoundingBox() const
{
Base::BoundBox3d box;
std::vector<Gui::ViewProviderDocumentObject*>::const_iterator it;
for (it = this->_views.begin(); it != this->_views.end(); ++it) {
if ((*it)->isDerivedFrom(Gui::ViewProviderGeometryObject::getClassTypeId())) {
App::GeoFeature* geo = static_cast<App::GeoFeature*>((*it)->getObject());
const App::PropertyComplexGeoData* prop = geo->getPropertyOfGeometry();
if (prop)
box.Add(prop->getBoundingBox());
}
}
return box;
}
// ------------------------------------------------------------------
MovableGroup::MovableGroup()
@@ -334,6 +349,16 @@ const MovableGroup& MovableGroupModel::getGroup(int i) const
return this->_groups[i];
}
Base::BoundBox3d MovableGroupModel::getBoundingBox() const
{
Base::BoundBox3d box;
std::vector<MovableGroup>::const_iterator it;
for (it = this->_groups.begin(); it != this->_groups.end(); ++it) {
box.Add(it->getBoundingBox());
}
return box;
}
// ------------------------------------------------------------------
namespace Gui {

View File

@@ -25,6 +25,7 @@
#define GUI_MANUALALIGNMENT_H
#include <QPointer>
#include <Base/BoundBox.h>
#include <Base/Placement.h>
#include <Base/Vector3D.h>
#include <Gui/Application.h>
@@ -123,6 +124,10 @@ public:
* Return the number of added views.
*/
int count() const;
/**
* Get the overall bounding box of all views.
*/
Base::BoundBox3d getBoundingBox() const;
protected:
std::vector<PickedPoint> _pickedPoints;
@@ -170,6 +175,7 @@ public:
bool isEmpty() const;
int count() const;
const MovableGroup& getGroup(int i) const;
Base::BoundBox3d getBoundingBox() const;
protected:
void removeActiveGroup();

View File

@@ -37,6 +37,7 @@ SET(FemExamples_SRCS
femexamples/__init__.py
femexamples/boxanalysis.py
femexamples/ccx_cantilever_std.py
femexamples/contact_shell_shell.py
femexamples/manager.py
femexamples/material_multiple_twoboxes.py
femexamples/material_nl_platewithhole.py
@@ -50,6 +51,7 @@ SET(FemExampleMeshes_SRCS
femexamples/meshes/mesh_boxanalysis_tetra10.py
femexamples/meshes/mesh_boxes_2_vertikal_tetra10.py
femexamples/meshes/mesh_canticcx_tetra10.py
femexamples/meshes/mesh_contact_tube_tube_tria3.py
femexamples/meshes/mesh_rc_wall_2d_tria6.py
femexamples/meshes/mesh_platewithhole_tetra10.py
femexamples/meshes/mesh_thermomech_flow1d_seg3.py
@@ -161,6 +163,8 @@ SET(FemTestsFiles_SRCS
SET(FemTestsCcx_SRCS
femtest/data/ccx/__init__.py
femtest/data/ccx/contact_shell_shell.FCStd
femtest/data/ccx/contact_shell_shell.inp
femtest/data/ccx/cube_frequency.inp
femtest/data/ccx/cube_frequency.dat
femtest/data/ccx/cube_frequency.frd
@@ -172,7 +176,8 @@ SET(FemTestsCcx_SRCS
femtest/data/ccx/cube_static_expected_values
femtest/data/ccx/cube_static.FCStd
femtest/data/ccx/cube.FCStd
femtest/data/ccx/multimat.inp
femtest/data/ccx/mat_multiple.inp
femtest/data/ccx/mat_nonlinear.inp
femtest/data/ccx/spine_thermomech.inp
femtest/data/ccx/spine_thermomech.dat
femtest/data/ccx/spine_thermomech.frd

View File

@@ -37,24 +37,33 @@ using namespace FemGui;
#if 0 // needed for Qt's lupdate utility
qApp->translate("Workbench", "FEM");
qApp->translate("Workbench", "&FEM");
//
qApp->translate("Workbench", "Model");
qApp->translate("Workbench", "M&odel");
qApp->translate("Workbench", "Materials");
qApp->translate("Workbench", "&Materials");
qApp->translate("Workbench", "Element Geometry");
qApp->translate("Workbench", "&Element Geometry");
qApp->translate("Workbench", "Electrostatic Constraints");
qApp->translate("Workbench", "&Electrostatic Constraints");
qApp->translate("Workbench", "Fluid Constraints");
qApp->translate("Workbench", "&Fluid Constraints");
qApp->translate("Workbench", "Mechanical Constraints");
qApp->translate("Workbench", "&Mechanical Constraints");
qApp->translate("Workbench", "Thermal Constraints");
qApp->translate("Workbench", "&Thermal Constraints");
//
qApp->translate("Workbench", "Mesh");
qApp->translate("Workbench", "M&esh");
qApp->translate("Workbench", "Fluid Constraints");
qApp->translate("Workbench", "&Fluid Constraints");
qApp->translate("Workbench", "Electrostatic Constraints");
qApp->translate("Workbench", "&Electrostatic Constraints");
//
qApp->translate("Workbench", "Solve");
qApp->translate("Workbench", "&Solve");
//
qApp->translate("Workbench", "Results");
qApp->translate("Workbench", "&Results");
qApp->translate("Workbench", "Materials");
qApp->translate("Workbench", "&Element Geometry");
qApp->translate("Workbench", "Filter functions");
qApp->translate("Workbench", "&Filter functions");
//
qApp->translate("Workbench", "Utilities");
#endif

View File

@@ -123,11 +123,13 @@ from femtest.utilstest import get_fem_test_defs as gf
gf()
./bin/FreeCADCmd --run-test "femtest.app.test_femimport.TestObjectExistance.test_objects_existance"
./bin/FreeCADCmd --run-test "femtest.app.test_ccxtools.TestCcxTools.test_1_static_analysis"
./bin/FreeCADCmd --run-test "femtest.app.test_ccxtools.TestCcxTools.test_2_static_multiple_material"
./bin/FreeCADCmd --run-test "femtest.app.test_ccxtools.TestCcxTools.test_3_freq_analysis"
./bin/FreeCADCmd --run-test "femtest.app.test_ccxtools.TestCcxTools.test_4_thermomech_analysis"
./bin/FreeCADCmd --run-test "femtest.app.test_ccxtools.TestCcxTools.test_5_Flow1D_thermomech_analysis"
./bin/FreeCADCmd --run-test "femtest.app.test_ccxtools.TestCcxTools.test_freq_analysis"
./bin/FreeCADCmd --run-test "femtest.app.test_ccxtools.TestCcxTools.test_static_analysis"
./bin/FreeCADCmd --run-test "femtest.app.test_ccxtools.TestCcxTools.test_static_contact_shell_shell"
./bin/FreeCADCmd --run-test "femtest.app.test_ccxtools.TestCcxTools.test_static_material_multiple"
./bin/FreeCADCmd --run-test "femtest.app.test_ccxtools.TestCcxTools.test_static_material_nonlinar"
./bin/FreeCADCmd --run-test "femtest.app.test_ccxtools.TestCcxTools.test_thermomech_flow1D_analysis"
./bin/FreeCADCmd --run-test "femtest.app.test_ccxtools.TestCcxTools.test_thermomech_spine_analysis"
./bin/FreeCADCmd --run-test "femtest.app.test_common.TestFemCommon.test_adding_refshaps"
./bin/FreeCADCmd --run-test "femtest.app.test_common.TestFemCommon.test_pyimport_all_FEM_modules"
./bin/FreeCADCmd --run-test "femtest.app.test_material.TestMaterialUnits.test_known_quantity_units"
@@ -163,19 +165,25 @@ from femtest.utilstest import get_fem_test_defs as gf
gf("in")
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_ccxtools.TestCcxTools.test_1_static_analysis"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_ccxtools.TestCcxTools.test_freq_analysis"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_ccxtools.TestCcxTools.test_2_static_multiple_material"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_ccxtools.TestCcxTools.test_static_analysis"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_ccxtools.TestCcxTools.test_3_freq_analysis"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_ccxtools.TestCcxTools.test_static_contact_shell_shell"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_ccxtools.TestCcxTools.test_4_thermomech_analysis"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_ccxtools.TestCcxTools.test_static_material_multiple"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_ccxtools.TestCcxTools.test_5_Flow1D_thermomech_analysis"))
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_ccxtools.TestCcxTools.test_static_material_nonlinar"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_ccxtools.TestCcxTools.test_thermomech_flow1D_analysis"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_ccxtools.TestCcxTools.test_thermomech_spine_analysis"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.app.test_common.TestFemCommon.test_adding_refshaps"))

View File

@@ -0,0 +1,194 @@
# ***************************************************************************
# * Copyright (c) 2020 Bernd Hahnebach <bernd@bimstatik.org> *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU Lesser General Public License (LGPL) *
# * as published by the Free Software Foundation; either version 2 of *
# * the License, or (at your option) any later version. *
# * for detail see the LICENCE text file. *
# * *
# * 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 Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with FreeCAD; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
# * USA *
# * *
# ***************************************************************************
# contact example shell to shell elements
# https://forum.freecadweb.org/viewtopic.php?f=18&t=42228
# based on https://forum.freecadweb.org/viewtopic.php?f=18&t=42228#p359488
import FreeCAD
import ObjectsFem
import Fem
import Part
import BOPTools.SplitFeatures
mesh_name = "Mesh" # needs to be Mesh to work with unit tests
def init_doc(doc=None):
if doc is None:
doc = FreeCAD.newDocument()
return doc
def setup(doc=None, solvertype="ccxtools"):
# setup model
if doc is None:
doc = init_doc()
# parts
# TODO turn circle of upper tube to have the line on the other side
# make a boolean fragment of them to be sure there is a mesh point on remesh
# but as long as we do not remesh it works without the boolean fragment too
# tubes
tube_radius = 25
tube_length = 500
sh_lower_circle = Part.Wire(Part.makeCircle(tube_radius))
sh_lower_tube = sh_lower_circle.extrude(FreeCAD.Vector(0, 0, tube_length))
sh_lower_tube.reverse()
lower_tube = doc.addObject("Part::Feature", "Lower_tube")
lower_tube.Shape = sh_lower_tube
sh_upper_circle = Part.Wire(Part.makeCircle(tube_radius))
sh_upper_tube = sh_upper_circle.extrude(FreeCAD.Vector(0, 0, tube_length))
sh_upper_tube.reverse()
upper_tube = doc.addObject("Part::Feature", "Upper_tube")
upper_tube.Shape = sh_upper_tube
upper_tube.Placement = FreeCAD.Placement(
FreeCAD.Vector(-25, 51, 475),
FreeCAD.Rotation(90, 0, 90),
FreeCAD.Vector(0, 0, 0),
)
# point for load
v_force_pt = FreeCAD.Vector(0, 76, 475)
sh_force_point = Part.Vertex(v_force_pt)
force_point = doc.addObject("Part::Feature", "Load_place_point")
force_point.Shape = sh_force_point
if FreeCAD.GuiUp:
force_point.ViewObject.PointSize = 10.0
force_point.ViewObject.PointColor = (1.0, 0.0, 0.0)
BooleanFrag = BOPTools.SplitFeatures.makeBooleanFragments(name='BooleanFragments')
BooleanFrag.Objects = [upper_tube, force_point]
compound = doc.addObject("Part::Compound", "Compound")
compound.Links = [BooleanFrag, lower_tube]
# line for load direction
sh_load_line = Part.makeLine(v_force_pt, FreeCAD.Vector(0, 150, 475))
load_line = doc.addObject("Part::Feature", "Load_direction_line")
load_line.Shape = sh_load_line
if FreeCAD.GuiUp:
load_line.ViewObject.LineWidth = 5.0
load_line.ViewObject.LineColor = (1.0, 0.0, 0.0)
doc.recompute()
if FreeCAD.GuiUp:
import FreeCADGui
FreeCADGui.ActiveDocument.activeView().viewAxonometric()
FreeCADGui.SendMsgToActiveView("ViewFit")
# analysis
analysis = ObjectsFem.makeAnalysis(doc, "Analysis")
# solver
if solvertype == "calculix":
solver_object = analysis.addObject(
ObjectsFem.makeSolverCalculix(doc, "SolverCalculiX")
)[0]
elif solvertype == "ccxtools":
solver_object = analysis.addObject(
ObjectsFem.makeSolverCalculixCcxTools(doc, "CalculiXccxTools")
)[0]
solver_object.WorkingDir = u""
if solvertype == "calculix" or solvertype == "ccxtools":
solver_object.AnalysisType = "static"
solver_object.BeamShellResultOutput3D = True
solver_object.GeometricalNonlinearity = "linear" # really?
# TODO iterations parameter !!!
solver_object.ThermoMechSteadyState = False
solver_object.MatrixSolverType = "default"
solver_object.IterationsControlParameterTimeUse = False
solver_object.SplitInputWriter = False
# shell thickness
analysis.addObject(ObjectsFem.makeElementGeometry2D(doc, 0.5, 'ShellThickness'))
# material
material_obj = analysis.addObject(
ObjectsFem.makeMaterialSolid(doc, "MechanicalMaterial")
)[0]
mat = material_obj.Material
mat["Name"] = "AlCuMgPb"
mat["YoungsModulus"] = "72000 MPa"
mat["PoissonRatio"] = "0.30"
material_obj.Material = mat
analysis.addObject(material_obj)
# fixed_constraint
fixed_constraint = analysis.addObject(
ObjectsFem.makeConstraintFixed(doc, "ConstraintFixed")
)[0]
fixed_constraint.References = [
(lower_tube, "Edge2"),
(upper_tube, "Edge3"),
]
# force_constraint
force_constraint = doc.Analysis.addObject(
ObjectsFem.makeConstraintForce(doc, name="ConstraintForce")
)[0]
# TODO use point of tube boolean fragment
force_constraint.References = [(force_point, "Vertex1")]
force_constraint.Force = 5000.0
force_constraint.Direction = (load_line, ["Edge1"])
force_constraint.Reversed = True
# contact constraint
contact_constraint = doc.Analysis.addObject(
ObjectsFem.makeConstraintContact(doc, name="ConstraintContact")
)[0]
contact_constraint.References = [
(lower_tube, "Face1"),
(upper_tube, "Face1"),
]
contact_constraint.Friction = 0.0
# contact_constrsh_aint.Slope = "1000000.0 kg/(mm*s^2)" # contact stiffness
contact_constraint.Slope = 1000000.0 # should be 1000000.0 kg/(mm*s^2)
# mesh
from .meshes.mesh_contact_tube_tube_tria3 import create_nodes, create_elements
fem_mesh = Fem.FemMesh()
control = create_nodes(fem_mesh)
if not control:
FreeCAD.Console.PrintError("Error on creating nodes.\n")
control = create_elements(fem_mesh)
if not control:
FreeCAD.Console.PrintError("Error on creating elements.\n")
femmesh_obj = analysis.addObject(
doc.addObject("Fem::FemMeshObject", mesh_name)
)[0]
femmesh_obj.FemMesh = fem_mesh
doc.recompute()
return doc
"""
from femexamples.contact_shell_shell import setup
setup()
"""

View File

@@ -148,6 +148,21 @@ def run_ccx_cantileverprescribeddisplacement(solver=None, base_name=None):
return doc
def run_contact_shell_shell(solver=None, base_name=None):
from .contact_shell_shell import setup
doc = setup()
if base_name is None:
base_name = "Contact_Shell_Shell"
if solver is not None:
base_name += "_" + solver
run_analysis(doc, base_name)
doc.recompute()
return doc
def run_material_multiple_twoboxes(solver=None, base_name=None):
from .material_multiple_twoboxes import setup
@@ -180,7 +195,7 @@ def run_material_nl_platewithhole(solver=None, base_name=None):
def run_rcwall2d(solver=None, base_name=None):
from .rc_wall_2d import setup as setup
from .rc_wall_2d import setup
doc = setup()
if base_name is None:
@@ -246,6 +261,7 @@ doc = run_boxanalysisfrequency()
doc = run_ccx_cantileverfaceload()
doc = run_ccx_cantilevernodeload()
doc = run_ccx_cantileverprescribeddisplacement()
doc = run_contact_shell_shell()
doc = run_material_nl_platewithhole()
doc = run_material_multiple_twoboxes()
doc = run_rcwall2d()

View File

@@ -157,7 +157,7 @@ def setup(doc=None, solvertype="ccxtools"):
"""
from femexamples import material_multiple_twoboxes as twoboxes
twoboxes.setup()
from femexamples.material_multiple_twoboxes import setup
setup()
"""

View File

@@ -157,7 +157,7 @@ def setup(doc=None, solvertype="ccxtools"):
"""
from femexamples import material_nl_platewithhole as nlmat
nlmat.setup()
from femexamples.material_nl_platewithhole import setup
setup()
"""

File diff suppressed because it is too large Load Diff

View File

@@ -159,7 +159,7 @@ def setup(doc=None, solvertype="ccxtools"):
"""
from femexamples import rc_wall_2d as rc
rc.setup()
from femexamples.rc_wall_2d import setup
setup()
"""

View File

@@ -250,7 +250,7 @@ def setup(doc=None, solvertype="ccxtools"):
"""
from femexamples import thermomech_flow1d as flow
flow.setup()
from femexamples.thermomech_flow1d import setup
setup()
"""

View File

@@ -143,7 +143,7 @@ def setup(doc=None, solvertype="ccxtools"):
"""
from femexamples import thermomech_spine as spine
spine.setup()
from femexamples.thermomech_spine import setup
setup()
"""

View File

@@ -92,7 +92,7 @@ def femmesh_2_mesh(myFemMesh, myResults=None):
# This code generates a dict and a faceCode for each face of all elements
# All faceCodes are than sorted.
start_time = time.clock()
start_time = time.process_time()
faceCodeList = []
faceCodeDict = {}
@@ -196,7 +196,7 @@ def femmesh_2_mesh(myFemMesh, myResults=None):
output_mesh.extend(triangle)
# print("my 2. triangle: ", triangle)
end_time = time.clock()
end_time = time.process_time()
FreeCAD.Console.PrintMessage(
"Mesh by surface search method: {}\n".format(end_time - start_time)
)

View File

@@ -97,7 +97,7 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
)
def write_calculix_input_file(self):
timestart = time.clock()
timestart = time.process_time()
FreeCAD.Console.PrintMessage("Start writing CalculiX input file\n")
FreeCAD.Console.PrintMessage("Write ccx input file to: {}\n".format(self.file_name))
FreeCAD.Console.PrintLog(
@@ -115,7 +115,7 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
self.write_calculix_one_input_file()
writing_time_string = (
"Writing time CalculiX input file: {} seconds"
.format(round((time.clock() - timestart), 2))
.format(round((time.process_time() - timestart), 2))
)
if self.femelement_count_test is True:
FreeCAD.Console.PrintMessage(writing_time_string + " \n\n")
@@ -608,9 +608,32 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
else:
name = "IND" + str(obj)
f.write("*SURFACE, NAME =" + name + "\n")
v = self.mesh_object.FemMesh.getccxVolumesByFace(ref_shape)
for i in v:
f.write("{},S{}\n".format(i[0], i[1]))
if len(v) > 0:
# volume elements found
FreeCAD.Console.PrintLog(
"{}, surface {}, {} touching volume elements found\n"
.format(contact_obj.Label, name, len(v))
)
for i in v:
f.write("{},S{}\n".format(i[0], i[1]))
else:
# try shell elements
v = self.mesh_object.FemMesh.getFacesByFace(ref_shape)
if len(v) > 0:
FreeCAD.Console.PrintLog(
"{}, surface {}, {} touching shell elements found\n"
.format(contact_obj.Label, name, len(v))
)
for i in v:
f.write("{},S2\n".format(i))
else:
FreeCAD.Console.PrintError(
"{}, surface {}, Error: "
"Neither volume nor shell elements found!\n"
.format(contact_obj.Label, name)
)
def write_node_sets_constraints_transform(self, f):
# get nodes

View File

@@ -92,7 +92,7 @@ class FemInputWriterZ88(FemInputWriter.FemInputWriter):
)
def write_z88_input(self):
timestart = time.clock()
timestart = time.process_time()
if not self.femnodes_mesh:
self.femnodes_mesh = self.femmesh.Nodes
if not self.femelement_table:
@@ -109,7 +109,7 @@ class FemInputWriterZ88(FemInputWriter.FemInputWriter):
self.write_z88_solver_parameter()
writing_time_string = (
"Writing time input file: {} seconds"
.format(round((time.clock() - timestart), 2))
.format(round((time.process_time() - timestart), 2))
)
FreeCAD.Console.PrintMessage(writing_time_string + " \n\n")
return self.dir_name

View File

@@ -68,412 +68,234 @@ class TestCcxTools(unittest.TestCase):
))
# ********************************************************************************************
def test_1_static_analysis(
def test_freq_analysis(
self
):
fcc_print("\n--------------- Start of FEM ccxtools static analysis test ---------------")
# set up the static analysis example
from femexamples import boxanalysis as box
box.setup_static(self.active_doc, "ccxtools")
analysis = self.active_doc.Analysis
solver_object = self.active_doc.CalculiXccxTools
fcc_print("Analysis {}".format(type(analysis)))
fcc_print("Analysis {}".format(analysis.TypeId))
static_analysis_dir = testtools.get_unit_test_tmp_dir(
self.temp_dir,
"FEM_ccx_static"
)
fea = ccxtools.FemToolsCcx(analysis, solver_object, test_mode=True)
fea.update_objects()
fcc_print("fea Analysis {}".format(type(fea.analysis)))
fcc_print("fea Analysis {}".format(fea.analysis.TypeId))
fcc_print("Setting up working directory {}".format(static_analysis_dir))
fea.setup_working_dir(static_analysis_dir)
self.assertTrue(
True if fea.working_dir == static_analysis_dir else False,
"Setting working directory {} failed".format(static_analysis_dir)
)
fcc_print("Checking FEM inp file prerequisites for static analysis...")
error = fea.check_prerequisites()
self.assertFalse(
error,
"ccxtools check_prerequisites returned error message: {}".format(error)
)
static_base_name = "cube_static"
inpfile_given = join(self.test_file_dir, (static_base_name + ".inp"))
inpfile_totest = join(static_analysis_dir, (self.mesh_name + ".inp"))
fcc_print("Checking FEM inp file write...")
fcc_print("Writing {} for static analysis".format(inpfile_totest))
error = fea.write_inp_file()
self.assertFalse(
error,
"Writing failed"
)
fcc_print("Comparing {} to {}".format(inpfile_given, inpfile_totest))
ret = testtools.compare_inp_files(inpfile_given, inpfile_totest)
self.assertFalse(
ret,
"ccxtools write_inp_file test failed.\n{}".format(ret)
)
fcc_print(
"Setting up working directory to {} in order to read simulated calculations"
.format(self.test_file_dir)
)
fea.setup_working_dir(self.test_file_dir)
fcc_print(fea.working_dir)
fcc_print(self.test_file_dir)
self.assertTrue(
True if fea.working_dir == self.test_file_dir else False,
"Setting working directory {} failed".format(self.test_file_dir)
)
fcc_print("Setting base name to read test {}.frd file...".format("cube_static"))
fea.set_base_name(static_base_name)
self.assertTrue(
True if fea.base_name == static_base_name else False,
"Setting base name to {} failed".format(static_base_name)
)
fcc_print("Setting inp file name to read test {}.frd file...".format("cube_static"))
fea.set_inp_file_name()
self.assertTrue(
True if fea.inp_file_name == inpfile_given else False,
"Setting inp file name to {} failed".format(inpfile_given)
)
fcc_print("Checking FEM frd file read from static analysis...")
fea.load_results()
self.assertTrue(
fea.results_present,
"Cannot read results from {}.frd frd file".format(fea.base_name)
)
fcc_print("Reading stats from result object for static analysis...")
static_expected_values = join(self.test_file_dir, "cube_static_expected_values")
ret = testtools.compare_stats(
fea,
static_expected_values,
"CCX_Results"
)
self.assertFalse(
ret,
"Invalid results read from .frd file"
)
static_save_fc_file = static_analysis_dir + static_base_name + ".FCStd"
fcc_print("Save FreeCAD file for static analysis to {}...".format(static_save_fc_file))
self.active_doc.saveAs(static_save_fc_file)
fcc_print("--------------- End of FEM ccxtools static analysis test -------------------")
# ********************************************************************************************
def test_2_static_multiple_material(
self
):
fcc_print("\n--------------- Start of FEM ccxtools multiple material test -------------")
# set up the simple multimat example
from femexamples import material_multiple_twoboxes
material_multiple_twoboxes.setup(self.active_doc, "ccxtools")
analysis = self.active_doc.Analysis
solver_object = self.active_doc.CalculiXccxTools
static_multiplemat_dir = testtools.get_unit_test_tmp_dir(
self.temp_dir,
"FEM_ccx_multimat/"
)
fea = ccxtools.FemToolsCcx(analysis, solver_object, test_mode=True)
fea.update_objects()
fea.setup_working_dir(static_multiplemat_dir)
fcc_print("Checking FEM inp file prerequisites for ccxtools multimat analysis...")
error = fea.check_prerequisites()
self.assertFalse(
error,
"ccxtools check_prerequisites returned error message: {}".format(error)
)
static_base_name = "multimat"
inpfile_given = join(self.test_file_dir, (static_base_name + ".inp"))
inpfile_totest = join(static_multiplemat_dir, (self.mesh_name + ".inp"))
fcc_print("Checking FEM inp file write...")
fcc_print("Writing {} for static multiple material".format(inpfile_totest))
error = fea.write_inp_file()
self.assertFalse(
error,
"Writing failed"
)
fcc_print("Comparing {} to {}".format(inpfile_given, inpfile_totest))
ret = testtools.compare_inp_files(inpfile_given, inpfile_totest)
self.assertFalse(
ret,
"ccxtools write_inp_file test failed.\n{}".format(ret)
)
static_save_fc_file = static_multiplemat_dir + static_base_name + ".FCStd"
fcc_print("Save FreeCAD file for static analysis to {}...".format(static_save_fc_file))
self.active_doc.saveAs(static_save_fc_file)
fcc_print("--------------- End of FEM ccxtools multiple material test -----------------")
# ********************************************************************************************
def test_3_freq_analysis(
self
):
fcc_print("\n--------------- Start of FEM ccxtools frequency analysis test ------------")
# set up the static analysis example
from femexamples import boxanalysis as box
box.setup_frequency(self.active_doc, "ccxtools")
analysis = self.active_doc.Analysis
solver_object = self.active_doc.CalculiXccxTools
frequency_analysis_dir = testtools.get_unit_test_tmp_dir(
# set up
from femexamples.boxanalysis import setup_frequency as setup
setup(self.active_doc, "ccxtools")
test_name = "frequency"
base_name = "cube_frequency"
res_obj_name = "CCX_Mode1_Results"
analysis_dir = testtools.get_unit_test_tmp_dir(
self.temp_dir,
"FEM_ccx_frequency"
)
fea = ccxtools.FemToolsCcx(analysis, solver_object, test_mode=True)
fea.update_objects()
fcc_print("Setting up working directory {}".format(frequency_analysis_dir))
fea.setup_working_dir(frequency_analysis_dir)
self.assertTrue(
True if fea.working_dir == frequency_analysis_dir else False,
"Setting working directory {} failed".format(frequency_analysis_dir)
# test input file writing
fea = self.input_file_writing_test(
test_name=test_name,
base_name=base_name,
analysis_dir=analysis_dir,
test_end=True,
)
fcc_print("Checking FEM inp file prerequisites for frequency analysis...")
error = fea.check_prerequisites()
self.assertFalse(
error,
"ccxtools check_prerequisites returned error message: {}".format(error)
# test result reading
self.result_reading_test(
test_name=test_name,
base_name=base_name,
analysis_dir=analysis_dir,
fea=fea,
res_obj_name=res_obj_name,
)
frequency_base_name = "cube_frequency"
inpfile_given = join(self.test_file_dir, (frequency_base_name + ".inp"))
inpfile_totest = join(frequency_analysis_dir, (self.mesh_name + ".inp"))
fcc_print("Checking FEM inp file write...")
fcc_print("Writing {} for frequency analysis".format(inpfile_totest))
error = fea.write_inp_file()
self.assertFalse(
error,
"Writing failed"
)
fcc_print("Comparing {} to {}".format(inpfile_given, inpfile_totest))
ret = testtools.compare_inp_files(inpfile_given, inpfile_totest)
self.assertFalse(
ret,
"ccxtools write_inp_file test failed.\n{}".format(ret)
)
fcc_print(
"Setting up working directory to {} in order to read simulated calculations".
format(self.test_file_dir)
)
fea.setup_working_dir(self.test_file_dir)
self.assertTrue(
True if fea.working_dir == self.test_file_dir else False,
"Setting working directory {} failed".format(self.test_file_dir)
)
fcc_print("Setting base name to read test {}.frd file...".format(frequency_base_name))
fea.set_base_name(frequency_base_name)
self.assertTrue(
True if fea.base_name == frequency_base_name else False,
"Setting base name to {} failed".format(frequency_base_name)
)
fcc_print("Setting inp file name to read test {}.frd file...".format("cube_frequency"))
fea.set_inp_file_name()
self.assertTrue(
True if fea.inp_file_name == inpfile_given else False,
"Setting inp file name to {} failed".format(inpfile_given)
)
fcc_print("Checking FEM frd file read from frequency analysis...")
fea.load_results()
self.assertTrue(
fea.results_present,
"Cannot read results from {}.frd frd file".format(fea.base_name)
)
fcc_print("Reading stats from result object for frequency analysis...")
frequency_expected_values = join(self.test_file_dir, "cube_frequency_expected_values")
ret = testtools.compare_stats(
fea,
frequency_expected_values,
"CCX_Mode1_Results"
)
self.assertFalse(
ret,
"Invalid results read from .frd file"
)
frequency_save_fc_file = frequency_analysis_dir + frequency_base_name + ".FCStd"
fcc_print(
"Save FreeCAD file for frequency analysis to {}..."
.format(frequency_save_fc_file)
)
self.active_doc.saveAs(frequency_save_fc_file)
fcc_print("--------------- End of FEM ccxtools frequency analysis test ----------------")
# ********************************************************************************************
def test_4_thermomech_analysis(
def test_static_analysis(
self
):
fcc_print("\n--------------- Start of FEM ccxtools thermomechanical analysis test -----")
# set up the thermomech example
from femexamples.thermomech_spine import setup as thermomech
thermomech(self.active_doc, "ccxtools")
analysis = self.active_doc.Analysis
thermomech_analysis_dir = testtools.get_unit_test_tmp_dir(
# set up
from femexamples.boxanalysis import setup_static as setup
setup(self.active_doc, "ccxtools")
test_name = "ccxtools static"
base_name = "cube_static"
res_obj_name = "CCX_Results"
analysis_dir = testtools.get_unit_test_tmp_dir(
self.temp_dir,
"FEM_ccx_thermomech"
)
fea = ccxtools.FemToolsCcx(analysis, test_mode=True)
fea.update_objects()
fcc_print("Setting up working directory {}".format(thermomech_analysis_dir))
fea.setup_working_dir(thermomech_analysis_dir)
self.assertTrue(
True if fea.working_dir == thermomech_analysis_dir else False,
"Setting working directory {} failed".format(thermomech_analysis_dir)
"FEM_ccx_static"
)
fcc_print("Checking FEM inp file prerequisites for thermo-mechanical analysis...")
error = fea.check_prerequisites()
self.assertFalse(
error,
"ccxtools check_prerequisites returned error message: {}".format(error)
# test input file writing
fea = self.input_file_writing_test(
test_name=test_name,
base_name=base_name,
analysis_dir=analysis_dir,
test_end=True,
)
thermomech_base_name = "spine_thermomech"
inpfile_given = join(self.test_file_dir, (thermomech_base_name + ".inp"))
inpfile_totest = join(thermomech_analysis_dir, (self.mesh_name + ".inp"))
fcc_print("Checking FEM inp file write...")
fcc_print("Writing {} for thermomech analysis".format(inpfile_totest))
error = fea.write_inp_file()
self.assertFalse(
error,
"Writing failed"
# test result reading
self.result_reading_test(
test_name=test_name,
base_name=base_name,
analysis_dir=analysis_dir,
fea=fea,
res_obj_name=res_obj_name,
)
fcc_print("Comparing {} to {}".format(inpfile_given, inpfile_totest))
ret = testtools.compare_inp_files(inpfile_given, inpfile_totest)
self.assertFalse(
ret,
"ccxtools write_inp_file test failed.\n{}".format(ret)
)
fcc_print(
"Setting up working directory to {} in order to read simulated calculations"
.format(self.test_file_dir)
)
fea.setup_working_dir(self.test_file_dir)
self.assertTrue(
True if fea.working_dir == self.test_file_dir else False,
"Setting working directory {} failed".format(self.test_file_dir)
)
fcc_print("Setting base name to read test {}.frd file...".format("spine_thermomech"))
fea.set_base_name(thermomech_base_name)
self.assertTrue(
True if fea.base_name == thermomech_base_name else False,
"Setting base name to {} failed".format(thermomech_base_name)
)
fcc_print("Setting inp file name to read test {}.frd file...".format("spine_thermomech"))
fea.set_inp_file_name()
self.assertTrue(
True if fea.inp_file_name == inpfile_given else False,
"Setting inp file name to {} failed".format(inpfile_given)
)
fcc_print("Checking FEM frd file read from thermomech analysis...")
fea.load_results()
self.assertTrue(
fea.results_present,
"Cannot read results from {}.frd frd file".format(fea.base_name)
)
fcc_print("Reading stats from result object for thermomech analysis...")
thermomech_expected_values = join(
self.test_file_dir,
"spine_thermomech_expected_values"
)
ret = testtools.compare_stats(
fea,
thermomech_expected_values,
"CCX_Results"
)
self.assertFalse(
ret,
"Invalid results read from .frd file"
)
thermomech_save_fc_file = thermomech_analysis_dir + thermomech_base_name + ".FCStd"
fcc_print(
"Save FreeCAD file for thermomech analysis to {}..."
.format(thermomech_save_fc_file)
)
self.active_doc.saveAs(thermomech_save_fc_file)
fcc_print("--------------- End of FEM ccxtools thermomechanical analysis test ---------")
# ********************************************************************************************
def test_5_Flow1D_thermomech_analysis(
def test_static_contact_shell_shell(
self
):
fcc_print("\n--------------- Start of FEM ccxtools Flow1D analysis test ---------------")
# set up
from femexamples.contact_shell_shell import setup
setup(self.active_doc, "ccxtools")
test_name = "contact shell shell"
base_name = "contact_shell_shell"
analysis_dir = testtools.get_unit_test_tmp_dir(
self.temp_dir,
"FEM_ccx_contact_shell_shell",
)
# set up the thermomech flow1d example
from femexamples.thermomech_flow1d import setup as flow1d
flow1d(self.active_doc, "ccxtools")
analysis = self.active_doc.Analysis
# test input file writing
self.input_file_writing_test(
test_name=test_name,
base_name=base_name,
analysis_dir=analysis_dir,
)
Flow1D_thermomech_analysis_dir = testtools.get_unit_test_tmp_dir(
# ********************************************************************************************
def test_static_material_multiple(
self
):
# set up
from femexamples.material_multiple_twoboxes import setup
setup(self.active_doc, "ccxtools")
test_name = "multiple material"
base_name = "mat_multiple"
analysis_dir = testtools.get_unit_test_tmp_dir(
self.temp_dir,
"FEM_ccx_multimat"
)
# test input file writing
self.input_file_writing_test(
test_name=test_name,
base_name=base_name,
analysis_dir=analysis_dir,
)
# ********************************************************************************************
def test_static_material_nonlinar(
self
):
# set up
from femexamples.material_nl_platewithhole import setup
setup(self.active_doc, "ccxtools")
test_name = "nonlinear material"
base_name = "mat_nonlinear"
analysis_dir = testtools.get_unit_test_tmp_dir(
self.temp_dir,
"FEM_ccx_matnonlinear"
)
# test input file writing
self.input_file_writing_test(
test_name=test_name,
base_name=base_name,
analysis_dir=analysis_dir,
)
# ********************************************************************************************
def test_thermomech_flow1D_analysis(
self
):
# set up
from femexamples.thermomech_flow1d import setup
setup(self.active_doc, "ccxtools")
test_name = "Flow1D"
base_name = "Flow1D_thermomech"
res_obj_name = "CCX_Time1_0_Results"
analysis_dir = testtools.get_unit_test_tmp_dir(
self.temp_dir,
"FEM_ccx_Flow1D_thermomech"
)
fea = ccxtools.FemToolsCcx(analysis, test_mode=True)
fea.update_objects()
fcc_print("Setting up working directory {}".format(Flow1D_thermomech_analysis_dir))
fea.setup_working_dir(Flow1D_thermomech_analysis_dir)
self.assertTrue(
True if fea.working_dir == Flow1D_thermomech_analysis_dir else False,
"Setting working directory {} failed".format(Flow1D_thermomech_analysis_dir)
# test input file writing
fea = self.input_file_writing_test(
test_name=test_name,
base_name=base_name,
analysis_dir=analysis_dir,
test_end=True,
)
fcc_print("Checking FEM inp file prerequisites for thermo-mechanical analysis...")
# test result reading
self.result_reading_test(
test_name=test_name,
base_name=base_name,
analysis_dir=analysis_dir,
fea=fea,
res_obj_name=res_obj_name,
)
# ********************************************************************************************
def test_thermomech_spine_analysis(
self
):
# set up
from femexamples.thermomech_spine import setup
setup(self.active_doc, "ccxtools")
test_name = "thermomechanical"
base_name = "spine_thermomech"
res_obj_name = "CCX_Results"
analysis_dir = testtools.get_unit_test_tmp_dir(
self.temp_dir,
"FEM_ccx_thermomech"
)
# test input file writing
fea = self.input_file_writing_test(
test_name=test_name,
base_name=base_name,
analysis_dir=analysis_dir,
test_end=True,
)
# test result reading
self.result_reading_test(
test_name=test_name,
base_name=base_name,
analysis_dir=analysis_dir,
fea=fea,
res_obj_name=res_obj_name,
)
# ********************************************************************************************
def input_file_writing_test(
self,
test_name,
base_name,
analysis_dir,
test_end=False,
):
fcc_print(
"\n--------------- "
"Start of FEM ccxtools {} test"
"---------------"
.format(test_name)
)
analysis = self.active_doc.Analysis
solver_object = self.active_doc.CalculiXccxTools
fea = ccxtools.FemToolsCcx(analysis, solver_object, test_mode=True)
fea.update_objects()
fcc_print("Setting up working directory {}".format(analysis_dir))
fea.setup_working_dir(analysis_dir)
self.assertTrue(
True if fea.working_dir == analysis_dir else False,
"Setting working directory {} failed".format(analysis_dir)
)
fcc_print("Checking FEM inp file prerequisites for {} ...".format(test_name))
error = fea.check_prerequisites()
self.assertFalse(
error,
"ccxtools check_prerequisites returned error message: {}".format(error)
)
Flow1D_thermomech_base_name = "Flow1D_thermomech"
inpfile_given = join(self.test_file_dir, (Flow1D_thermomech_base_name + ".inp"))
inpfile_totest = join(Flow1D_thermomech_analysis_dir, (self.mesh_name + ".inp"))
inpfile_given = join(self.test_file_dir, (base_name + ".inp"))
inpfile_totest = join(analysis_dir, (self.mesh_name + ".inp"))
fcc_print("Checking FEM inp file write...")
fcc_print("Writing {} for thermomech analysis".format(inpfile_totest))
fcc_print("Writing {} for {}".format(inpfile_totest, test_name))
error = fea.write_inp_file()
self.assertFalse(
error,
@@ -487,6 +309,35 @@ class TestCcxTools(unittest.TestCase):
"ccxtools write_inp_file test failed.\n{}".format(ret)
)
if test_end is True:
# do not save and print End of tests
return fea
save_fc_file = analysis_dir + base_name + ".FCStd"
fcc_print(
"Save FreeCAD file for {} to {}..."
.format(test_name, save_fc_file)
)
self.active_doc.saveAs(save_fc_file)
fcc_print(
"\n--------------- "
"End of FEM ccxtools {}"
"---------------"
.format(test_name)
)
# ********************************************************************************************
def result_reading_test(
self,
test_name,
base_name,
analysis_dir,
fea,
res_obj_name,
):
inpfile_given = join(self.test_file_dir, (base_name + ".inp"))
fcc_print(
"Setting up working directory to {} in order to read simulated calculations"
.format(self.test_file_dir)
@@ -497,53 +348,59 @@ class TestCcxTools(unittest.TestCase):
"Setting working directory {} failed".format(self.test_file_dir)
)
fcc_print("Setting base name to read test {}.frd file...".format("Flow1D_thermomech"))
fea.set_base_name(Flow1D_thermomech_base_name)
fcc_print(
"Setting base name to read test {}.frd file..."
.format(base_name)
)
fea.set_base_name(base_name)
self.assertTrue(
True if fea.base_name == Flow1D_thermomech_base_name else False,
"Setting base name to {} failed".format(Flow1D_thermomech_base_name)
True if fea.base_name == base_name else False,
"Setting base name to {} failed".format(base_name)
)
fcc_print("Setting inp file name to read test {}.frd file...".format("Flow1D_thermomech"))
fcc_print(
"Setting inp file name to read test {}.frd file..."
.format(base_name)
)
fea.set_inp_file_name()
self.assertTrue(
True if fea.inp_file_name == inpfile_given else False,
"Setting inp file name to {} failed".format(inpfile_given)
)
fcc_print("Checking FEM frd file read from Flow1D thermomech analysis...")
fcc_print("Checking FEM frd file read from {}...".format(test_name))
fea.load_results()
self.assertTrue(
fea.results_present,
"Cannot read results from {}.frd frd file".format(fea.base_name)
)
fcc_print("Reading stats from result object for Flow1D thermomech analysis...")
Flow1D_thermomech_expected_values = join(
fcc_print("Reading stats from result object for {}...".format(test_name))
expected_values = join(
self.test_file_dir,
"Flow1D_thermomech_expected_values"
base_name + "_expected_values"
)
ret = testtools.compare_stats(
fea,
Flow1D_thermomech_expected_values,
"CCX_Time1_0_Results"
expected_values,
res_obj_name
)
self.assertFalse(
ret,
"Invalid results read from .frd file"
)
Flow1D_thermomech_save_fc_file = join(
Flow1D_thermomech_analysis_dir,
(Flow1D_thermomech_base_name + ".FCStd")
save_fc_file = join(
analysis_dir,
(base_name + ".FCStd")
)
fcc_print(
"Save FreeCAD file for thermomech analysis to {}..."
.format(Flow1D_thermomech_save_fc_file)
"Save FreeCAD file for {} to {}..."
.format(test_name, save_fc_file)
)
self.active_doc.saveAs(Flow1D_thermomech_save_fc_file)
self.active_doc.saveAs(save_fc_file)
fcc_print("--------------- End of FEM ccxtools Flow1D analysis test -------------------")
fcc_print("--------------- End of {} -------------------".format(test_name))
# ********************************************************************************************
def tearDown(

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -163,7 +163,6 @@ private:
Handle(XCAFApp_Application) hApp = XCAFApp_Application::GetApplication();
Handle(TDocStd_Document) hDoc;
hApp->NewDocument(TCollection_ExtendedString("MDTV-CAF"), hDoc);
ImportOCAFExt ocaf(hDoc, pcDoc, file.fileNamePure());
if (file.hasExtension("stp") || file.hasExtension("step")) {
try {
@@ -230,15 +229,19 @@ private:
}
#if 1
if(merge!=Py_None)
ImportOCAFExt ocaf(hDoc, pcDoc, file.fileNamePure());
if (merge != Py_None)
ocaf.setMerge(PyObject_IsTrue(merge));
if(importHidden!=Py_None)
if (importHidden != Py_None)
ocaf.setImportHiddenObject(PyObject_IsTrue(importHidden));
if(useLinkGroup!=Py_None)
if (useLinkGroup != Py_None)
ocaf.setUseLinkGroup(PyObject_IsTrue(useLinkGroup));
if(mode>=0)
if (mode >= 0)
ocaf.setMode(mode);
ocaf.loadShapes();
#elif 1
Import::ImportOCAFCmd ocaf(hDoc, pcDoc, file.fileNamePure());
ocaf.loadShapes();
#else
Import::ImportXCAF xcaf(hDoc, pcDoc, file.fileNamePure());
xcaf.loadShapes();
@@ -246,7 +249,7 @@ private:
#endif
hApp->Close(hDoc);
if (!ocaf.partColors.size()) {
if (!ocaf.partColors.empty()) {
Py::List list;
for (auto &it : ocaf.partColors) {
Py::Tuple tuple(2);

View File

@@ -29,6 +29,10 @@
#***************************************************************************/
# Registered in Part's Init.py file
FreeCAD.changeImportModule("STEP with colors (*.step *.stp)","Import","ImportGui")
FreeCAD.changeExportModule("STEP with colors (*.step *.stp)","Import","ImportGui")
"""
class ImportWorkbench ( Workbench ):
"Import workbench object"

View File

@@ -32,7 +32,7 @@ FreeCAD.addImportType("BREP format (*.brep *.brp)","Part")
FreeCAD.addExportType("BREP format (*.brep *.brp)","Part")
FreeCAD.addImportType("IGES format (*.iges *.igs)","Part")
FreeCAD.addExportType("IGES format (*.iges *.igs)","Part")
FreeCAD.addImportType("STEP with colors (*.step *.stp)","ImportGui")
FreeCAD.addExportType("STEP with colors (*.step *.stp)","ImportGui")
FreeCAD.addImportType("STEP with colors (*.step *.stp)","Import")
FreeCAD.addExportType("STEP with colors (*.step *.stp)","Import")
FreeCAD.__unit_test__ += [ "TestPartApp" ]

View File

@@ -60,7 +60,7 @@ Command::~Command()
// New methods
Placement Command::getPlacement (void) const
Placement Command::getPlacement (const Base::Vector3d pos) const
{
static const std::string x = "X";
static const std::string y = "Y";
@@ -68,7 +68,7 @@ Placement Command::getPlacement (void) const
static const std::string a = "A";
static const std::string b = "B";
static const std::string c = "C";
Vector3d vec(getParam(x),getParam(y),getParam(z));
Vector3d vec(getParam(x, pos.x),getParam(y, pos.y),getParam(z, pos.z));
Rotation rot;
rot.setYawPitchRoll(getParam(a),getParam(b),getParam(c));
Placement plac(vec,rot);

View File

@@ -49,7 +49,7 @@ namespace Path
virtual void Restore(Base::XMLReader &/*reader*/);
// specific methods
Base::Placement getPlacement (void) const; // returns a placement from the x,y,z,a,b,c parameters
Base::Placement getPlacement (const Base::Vector3d pos = Base::Vector3d()) const; // returns a placement from the x,y,z,a,b,c parameters
Base::Vector3d getCenter (void) const; // returns a 3d vector from the i,j,k parameters
void setCenter(const Base::Vector3d&, bool clockwise=true); // sets the center coordinates and the command name
std::string toGCode (int precision=6, bool padzero=true) const; // returns a GCode string representation of the command
@@ -61,9 +61,9 @@ namespace Path
void scaleBy(double factor); // scales the receiver - use for imperial/metric conversions
// this assumes the name is upper case
inline double getParam(const std::string &name) const {
inline double getParam(const std::string &name, double fallback = 0.0) const {
auto it = Parameters.find(name);
return it==Parameters.end()?0.0:it->second;
return it==Parameters.end() ? fallback : it->second;
}
// attributes

View File

@@ -129,7 +129,7 @@ double Toolpath::getLength()
Vector3d next;
for(std::vector<Command*>::const_iterator it = vpcCommands.begin();it!=vpcCommands.end();++it) {
std::string name = (*it)->Name;
next = (*it)->getPlacement().getPosition();
next = (*it)->getPlacement(last).getPosition();
if ( (name == "G0") || (name == "G00") || (name == "G1") || (name == "G01") ) {
// straight line
l += (next - last).Length();

View File

@@ -52,11 +52,11 @@ class ObjectDressup:
obj.addProperty("App::PropertyAngle", "Angle", "Path", QtCore.QT_TRANSLATE_NOOP("Path_DressupRampEntry", "Angle of ramp."))
obj.addProperty("App::PropertyEnumeration", "Method", "Path", QtCore.QT_TRANSLATE_NOOP("App::Property", "Ramping Method"))
obj.addProperty("App::PropertyEnumeration", "RampFeedRate", "FeedRate", QtCore.QT_TRANSLATE_NOOP("App::Property", "Which feed rate to use for ramping"))
obj.addProperty("App::PropertySpeed", "CustomFeedRate", "FeedRate", QtCore.QT_TRANSLATE_NOOP("App::Property", "Custom feedrate"))
obj.addProperty("App::PropertySpeed", "CustomFeedRate", "FeedRate", QtCore.QT_TRANSLATE_NOOP("App::Property", "Custom feed rate"))
obj.addProperty("App::PropertyBool", "UseStartDepth", "StartDepth", QtCore.QT_TRANSLATE_NOOP("App::Property", "Should the dressup ignore motion commands above DressupStartDepth"))
obj.addProperty("App::PropertyDistance", "DressupStartDepth", "StartDepth", QtCore.QT_TRANSLATE_NOOP("App::Property", "The depth where the ramp dressup is enabled. Above this ramps are not generated, but motion commands are passed through as is."))
obj.Method = ['RampMethod1', 'RampMethod2', 'RampMethod3', 'Helix']
obj.RampFeedRate = ['Horizontal Feed Rate', 'Vertical Feed Rate', 'Custom']
obj.RampFeedRate = ['Horizontal Feed Rate', 'Vertical Feed Rate', 'Ramp Feed Rate', 'Custom']
obj.Proxy = self
self.setEditorProperties(obj)
@@ -582,12 +582,16 @@ class ObjectDressup:
horizFeed = tc.HorizFeed.Value
vertFeed = tc.VertFeed.Value
if obj.RampFeedRate == "Horizontal Feed Rate":
rampFeed = tc.HorizFeed.Value
elif obj.RampFeedRate == "Vertical Feed Rate":
rampFeed = tc.VertFeed.Value
elif obj.RampFeedRate == 'Ramp Feed Rate':
rampFeed = math.sqrt(pow(tc.VertFeed.Value, 2) + pow(tc.HorizFeed.Value, 2))
else:
rampFeed = obj.CustomFeedRate.Value
horizRapid = tc.HorizRapid.Value
vertRapid = tc.VertRapid.Value

View File

@@ -1,39 +1,52 @@
#***************************************************************************
#* (c) sliptonic (shopinthewoods@gmail.com) 2014 *
#* *
#* This file is part of the FreeCAD CAx development system. *
#* *
#* This program is free software; you can redistribute it and/or modify *
#* it under the terms of the GNU Lesser General Public License (LGPL) *
#* as published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* for detail see the LICENCE text file. *
#* *
#* 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 Library General Public *
#* License along with FreeCAD; if not, write to the Free Software *
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
#* USA *
#* *
#* This file has been modified from Sliptonis original Linux CNC post *
#* for use with a Dynapath 20 controller all changes and Modifications *
#* (c) Linden (Linden@aktfast.net) 2016 *
#* *
#***************************************************************************/
from __future__ import print_function
# ***************************************************************************
# * (c) sliptonic (shopinthewoods@gmail.com) 2014 *
# * *
# * This file is part of the FreeCAD CAx development system. *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU Lesser General Public License (LGPL) *
# * as published by the Free Software Foundation; either version 2 of *
# * the License, or (at your option) any later version. *
# * for detail see the LICENCE text file. *
# * *
# * 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 Library General Public *
# * License along with FreeCAD; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
# * USA *
# * *
# * This file has been modified from Sliptonic original Linux CNC post *
# * for use with a Dynapath 20 controller all changes and Modifications *
# * (c) Linden (Linden@aktfast.net) 2016 *
# * *
# * Additional changes 2020 adding arguments to control units, precision *
# * editor, header, etc. Now uses FreeCAD unit system to correctly *
# * set Feed rate - sliptonic *
# * *
# * *
# ***************************************************************************
TOOLTIP='''
from __future__ import print_function
import FreeCAD
from FreeCAD import Units
import argparse
import datetime
import shlex
from PathScripts import PostUtils
TOOLTIP = '''
This is a postprocessor file for the Path workbench. It is used to
take a pseudo-gcode fragment outputted by a Path object, and output
real GCode suitable for a Tree Journyman 325 3 axis mill with Dynapath 20 controller in MM.
This is a work in progress and very few of the functions available on the Dynapath have been
implemented at this time.
This postprocessor, once placed in the appropriate PathScripts folder, can be used directly
from inside FreeCAD, via the GUI importer or via python scripts with:
real GCode suitable for a Tree Journyman 325 3 axis mill with Dynapath 20
controller in MM. This is a work in progress and very few of the functions
available on the Dynapath have been implemented at this time.
This postprocessor, once placed in the appropriate PathScripts folder,
can be used directly from inside FreeCAD, via the GUI importer or via python
scripts with:
Done
Coordinate Decimal limited to 3 places
@@ -48,35 +61,60 @@ To Do
Change G20 and G21 to G70 and G71 for metric or imperial units
Convert arcs to absolute
Strip comments and white spaces
Add file name in brackets limited to 8 alpha numeric no spaces all caps as first line in file
Add file name in brackets limited to 8 alpha numeric no spaces all caps as
first line in file
Change Q to K For depth of peck on G83
Fix tool change
Limit comments length and characters to Uppercase, alpha numeric and spaces add / prior to comments
Limit comments length and characters to Uppercase, alpha numeric and
spaces add / prior to comments
import linuxcnc_post
linuxcnc_post.export(object,"/path/to/file.ncc","")
import dynapath_post
dynapath_post.export(object,"/path/to/file.ncc","")
'''
import datetime
now = datetime.datetime.now()
from PathScripts import PostUtils
parser = argparse.ArgumentParser(prog='dynapath_post',
add_help=False)
parser.add_argument('--no-header', action='store_true',
help='suppress header output')
parser.add_argument('--no-comments', action='store_true',
help='suppress comment output')
parser.add_argument('--line-numbers', action='store_true',
help='prefix with line numbers')
parser.add_argument('--no-show-editor', action='store_true',
help='don\'t pop up editor before writing output')
parser.add_argument('--precision', default='3',
help='number of digits of precision, default=3')
parser.add_argument('--preamble',
help='set commands to be issued before the first command, default="G17\nG90\nG80\nG40"')
parser.add_argument('--postamble',
help='set commands to be issued after the last command, default="M09\nM05\nG80\nG40\nG17\nG90\nM30"')
parser.add_argument('--inches', action='store_true',
help='Convert output for US imperial mode (G20)')
#These globals set common customization preferences
TOOLTIP_ARGS = parser.format_help()
now = datetime.datetime.now()
# These globals set common customization preferences
OUTPUT_COMMENTS = True
OUTPUT_HEADER = False
OUTPUT_HEADER = True
OUTPUT_LINE_NUMBERS = False
SHOW_EDITOR = True
MODAL = False #if true commands are suppressed if the same as previous line.
MODAL = False # if true commands are suppressed if the same as previous line.
COMMAND_SPACE = " "
LINENR = 1 #line number starting value
LINENR = 1 # line number starting value
#These globals will be reflected in the Machine configuration of the project
UNITS = "G21" #G21 for metric, G20 for us standard
UNIT_SPEED_FORMAT = 'mm/min'
UNIT_FORMAT = 'mm'
# These globals will be reflected in the Machine configuration of the project
UNITS = "G21" # G21 for metric, G20 for us standard
MACHINE_NAME = "Tree MM"
CORNER_MIN = {'x':-340, 'y':0, 'z':0 }
CORNER_MAX = {'x':340, 'y':-355, 'z':-150 }
CORNER_MIN = {'x': -340, 'y': 0, 'z': 0}
CORNER_MAX = {'x': 340, 'y': -355, 'z': -150}
#Preamble text will appear at the beginning of the GCODE output file.
# Preamble text will appear at the beginning of the GCODE output file.
PREAMBLE = '''G17
G90
;G90.1 ;needed for simulation only
@@ -84,7 +122,7 @@ G80
G40
'''
#Postamble text will appear following the last operation.
# Postamble text will appear following the last operation.
POSTAMBLE = '''M09
M05
G80
@@ -95,37 +133,86 @@ M30
'''
#Pre operation text will be inserted before every operation
# Pre operation text will be inserted before every operation
PRE_OPERATION = ''''''
#Post operation text will be inserted after every operation
# Post operation text will be inserted after every operation
POST_OPERATION = ''''''
#Tool Change commands will be inserted before a tool change
# Tool Change commands will be inserted before a tool change
TOOL_CHANGE = ''''''
# to distinguish python built-in open function from the one declared below
if open.__module__ in ['__builtin__','io']:
if open.__module__ in ['__builtin__', 'io']:
pythonopen = open
def export(objectslist,filename,argstring):
def processArguments(argstring):
# pylint: disable=global-statement
global OUTPUT_HEADER
global OUTPUT_COMMENTS
global OUTPUT_LINE_NUMBERS
global SHOW_EDITOR
global PRECISION
global PREAMBLE
global POSTAMBLE
global UNITS
global UNIT_SPEED_FORMAT
global UNIT_FORMAT
global MODAL
global USE_TLO
global OUTPUT_DOUBLES
try:
args = parser.parse_args(shlex.split(argstring))
if args.no_header:
OUTPUT_HEADER = False
if args.no_comments:
OUTPUT_COMMENTS = False
if args.line_numbers:
OUTPUT_LINE_NUMBERS = True
if args.no_show_editor:
SHOW_EDITOR = False
print("Show editor = %d" % SHOW_EDITOR)
PRECISION = args.precision
if args.preamble is not None:
PREAMBLE = args.preamble
if args.postamble is not None:
POSTAMBLE = args.postamble
if args.inches:
UNITS = 'G20'
UNIT_SPEED_FORMAT = 'in/min'
UNIT_FORMAT = 'in'
PRECISION = 4
except Exception: # pylint: disable=broad-except
return False
return True
def export(objectslist, filename, argstring):
# pylint: disable=unused-argument
global UNITS # pylint: disable=global-statement
if not processArguments(argstring):
return None
global UNITS
global UNIT_FORMAT
global UNIT_SPEED_FORMAT
for obj in objectslist:
if not hasattr(obj,"Path"):
if not hasattr(obj, "Path"):
print("the object " + obj.Name + " is not a path. Please select only path and Compounds.")
return
print("postprocessing...")
gcode = ""
#Find the machine.
#The user my have overridden post processor defaults in the GUI. Make sure we're using the current values in the Machine Def.
# Find the machine.
# The user my have overridden post processor defaults in the GUI. Make sure we're using the current values in the Machine Def.
myMachine = None
for pathobj in objectslist:
if hasattr(pathobj,"MachineName"):
if hasattr(pathobj, "MachineName"):
myMachine = pathobj.MachineName
if hasattr(pathobj, "MachineUnits"):
if pathobj.MachineUnits == "Metric":
@@ -138,36 +225,41 @@ def export(objectslist,filename,argstring):
# write header
if OUTPUT_HEADER:
gcode += linenumber() + "(Exported by FreeCAD)\n"
gcode += linenumber() + "(Post Processor: " + __name__ +")\n"
gcode += linenumber() + "(Post Processor: " + __name__ + ")\n"
gcode += linenumber() + "(Output Time:"+str(now)+")\n"
#Write the preamble
if OUTPUT_COMMENTS: gcode += linenumber() + "(begin preamble)\n"
# Write the preamble
if OUTPUT_COMMENTS:
gcode += linenumber() + "(begin preamble)\n"
for line in PREAMBLE.splitlines(True):
gcode += linenumber() + line
gcode += linenumber() + UNITS + "\n"
for obj in objectslist:
#do the pre_op
if OUTPUT_COMMENTS: gcode += linenumber() + "(begin operation: " + obj.Label + ")\n"
# do the pre_op
if OUTPUT_COMMENTS:
gcode += linenumber() + "(begin operation: " + obj.Label + ")\n"
for line in PRE_OPERATION.splitlines(True):
gcode += linenumber() + line
gcode += parse(obj)
#do the post_op
if OUTPUT_COMMENTS: gcode += linenumber() + "(finish operation: " + obj.Label + ")\n"
# do the post_op
if OUTPUT_COMMENTS:
gcode += linenumber() + "(finish operation: " + obj.Label + ")\n"
for line in POST_OPERATION.splitlines(True):
gcode += linenumber() + line
#do the post_amble
# do the post_amble
if OUTPUT_COMMENTS: gcode += "(begin postamble)\n"
if OUTPUT_COMMENTS:
gcode += "(begin postamble)\n"
for line in POSTAMBLE.splitlines(True):
gcode += linenumber() + line
if SHOW_EDITOR:
print(f'show editor: {SHOW_EDITOR}')
if FreeCAD.GuiUp and SHOW_EDITOR:
dia = PostUtils.GCodeEditorDialog()
dia.editor.setText(gcode)
result = dia.exec_()
@@ -180,85 +272,99 @@ def export(objectslist,filename,argstring):
print("done postprocessing.")
gfile = pythonopen(filename,"w")
gfile = pythonopen(filename, "w")
gfile.write(final)
gfile.close()
def linenumber():
global LINENR # pylint: disable=global-statement
if OUTPUT_LINE_NUMBERS == True:
global LINENR # pylint: disable=global-statement
if OUTPUT_LINE_NUMBERS is True:
LINENR += 1
return "N" + str(LINENR) + " "
return ""
def parse(pathobj):
# pylint: disable=global-statement
global PRECISION
global UNIT_FORMAT
global UNIT_SPEED_FORMAT
out = ""
lastcommand = None
#params = ['X','Y','Z','A','B','I','J','K','F','S'] #This list control the order of parameters
params = ['X','Y','Z','A','B','I','J','F','S','T','Q','R','L'] #linuxcnc doesn't want K properties on XY plane Arcs need work.
precision_string = '.' + str(PRECISION) + 'f'
if hasattr(pathobj,"Group"): #We have a compound or project.
if OUTPUT_COMMENTS: out += linenumber() + "(compound: " + pathobj.Label + ")\n"
# params = ['X','Y','Z','A','B','I','J','K','F','S'] #This list control the order of parameters
params = ['X', 'Y', 'Z', 'A', 'B', 'I', 'J', 'F', 'S', 'T', 'Q', 'R', 'L']
if hasattr(pathobj, "Group"): # We have a compound or project.
if OUTPUT_COMMENTS:
out += linenumber() + "(compound: " + pathobj.Label + ")\n"
for p in pathobj.Group:
out += parse(p)
return out
else: #parsing simple path
else: # parsing simple path
if not hasattr(pathobj,"Path"): #groups might contain non-path things like stock.
if not hasattr(pathobj, "Path"): # groups might contain non-path things like stock.
return out
if OUTPUT_COMMENTS: out += linenumber() + "(Path: " + pathobj.Label + ")\n"
if OUTPUT_COMMENTS:
out += linenumber() + "(Path: " + pathobj.Label + ")\n"
for c in pathobj.Path.Commands:
outstring = []
command = c.Name
outstring.append(command)
# if modal: only print the command if it is not the same as the last one
if MODAL == True:
if MODAL is True:
if command == lastcommand:
outstring.pop(0)
# Now add the remaining parameters in order
for param in params:
if param in c.Parameters:
if param == 'F':
outstring.append(param + format(c.Parameters['F'], '.0f'))
speed = Units.Quantity(c.Parameters['F'], FreeCAD.Units.Velocity)
if speed.getValueAs(UNIT_SPEED_FORMAT) > 0.0:
outstring.append(param + format(float(speed.getValueAs(UNIT_SPEED_FORMAT)), precision_string))
elif param == 'S':
outstring.append(param + format(c.Parameters[param], '.0f'))
outstring.append(param + format(c.Parameters[param], precision_string))
elif param == 'T':
outstring.append(param + format(c.Parameters['T'], '.0f'))
outstring.append(param + format(c.Parameters['T'], precision_string))
else:
outstring.append(param + format(c.Parameters[param], '.3f'))
pos = Units.Quantity(c.Parameters[param], FreeCAD.Units.Length)
outstring.append(
param + format(float(pos.getValueAs(UNIT_FORMAT)), precision_string))
# store the latest command
lastcommand = command
# Check for Tool Change:
if command == 'M6':
if OUTPUT_COMMENTS: out += linenumber() + "(begin toolchange)\n"
if OUTPUT_COMMENTS:
out += linenumber() + "(begin toolchange)\n"
for line in TOOL_CHANGE.splitlines(True):
out += linenumber() + line
if command == "message":
if OUTPUT_COMMENTS == False:
if OUTPUT_COMMENTS is False:
out = []
else:
outstring.pop(0) #remove the command
outstring.pop(0) # remove the command
#prepend a line number and append a newline
# prepend a line number and append a newline
if len(outstring) >= 1:
if OUTPUT_LINE_NUMBERS:
outstring.insert(0,(linenumber()))
outstring.insert(0, (linenumber()))
#append the line to the final output
# append the line to the final output
for w in outstring:
out += w + COMMAND_SPACE
out = out.strip() + "\n"
return out
print(__name__ + " gcode postprocessor loaded.")
print(__name__ + " gcode postprocessor loaded.")

View File

@@ -155,3 +155,12 @@ G0 Z0.500000
self.assertEqual(len(table.Tools), 2)
self.assertEqual(str(table.Tools), '{1: Tool 12.7mm Drill Bit, 2: Tool my other tool}' )
def test50(self):
"""Test Path.Length calculation"""
commands = []
commands.append(Path.Command("G1",{"X":1}))
commands.append(Path.Command("G1",{"Y":1}))
path = Path.Path(commands)
self.assertEqual(path.Length, 2)

View File

@@ -87,14 +87,14 @@ void DrawWeldSymbol::onSettingDocument()
return;
}
std::string tileName1 = doc->getUniqueObjectName("DrawTileWeld");
std::string tileName1 = doc->getUniqueObjectName("TileWeld");
auto tile1Obj( doc->addObject( "TechDraw::DrawTileWeld", tileName1.c_str() ) );
DrawTileWeld* tile1 = dynamic_cast<DrawTileWeld*>(tile1Obj);
if (tile1 != nullptr) {
tile1->TileParent.setValue(this);
}
std::string tileName2 = doc->getUniqueObjectName("DrawTileWeld");
std::string tileName2 = doc->getUniqueObjectName("TileWeld");
auto tile2Obj( doc->addObject( "TechDraw::DrawTileWeld", tileName2.c_str() ) );
DrawTileWeld* tile2 = dynamic_cast<DrawTileWeld*>(tile2Obj);
if (tile2 != nullptr) {

View File

@@ -151,7 +151,7 @@ private:
}
}
else {
throw Py::TypeError("Export of this object type is not supported by TechDraw module");
throw Py::TypeError("No Technical Drawing Page found in selection.");
}
}
}

View File

@@ -400,9 +400,6 @@ void MDIViewPage::onDeleteObject(const App::DocumentObject& obj)
//if this page has a QView for this obj, delete it.
if (obj.isDerivedFrom(TechDraw::DrawView::getClassTypeId())) {
(void) m_view->removeQViewByName(obj.getNameInDocument());
} else if (m_objectName == obj.getNameInDocument()) {
// if obj is me, hide myself and my tab
m_vpPage->hide();
}
}

View File

@@ -1,6 +1,5 @@
<RCC>
<qresource prefix="/">
<file>icons/TechDraw_Tree_Annotation.svg</file>
<file>icons/TechDraw_Tree_Hatch.svg</file>
<file>icons/TechDraw_Tree_Page.svg</file>
<file>icons/TechDraw_Tree_Page_Unsync.svg</file>

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -116,7 +116,7 @@ TechDraw::DrawViewSymbol* TaskActiveView::createActiveView(void)
{
// Base::Console().Message("TAV::createActiveView()\n");
std::string symbolName = m_pageFeat->getDocument()->getUniqueObjectName("DrawActiveView");
std::string symbolName = m_pageFeat->getDocument()->getUniqueObjectName("ActiveView");
std::string symbolType = "TechDraw::DrawViewSymbol";
std::string pageName = m_pageFeat->getNameInDocument();

View File

@@ -261,7 +261,7 @@ void TaskLeaderLine::setUiEdit()
void TaskLeaderLine::createLeaderFeature(std::vector<Base::Vector3d> converted)
{
// Base::Console().Message("TTL::createLeaderFeature()\n");
m_leaderName = m_basePage->getDocument()->getUniqueObjectName("DrawLeaderLine");
m_leaderName = m_basePage->getDocument()->getUniqueObjectName("LeaderLine");
m_leaderType = "TechDraw::DrawLeaderLine";
std::string PageName = m_basePage->getNameInDocument();

View File

@@ -281,7 +281,7 @@ void TaskRichAnno::onEditorExit(void)
void TaskRichAnno::createAnnoFeature()
{
// Base::Console().Message("TRA::createAnnoFeature()");
std::string annoName = m_basePage->getDocument()->getUniqueObjectName("DrawRichAnno");
std::string annoName = m_basePage->getDocument()->getUniqueObjectName("RichTextAnnotation");
std::string annoType = "TechDraw::DrawRichAnno";
std::string PageName = m_basePage->getNameInDocument();

View File

@@ -351,7 +351,7 @@ TechDraw::DrawViewSection* TaskSectionView::createSectionView(void)
Gui::Command::openCommand("Create SectionView");
TechDraw::DrawViewSection* newSection = nullptr;
if (m_section == nullptr) {
sectionName = m_base->getDocument()->getUniqueObjectName("DrawViewSection");
sectionName = m_base->getDocument()->getUniqueObjectName("SectionView");
std::string sectionType = "TechDraw::DrawViewSection";
TechDraw::DrawPage* page = m_base->findParentPage();

View File

@@ -434,7 +434,7 @@ TechDraw::DrawWeldSymbol* TaskWeldingSymbol::createWeldingSymbol(void)
{
// Base::Console().Message("TWS::createWeldingSymbol()\n");
std::string symbolName = m_leadFeat->getDocument()->getUniqueObjectName("DrawWeldSymbol");
std::string symbolName = m_leadFeat->getDocument()->getUniqueObjectName("WeldSymbol");
std::string symbolType = "TechDraw::DrawWeldSymbol";
TechDraw::DrawPage* page = m_leadFeat->findParentPage();

View File

@@ -49,7 +49,7 @@ PROPERTY_SOURCE(TechDrawGui::ViewProviderAnnotation, TechDrawGui::ViewProviderDr
ViewProviderAnnotation::ViewProviderAnnotation()
{
sPixmap = "TechDraw_Tree_Annotation";
sPixmap = "actions/techdraw-annotation";
}
ViewProviderAnnotation::~ViewProviderAnnotation()