Merge branch 'master' into feature/add-experimental-features-to-preferences

This commit is contained in:
mlampert
2021-02-14 17:54:04 -08:00
committed by GitHub
22 changed files with 239 additions and 162 deletions

View File

@@ -26,14 +26,11 @@
from __future__ import print_function
import os
import re
import shutil
import stat
import sys
import tempfile
from PySide import QtGui, QtCore
import AddonManager_rc
import FreeCADGui
from addonmanager_utilities import translate # this needs to be as is for pylupdate

View File

@@ -4,7 +4,6 @@
# License LGPL
import AddonManager
import AddonManager_rc
FreeCADGui.addLanguagePath(":/translations")
FreeCADGui.addCommand('Std_AddonMgr', AddonManager.CommandAddonManager())

View File

@@ -24,9 +24,7 @@
import os
import re
import shutil
import stat
import sys
import tempfile
from PySide import QtCore, QtGui

View File

@@ -404,7 +404,7 @@ TaskDlgFemConstraintContact::TaskDlgFemConstraintContact(ViewProviderFemConstrai
{
this->ConstraintView = ConstraintView;
assert(ConstraintView);
this->parameter = new TaskFemConstraintContact(ConstraintView);;
this->parameter = new TaskFemConstraintContact(ConstraintView);
Content.push_back(parameter);
}

View File

@@ -571,7 +571,7 @@ TaskDlgFemConstraintDisplacement::TaskDlgFemConstraintDisplacement(ViewProviderF
{
this->ConstraintView = ConstraintView;
assert(ConstraintView);
this->parameter = new TaskFemConstraintDisplacement(ConstraintView);;
this->parameter = new TaskFemConstraintDisplacement(ConstraintView);
Content.push_back(parameter);
}

View File

@@ -252,7 +252,7 @@ TaskDlgFemConstraintFixed::TaskDlgFemConstraintFixed(ViewProviderFemConstraintFi
{
this->ConstraintView = ConstraintView;
assert(ConstraintView);
this->parameter = new TaskFemConstraintFixed(ConstraintView);;
this->parameter = new TaskFemConstraintFixed(ConstraintView);
Content.push_back(parameter);
}

View File

@@ -872,7 +872,7 @@ TaskDlgFemConstraintFluidBoundary::TaskDlgFemConstraintFluidBoundary(ViewProvide
{
this->ConstraintView = ConstraintView;
assert(ConstraintView);
this->parameter = new TaskFemConstraintFluidBoundary(ConstraintView);;
this->parameter = new TaskFemConstraintFluidBoundary(ConstraintView);
Content.push_back(parameter);
}

View File

@@ -394,7 +394,7 @@ TaskDlgFemConstraintForce::TaskDlgFemConstraintForce(ViewProviderFemConstraintFo
{
this->ConstraintView = ConstraintView;
assert(ConstraintView);
this->parameter = new TaskFemConstraintForce(ConstraintView);;
this->parameter = new TaskFemConstraintForce(ConstraintView);
Content.push_back(parameter);
}

View File

@@ -383,7 +383,7 @@ TaskDlgFemConstraintHeatflux::TaskDlgFemConstraintHeatflux(ViewProviderFemConstr
{
this->ConstraintView = ConstraintView;
assert(ConstraintView);
this->parameter = new TaskFemConstraintHeatflux(ConstraintView);;
this->parameter = new TaskFemConstraintHeatflux(ConstraintView);
Content.push_back(parameter);
}

View File

@@ -106,7 +106,7 @@ TaskDlgFemConstraintInitialTemperature::TaskDlgFemConstraintInitialTemperature(V
{
this->ConstraintView = ConstraintView;
assert(ConstraintView);
this->parameter = new TaskFemConstraintInitialTemperature(ConstraintView);;
this->parameter = new TaskFemConstraintInitialTemperature(ConstraintView);
Content.push_back(parameter);
}

View File

@@ -273,7 +273,7 @@ TaskDlgFemConstraintPlaneRotation::TaskDlgFemConstraintPlaneRotation(ViewProvide
{
this->ConstraintView = ConstraintView;
assert(ConstraintView);
this->parameter = new TaskFemConstraintPlaneRotation(ConstraintView);;
this->parameter = new TaskFemConstraintPlaneRotation(ConstraintView);
Content.push_back(parameter);
}

View File

@@ -269,7 +269,7 @@ TaskDlgFemConstraintPressure::TaskDlgFemConstraintPressure(ViewProviderFemConstr
{
this->ConstraintView = ConstraintView;
assert(ConstraintView);
this->parameter = new TaskFemConstraintPressure(ConstraintView);;
this->parameter = new TaskFemConstraintPressure(ConstraintView);
Content.push_back(parameter);
}

View File

@@ -182,7 +182,7 @@ TaskDlgFemConstraintPulley::TaskDlgFemConstraintPulley(ViewProviderFemConstraint
{
this->ConstraintView = ConstraintView;
assert(ConstraintView);
this->parameter = new TaskFemConstraintPulley(ConstraintView);;
this->parameter = new TaskFemConstraintPulley(ConstraintView);
Content.push_back(parameter);
}

View File

@@ -324,7 +324,7 @@ TaskDlgFemConstraintTemperature::TaskDlgFemConstraintTemperature(ViewProviderFem
{
this->ConstraintView = ConstraintView;
assert(ConstraintView);
this->parameter = new TaskFemConstraintTemperature(ConstraintView);;
this->parameter = new TaskFemConstraintTemperature(ConstraintView);
Content.push_back(parameter);
}

View File

@@ -486,7 +486,7 @@ TaskDlgFemConstraintTransform::TaskDlgFemConstraintTransform(ViewProviderFemCons
{
this->ConstraintView = ConstraintView;
assert(ConstraintView);
this->parameter = new TaskFemConstraintTransform(ConstraintView);;
this->parameter = new TaskFemConstraintTransform(ConstraintView);
Content.push_back(parameter);
}

View File

@@ -73,7 +73,7 @@ class FemInputWriterZ88(writerbase.FemInputWriter):
self.element_count = len(self.femelement_table)
self.set_z88_elparam()
self.write_z88_mesh()
self.write_z88_contraints()
self.write_z88_constraints()
self.write_z88_face_loads()
self.write_z88_materials()
self.write_z88_elements_properties()
@@ -120,7 +120,7 @@ class FemInputWriterZ88(writerbase.FemInputWriter):
)
f.close()
def write_z88_contraints(self):
def write_z88_constraints(self):
constraints_data = [] # will be a list of tuple for better sorting
# fixed constraints
@@ -155,8 +155,8 @@ class FemInputWriterZ88(writerbase.FemInputWriter):
constraints_data.append((n, str(n) + " 3 1 " + str(v3) + "\n"))
# write constraints_data to file
contraints_file_path = self.file_name + "i2.txt"
f = open(contraints_file_path, "w")
constraints_file_path = self.file_name + "i2.txt"
f = open(constraints_file_path, "w")
f.write(str(len(constraints_data)) + "\n")
for c in sorted(constraints_data):
f.write(c[1])

View File

@@ -436,6 +436,113 @@ void TaskPipeParameters::exitSelectionMode() {
Gui::Selection().clearSelection();
}
bool TaskPipeParameters::accept()
{
//see what to do with external references
//check the prerequisites for the selected objects
//the user has to decide which option we should take if external references are used
PartDesign::Pipe* pcPipe = static_cast<PartDesign::Pipe*>(getPipeView()->getObject());
auto pcActiveBody = PartDesignGui::getBodyFor(pcPipe, false);
if (!pcActiveBody) {
QMessageBox::warning(this, tr("Input error"), tr("No active body"));
return false;
}
//auto pcActivePart = PartDesignGui::getPartFor(pcActiveBody, false);
std::vector<App::DocumentObject*> copies;
bool extReference = false;
App::DocumentObject* spine = pcPipe->Spine.getValue();
App::DocumentObject* auxSpine = pcPipe->AuxillerySpine.getValue();
// If a spine isn't set but user entered a label then search for the appropriate document object
QString label = ui->spineBaseEdit->text();
if (!spine && !label.isEmpty()) {
QByteArray ba = label.toUtf8();
std::vector<App::DocumentObject*> objs = pcPipe->getDocument()->findObjects(App::DocumentObject::getClassTypeId(), nullptr, ba.constData());
if (!objs.empty()) {
pcPipe->Spine.setValue(objs.front());
spine = objs.front();
}
}
if (spine && !pcActiveBody->hasObject(spine) && !pcActiveBody->getOrigin()->hasObject(spine)) {
extReference = true;
}
else if (auxSpine && !pcActiveBody->hasObject(auxSpine) && !pcActiveBody->getOrigin()->hasObject(auxSpine)) {
extReference = true;
}
else {
for(App::DocumentObject* obj : pcPipe->Sections.getValues()) {
if (!pcActiveBody->hasObject(obj) && !pcActiveBody->getOrigin()->hasObject(obj)) {
extReference = true;
break;
}
}
}
if (extReference) {
QDialog dia(Gui::getMainWindow());
Ui_DlgReference dlg;
dlg.setupUi(&dia);
dia.setModal(true);
int result = dia.exec();
if (result == QDialog::DialogCode::Rejected)
return false;
if (!dlg.radioXRef->isChecked()) {
if (!pcActiveBody->hasObject(spine) && !pcActiveBody->getOrigin()->hasObject(spine)) {
pcPipe->Spine.setValue(PartDesignGui::TaskFeaturePick::makeCopy(spine, "",
dlg.radioIndependent->isChecked()),
pcPipe->Spine.getSubValues());
copies.push_back(pcPipe->Spine.getValue());
}
else if (!pcActiveBody->hasObject(auxSpine) && !pcActiveBody->getOrigin()->hasObject(auxSpine)){
pcPipe->AuxillerySpine.setValue(PartDesignGui::TaskFeaturePick::makeCopy(auxSpine, "",
dlg.radioIndependent->isChecked()),
pcPipe->AuxillerySpine.getSubValues());
copies.push_back(pcPipe->AuxillerySpine.getValue());
}
std::vector<App::DocumentObject*> objs;
int index = 0;
for(App::DocumentObject* obj : pcPipe->Sections.getValues()) {
if(!pcActiveBody->hasObject(obj) && !pcActiveBody->getOrigin()->hasObject(obj)) {
objs.push_back(PartDesignGui::TaskFeaturePick::makeCopy(obj, "", dlg.radioIndependent->isChecked()));
copies.push_back(objs.back());
}
else {
objs.push_back(obj);
}
index++;
}
pcPipe->Sections.setValues(objs);
}
}
try {
Gui::cmdAppDocument(pcPipe, "recompute()");
if (!vp->getObject()->isValid())
throw Base::RuntimeError(vp->getObject()->getStatusString());
Gui::cmdGuiDocument(pcPipe, "resetEdit()");
Gui::Command::commitCommand();
//we need to add the copied features to the body after the command action, as otherwise FreeCAD crashes unexplainably
for (auto obj : copies) {
pcActiveBody->addObject(obj);
}
}
catch (const Base::Exception& e) {
QMessageBox::warning(this, tr("Input error"), QString::fromUtf8(e.what()));
return false;
}
return true;
}
//**************************************************************************
//**************************************************************************
@@ -1014,89 +1121,7 @@ TaskDlgPipeParameters::~TaskDlgPipeParameters()
bool TaskDlgPipeParameters::accept()
{
//see what to do with external references
//check the prerequisites for the selected objects
//the user has to decide which option we should take if external references are used
PartDesign::Pipe* pcPipe = static_cast<PartDesign::Pipe*>(getPipeView()->getObject());
auto pcActiveBody = PartDesignGui::getBodyFor(pcPipe, false);
//auto pcActivePart = PartDesignGui::getPartFor(pcActiveBody, false);
std::vector<App::DocumentObject*> copies;
bool extReference = false;
if(!pcActiveBody->hasObject(pcPipe->Spine.getValue()) && !pcActiveBody->getOrigin()->hasObject(pcPipe->Spine.getValue()))
extReference = true;
else if(pcPipe->AuxillerySpine.getValue() && !pcActiveBody->hasObject(pcPipe->AuxillerySpine.getValue()) &&
!pcActiveBody->getOrigin()->hasObject(pcPipe->AuxillerySpine.getValue()))
extReference = true;
else {
for(App::DocumentObject* obj : pcPipe->Sections.getValues()) {
if(!pcActiveBody->hasObject(obj) && !pcActiveBody->getOrigin()->hasObject(obj))
extReference = true;
}
}
if (extReference) {
QDialog dia(Gui::getMainWindow());
Ui_DlgReference dlg;
dlg.setupUi(&dia);
dia.setModal(true);
int result = dia.exec();
if (result == QDialog::DialogCode::Rejected)
return false;
if(!dlg.radioXRef->isChecked()) {
if(!pcActiveBody->hasObject(pcPipe->Spine.getValue()) && !pcActiveBody->getOrigin()->hasObject(pcPipe->Spine.getValue())) {
pcPipe->Spine.setValue(PartDesignGui::TaskFeaturePick::makeCopy(pcPipe->Spine.getValue(), "", dlg.radioIndependent->isChecked()),
pcPipe->Spine.getSubValues());
copies.push_back(pcPipe->Spine.getValue());
}
else if(!pcActiveBody->hasObject(pcPipe->AuxillerySpine.getValue()) && !pcActiveBody->getOrigin()->hasObject(pcPipe->AuxillerySpine.getValue())){
pcPipe->AuxillerySpine.setValue(PartDesignGui::TaskFeaturePick::makeCopy(pcPipe->AuxillerySpine.getValue(), "", dlg.radioIndependent->isChecked()),
pcPipe->AuxillerySpine.getSubValues());
copies.push_back(pcPipe->AuxillerySpine.getValue());
}
std::vector<App::DocumentObject*> objs;
int index = 0;
for(App::DocumentObject* obj : pcPipe->Sections.getValues()) {
if(!pcActiveBody->hasObject(obj) && !pcActiveBody->getOrigin()->hasObject(obj)) {
objs.push_back(PartDesignGui::TaskFeaturePick::makeCopy(obj, "", dlg.radioIndependent->isChecked()));
copies.push_back(objs.back());
}
else
objs.push_back(obj);
index++;
}
pcPipe->Sections.setValues(objs);
}
}
try {
Gui::cmdAppDocument(pcPipe, "recompute()");
if (!vp->getObject()->isValid())
throw Base::RuntimeError(vp->getObject()->getStatusString());
Gui::cmdGuiDocument(pcPipe, "resetEdit()");
Gui::Command::commitCommand();
//we need to add the copied features to the body after the command action, as otherwise FreeCAD crashes unexplainably
for(auto obj : copies) {
//Dead code: pcActiveBody was previously used without checking for null, so it won't be null here either.
//if(pcActiveBody)
pcActiveBody->addObject(obj);
//else if (pcActivePart)
// pcActivePart->addObject(obj);
}
}
catch (const Base::Exception& e) {
QMessageBox::warning(parameter, tr("Input error"), QString::fromUtf8(e.what()));
return false;
}
return true;
return parameter->accept();
}

View File

@@ -32,10 +32,6 @@
#include "ViewProviderPipe.h"
#include "TaskDressUpParameters.h"
class Ui_TaskPipeParameters;
class Ui_TaskPipeOrientation;
class Ui_TaskPipeScaling;
namespace App {
class Property;
@@ -47,6 +43,9 @@ class ViewProvider;
namespace PartDesignGui {
class Ui_TaskPipeParameters;
class Ui_TaskPipeOrientation;
class Ui_TaskPipeScaling;
class TaskPipeParameters : public TaskSketchBasedParameters
@@ -57,7 +56,8 @@ public:
TaskPipeParameters(ViewProviderPipe *PipeView,bool newObj=false,QWidget *parent = 0);
~TaskPipeParameters();
bool accept();
private Q_SLOTS:
void onTangentChanged(bool checked);
void onTransitionChanged(int);
@@ -80,6 +80,9 @@ private:
void clearButtons();
void exitSelectionMode();
ViewProviderPipe* getPipeView() const
{ return static_cast<ViewProviderPipe*>(vp); }
bool spineShow = false;
private:
@@ -135,7 +138,6 @@ public:
TaskPipeScaling(ViewProviderPipe *PipeView,bool newObj=false,QWidget *parent = 0);
virtual ~TaskPipeScaling();
private Q_SLOTS:
void onScalingChanged(int);
void onButtonRefAdd(bool checked);
@@ -170,10 +172,6 @@ public:
TaskDlgPipeParameters(ViewProviderPipe *PipeView,bool newObj=false);
~TaskDlgPipeParameters();
ViewProviderPipe* getPipeView() const
{ return static_cast<ViewProviderPipe*>(vp); }
public:
/// is called by the framework if the dialog is accepted (Ok)
virtual bool accept();

View File

@@ -34,6 +34,11 @@ import math
import area
from pivy import coin
# lazily loaded modules
from lazy_loader.lazy_loader import LazyLoader
Part = LazyLoader('Part', globals(), 'Part')
TechDraw = LazyLoader('TechDraw', globals(), 'TechDraw')
__doc__ = "Class and implementation of the Adaptive path operation."
def convertTo2d(pathArray):
@@ -399,14 +404,9 @@ def Execute(op,obj):
if obj.Tolerance < 0.001:
obj.Tolerance = 0.001
pathArray = []
for base, subs in obj.Base:
for sub in subs:
shape = base.Shape.getElement(sub)
for edge in shape.Edges:
pathArray.append([discretize(edge)])
# Get list of working edges for adaptive algorithm
pathArray = _get_working_edges(op, obj)
#pathArray=connectEdges(edges)
path2d = convertTo2d(pathArray)
stockPaths = []
@@ -529,6 +529,35 @@ def Execute(op,obj):
sceneClean()
def _get_working_edges(op, obj):
"""_get_working_edges(op, obj)...
Compile all working edges from the Base Geometry selection (obj.Base)
for the current operation.
Additional modifications to selected region(face), such as extensions,
should be placed within this function.
"""
pathArray = list()
for base, subs in obj.Base:
for sub in subs:
if obj.UseOutline:
face = base.Shape.getElement(sub)
zmin = face.BoundBox.ZMin
# get face outline with same method in PocketShape
wire = TechDraw.findShapeOutline(face, 1, FreeCAD.Vector(0.0, 0.0, 1.0))
shape = Part.Face(wire)
# translate to face height if necessary
if shape.BoundBox.ZMin != zmin:
shape.translate(FreeCAD.Vector(0.0, 0.0, zmin - shape.BoundBox.ZMin))
else:
shape = base.Shape.getElement(sub)
for edge in shape.Edges:
pathArray.append([discretize(edge)])
return pathArray
class PathAdaptive(PathOp.ObjectOp):
def opFeatures(self, obj):
'''opFeatures(obj) ... returns the OR'ed list of features used and supported by the operation.
@@ -574,6 +603,11 @@ class PathAdaptive(PathOp.ObjectOp):
obj.addProperty("App::PropertyAngle", "HelixConeAngle", "Adaptive", "Helix cone angle (degrees)")
obj.addProperty("App::PropertyLength", "HelixDiameterLimit", "Adaptive", "Limit helix entry diameter, if limit larger than tool diameter or 0, tool diameter is used")
if not hasattr(obj, "UseOutline"):
obj.addProperty("App::PropertyBool",
"UseOutline",
"Adaptive",
"Uses the outline of the base geometry.")
def opSetDefaultValues(self, obj, job):
obj.Side="Inside"
@@ -594,6 +628,7 @@ class PathAdaptive(PathOp.ObjectOp):
obj.StockToLeave = 0
obj.KeepToolDownRatio = 3.0
obj.UseHelixArcs = False
obj.UseOutline = False
def opExecute(self, obj):
'''opExecute(obj) ... called whenever the receiver needs to be recalculated.

View File

@@ -140,6 +140,11 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
form.FinishingProfile.setChecked(True)
formLayout.addRow(QtGui.QLabel("Finishing Profile"), form.FinishingProfile)
# Use outline checkbox
form.useOutline = QtGui.QCheckBox()
form.useOutline.setChecked(False)
formLayout.addRow(QtGui.QLabel("Use outline"), form.useOutline)
layout.addLayout(formLayout)
# stop button
@@ -170,6 +175,7 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
# signals.append(self.form.ProcessHoles.stateChanged)
signals.append(self.form.ForceInsideOut.stateChanged)
signals.append(self.form.FinishingProfile.stateChanged)
signals.append(self.form.useOutline.stateChanged)
signals.append(self.form.StopButton.toggled)
return signals
@@ -191,6 +197,7 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
# self.form.ProcessHoles.setChecked(obj.ProcessHoles)
self.form.ForceInsideOut.setChecked(obj.ForceInsideOut)
self.form.FinishingProfile.setChecked(obj.FinishingProfile)
self.form.useOutline.setChecked(obj.UseOutline)
self.setupToolController(obj, self.form.ToolController)
self.setupCoolant(obj, self.form.coolantController)
self.form.StopButton.setChecked(obj.Stopped)
@@ -221,6 +228,7 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
obj.ForceInsideOut = self.form.ForceInsideOut.isChecked()
obj.FinishingProfile = self.form.FinishingProfile.isChecked()
obj.UseOutline = self.form.useOutline.isChecked()
obj.Stopped = self.form.StopButton.isChecked()
if(obj.Stopped):
self.form.StopButton.setChecked(False) # reset the button

View File

@@ -284,29 +284,21 @@ def cmdsForEdge(edge, flip = False, useHelixForBSpline = True, segm = 50, hSpeed
else:
# We're dealing with a helix or a more complex shape and it has to get approximated
# by a number of straight segments
eStraight = Part.Edge(Part.LineSegment(p1, p3))
esP2 = eStraight.valueAt((eStraight.FirstParameter + eStraight.LastParameter)/2)
deviation = (p2 - esP2).Length
if isRoughly(deviation, 0):
return [ Path.Command('G1', {'X': p3.x, 'Y': p3.y, 'Z': p3.z}) ]
# at this point pixellation is all we can do
points = edge.discretize(Deflection=0.01)
if flip:
points = points[::-1]
commands = []
segments = int(math.ceil((deviation / eStraight.Length) * segm))
#print("**** pixellation with %d segments" % segments)
dParameter = (edge.LastParameter - edge.FirstParameter) / segments
# starting point
p0 = edge.valueAt(edge.LastParameter) if flip else edge.valueAt(edge.FirstParameter)
for i in range(0, segments):
if flip:
p = edge.valueAt(edge.LastParameter - (i + 1) * dParameter)
else:
p = edge.valueAt(edge.FirstParameter + (i + 1) * dParameter)
if hSpeed > 0 and vSpeed > 0:
params.update({'F': speedBetweenPoints(p0, p, hSpeed, vSpeed)})
cmd = Path.Command('G1', {'X': p.x, 'Y': p.y, 'Z': p.z})
#print("***** %s" % cmd)
commands.append(cmd)
p0 = p
if points:
p0 = points[0]
for p in points[1:]:
params = {'X': p.x, 'Y': p.y, 'Z': p.z}
if hSpeed > 0 and vSpeed > 0:
params['F'] = speedBetweenPoints(p0, p, hSpeed, vSpeed)
cmd = Path.Command('G1', params)
# print("***** {}".format(cmd))
commands.append(cmd)
p0 = p
#print commands
return commands
@@ -542,13 +534,18 @@ def flipEdge(edge):
flipped.buildFromPolesMultsKnots(poles, mults , knots, perio, degree, weights, ratio)
return Part.Edge(flipped)
elif type(edge.Curve) == Part.OffsetCurve:
return edge.reversed()
global OddsAndEnds # pylint: disable=global-statement
OddsAndEnds.append(edge)
PathLog.warning(translate('PathGeom', "%s not support for flipping") % type(edge.Curve))
PathLog.warning(translate('PathGeom', "%s not supported for flipping") % type(edge.Curve))
Wire = []
def flipWire(wire):
'''Flip the entire wire and all its edges so it is being processed the other way around.'''
Wire.append(wire)
edges = [flipEdge(e) for e in wire.Edges]
edges.reverse()
PathLog.debug(edges)

View File

@@ -29,10 +29,10 @@ from FreeCAD import Vector
from PathTests.PathTestUtils import PathTestBase
class TestPathGeom(PathTestBase):
"""Test Path <-> Wire conversion."""
'''Test Path <-> Wire conversion.'''
def test00(self):
"""Verify getAngle functionality."""
'''Verify getAngle functionality.'''
self.assertRoughly(PathGeom.getAngle(Vector(1, 0, 0)), 0)
self.assertRoughly(PathGeom.getAngle(Vector(1, 1, 0)), math.pi/4)
self.assertRoughly(PathGeom.getAngle(Vector(0, 1, 0)), math.pi/2)
@@ -43,7 +43,7 @@ class TestPathGeom(PathTestBase):
self.assertRoughly(PathGeom.getAngle(Vector(1, -1, 0)), -math.pi/4)
def test01(self):
"""Verify diffAngle functionality."""
'''Verify diffAngle functionality.'''
self.assertRoughly(PathGeom.diffAngle(0, +0*math.pi/4, 'CW') / math.pi, 0/4.)
self.assertRoughly(PathGeom.diffAngle(0, +3*math.pi/4, 'CW') / math.pi, 5/4.)
self.assertRoughly(PathGeom.diffAngle(0, -3*math.pi/4, 'CW') / math.pi, 3/4.)
@@ -68,7 +68,7 @@ class TestPathGeom(PathTestBase):
self.assertRoughly(PathGeom.diffAngle(-math.pi/4, -1*math.pi/4, 'CCW') / math.pi, 0/4.)
def test02(self):
"""Verify isVertical/isHorizontal for Vector"""
'''Verify isVertical/isHorizontal for Vector'''
self.assertTrue(PathGeom.isVertical(Vector(0, 0, 1)))
self.assertTrue(PathGeom.isVertical(Vector(0, 0, -1)))
self.assertFalse(PathGeom.isVertical(Vector(1, 0, 1)))
@@ -89,7 +89,7 @@ class TestPathGeom(PathTestBase):
self.assertFalse(PathGeom.isHorizontal(Vector(0, -1, -1)))
def test03(self):
"""Verify isVertical/isHorizontal for Edges"""
'''Verify isVertical/isHorizontal for Edges'''
# lines
self.assertTrue(PathGeom.isVertical(Part.Edge(Part.LineSegment(Vector(-1, -1, -1), Vector(-1, -1, 8)))))
@@ -136,7 +136,7 @@ class TestPathGeom(PathTestBase):
def test04(self):
"""Verify isVertical/isHorizontal for faces"""
'''Verify isVertical/isHorizontal for faces'''
# planes
xPlane = Part.makePlane(100, 100, Vector(), Vector(1, 0, 0))
@@ -176,7 +176,7 @@ class TestPathGeom(PathTestBase):
self.assertFalse(PathGeom.isHorizontal(yzCylinder))
def test07(self):
"""Verify speed interpolation works for different pitches"""
'''Verify speed interpolation works for different pitches'''
# horizontal
self.assertRoughly(100, PathGeom.speedBetweenPoints(Vector(), Vector(1,1,0), 100, 50))
self.assertRoughly(100, PathGeom.speedBetweenPoints(Vector(1,1,0), Vector(), 100, 50))
@@ -202,7 +202,7 @@ class TestPathGeom(PathTestBase):
self.assertRoughly( 83.33, PathGeom.speedBetweenPoints(Vector(0,1,0.5774), Vector(), 100, 50), 0.01)
def test08(self):
"""Verify speed interpolation works for different pitches if vSpeed > hSpeed"""
'''Verify speed interpolation works for different pitches if vSpeed > hSpeed'''
# horizontal
self.assertRoughly( 50, PathGeom.speedBetweenPoints(Vector(), Vector(1,1,0), 50, 100))
self.assertRoughly( 50, PathGeom.speedBetweenPoints(Vector(1,1,0), Vector(), 50, 100))
@@ -228,13 +228,13 @@ class TestPathGeom(PathTestBase):
self.assertRoughly( 66.66, PathGeom.speedBetweenPoints(Vector(0,1,0.5774), Vector(), 50, 100), 0.01)
def test10(self):
"""Verify proper geometry objects for G1 and G01 commands are created."""
'''Verify proper geometry objects for G1 and G01 commands are created.'''
spt = Vector(1,2,3)
self.assertLine(PathGeom.edgeForCmd(Path.Command('G1', {'X': 7, 'Y': 2, 'Z': 3}), spt), spt, Vector(7, 2, 3))
self.assertLine(PathGeom.edgeForCmd(Path.Command('G01', {'X': 1, 'Y': 3, 'Z': 5}), spt), spt, Vector(1, 3, 5))
def test20(self):
"""Verify proper geometry for arcs in the XY-plane are created."""
'''Verify proper geometry for arcs in the XY-plane are created.'''
p1 = Vector(0, -1, 2)
p2 = Vector(-1, 0, 2)
self.assertArc(
@@ -247,7 +247,7 @@ class TestPathGeom(PathTestBase):
p2, p1, 'CCW')
def test30(self):
"""Verify proper geometry for arcs with rising and fall ing Z-axis are created."""
'''Verify proper geometry for arcs with rising and fall ing Z-axis are created.'''
#print("------ rising helix -------")
p1 = Vector(0, 1, 0)
p2 = Vector(1, 0, 2)
@@ -277,7 +277,7 @@ class TestPathGeom(PathTestBase):
p1, Vector(-1/math.sqrt(2), -1/math.sqrt(2), 1), p2)
def test40(self):
"""Verify arc results in proper G2/3 command."""
'''Verify arc results in proper G2/3 command.'''
p1 = Vector( 0, -10, 0)
p2 = Vector(-10, 0, 0)
p3 = Vector( 0, +10, 0)
@@ -295,7 +295,7 @@ class TestPathGeom(PathTestBase):
self.assertCommandEqual(cmds(p1, p4, p3, True), cmd('G2', p1, Vector(0, -10, 0)))
def test41(self):
"""Verify circle results in proper G2/G3 commands."""
'''Verify circle results in proper G2/G3 commands.'''
def cmds(center, radius, up = True):
norm = Vector(0, 0, 1) if up else Vector(0, 0, -1)
@@ -308,8 +308,16 @@ class TestPathGeom(PathTestBase):
self.assertCommandEqual(cmds(center, radius), cmd('G3', Vector(15, 10, 0), Vector(-5, 0, 0)))
def test42(self):
'''Verify ellipsis results in a proper segmentation of G1 commands.'''
ellipse = Part.Edge(Part.Ellipse())
cmds = PathGeom.cmdsForEdge(ellipse)
# let's make sure all commands are G1 and there are more than 20 of those
self.assertGreater(len(cmds), 20)
self.assertTrue(all([cmd.Name == 'G1' for cmd in cmds]))
def test50(self):
"""Verify proper wire(s) aggregation from a Path."""
'''Verify proper wire(s) aggregation from a Path.'''
commands = []
commands.append(Path.Command('G1', {'X': 1}))
commands.append(Path.Command('G1', {'Y': 1}))
@@ -335,7 +343,7 @@ class TestPathGeom(PathTestBase):
def test60(self):
"""Verify arcToHelix returns proper helix."""
'''Verify arcToHelix returns proper helix.'''
p1 = Vector(10,-10,0)
p2 = Vector(0,0,0)
p3 = Vector(10,10,0)
@@ -368,7 +376,7 @@ class TestPathGeom(PathTestBase):
def test62(self):
"""Verify splitArcAt returns proper subarcs."""
'''Verify splitArcAt returns proper subarcs.'''
p1 = Vector(10,-10,0)
p2 = Vector(0,0,0)
p3 = Vector(10,10,0)
@@ -392,7 +400,7 @@ class TestPathGeom(PathTestBase):
def test65(self):
"""Verify splitEdgeAt."""
'''Verify splitEdgeAt.'''
# split a line segment
e = PathGeom.splitEdgeAt(Part.Edge(Part.LineSegment(Vector(), Vector(2, 4, 6))), Vector(1, 2, 3))
@@ -522,4 +530,16 @@ class TestPathGeom(PathTestBase):
edge = Part.Edge(Part.BSplineCurve([Vector(-8,4,0), Vector(1,-5,0), Vector(5,11,0), Vector(12,-5,0)], weights=[2,3,5,7]))
self.assertEdgeShapesMatch(edge, PathGeom.flipEdge(edge))
def test76(self):
'''Flip an offset wire'''
e0 = Part.Edge(Part.BSplineCurve([Vector(-8,4,0), Vector(1,-5,0), Vector(5,11,0), Vector(12,-5,0)], weights=[2,3,5,7]))
e1 = Part.Edge(Part.LineSegment(Vector(12,-5,0), Vector(0,-7,0)))
e2 = Part.Edge(Part.LineSegment(Vector(0,-7,0), Vector(-8,4,0)))
w0 = Part.Wire([e0, e1, e2])
w1 = w0.makeOffset2D(1)
w2 = PathGeom.flipWire(w1)
# do some sanity checks
self.assertTrue(w2.isValid())
self.assertTrue(w2.isClosed())