Merge branch 'main' into core_LCS3

This commit is contained in:
PaddleStroke
2024-12-13 18:48:35 +01:00
committed by GitHub
20 changed files with 636 additions and 364 deletions

View File

@@ -47,9 +47,11 @@
# include <Inventor/nodes/SoOrthographicCamera.h>
# include <Inventor/nodes/SoPerspectiveCamera.h>
# include <Inventor/nodes/SoSeparator.h>
# include <Inventor/SoPickedPoint.h>
#endif
#include <App/Document.h>
#include <App/GeoFeature.h>
#include <Base/Builder3D.h>
#include <Base/Console.h>
#include <Base/Interpreter.h>
@@ -70,8 +72,10 @@
#include "View3DInventorViewer.h"
#include "View3DPy.h"
#include "ViewProvider.h"
#include "ViewProviderDocumentObject.h"
#include "WaitCursor.h"
#include "Utilities.h"
using namespace Gui;
@@ -773,6 +777,97 @@ void View3DInventor::setCurrentViewMode(ViewMode newmode)
}
}
RayPickInfo View3DInventor::getObjInfoRay(Base::Vector3d* startvec, Base::Vector3d* dirvec)
{
double vsx, vsy, vsz;
double vdx, vdy, vdz;
vsx = startvec->x;
vsy = startvec->y;
vsz = startvec->z;
vdx = dirvec->x;
vdy = dirvec->y;
vdz = dirvec->z;
// near plane clipping is required to avoid false intersections
float near = 0.1;
RayPickInfo ret = {.isValid = false,
.point = Base::Vector3d(),
.document = "",
.object = "",
.parentObject = std::nullopt,
.component = std::nullopt,
.subName = std::nullopt};
SoRayPickAction action(getViewer()->getSoRenderManager()->getViewportRegion());
action.setRay(SbVec3f(vsx, vsy, vsz), SbVec3f(vdx, vdy, vdz), near);
action.apply(getViewer()->getSoRenderManager()->getSceneGraph());
SoPickedPoint* Point = action.getPickedPoint();
if (!Point) {
return ret;
}
ret.point = Base::convertTo<Base::Vector3d>(Point->getPoint());
ViewProvider* vp = getViewer()->getViewProviderByPath(Point->getPath());
if (vp && vp->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) {
if (!vp->isSelectable()) {
return ret;
}
auto vpd = static_cast<ViewProviderDocumentObject*>(vp);
if (vp->useNewSelectionModel()) {
std::string subname;
if (!vp->getElementPicked(Point, subname)) {
return ret;
}
auto obj = vpd->getObject();
if (!obj) {
return ret;
}
if (!subname.empty()) {
App::ElementNamePair elementName;
auto sobj = App::GeoFeature::resolveElement(obj, subname.c_str(), elementName);
if (!sobj) {
return ret;
}
if (sobj != obj) {
ret.parentObject = obj->getExportName();
ret.subName = subname;
obj = sobj;
}
subname = !elementName.oldName.empty() ? elementName.oldName : elementName.newName;
}
ret.document = obj->getDocument()->getName();
ret.object = obj->getNameInDocument();
ret.component = subname;
ret.isValid = true;
}
else {
ret.document = vpd->getObject()->getDocument()->getName();
ret.object = vpd->getObject()->getNameInDocument();
// search for a SoFCSelection node
SoFCDocumentObjectAction objaction;
objaction.apply(Point->getPath());
if (objaction.isHandled()) {
ret.component = objaction.componentName.getString();
}
}
// ok, found the node of interest
ret.isValid = true;
}
else {
// custom nodes not in a VP: search for a SoFCSelection node
SoFCDocumentObjectAction objaction;
objaction.apply(Point->getPath());
if (objaction.isHandled()) {
ret.document = objaction.documentName.getString();
ret.object = objaction.objectName.getString();
ret.component = objaction.componentName.getString();
// ok, found the node of interest
ret.isValid = true;
}
}
return ret;
}
bool View3DInventor::eventFilter(QObject* watched, QEvent* e)
{
// As long as this widget is a top-level window (either in 'TopLevel' or 'FullScreen' mode) we

View File

@@ -31,6 +31,7 @@
#include "MDIView.h"
#include "Base/Vector3D.h"
class QPrinter;
class QStackedWidget;
@@ -43,6 +44,16 @@ class View3DPy;
class View3DSettings;
class NaviCubeSettings;
struct RayPickInfo
{
bool isValid;
Base::Vector3d point;
std::string document;
std::string object;
std::optional<std::string> parentObject;
std::optional<std::string> component;
std::optional<std::string> subName;
};
class GuiExport GLOverlayWidget : public QWidget
{
Q_OBJECT
@@ -98,6 +109,8 @@ public:
* GL widget to get all key events in \a TopLevel or \a Fullscreen mode.
*/
void setCurrentViewMode(ViewMode b) override;
RayPickInfo getObjInfoRay(Base::Vector3d* startvec,
Base::Vector3d* dirvec);
bool setCamera(const char* pCamera);
void toggleClippingPlane();
bool hasClippingPlane() const;

View File

@@ -158,6 +158,14 @@ void View3DInventorPy::init_type()
"\n"
"Does the same as getObjectInfo() but returns a list of dictionaries or None.\n");
add_noargs_method("getSize",&View3DInventorPy::getSize,"getSize()");
add_varargs_method("getObjectInfoRay",&View3DInventorPy::getObjectInfoRay,
"getObjectInfoRay(tuple(3D vector,3D vector) or tuple of 6 floats) -> dictionary or None\n"
"\n"
"Vectors represent start point and direction of intersection ray\n"
"Return a dictionary with the name of document, object and component. The\n"
"dictionary also contains the coordinates of the appropriate 3d point of\n"
"the underlying geometry in the scenegraph.\n"
"If no geometry was found 'None' is returned, instead.\n");
add_varargs_method("getPoint",&View3DInventorPy::getPointOnFocalPlane,
"Same as getPointOnFocalPlane");
add_varargs_method("getPointOnFocalPlane",&View3DInventorPy::getPointOnFocalPlane,
@@ -1501,6 +1509,54 @@ Py::Object View3DInventorPy::getObjectsInfo(const Py::Tuple& args)
}
}
Py::Object View3DInventorPy::getObjectInfoRay(const Py::Tuple& args)
{
PyObject* vs;
PyObject* vd;
double vsx, vsy, vsz;
double vdx, vdy, vdz;
Py::Object ret = Py::None();
if (PyArg_ParseTuple(args.ptr(),
"O!O!",
&Base::VectorPy::Type,
&vs,
&Base::VectorPy::Type,
&vd)) {
Base::Vector3d* startvec = static_cast<Base::VectorPy*>(vs)->getVectorPtr();
Base::Vector3d* dirvec = static_cast<Base::VectorPy*>(vd)->getVectorPtr();
try {
RayPickInfo pinfo = getView3DIventorPtr()->getObjInfoRay(startvec, dirvec);
if (!pinfo.isValid) {
return ret;
}
Py::Dict dict;
dict.setItem("PickedPoint", Py::asObject(new Base::VectorPy(pinfo.point)));
dict.setItem("Document", Py::String(pinfo.document));
dict.setItem("Object", Py::String(pinfo.object));
if (pinfo.parentObject) {
dict.setItem("ParentObject", Py::String(pinfo.parentObject.value()));
}
if (pinfo.component) {
dict.setItem("Component", Py::String(pinfo.component.value()));
}
if (pinfo.subName) {
dict.setItem("SubName", Py::String(pinfo.subName.value()));
}
ret = dict;
}
catch (const Py::Exception&) {
throw;
}
}
else {
PyErr_Clear();
if (!PyArg_ParseTuple(args.ptr(), "dddddd", &vsx, &vsy, &vsz, &vdx, &vdy, &vdz)) {
throw Py::TypeError("Wrong arguments, two Vectors or six floats expected");
}
}
return ret;
}
Py::Object View3DInventorPy::getSize()
{
try {

View File

@@ -95,6 +95,7 @@ public:
Py::Object getObjectInfo(const Py::Tuple&);
Py::Object getObjectsInfo(const Py::Tuple&);
Py::Object getSize();
Py::Object getObjectInfoRay(const Py::Tuple&);
Py::Object getPointOnFocalPlane(const Py::Tuple&);
Py::Object projectPointToLine(const Py::Tuple&);
Py::Object getPointOnViewport(const Py::Tuple&);

View File

@@ -95,27 +95,9 @@ FC_LOG_LEVEL_INIT("Assembly", true, true, true)
using namespace Assembly;
using namespace MbD;
namespace PartApp = Part;
/*
static void printPlacement(Base::Placement plc, const char* name)
{
Base::Vector3d pos = plc.getPosition();
Base::Vector3d axis;
double angle;
Base::Rotation rot = plc.getRotation();
rot.getRawValue(axis, angle);
Base::Console().Warning(
"placement %s : position (%.1f, %.1f, %.1f) - axis (%.1f, %.1f, %.1f) angle %.1f\n",
name,
pos.x,
pos.y,
pos.z,
axis.x,
axis.y,
axis.z,
angle);
}*/
// ================================ Assembly Object ============================
@@ -1617,8 +1599,6 @@ std::string AssemblyObject::handleOneSideOfJoint(App::DocumentObject* joint,
// containing Part.
if (obj->getNameInDocument() != part->getNameInDocument()) {
// Make plc relative to the containing part
// plc = objPlc * plc; // this would not work for nested parts.
auto* ref = dynamic_cast<App::PropertyXLinkSub*>(joint->getPropertyByName(propRefName));
if (!ref) {
@@ -1861,9 +1841,6 @@ AssemblyObject::makeMbdPart(std::string& name, Base::Placement plc, double mass)
Base::Vector3d r1 = mat.getRow(1);
Base::Vector3d r2 = mat.getRow(2);
mbdPart->setRotationMatrix(r0.x, r0.y, r0.z, r1.x, r1.y, r1.z, r2.x, r2.y, r2.z);
/*double q0, q1, q2, q3;
rot.getValue(q0, q1, q2, q3);
mbdPart->setQuarternions(q0, q1, q2, q3);*/
return mbdPart;
}
@@ -1884,9 +1861,7 @@ std::shared_ptr<ASMTMarker> AssemblyObject::makeMbdMarker(std::string& name, Bas
Base::Vector3d r1 = mat.getRow(1);
Base::Vector3d r2 = mat.getRow(2);
mbdMarker->setRotationMatrix(r0.x, r0.y, r0.z, r1.x, r1.y, r1.z, r2.x, r2.y, r2.z);
/*double q0, q1, q2, q3;
rot.getValue(q0, q1, q2, q3);
mbdMarker->setQuarternions(q0, q1, q2, q3);*/
return mbdMarker;
}

View File

@@ -136,8 +136,6 @@ void ViewProviderAssembly::setupContextMenu(QMenu* menu, QObject* receiver, cons
bool ViewProviderAssembly::doubleClicked()
{
if (isInEditMode()) {
// Part is already 'Active' so we exit edit mode.
// Gui::Command::doCommand(Gui::Command::Gui, "Gui.activeDocument().resetEdit()");
getDocument()->resetEdit();
}
else {
@@ -165,7 +163,6 @@ bool ViewProviderAssembly::canDragObject(App::DocumentObject* obj) const
if (!obj || obj->getTypeId() == Assembly::JointGroup::getClassTypeId()) {
return false;
}
return true;
}
@@ -214,7 +211,6 @@ bool ViewProviderAssembly::canDragObjectToTarget(App::DocumentObject* obj,
joint->getNameInDocument());
}
}
return true;
}
@@ -239,7 +235,6 @@ bool ViewProviderAssembly::setEdit(int mode)
return true;
}
return ViewProviderPart::setEdit(mode);
}
@@ -251,7 +246,6 @@ void ViewProviderAssembly::unsetEdit(int mode)
docsToMove.clear();
unsetDragger();
detachSelection();
// Check if the view is still active before trying to deactivate the assembly.
@@ -268,7 +262,6 @@ void ViewProviderAssembly::unsetEdit(int mode)
PARTKEY);
return;
}
ViewProviderPart::unsetEdit(mode);
}
@@ -319,7 +312,6 @@ App::DocumentObject* ViewProviderAssembly::getActivePart() const
if (!activeView) {
return nullptr;
}
return activeView->getActiveObject<App::DocumentObject*>(PARTKEY);
}
@@ -341,7 +333,6 @@ bool ViewProviderAssembly::keyPressed(bool pressed, int key)
if (key == SoKeyboardEvent::LEFT_CONTROL || key == SoKeyboardEvent::RIGHT_CONTROL) {
ctrlPressed = pressed;
}
return false; // handle all other key events
}
@@ -406,14 +397,12 @@ bool ViewProviderAssembly::tryMouseMove(const SbVec2s& cursorPos, Gui::View3DInv
newPos = Base::Vector3d(vec[0], vec[1], vec[2]);
}
for (auto& objToMove : docsToMove) {
App::DocumentObject* obj = objToMove.obj;
auto* propPlacement =
dynamic_cast<App::PropertyPlacement*>(obj->getPropertyByName("Placement"));
if (propPlacement) {
Base::Placement plc = objToMove.plc;
// Base::Console().Warning("newPos %f %f %f\n", newPos.x, newPos.y, newPos.z);
if (dragMode == DragMode::RotationOnPlane) {
Base::Vector3d center = jcsGlobalPlc.getPosition();
@@ -421,7 +410,6 @@ bool ViewProviderAssembly::tryMouseMove(const SbVec2s& cursorPos, Gui::View3DInv
jcsGlobalPlc.getRotation().multVec(Base::Vector3d(0., 0., -1.));
double angle =
(newPosRot - center).GetAngleOriented(initialPositionRot - center, norm);
// Base::Console().Warning("angle %f\n", angle);
Base::Rotation zRotation = Base::Rotation(Base::Vector3d(0., 0., 1.), angle);
Base::Placement rotatedGlovalJcsPlc =
jcsGlobalPlc * Base::Placement(Base::Vector3d(), zRotation);
@@ -449,7 +437,6 @@ bool ViewProviderAssembly::tryMouseMove(const SbVec2s& cursorPos, Gui::View3DInv
boost::ignore_unused(projInitialPositionRot);
double angle =
(newPosRot - center).GetAngleOriented(initialPositionRot - center, norm);
// Base::Console().Warning("angle %f\n", angle);
Base::Rotation zRotation = Base::Rotation(Base::Vector3d(0., 0., 1.), angle);
Base::Placement rotatedGlovalJcsPlc =
newJcsGlobalPlc * Base::Placement(Base::Vector3d(), zRotation);
@@ -464,7 +451,6 @@ bool ViewProviderAssembly::tryMouseMove(const SbVec2s& cursorPos, Gui::View3DInv
Base::Vector3d delta = newPos - prevPosition;
Base::Vector3d pos = propPlacement->getValue().getPosition() + delta;
// Base::Vector3d pos = newPos + (plc.getPosition() - initialPosition);
plc.setPosition(pos);
}
propPlacement->setValue(plc);
@@ -478,7 +464,6 @@ bool ViewProviderAssembly::tryMouseMove(const SbVec2s& cursorPos, Gui::View3DInv
"User parameter:BaseApp/Preferences/Mod/Assembly");
bool solveOnMove = hGrp->GetBool("SolveOnMove", true);
if (solveOnMove && dragMode != DragMode::TranslationNoSolve) {
// assemblyPart->solve(/*enableRedo = */ false, /*updateJCS = */ false);
assemblyPart->doDragStep();
}
else {
@@ -540,7 +525,6 @@ bool ViewProviderAssembly::mouseButtonPressed(int Button,
}
}
}
return false;
}
@@ -583,7 +567,6 @@ bool ViewProviderAssembly::canDragObjectIn3d(App::DocumentObject* obj) const
return true;
}
}
return false;
}
@@ -682,9 +665,6 @@ bool ViewProviderAssembly::getSelectedObjectsWithinAssembly(bool addPreselection
// it is not selected at that point. So we need to get the preselection too.
if (addPreselection && Gui::Selection().hasPreselection()) {
// Base::Console().Warning("Gui::Selection().getPreselection().pSubName %s\n",
// Gui::Selection().getPreselection().pSubName);
App::DocumentObject* selRoot = Gui::Selection().getPreselection().Object.getObject();
std::string sub = Gui::Selection().getPreselection().pSubName;
@@ -1134,7 +1114,6 @@ bool ViewProviderAssembly::canDelete(App::DocumentObject* objBeingDeleted) const
joint->getNameInDocument());
}
}
return res;
}

View File

@@ -245,7 +245,7 @@ class ifc_vp_object:
import Part # lazy loading
self.Object.Shape = Part.Shape()
elif self.Object.ShapeMode == "Coin":
else:
self.Object.ShapeMode = "Shape"
self.Object.Document.recompute()
self.Object.ViewObject.DiffuseColor = self.Object.ViewObject.DiffuseColor

View File

@@ -2420,14 +2420,10 @@ void Area::makeOffset(list<shared_ptr<CArea>>& areas,
#endif
if (offset < 0) {
stepover = -fabs(stepover);
if (count < 0) {
if (!last_stepover) {
last_stepover = offset * 0.5;
}
else {
last_stepover = -fabs(last_stepover);
}
}
else {
last_stepover = 0;

View File

@@ -115,6 +115,43 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="numPassesLabel">
<property name="text">
<string>Number of Passes</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="numPasses">
<property name="minimum">
<number>1</number>
</property>
<property name="toolTip">
<string>The number of passes to do. If more than one, requires a non-zero value for Pass Stepover.</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="stepoverLabel">
<property name="text">
<string>Pass Stepover</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="Gui::InputField" name="stepover">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>If doing multiple passes, the extra offset of each additional pass.</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@@ -77,6 +77,8 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
if obj.Direction != str(self.form.direction.currentData()):
obj.Direction = str(self.form.direction.currentData())
PathGuiUtil.updateInputField(obj, "OffsetExtra", self.form.extraOffset)
obj.NumPasses = self.form.numPasses.value()
PathGuiUtil.updateInputField(obj, "Stepover", self.form.stepover)
if obj.UseComp != self.form.useCompensation.isChecked():
obj.UseComp = self.form.useCompensation.isChecked()
@@ -100,6 +102,10 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
self.form.extraOffset.setText(
FreeCAD.Units.Quantity(obj.OffsetExtra.Value, FreeCAD.Units.Length).UserString
)
self.form.numPasses.setValue(obj.NumPasses)
self.form.stepover.setText(
FreeCAD.Units.Quantity(obj.Stepover.Value, FreeCAD.Units.Length).UserString
)
self.form.useCompensation.setChecked(obj.UseComp)
self.form.useStartPoint.setChecked(obj.UseStartPoint)
@@ -117,6 +123,8 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
signals.append(self.form.cutSide.currentIndexChanged)
signals.append(self.form.direction.currentIndexChanged)
signals.append(self.form.extraOffset.editingFinished)
signals.append(self.form.numPasses.editingFinished)
signals.append(self.form.stepover.editingFinished)
signals.append(self.form.useCompensation.stateChanged)
signals.append(self.form.useStartPoint.stateChanged)
signals.append(self.form.processHoles.stateChanged)
@@ -148,8 +156,11 @@ class TaskPanelOpPage(PathOpGui.TaskPanelPage):
self.form.processHoles.hide()
self.form.processPerimeter.hide()
self.form.stepover.setEnabled(self.obj.NumPasses > 1)
def registerSignalHandlers(self, obj):
self.form.useCompensation.stateChanged.connect(self.updateVisibility)
self.form.numPasses.editingFinished.connect(self.updateVisibility)
# Eclass

View File

@@ -172,6 +172,24 @@ class ObjectProfile(PathAreaOp.ObjectOp):
"App::Property", "Make True, if using Cutter Radius Compensation"
),
),
(
"App::PropertyInteger",
"NumPasses",
"Profile",
QT_TRANSLATE_NOOP(
"App::Property",
"The number of passes to do. If more than one, requires a non-zero value for Stepover",
),
),
(
"App::PropertyDistance",
"Stepover",
"Profile",
QT_TRANSLATE_NOOP(
"App::Property",
"If doing multiple passes, the extra offset of each additional pass",
),
),
]
@classmethod
@@ -235,6 +253,8 @@ class ObjectProfile(PathAreaOp.ObjectOp):
"processCircles": False,
"processHoles": False,
"processPerimeter": True,
"Stepover": 0,
"NumPasses": 1,
}
def areaOpApplyPropertyDefaults(self, obj, job, propList):
@@ -295,6 +315,26 @@ class ObjectProfile(PathAreaOp.ObjectOp):
self.initAreaOpProperties(obj, warn=True)
self.areaOpSetDefaultValues(obj, PathUtils.findParentJob(obj))
self.setOpEditorProperties(obj)
if not hasattr(obj, "NumPasses"):
obj.addProperty(
"App::PropertyInteger",
"NumPasses",
"Profile",
QT_TRANSLATE_NOOP(
"App::Property",
"The number of passes to do. Requires a non-zero value for Stepover",
),
)
if not hasattr(obj, "Stepover"):
obj.addProperty(
"App::PropertyDistance",
"Stepover",
"Profile",
QT_TRANSLATE_NOOP(
"App::Property",
"If doing multiple passes, the extra offset of each additional pass",
),
)
def areaOpOnChanged(self, obj, prop):
"""areaOpOnChanged(obj, prop) ... updates certain property visibilities depending on changed properties."""
@@ -311,13 +351,31 @@ class ObjectProfile(PathAreaOp.ObjectOp):
params["SectionCount"] = -1
offset = obj.OffsetExtra.Value # 0.0
num_passes = max(1, obj.NumPasses)
stepover = obj.Stepover.Value
if num_passes > 1 and stepover == 0:
# This check is important because C++ code has a default value for stepover if it's 0 and extra passes are requested
num_passes = 1
Path.Log.warning(
"Multipass profile requires a non-zero stepover. Reducing to a single pass."
)
if obj.UseComp:
offset = self.radius + obj.OffsetExtra.Value
if obj.Side == "Inside":
offset = 0 - offset
stepover = -stepover
if isHole:
offset = 0 - offset
stepover = -stepover
# Modify offset and stepover to do passes from most-offset to least
offset += stepover * (num_passes - 1)
stepover = -stepover
params["Offset"] = offset
params["ExtraPass"] = num_passes - 1
params["Stepover"] = stepover
jointype = ["Round", "Square", "Miter"]
params["JoinType"] = jointype.index(obj.JoinType)
@@ -356,6 +414,10 @@ class ObjectProfile(PathAreaOp.ObjectOp):
else:
params["orientation"] = 0
if obj.NumPasses > 1:
# Disable path sorting to ensure that offsets appear in order, from farthest offset to closest, on all layers
params["sort_mode"] = 0
return params
def areaOpUseProjection(self, obj):
@@ -590,7 +652,11 @@ class ObjectProfile(PathAreaOp.ObjectOp):
if flattened and zDiff >= self.JOB.GeometryTolerance.Value:
cutWireObjs = False
openEdges = []
passOffsets = [self.ofstRadius]
params = self.areaOpAreaParams(obj, False)
passOffsets = [
self.ofstRadius + i * abs(params["Stepover"])
for i in range(params["ExtraPass"] + 1)
][::-1]
(origWire, flatWire) = flattened
self._addDebugObject("FlatWire", flatWire)

View File

@@ -141,8 +141,13 @@ TopoShape FeatureExtrude::makeShellFromUpToShape(TopoShape shape, TopoShape sket
dir = -dir;
cfaces = Part::findAllFacesCutBy(shape, sketchshape, dir);
}
struct Part::cutTopoShapeFaces *nearFace;
struct Part::cutTopoShapeFaces *farFace;
if (cfaces.empty()) {
return shape;
}
struct Part::cutTopoShapeFaces *nearFace {};
struct Part::cutTopoShapeFaces *farFace {};
nearFace = farFace = &cfaces.front();
for (auto &face : cfaces) {
if (face.distsq > farFace->distsq) {

View File

@@ -1141,7 +1141,7 @@ double BSpline::splineValue(double x, size_t k, unsigned int p, VEC_D& d, const
}
}
return d[p];
return p < d.size() ? d[p] : 0.0;
}
void BSpline::setupFlattenedKnots()

View File

@@ -554,6 +554,7 @@ public:
static_cast<int>(lastEndPosId),
firstCurve,
static_cast<int>(firstPosId));
firstsegment = true;
}
Gui::Command::commitCommand();

View File

@@ -37,6 +37,7 @@
#include "DrawTemplatePy.h"
#include "DrawPage.h"
#include "DrawUtil.h"
#include "Preferences.h"
using namespace TechDraw;
@@ -129,6 +130,7 @@ std::pair<int, int> DrawTemplate::getPageNumbers() const
//! get replacement values from document
QString DrawTemplate::getAutofillValue(const QString &id) const
{
constexpr int ISODATELENGTH {10};
auto doc = getDocument();
if (!doc) {
return QString();
@@ -142,8 +144,14 @@ QString DrawTemplate::getAutofillValue(const QString &id) const
}
// date
else if (id.compare(QString::fromUtf8(Autofill::Date)) == 0) {
auto timeLocale = std::setlocale(LC_TIME, nullptr);
QDateTime date = QDateTime::currentDateTime();
return date.toString(QLocale().dateFormat(QLocale::ShortFormat));
if (Preferences::enforceISODate()) {
auto rawDate = date.toString(Qt::ISODate);
return rawDate.left(ISODATELENGTH);
}
auto qTimeLocale = QString::fromUtf8(timeLocale);
return date.toString(QLocale(qTimeLocale).dateFormat(QLocale::ShortFormat));
}
// organization ( also organisation/owner/company )
else if (id.compare(QString::fromUtf8(Autofill::Organization)) == 0 ||

View File

@@ -650,6 +650,11 @@ void Preferences::setBalloonDragModifiers(Qt::KeyboardModifiers newModifiers)
getPreferenceGroup("General")->SetUnsigned("BalloonDragModifier", (uint)newModifiers);
}
bool Preferences::enforceISODate()
{
return getPreferenceGroup("Standards")->GetBool("EnforceISODate", false);
}
//! if true, shapes are validated before use and problematic ones are skipped.
//! validating shape takes time, but can prevent crashes/bad results in occt.
//! this would normally be set to false and set to true to aid in debugging/support.

View File

@@ -151,6 +151,7 @@ public:
static Qt::KeyboardModifiers balloonDragModifiers();
static void setBalloonDragModifiers(Qt::KeyboardModifiers newModifiers);
static bool enforceISODate();
static bool switchOnClick();
static bool checkShapesBeforeUse();

View File

@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>580</width>
<height>795</height>
<width>835</width>
<height>956</height>
</rect>
</property>
<property name="sizePolicy">
@@ -28,231 +28,6 @@
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0">
<layout class="QGridLayout" name="gridLayout_2" columnstretch="2,0,1">
<item row="9" column="2">
<widget class="Gui::PrefUnitSpinBox" name="pdsbBalloonKink">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Length of balloon leader line kink</string>
</property>
<property name="value">
<double>5.000000000000000</double>
</property>
<property name="prefEntry" stdset="0">
<cstring>BalloonKink</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/TechDraw/Dimensions</cstring>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="Gui::PrefCheckBox" name="pcbDetailHighlight">
<property name="toolTip">
<string>This checkbox controls whether or not to display a highlight around the detail area in the detail's source view.</string>
</property>
<property name="text">
<string>Detail Source Show Highlight</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>ShowDetailHighlight</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>/Mod/TechDraw/General</cstring>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_19">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string>Section Cut Surface</string>
</property>
</widget>
</item>
<item row="8" column="2">
<widget class="Gui::PrefComboBox" name="pcbBalloonArrow">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Style for balloon leader line ends</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>BalloonArrow</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/TechDraw/Decorations</cstring>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_3">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string>Balloon Leader End</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="Gui::PrefCheckBox" name="cb_IncludeCutLine">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="toolTip">
<string>If checked, the cut line will be drawn on the Source view. If unchecked, only the change marks, arrows and symbols will be displayed.</string>
</property>
<property name="text">
<string>Include Cut Line in Section Annotation</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>IncludeCutLine</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/TechDraw/Decorations</cstring>
</property>
</widget>
</item>
<item row="4" column="1">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="0">
<widget class="Gui::PrefCheckBox" name="cbComplexMarks">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="toolTip">
<string>Show or hide marks at direction changes on ComplexSection lines.</string>
</property>
<property name="text">
<string>Complex Section Line Marks</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>SectionLineMarks</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/TechDraw/Decorations</cstring>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="Gui::PrefCheckBox" name="pcbDetailMatting">
<property name="toolTip">
<string>This checkbox controls whether or not to display the outline around a detail view.</string>
</property>
<property name="text">
<string>Detail View Show Matting</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>ShowDetailMatting</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>/Mod/TechDraw/General</cstring>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="Gui::PrefCheckBox" name="cb_ShowSectionLine">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="toolTip">
<string>If checked, the section annotation will be drawn on the Source view. If unchecked, no section line, arrows or symbol will be shown in the Source view.</string>
</property>
<property name="text">
<string>Show Section Line in Source View</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>ShowSectionLine</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/TechDraw/Decorations</cstring>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label">
<property name="font">
<font>
<italic>false</italic>
</font>
</property>
<property name="text">
<string>Detail View Outline Shape</string>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="Gui::PrefCheckBox" name="cbPyramidOrtho">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Restrict Filled Triangle line end to vertical or horizontal directions</string>
</property>
<property name="text">
<string>Balloon Orthogonal Triangle</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>PyramidOrtho</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/TechDraw/Decorations</cstring>
</property>
</widget>
</item>
<item row="12" column="2">
<widget class="Gui::PrefCheckBox" name="cbPrintCenterMarks">
<property name="sizePolicy">
@@ -275,36 +50,6 @@
</property>
</widget>
</item>
<item row="10" column="2">
<widget class="Gui::PrefCheckBox" name="cbAutoHoriz">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="toolTip">
<string>Forces last leader line segment to be horizontal</string>
</property>
<property name="text">
<string>Leader Line Auto Horizontal</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>AutoHorizontal</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/TechDraw/LeaderLine</cstring>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="Gui::PrefCheckBox" name="cbShowCenterMarks">
<property name="sizePolicy">
@@ -335,15 +80,141 @@
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_5">
<item row="1" column="0">
<widget class="Gui::PrefCheckBox" name="cb_ShowSectionLine">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="toolTip">
<string>If checked, the section annotation will be drawn on the Source view. If unchecked, no section line, arrows or symbol will be shown in the Source view.</string>
</property>
<property name="text">
<string>Show Section Line in Source View</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>ShowSectionLine</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/TechDraw/Decorations</cstring>
</property>
</widget>
</item>
<item row="7" column="2">
<widget class="Gui::PrefComboBox" name="pcbBalloonShape">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Shape of balloon annotations</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>BalloonShape</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/TechDraw/Decorations</cstring>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="Gui::PrefCheckBox" name="cb_IncludeCutLine">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="toolTip">
<string>If checked, the cut line will be drawn on the Source view. If unchecked, only the change marks, arrows and symbols will be displayed.</string>
</property>
<property name="text">
<string>Include Cut Line in Section Annotation</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>IncludeCutLine</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/TechDraw/Decorations</cstring>
</property>
</widget>
</item>
<item row="8" column="2">
<widget class="Gui::PrefComboBox" name="pcbBalloonArrow">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Style for balloon leader line ends</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>BalloonArrow</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/TechDraw/Decorations</cstring>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_18">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="toolTip">
<string>Length of horizontal portion of Balloon leader</string>
</property>
<property name="text">
<string>Balloon Leader Kink Length</string>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_11">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string>Balloon Shape</string>
<string>Broken View Break Type</string>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="Gui::PrefCheckBox" name="cbPyramidOrtho">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Restrict Filled Triangle line end to vertical or horizontal directions</string>
</property>
<property name="text">
<string>Balloon Orthogonal Triangle</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>PyramidOrtho</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/TechDraw/Decorations</cstring>
</property>
</widget>
</item>
@@ -383,68 +254,108 @@
</item>
</widget>
</item>
<item row="4" column="2">
<widget class="Gui::PrefComboBox" name="pcbMatting">
<item row="5" column="0">
<widget class="Gui::PrefCheckBox" name="pcbDetailMatting">
<property name="toolTip">
<string>This checkbox controls whether or not to display the outline around a detail view.</string>
</property>
<property name="text">
<string>Detail View Show Matting</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>ShowDetailMatting</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>/Mod/TechDraw/General</cstring>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="Gui::PrefCheckBox" name="pcbDetailHighlight">
<property name="toolTip">
<string>This checkbox controls whether or not to display a highlight around the detail area in the detail's source view.</string>
</property>
<property name="text">
<string>Detail Source Show Highlight</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>ShowDetailHighlight</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>/Mod/TechDraw/General</cstring>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label">
<property name="font">
<font>
<italic>false</italic>
</font>
</property>
<property name="text">
<string>Detail View Outline Shape</string>
</property>
</widget>
</item>
<item row="10" column="2">
<widget class="Gui::PrefCheckBox" name="cbAutoHoriz">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Outline shape for detail views</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>MattingStyle</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>/Mod/TechDraw/Decorations</cstring>
</property>
</widget>
</item>
<item row="7" column="2">
<widget class="Gui::PrefComboBox" name="pcbBalloonShape">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Shape of balloon annotations</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>BalloonShape</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/TechDraw/Decorations</cstring>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_18">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="toolTip">
<string>Length of horizontal portion of Balloon leader</string>
<string>Forces last leader line segment to be horizontal</string>
</property>
<property name="text">
<string>Balloon Leader Kink Length</string>
<string>Leader Line Auto Horizontal</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>AutoHorizontal</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/TechDraw/LeaderLine</cstring>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_11">
<item row="4" column="1">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_3">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string>Broken View Break Type</string>
<string>Balloon Leader End</string>
</property>
</widget>
</item>
@@ -476,6 +387,111 @@
</item>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_5">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string>Balloon Shape</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_19">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string>Section Cut Surface</string>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="Gui::PrefComboBox" name="pcbMatting">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Outline shape for detail views</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>MattingStyle</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>/Mod/TechDraw/Decorations</cstring>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="Gui::PrefCheckBox" name="cbComplexMarks">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="toolTip">
<string>Show or hide marks at direction changes on ComplexSection lines.</string>
</property>
<property name="text">
<string>Complex Section Line Marks</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>SectionLineMarks</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/TechDraw/Decorations</cstring>
</property>
</widget>
</item>
<item row="9" column="2">
<widget class="Gui::PrefUnitSpinBox" name="pdsbBalloonKink" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Length of balloon leader line kink</string>
</property>
<property name="value" stdset="0">
<double>5.000000000000000</double>
</property>
<property name="prefEntry" stdset="0">
<cstring>BalloonKink</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/TechDraw/Dimensions</cstring>
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="Gui::PrefCheckBox" name="cbISODates">
<property name="toolTip">
<string>If this box is checked, templates will auto fill date fields using ccyy-mm-dd format even if that is not the standard format for the current locale.</string>
</property>
<property name="text">
<string>Enforce ISO 8601 Date Format</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>EnforceISODate</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/TechDraw/Standards</cstring>
</property>
</widget>
</item>
</layout>
</item>
</layout>
@@ -507,7 +523,7 @@
<number>6</number>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
<enum>QComboBox::SizeAdjustPolicy::AdjustToContents</enum>
</property>
<property name="iconSize">
<size>
@@ -775,7 +791,7 @@ if you are planning to use a drawing as a 1:1 cutting guide.
<item row="0" column="1">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@@ -837,7 +853,7 @@ if you are planning to use a drawing as a 1:1 cutting guide.
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@@ -871,8 +887,6 @@ if you are planning to use a drawing as a 1:1 cutting guide.
<header>Gui/PrefWidgets.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="Resources/TechDraw.qrc"/>
</resources>
<resources/>
<connections/>
</ui>

View File

@@ -127,6 +127,7 @@ void DlgPrefsTechDrawAnnotationImp::saveSettings()
ui->pcbBreakType->onSave();
ui->pcbBreakStyle->onSave();
ui->cbISODates->onSave();
}
void DlgPrefsTechDrawAnnotationImp::loadSettings()
@@ -186,6 +187,7 @@ void DlgPrefsTechDrawAnnotationImp::loadSettings()
loadLineStyleBoxes();
ui->pcbBreakType->onRestore();
ui->cbISODates->onRestore();
}
/**

View File

@@ -77,14 +77,21 @@ void TemplateTextField::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
ui.setFieldName(fieldNameStr);
ui.setFieldContent(tmplte->EditableTexts[fieldNameStr]);
auto qName = QString::fromStdString(fieldNameStr);
auto svgTemplate = dynamic_cast<DrawSVGTemplate*>(tmplte);
if (svgTemplate) {
// preset the autofill with the current value - something might have changed since this field was created
m_autofillString = svgTemplate->getAutofillByEditableName(qName);
}
ui.setAutofillContent(m_autofillString.toStdString());
if (ui.exec() == QDialog::Accepted) {
QString qsClean = ui.getFieldContent();
std::string utf8Content = qsClean.toUtf8().constData();
if (ui.getAutofillState()) {
auto svgTemplate = dynamic_cast<DrawSVGTemplate*>(tmplte);
if (svgTemplate) {
// unlikely, but something could have changed since we grabbed the autofill value
QString fieldName = QString::fromStdString(fieldNameStr);
QString autofillValue = svgTemplate->getAutofillByEditableName(fieldName);
if (!autofillValue.isEmpty()) {