FreeCAD

Форк
0
/
DlgPrimitives.cpp 
2255 строк · 85.8 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2007 Werner Mayer <wmayer[at]users.sourceforge.net>     *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
6
 *   This library is free software; you can redistribute it and/or         *
7
 *   modify it under the terms of the GNU Library General Public           *
8
 *   License as published by the Free Software Foundation; either          *
9
 *   version 2 of the License, or (at your option) any later version.      *
10
 *                                                                         *
11
 *   This library  is distributed in the hope that it will be useful,      *
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14
 *   GNU Library General Public License for more details.                  *
15
 *                                                                         *
16
 *   You should have received a copy of the GNU Library General Public     *
17
 *   License along with this library; see the file COPYING.LIB. If not,    *
18
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
19
 *   Suite 330, Boston, MA  02111-1307, USA                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23
#include "PreCompiled.h"
24
#ifndef _PreComp_
25
#include <GC_MakeArcOfCircle.hxx>
26
#include <Geom_Circle.hxx>
27
#include <Geom_TrimmedCurve.hxx>
28
#include <gp_Ax3.hxx>
29
#include <gp_Dir.hxx>
30
#include <gp_Pnt.hxx>
31
#include <QMessageBox>
32
#include <QSignalMapper>
33
#include <Inventor/SoPickedPoint.h>
34
#include <Inventor/events/SoMouseButtonEvent.h>
35
#endif
36

37
#include <App/Application.h>
38
#include <App/Part.h>
39
#include <App/Document.h>
40
#include <Base/Rotation.h>
41
#include <Base/Tools.h>
42
#include <Base/UnitsApi.h>
43
#include <Gui/Application.h>
44
#include <Gui/Document.h>
45
#include <Gui/Command.h>
46
#include <Gui/View3DInventor.h>
47
#include <Gui/View3DInventorViewer.h>
48
#include <Gui/SoFCUnifiedSelection.h>
49
#include <Gui/TaskView/TaskView.h>
50
#include <Mod/Part/App/PrimitiveFeature.h>
51
#include <Mod/Part/App/FeaturePartBox.h>
52
#include <Mod/Part/App/FeaturePartCircle.h>
53
#include <Mod/Part/App/Tools.h>
54

55
#include "DlgPrimitives.h"
56
#include "ui_DlgPrimitives.h"
57
#include "ui_Location.h"
58

59

60
using namespace PartGui;
61

62
namespace PartGui {
63

64
    QString getAutoGroupCommandStr(QString objectName)
65
        // Helper function to get the python code to add the newly created object to the active Part object if present
66
    {
67
        App::Part* activePart = Gui::Application::Instance->activeView()->getActiveObject<App::Part*>("part");
68
        if (activePart) {
69
            QString activeObjectName = QString::fromLatin1(activePart->getNameInDocument());
70
            return QString::fromLatin1("App.ActiveDocument.getObject('%1\')."
71
                "addObject(App.ActiveDocument.getObject('%2\'))\n")
72
                .arg(activeObjectName, objectName);
73
        }
74
        return QString::fromLatin1("# Object %1 created at document root").arg(objectName);
75
    }
76

77
const char* gce_ErrorStatusText(gce_ErrorType et)
78
{
79
    switch (et)
80
    {
81
    case gce_Done:
82
        return "Construction was successful";
83
    case gce_ConfusedPoints:
84
        return "Two points are coincident";
85
    case gce_NegativeRadius:
86
        return "Radius value is negative";
87
    case gce_ColinearPoints:
88
        return "Three points are collinear";
89
    case gce_IntersectionError:
90
        return "Intersection cannot be computed";
91
    case gce_NullAxis:
92
        return "Axis is undefined";
93
    case gce_NullAngle:
94
        return "Angle value is invalid (usually null)";
95
    case gce_NullRadius:
96
        return "Radius is null";
97
    case gce_InvertAxis:
98
        return "Axis value is invalid";
99
    case gce_BadAngle:
100
        return "Angle value is invalid";
101
    case gce_InvertRadius:
102
        return "Radius value is incorrect (usually with respect to another radius)";
103
    case gce_NullFocusLength:
104
        return "Focal distance is null";
105
    case gce_NullVector:
106
        return "Vector is null";
107
    case gce_BadEquation:
108
        return "Coefficients are incorrect (applies to the equation of a geometric object)";
109
    default:
110
        return "Creation of geometry failed";
111
    }
112
}
113

114
void Picker::createPrimitive(QWidget* widget, const QString& descr, Gui::Document* doc)
115
{
116
    try {
117
        App::Document* app = doc->getDocument();
118
        QString cmd = this->command(app);
119

120
        // Execute the Python block
121
        doc->openCommand(descr.toUtf8());
122
        Gui::Command::runCommand(Gui::Command::Doc, cmd.toLatin1());
123
        doc->commitCommand();
124
        Gui::Command::runCommand(Gui::Command::Doc, "App.ActiveDocument.recompute()");
125
        Gui::Command::runCommand(Gui::Command::Gui, "Gui.SendMsgToActiveView(\"ViewFit\")");
126
    }
127
    catch (const Base::Exception& e) {
128
        QMessageBox::warning(widget, descr, QCoreApplication::translate("Exception", e.what()));
129
    }
130
}
131

132
QString Picker::toPlacement(const gp_Ax2& axis) const
133
{
134
    gp_Dir dir = axis.Direction();
135
    gp_Pnt pnt = gp_Pnt(0.0,0.0,0.0);
136
    gp_Ax3 ax3(pnt, dir, axis.XDirection());
137

138
    gp_Trsf Trf;
139
    Trf.SetTransformation(ax3);
140
    Trf.Invert();
141

142
    gp_XYZ theAxis(0,0,1);
143
    Standard_Real theAngle = 0.0;
144
    Trf.GetRotation(theAxis,theAngle);
145

146
    Base::Rotation rot(Base::convertTo<Base::Vector3d>(theAxis), theAngle);
147
    gp_Pnt loc = axis.Location();
148

149
    return QString::fromLatin1("Base.Placement(Base.Vector(%1,%2,%3),Base.Rotation(%4,%5,%6,%7))")
150
        .arg(loc.X(),0,'g',Base::UnitsApi::getDecimals())
151
        .arg(loc.Y(),0,'g',Base::UnitsApi::getDecimals())
152
        .arg(loc.Z(),0,'g',Base::UnitsApi::getDecimals())
153
        .arg(rot[0],0,'g',Base::UnitsApi::getDecimals())
154
        .arg(rot[1],0,'g',Base::UnitsApi::getDecimals())
155
        .arg(rot[2],0,'g',Base::UnitsApi::getDecimals())
156
        .arg(rot[3],0,'g',Base::UnitsApi::getDecimals());
157
}
158

159
class CircleFromThreePoints : public Picker
160
{
161
public:
162
    CircleFromThreePoints() : Picker()
163
    {
164
    }
165
    bool pickedPoint(const SoPickedPoint * point) override
166
    {
167
        SbVec3f pnt = point->getPoint();
168
        points.emplace_back(pnt[0],pnt[1],pnt[2]);
169
        return points.size() == 3;
170
    }
171
    QString command(App::Document* doc) const override
172
    {
173
        GC_MakeArcOfCircle arc(points[0], points[1], points[2]);
174
        if (!arc.IsDone())
175
            throw Base::CADKernelError(gce_ErrorStatusText(arc.Status()));
176
        Handle(Geom_TrimmedCurve) trim = arc.Value();
177
        Handle(Geom_Circle) circle = Handle(Geom_Circle)::DownCast(trim->BasisCurve());
178

179
        QString name = QString::fromLatin1(doc->getUniqueObjectName("Circle").c_str());
180
        return QString::fromLatin1(
181
            "App.ActiveDocument.addObject(\"Part::Circle\",\"%1\")\n"
182
            "App.ActiveDocument.%1.Radius=%2\n"
183
            "App.ActiveDocument.%1.Angle1=%3\n"
184
            "App.ActiveDocument.%1.Angle2=%4\n"
185
            "App.ActiveDocument.%1.Placement=%5\n")
186
            .arg(name)
187
            .arg(circle->Radius(),0,'g',Base::UnitsApi::getDecimals())
188
            .arg(Base::toDegrees(trim->FirstParameter()),0,'g',Base::UnitsApi::getDecimals())
189
            .arg(Base::toDegrees(trim->LastParameter ()),0,'g',Base::UnitsApi::getDecimals())
190
            .arg(toPlacement(circle->Position()));
191
    }
192

193
private:
194
    std::vector<gp_Pnt> points;
195
};
196

197
}
198

199
// ----------------------------------------------------------------------------
200

201
AbstractPrimitive::AbstractPrimitive(Part::Primitive* feature)
202
    : featurePtr(feature)
203
{
204
}
205

206
bool AbstractPrimitive::hasValidPrimitive() const
207
{
208
    return (!featurePtr.expired());
209
}
210

211
void AbstractPrimitive::connectSignalMapper(QSignalMapper* mapper)
212
{
213
#if QT_VERSION < QT_VERSION_CHECK(5,15,0)
214
        connect(mapper, qOverload<QObject*>(&QSignalMapper::mapped), this, &AbstractPrimitive::changeValue);
215
#else
216
        connect(mapper, &QSignalMapper::mappedObject, this, &AbstractPrimitive::changeValue);
217
#endif
218
}
219

220
namespace PartGui {
221

222
void mapSignalMapper(QObject *sender, QSignalMapper* mapper)
223
{
224
    mapper->setMapping(sender, sender);
225
}
226

227
template <typename Function>
228
void connectMapSignalMapper(typename QtPrivate::FunctionPointer<Function>::Object *sender, Function func, QSignalMapper* mapper)
229
{
230
    QObject::connect(sender, func, mapper, qOverload<>(&QSignalMapper::map));
231
    mapSignalMapper(sender, mapper);
232
}
233
}
234

235
// ----------------------------------------------------------------------------
236

237
PlanePrimitive::PlanePrimitive(std::shared_ptr<Ui_DlgPrimitives> ui, Part::Plane* feature)
238
    : AbstractPrimitive(feature)
239
    , ui(ui)
240
{
241
    ui->planeLength->setRange(0, INT_MAX);
242
    ui->planeWidth->setRange(0, INT_MAX);
243

244
    if (feature) {
245
        ui->planeLength->setValue(feature->Length.getQuantityValue());
246
        ui->planeLength->bind(feature->Length);
247
        ui->planeWidth->setValue(feature->Width.getQuantityValue());
248
        ui->planeWidth->bind(feature->Width);
249

250
        QSignalMapper* mapper = new QSignalMapper(this);
251
        connectSignalMapper(mapper);
252
        connectMapSignalMapper(ui->planeLength, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
253
        connectMapSignalMapper(ui->planeWidth, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
254
    }
255
}
256

257
const char* PlanePrimitive::getDefaultName() const
258
{
259
    return "Plane";
260
}
261

262
QString PlanePrimitive::create(const QString& objectName, const QString& placement) const
263
{
264
    return QString::fromLatin1(
265
        "App.ActiveDocument.addObject(\"Part::Plane\",\"%1\")\n"
266
        "App.ActiveDocument.%1.Length='%2'\n"
267
        "App.ActiveDocument.%1.Width='%3'\n"
268
        "App.ActiveDocument.%1.Placement=%4\n"
269
        "App.ActiveDocument.%1.Label='%5'\n")
270
        .arg(objectName,
271
             ui->planeLength->value().getSafeUserString(),
272
             ui->planeWidth->value().getSafeUserString(),
273
             placement,
274
             DlgPrimitives::tr("Plane"));
275
}
276

277
QString PlanePrimitive::change(const QString& objectName, const QString& placement) const
278
{
279
    return QString::fromLatin1(
280
        "%1.Length='%2'\n"
281
        "%1.Width='%3'\n"
282
        "%1.Placement=%4\n")
283
        .arg(objectName,
284
             ui->planeLength->value().getSafeUserString(),
285
             ui->planeWidth->value().getSafeUserString(),
286
             placement);
287
}
288

289
void PlanePrimitive::changeValue(QObject* widget)
290
{
291
    if (featurePtr.expired())
292
        return;
293
    Part::Plane* plane = featurePtr.get<Part::Plane>();
294
    if (widget == ui->planeLength) {
295
        plane->Length.setValue(ui->planeLength->value().getValue());
296
    }
297
    else if (widget == ui->planeWidth) {
298
        plane->Width.setValue(ui->planeWidth->value().getValue());
299
    }
300

301
    plane->recomputeFeature();
302
}
303

304
// ----------------------------------------------------------------------------
305

306
BoxPrimitive::BoxPrimitive(std::shared_ptr<Ui_DlgPrimitives> ui, Part::Box* feature)
307
    : AbstractPrimitive(feature)
308
    , ui(ui)
309
{
310
    ui->boxLength->setRange(0, INT_MAX);
311
    ui->boxWidth->setRange(0, INT_MAX);
312
    ui->boxHeight->setRange(0, INT_MAX);
313

314
    if (feature) {
315
        ui->boxLength->setValue(feature->Length.getQuantityValue());
316
        ui->boxLength->bind(feature->Length);
317
        ui->boxWidth->setValue(feature->Width.getQuantityValue());
318
        ui->boxWidth->bind(feature->Width);
319
        ui->boxHeight->setValue(feature->Height.getQuantityValue());
320
        ui->boxHeight->bind(feature->Height);
321

322
        QSignalMapper* mapper = new QSignalMapper(this);
323
        connectSignalMapper(mapper);
324
        connectMapSignalMapper(ui->boxLength, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
325
        connectMapSignalMapper(ui->boxWidth, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
326
        connectMapSignalMapper(ui->boxHeight, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
327
    }
328
}
329

330
const char* BoxPrimitive::getDefaultName() const
331
{
332
    return "Box";
333
}
334

335
QString BoxPrimitive::create(const QString& objectName, const QString& placement) const
336
{
337
    return QString::fromLatin1(
338
        "App.ActiveDocument.addObject(\"Part::Box\",\"%1\")\n"
339
        "App.ActiveDocument.%1.Length='%2'\n"
340
        "App.ActiveDocument.%1.Width='%3'\n"
341
        "App.ActiveDocument.%1.Height='%4'\n"
342
        "App.ActiveDocument.%1.Placement=%5\n"
343
        "App.ActiveDocument.%1.Label='%6'\n")
344
        .arg(objectName,
345
             ui->boxLength->value().getSafeUserString(),
346
             ui->boxWidth->value().getSafeUserString(),
347
             ui->boxHeight->value().getSafeUserString(),
348
             placement,
349
             DlgPrimitives::tr("Box"));
350
}
351

352
QString BoxPrimitive::change(const QString& objectName, const QString& placement) const
353
{
354
    return QString::fromLatin1(
355
        "%1.Length='%2'\n"
356
        "%1.Width='%3'\n"
357
        "%1.Height='%4'\n"
358
        "%1.Placement=%5\n")
359
        .arg(objectName,
360
             ui->boxLength->value().getSafeUserString(),
361
             ui->boxWidth->value().getSafeUserString(),
362
             ui->boxHeight->value().getSafeUserString(),
363
             placement);
364
}
365

366
void BoxPrimitive::changeValue(QObject* widget)
367
{
368
    if (featurePtr.expired())
369
        return;
370
    Part::Box* box = featurePtr.get<Part::Box>();
371
    if (widget == ui->boxLength) {
372
        box->Length.setValue(ui->boxLength->value().getValue());
373
    }
374
    else if (widget == ui->boxWidth) {
375
        box->Width.setValue(ui->boxWidth->value().getValue());
376
    }
377
    else if (widget == ui->boxHeight) {
378
        box->Height.setValue(ui->boxHeight->value().getValue());
379
    }
380

381
    box->recomputeFeature();
382
}
383

384
// ----------------------------------------------------------------------------
385

386
CylinderPrimitive::CylinderPrimitive(std::shared_ptr<Ui_DlgPrimitives> ui, Part::Cylinder* feature)
387
    : AbstractPrimitive(feature)
388
    , ui(ui)
389
{
390
    ui->cylinderRadius->setRange(0, INT_MAX);
391
    ui->cylinderHeight->setRange(0, INT_MAX);
392
    ui->cylinderAngle->setRange(0, 360);
393

394
    if (feature) {
395
        ui->cylinderRadius->setValue(feature->Radius.getQuantityValue());
396
        ui->cylinderRadius->bind(feature->Radius);
397
        ui->cylinderHeight->setValue(feature->Height.getQuantityValue());
398
        ui->cylinderHeight->bind(feature->Height);
399
        ui->cylinderXSkew->setValue(feature->FirstAngle.getQuantityValue());
400
        ui->cylinderXSkew->bind(feature->FirstAngle);
401
        ui->cylinderYSkew->setValue(feature->SecondAngle.getQuantityValue());
402
        ui->cylinderYSkew->bind(feature->SecondAngle);
403
        ui->cylinderAngle->setValue(feature->Angle.getQuantityValue());
404
        ui->cylinderAngle->bind(feature->Angle);
405

406
        QSignalMapper* mapper = new QSignalMapper(this);
407
        connectSignalMapper(mapper);
408
        connectMapSignalMapper(ui->cylinderRadius, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
409
        connectMapSignalMapper(ui->cylinderHeight, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
410
        connectMapSignalMapper(ui->cylinderXSkew, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
411
        connectMapSignalMapper(ui->cylinderYSkew, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
412
        connectMapSignalMapper(ui->cylinderAngle, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
413
    }
414
}
415

416
const char* CylinderPrimitive::getDefaultName() const
417
{
418
    return "Cylinder";
419
}
420

421
QString CylinderPrimitive::create(const QString& objectName, const QString& placement) const
422
{
423
    return QString::fromLatin1(
424
        "App.ActiveDocument.addObject(\"Part::Cylinder\",\"%1\")\n"
425
        "App.ActiveDocument.%1.Radius='%2'\n"
426
        "App.ActiveDocument.%1.Height='%3'\n"
427
        "App.ActiveDocument.%1.Angle='%4'\n"
428
        "App.ActiveDocument.%1.FirstAngle='%5'\n"
429
        "App.ActiveDocument.%1.SecondAngle='%6'\n"
430
        "App.ActiveDocument.%1.Placement=%7\n"
431
        "App.ActiveDocument.%1.Label='%8'\n")
432
        .arg(objectName,
433
             ui->cylinderRadius->value().getSafeUserString(),
434
             ui->cylinderHeight->value().getSafeUserString(),
435
             ui->cylinderAngle->value().getSafeUserString(),
436
             ui->cylinderXSkew->value().getSafeUserString(),
437
             ui->cylinderYSkew->value().getSafeUserString(),
438
             placement,
439
             DlgPrimitives::tr("Cylinder"));
440
}
441

442
QString CylinderPrimitive::change(const QString& objectName, const QString& placement) const
443
{
444
    return QString::fromLatin1(
445
        "%1.Radius='%2'\n"
446
        "%1.Height='%3'\n"
447
        "%1.Angle='%4'\n"
448
        "%1.FirstAngle='%5'\n"
449
        "%1.SecondAngle='%6'\n"
450
        "%1.Placement=%7\n")
451
        .arg(objectName,
452
             ui->cylinderRadius->value().getSafeUserString(),
453
             ui->cylinderHeight->value().getSafeUserString(),
454
             ui->cylinderAngle->value().getSafeUserString(),
455
             ui->cylinderXSkew->value().getSafeUserString(),
456
             ui->cylinderYSkew->value().getSafeUserString(),
457
             placement);
458
}
459

460
void CylinderPrimitive::changeValue(QObject* widget)
461
{
462
    if (featurePtr.expired())
463
        return;
464
    Part::Cylinder* cyl = featurePtr.get<Part::Cylinder>();
465
    if (widget == ui->cylinderRadius) {
466
        cyl->Radius.setValue(ui->cylinderRadius->value().getValue());
467
    }
468
    else if (widget == ui->cylinderHeight) {
469
        cyl->Height.setValue(ui->cylinderHeight->value().getValue());
470
    }
471
    else if (widget == ui->cylinderAngle) {
472
        cyl->Angle.setValue(ui->cylinderAngle->value().getValue());
473
    }
474
    else if (widget == ui->cylinderXSkew) {
475
        cyl->FirstAngle.setValue(ui->cylinderXSkew->value().getValue());
476
    }
477
    else if (widget == ui->cylinderYSkew) {
478
        cyl->SecondAngle.setValue(ui->cylinderYSkew->value().getValue());
479
    }
480

481
    cyl->recomputeFeature();
482
}
483

484
// ----------------------------------------------------------------------------
485

486
ConePrimitive::ConePrimitive(std::shared_ptr<Ui_DlgPrimitives> ui, Part::Cone* feature)
487
    : AbstractPrimitive(feature)
488
    , ui(ui)
489
{
490
    ui->coneRadius1->setRange(0, INT_MAX);
491
    ui->coneRadius2->setRange(0, INT_MAX);
492
    ui->coneHeight->setRange(0, INT_MAX);
493
    ui->coneAngle->setRange(0, 360);
494

495
    if (feature) {
496
        ui->coneRadius1->setValue(feature->Radius1.getQuantityValue());
497
        ui->coneRadius1->bind(feature->Radius1);
498
        ui->coneRadius2->setValue(feature->Radius2.getQuantityValue());
499
        ui->coneRadius2->bind(feature->Radius2);
500
        ui->coneHeight->setValue(feature->Height.getQuantityValue());
501
        ui->coneHeight->bind(feature->Height);
502
        ui->coneAngle->setValue(feature->Angle.getQuantityValue());
503
        ui->coneAngle->bind(feature->Angle);
504

505
        QSignalMapper* mapper = new QSignalMapper(this);
506
        connectSignalMapper(mapper);
507
        connectMapSignalMapper(ui->coneRadius1, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
508
        connectMapSignalMapper(ui->coneRadius2, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
509
        connectMapSignalMapper(ui->coneHeight, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
510
        connectMapSignalMapper(ui->coneAngle, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
511
    }
512
}
513

514
const char* ConePrimitive::getDefaultName() const
515
{
516
    return "Cone";
517
}
518

519
QString ConePrimitive::create(const QString& objectName, const QString& placement) const
520
{
521
    return QString::fromLatin1(
522
        "App.ActiveDocument.addObject(\"Part::Cone\",\"%1\")\n"
523
        "App.ActiveDocument.%1.Radius1='%2'\n"
524
        "App.ActiveDocument.%1.Radius2='%3'\n"
525
        "App.ActiveDocument.%1.Height='%4'\n"
526
        "App.ActiveDocument.%1.Angle='%5'\n"
527
        "App.ActiveDocument.%1.Placement=%6\n"
528
        "App.ActiveDocument.%1.Label='%7'\n")
529
        .arg(objectName,
530
             ui->coneRadius1->value().getSafeUserString(),
531
             ui->coneRadius2->value().getSafeUserString(),
532
             ui->coneHeight->value().getSafeUserString(),
533
             ui->coneAngle->value().getSafeUserString(),
534
             placement,
535
             DlgPrimitives::tr("Cone"));
536
}
537

538
QString ConePrimitive::change(const QString& objectName, const QString& placement) const
539
{
540
    return QString::fromLatin1(
541
        "%1.Radius1='%2'\n"
542
        "%1.Radius2='%3'\n"
543
        "%1.Height='%4'\n"
544
        "%1.Angle='%5'\n"
545
        "%1.Placement=%6\n")
546
        .arg(objectName,
547
             ui->coneRadius1->value().getSafeUserString(),
548
             ui->coneRadius2->value().getSafeUserString(),
549
             ui->coneHeight->value().getSafeUserString(),
550
             ui->coneAngle->value().getSafeUserString(),
551
             placement);
552
}
553

554
void ConePrimitive::changeValue(QObject* widget)
555
{
556
    if (featurePtr.expired())
557
        return;
558
    Part::Cone* cone = featurePtr.get<Part::Cone>();
559
    if (widget == ui->coneRadius1) {
560
        cone->Radius1.setValue(ui->coneRadius1->value().getValue());
561
    }
562
    else if (widget == ui->coneRadius2) {
563
        cone->Radius2.setValue(ui->coneRadius2->value().getValue());
564
    }
565
    else if (widget == ui->coneHeight) {
566
        cone->Height.setValue(ui->coneHeight->value().getValue());
567
    }
568
    else if (widget == ui->coneAngle) {
569
        cone->Angle.setValue(ui->coneAngle->value().getValue());
570
    }
571

572
    cone->recomputeFeature();
573
}
574

575
// ----------------------------------------------------------------------------
576

577
SpherePrimitive::SpherePrimitive(std::shared_ptr<Ui_DlgPrimitives> ui, Part::Sphere* feature)
578
    : AbstractPrimitive(feature)
579
    , ui(ui)
580
{
581
    ui->sphereRadius->setRange(0, INT_MAX);
582
    ui->sphereAngle1->setRange(-90, 90);
583
    ui->sphereAngle2->setRange(-90, 90);
584
    ui->sphereAngle3->setRange(0, 360);
585

586
    if (feature) {
587
        ui->sphereRadius->setValue(feature->Radius.getQuantityValue());
588
        ui->sphereRadius->bind(feature->Radius);
589
        ui->sphereAngle1->setValue(feature->Angle1.getQuantityValue());
590
        ui->sphereAngle1->bind(feature->Angle1);
591
        ui->sphereAngle2->setValue(feature->Angle2.getQuantityValue());
592
        ui->sphereAngle2->bind(feature->Angle2);
593
        ui->sphereAngle3->setValue(feature->Angle3.getQuantityValue());
594
        ui->sphereAngle3->bind(feature->Angle3);
595

596
        QSignalMapper* mapper = new QSignalMapper(this);
597
        connectSignalMapper(mapper);
598
        connectMapSignalMapper(ui->sphereRadius, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
599
        connectMapSignalMapper(ui->sphereAngle1, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
600
        connectMapSignalMapper(ui->sphereAngle2, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
601
        connectMapSignalMapper(ui->sphereAngle3, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
602
    }
603
}
604

605
const char* SpherePrimitive::getDefaultName() const
606
{
607
    return "Sphere";
608
}
609

610
QString SpherePrimitive::create(const QString& objectName, const QString& placement) const
611
{
612
    return QString::fromLatin1(
613
        "App.ActiveDocument.addObject(\"Part::Sphere\",\"%1\")\n"
614
        "App.ActiveDocument.%1.Radius='%2'\n"
615
        "App.ActiveDocument.%1.Angle1='%3'\n"
616
        "App.ActiveDocument.%1.Angle2='%4'\n"
617
        "App.ActiveDocument.%1.Angle3='%5'\n"
618
        "App.ActiveDocument.%1.Placement=%6\n"
619
        "App.ActiveDocument.%1.Label='%7'\n")
620
        .arg(objectName,
621
             ui->sphereRadius->value().getSafeUserString(),
622
             ui->sphereAngle1->value().getSafeUserString(),
623
             ui->sphereAngle2->value().getSafeUserString(),
624
             ui->sphereAngle3->value().getSafeUserString(),
625
             placement,
626
             DlgPrimitives::tr("Sphere"));
627
}
628

629
QString SpherePrimitive::change(const QString& objectName, const QString& placement) const
630
{
631
    return QString::fromLatin1(
632
        "%1.Radius='%2'\n"
633
        "%1.Angle1='%3'\n"
634
        "%1.Angle2='%4'\n"
635
        "%1.Angle3='%5'\n"
636
        "%1.Placement=%6\n")
637
        .arg(objectName,
638
             ui->sphereRadius->value().getSafeUserString(),
639
             ui->sphereAngle1->value().getSafeUserString(),
640
             ui->sphereAngle2->value().getSafeUserString(),
641
             ui->sphereAngle3->value().getSafeUserString(),
642
             placement);
643
}
644

645
void SpherePrimitive::changeValue(QObject* widget)
646
{
647
    if (featurePtr.expired())
648
        return;
649
    Part::Sphere* sphere = featurePtr.get<Part::Sphere>();
650
    if (widget == ui->sphereRadius) {
651
        sphere->Radius.setValue(ui->sphereRadius->value().getValue());
652
    }
653
    else if (widget == ui->sphereAngle1) {
654
        sphere->Angle1.setValue(ui->sphereAngle1->value().getValue());
655
    }
656
    else if (widget == ui->sphereAngle2) {
657
        sphere->Angle2.setValue(ui->sphereAngle2->value().getValue());
658
    }
659
    else if (widget == ui->sphereAngle3) {
660
        sphere->Angle3.setValue(ui->sphereAngle3->value().getValue());
661
    }
662

663
    sphere->recomputeFeature();
664
}
665

666
// ----------------------------------------------------------------------------
667

668
EllipsoidPrimitive::EllipsoidPrimitive(std::shared_ptr<Ui_DlgPrimitives> ui, Part::Ellipsoid* feature)
669
    : AbstractPrimitive(feature)
670
    , ui(ui)
671
{
672
    ui->ellipsoidRadius1->setRange(0, INT_MAX);
673
    ui->ellipsoidRadius2->setRange(0, INT_MAX);
674
    ui->ellipsoidRadius3->setRange(0, INT_MAX);
675
    ui->ellipsoidAngle1->setRange(-90, 90);
676
    ui->ellipsoidAngle2->setRange(-90, 90);
677
    ui->ellipsoidAngle3->setRange(0, 360);
678

679
    if (feature) {
680
        ui->ellipsoidRadius1->setValue(feature->Radius1.getQuantityValue());
681
        ui->ellipsoidRadius1->bind(feature->Radius1);
682
        ui->ellipsoidRadius2->setValue(feature->Radius2.getQuantityValue());
683
        ui->ellipsoidRadius2->bind(feature->Radius2);
684
        ui->ellipsoidRadius3->setValue(feature->Radius3.getQuantityValue());
685
        ui->ellipsoidRadius3->bind(feature->Radius3);
686
        ui->ellipsoidAngle1->setValue(feature->Angle1.getQuantityValue());
687
        ui->ellipsoidAngle1->bind(feature->Angle1);
688
        ui->ellipsoidAngle2->setValue(feature->Angle2.getQuantityValue());
689
        ui->ellipsoidAngle2->bind(feature->Angle2);
690
        ui->ellipsoidAngle3->setValue(feature->Angle3.getQuantityValue());
691
        ui->ellipsoidAngle3->bind(feature->Angle3);
692

693
        QSignalMapper* mapper = new QSignalMapper(this);
694
        connectSignalMapper(mapper);
695
        connectMapSignalMapper(ui->ellipsoidRadius1, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
696
        connectMapSignalMapper(ui->ellipsoidRadius2, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
697
        connectMapSignalMapper(ui->ellipsoidRadius3, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
698
        connectMapSignalMapper(ui->ellipsoidAngle1, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
699
        connectMapSignalMapper(ui->ellipsoidAngle2, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
700
        connectMapSignalMapper(ui->ellipsoidAngle3, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
701

702
    }
703
}
704

705
const char* EllipsoidPrimitive::getDefaultName() const
706
{
707
    return "Ellipsoid";
708
}
709

710
QString EllipsoidPrimitive::create(const QString& objectName, const QString& placement) const
711
{
712
    return QString::fromLatin1(
713
        "App.ActiveDocument.addObject(\"Part::Ellipsoid\",\"%1\")\n"
714
        "App.ActiveDocument.%1.Radius1='%2'\n"
715
        "App.ActiveDocument.%1.Radius2='%3'\n"
716
        "App.ActiveDocument.%1.Radius3='%4'\n"
717
        "App.ActiveDocument.%1.Angle1='%5'\n"
718
        "App.ActiveDocument.%1.Angle2='%6'\n"
719
        "App.ActiveDocument.%1.Angle3='%7'\n"
720
        "App.ActiveDocument.%1.Placement=%8\n"
721
        "App.ActiveDocument.%1.Label='%9'\n")
722
        .arg(objectName,
723
             ui->ellipsoidRadius1->value().getSafeUserString(),
724
             ui->ellipsoidRadius2->value().getSafeUserString(),
725
             ui->ellipsoidRadius3->value().getSafeUserString(),
726
             ui->ellipsoidAngle1->value().getSafeUserString(),
727
             ui->ellipsoidAngle2->value().getSafeUserString(),
728
             ui->ellipsoidAngle3->value().getSafeUserString(),
729
             placement,
730
             DlgPrimitives::tr("Ellipsoid"));
731
}
732

733
QString EllipsoidPrimitive::change(const QString& objectName, const QString& placement) const
734
{
735
    return QString::fromLatin1(
736
        "%1.Radius1='%2'\n"
737
        "%1.Radius2='%3'\n"
738
        "%1.Radius3='%4'\n"
739
        "%1.Angle1='%5'\n"
740
        "%1.Angle2='%6'\n"
741
        "%1.Angle3='%7'\n"
742
        "%1.Placement=%8\n")
743
        .arg(objectName,
744
             ui->ellipsoidRadius1->value().getSafeUserString(),
745
             ui->ellipsoidRadius2->value().getSafeUserString(),
746
             ui->ellipsoidRadius3->value().getSafeUserString(),
747
             ui->ellipsoidAngle1->value().getSafeUserString(),
748
             ui->ellipsoidAngle2->value().getSafeUserString(),
749
             ui->ellipsoidAngle3->value().getSafeUserString(),
750
             placement);
751
}
752

753
void EllipsoidPrimitive::changeValue(QObject* widget)
754
{
755
    if (featurePtr.expired())
756
        return;
757
    Part::Ellipsoid* ell = featurePtr.get<Part::Ellipsoid>();
758
    if (widget == ui->ellipsoidRadius1) {
759
        ell->Radius1.setValue(ui->ellipsoidRadius1->value().getValue());
760
    }
761
    else if (widget == ui->ellipsoidRadius2) {
762
        ell->Radius2.setValue(ui->ellipsoidRadius2->value().getValue());
763
    }
764
    else if (widget == ui->ellipsoidRadius3) {
765
        ell->Radius3.setValue(ui->ellipsoidRadius3->value().getValue());
766
    }
767
    else if (widget == ui->ellipsoidAngle1) {
768
        ell->Angle1.setValue(ui->ellipsoidAngle1->value().getValue());
769
    }
770
    else if (widget == ui->ellipsoidAngle2) {
771
        ell->Angle2.setValue(ui->ellipsoidAngle2->value().getValue());
772
    }
773
    else if (widget == ui->ellipsoidAngle3) {
774
        ell->Angle3.setValue(ui->ellipsoidAngle3->value().getValue());
775
    }
776

777
    ell->recomputeFeature();
778
}
779

780
// ----------------------------------------------------------------------------
781

782
TorusPrimitive::TorusPrimitive(std::shared_ptr<Ui_DlgPrimitives> ui, Part::Torus* feature)
783
    : AbstractPrimitive(feature)
784
    , ui(ui)
785
{
786
    ui->torusRadius1->setRange(0, INT_MAX);
787
    ui->torusRadius2->setRange(0, INT_MAX);
788
    ui->torusAngle1->setRange(-180, 180);
789
    ui->torusAngle2->setRange(-180, 180);
790
    ui->torusAngle3->setRange(0, 360);
791

792
    if (feature) {
793
        ui->torusRadius1->setValue(feature->Radius1.getQuantityValue());
794
        ui->torusRadius1->bind(feature->Radius1);
795
        ui->torusRadius2->setValue(feature->Radius2.getQuantityValue());
796
        ui->torusRadius2->bind(feature->Radius2);
797
        ui->torusAngle1->setValue(feature->Angle1.getQuantityValue());
798
        ui->torusAngle1->bind(feature->Angle1);
799
        ui->torusAngle2->setValue(feature->Angle2.getQuantityValue());
800
        ui->torusAngle2->bind(feature->Angle2);
801
        ui->torusAngle3->setValue(feature->Angle3.getQuantityValue());
802
        ui->torusAngle3->bind(feature->Angle3);
803

804
        QSignalMapper* mapper = new QSignalMapper(this);
805
        connectSignalMapper(mapper);
806
        connectMapSignalMapper(ui->torusRadius1, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
807
        connectMapSignalMapper(ui->torusRadius2, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
808
        connectMapSignalMapper(ui->torusAngle1, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
809
        connectMapSignalMapper(ui->torusAngle2, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
810
        connectMapSignalMapper(ui->torusAngle3, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
811
    }
812
}
813

814
const char* TorusPrimitive::getDefaultName() const
815
{
816
    return "Torus";
817
}
818

819
QString TorusPrimitive::create(const QString& objectName, const QString& placement) const
820
{
821
    return QString::fromLatin1(
822
        "App.ActiveDocument.addObject(\"Part::Torus\",\"%1\")\n"
823
        "App.ActiveDocument.%1.Radius1='%2'\n"
824
        "App.ActiveDocument.%1.Radius2='%3'\n"
825
        "App.ActiveDocument.%1.Angle1='%4'\n"
826
        "App.ActiveDocument.%1.Angle2='%5'\n"
827
        "App.ActiveDocument.%1.Angle3='%6'\n"
828
        "App.ActiveDocument.%1.Placement=%7\n"
829
        "App.ActiveDocument.%1.Label='%8'\n")
830
        .arg(objectName,
831
             ui->torusRadius1->value().getSafeUserString(),
832
             ui->torusRadius2->value().getSafeUserString(),
833
             ui->torusAngle1->value().getSafeUserString(),
834
             ui->torusAngle2->value().getSafeUserString(),
835
             ui->torusAngle3->value().getSafeUserString(),
836
             placement,
837
             DlgPrimitives::tr("Torus"));
838
}
839

840
QString TorusPrimitive::change(const QString& objectName, const QString& placement) const
841
{
842
    return QString::fromLatin1(
843
        "%1.Radius1='%2'\n"
844
        "%1.Radius2='%3'\n"
845
        "%1.Angle1='%4'\n"
846
        "%1.Angle2='%5'\n"
847
        "%1.Angle3='%6'\n"
848
        "%1.Placement=%7\n")
849
        .arg(objectName,
850
             ui->torusRadius1->value().getSafeUserString(),
851
             ui->torusRadius2->value().getSafeUserString(),
852
             ui->torusAngle1->value().getSafeUserString(),
853
             ui->torusAngle2->value().getSafeUserString(),
854
             ui->torusAngle3->value().getSafeUserString(),
855
             placement);
856
}
857

858
void TorusPrimitive::changeValue(QObject* widget)
859
{
860
    if (featurePtr.expired())
861
        return;
862
    Part::Torus* torus = featurePtr.get<Part::Torus>();
863
    if (widget == ui->torusRadius1) {
864
        torus->Radius1.setValue(ui->torusRadius1->value().getValue());
865
    }
866
    else if (widget == ui->torusRadius2) {
867
        torus->Radius2.setValue(ui->torusRadius2->value().getValue());
868
    }
869
    else if (widget == ui->torusAngle1) {
870
        torus->Angle1.setValue(ui->torusAngle1->value().getValue());
871
    }
872
    else if (widget == ui->torusAngle2) {
873
        torus->Angle2.setValue(ui->torusAngle2->value().getValue());
874
    }
875
    else if (widget == ui->torusAngle3) {
876
        torus->Angle3.setValue(ui->torusAngle3->value().getValue());
877
    }
878

879
    torus->recomputeFeature();
880
}
881

882
// ----------------------------------------------------------------------------
883

884
PrismPrimitive::PrismPrimitive(std::shared_ptr<Ui_DlgPrimitives> ui, Part::Prism* feature)
885
    : AbstractPrimitive(feature)
886
    , ui(ui)
887
{
888
    ui->prismCircumradius->setRange(0, INT_MAX);
889
    ui->prismHeight->setRange(0, INT_MAX);
890

891
    if (feature) {
892
        ui->prismPolygon->setValue(feature->Polygon.getValue());
893
        ui->prismCircumradius->setValue(feature->Circumradius.getQuantityValue());
894
        ui->prismCircumradius->bind(feature->Circumradius);
895
        ui->prismHeight->setValue(feature->Height.getQuantityValue());
896
        ui->prismHeight->bind(feature->Height);
897
        ui->prismXSkew->setValue(feature->FirstAngle.getQuantityValue());
898
        ui->prismXSkew->bind(feature->FirstAngle);
899
        ui->prismYSkew->setValue(feature->SecondAngle.getQuantityValue());
900
        ui->prismYSkew->bind(feature->SecondAngle);
901

902
        QSignalMapper* mapper = new QSignalMapper(this);
903
        connectSignalMapper(mapper);
904
        connectMapSignalMapper(ui->prismPolygon, qOverload<int>(&QSpinBox::valueChanged), mapper);
905
        connectMapSignalMapper(ui->prismCircumradius, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
906
        connectMapSignalMapper(ui->prismHeight, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
907
        connectMapSignalMapper(ui->prismXSkew, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
908
        connectMapSignalMapper(ui->prismYSkew, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
909
    }
910
}
911

912
const char* PrismPrimitive::getDefaultName() const
913
{
914
    return "Prism";
915
}
916

917
QString PrismPrimitive::create(const QString& objectName, const QString& placement) const
918
{
919
    return QString::fromLatin1(
920
        "App.ActiveDocument.addObject(\"Part::Prism\",\"%1\")\n"
921
        "App.ActiveDocument.%1.Polygon=%2\n"
922
        "App.ActiveDocument.%1.Circumradius='%3'\n"
923
        "App.ActiveDocument.%1.Height='%4'\n"
924
        "App.ActiveDocument.%1.FirstAngle='%5'\n"
925
        "App.ActiveDocument.%1.SecondAngle='%6'\n"
926
        "App.ActiveDocument.%1.Placement=%7\n"
927
        "App.ActiveDocument.%1.Label='%8'\n")
928
        .arg(objectName,
929
             QString::number(ui->prismPolygon->value()),
930
             ui->prismCircumradius->value().getSafeUserString(),
931
             ui->prismHeight->value().getSafeUserString(),
932
             ui->prismXSkew->value().getSafeUserString(),
933
             ui->prismYSkew->value().getSafeUserString(),
934
             placement,
935
             DlgPrimitives::tr("Prism"));
936
}
937

938
QString PrismPrimitive::change(const QString& objectName, const QString& placement) const
939
{
940
    return QString::fromLatin1(
941
        "%1.Polygon=%2\n"
942
        "%1.Circumradius='%3'\n"
943
        "%1.Height='%4'\n"
944
        "%1.FirstAngle='%5'\n"
945
        "%1.SecondAngle='%6'\n"
946
        "%1.Placement=%7\n")
947
        .arg(objectName,
948
             QString::number(ui->prismPolygon->value()),
949
             ui->prismCircumradius->value().getSafeUserString(),
950
             ui->prismHeight->value().getSafeUserString(),
951
             ui->prismXSkew->value().getSafeUserString(),
952
             ui->prismYSkew->value().getSafeUserString(),
953
             placement);
954
}
955

956
void PrismPrimitive::changeValue(QObject* widget)
957
{
958
    if (featurePtr.expired())
959
        return;
960
    Part::Prism* prism = featurePtr.get<Part::Prism>();
961
    if (widget == ui->prismPolygon) {
962
        prism->Polygon.setValue(ui->prismPolygon->value());
963
    }
964
    else if (widget == ui->prismCircumradius) {
965
        prism->Circumradius.setValue(ui->prismCircumradius->value().getValue());
966
    }
967
    else if (widget == ui->prismHeight) {
968
        prism->Height.setValue(ui->prismHeight->value().getValue());
969
    }
970
    else if (widget == ui->prismXSkew) {
971
        prism->FirstAngle.setValue(ui->prismXSkew->value().getValue());
972
    }
973
    else if (widget == ui->prismYSkew) {
974
        prism->SecondAngle.setValue(ui->prismYSkew->value().getValue());
975
    }
976

977
    prism->recomputeFeature();
978
}
979

980
// ----------------------------------------------------------------------------
981

982
WedgePrimitive::WedgePrimitive(std::shared_ptr<Ui_DlgPrimitives> ui, Part::Wedge* feature)
983
    : AbstractPrimitive(feature)
984
    , ui(ui)
985
{
986
    ui->wedgeXmin->setMinimum(INT_MIN);
987
    ui->wedgeXmin->setMaximum(INT_MAX);
988
    ui->wedgeYmin->setMinimum(INT_MIN);
989
    ui->wedgeYmin->setMaximum(INT_MAX);
990
    ui->wedgeZmin->setMinimum(INT_MIN);
991
    ui->wedgeZmin->setMaximum(INT_MAX);
992
    ui->wedgeX2min->setMinimum(INT_MIN);
993
    ui->wedgeX2min->setMaximum(INT_MAX);
994
    ui->wedgeZ2min->setMinimum(INT_MIN);
995
    ui->wedgeZ2min->setMaximum(INT_MAX);
996
    ui->wedgeXmax->setMinimum(INT_MIN);
997
    ui->wedgeXmax->setMaximum(INT_MAX);
998
    ui->wedgeYmax->setMinimum(INT_MIN);
999
    ui->wedgeYmax->setMaximum(INT_MAX);
1000
    ui->wedgeZmax->setMinimum(INT_MIN);
1001
    ui->wedgeZmax->setMaximum(INT_MAX);
1002
    ui->wedgeX2max->setMinimum(INT_MIN);
1003
    ui->wedgeX2max->setMaximum(INT_MAX);
1004
    ui->wedgeZ2max->setMinimum(INT_MIN);
1005
    ui->wedgeZ2max->setMaximum(INT_MAX);
1006

1007
    if (feature) {
1008
        ui->wedgeXmin->setValue(feature->Xmin.getQuantityValue());
1009
        ui->wedgeXmin->bind(feature->Xmin);
1010
        ui->wedgeYmin->setValue(feature->Ymin.getQuantityValue());
1011
        ui->wedgeYmin->bind(feature->Ymin);
1012
        ui->wedgeZmin->setValue(feature->Zmin.getQuantityValue());
1013
        ui->wedgeZmin->bind(feature->Zmin);
1014
        ui->wedgeX2min->setValue(feature->X2min.getQuantityValue());
1015
        ui->wedgeX2min->bind(feature->X2min);
1016
        ui->wedgeZ2min->setValue(feature->Z2min.getQuantityValue());
1017
        ui->wedgeZ2min->bind(feature->Z2min);
1018
        ui->wedgeXmax->setValue(feature->Xmax.getQuantityValue());
1019
        ui->wedgeXmax->bind(feature->Xmax);
1020
        ui->wedgeYmax->setValue(feature->Ymax.getQuantityValue());
1021
        ui->wedgeYmax->bind(feature->Ymax);
1022
        ui->wedgeZmax->setValue(feature->Zmax.getQuantityValue());
1023
        ui->wedgeZmax->bind(feature->Zmax);
1024
        ui->wedgeX2max->setValue(feature->X2max.getQuantityValue());
1025
        ui->wedgeX2max->bind(feature->X2max);
1026
        ui->wedgeZ2max->setValue(feature->Z2max.getQuantityValue());
1027
        ui->wedgeZ2max->bind(feature->Z2max);
1028

1029
        QSignalMapper* mapper = new QSignalMapper(this);
1030
        connectSignalMapper(mapper);
1031
        connectMapSignalMapper(ui->wedgeXmin, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1032
        connectMapSignalMapper(ui->wedgeYmin, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1033
        connectMapSignalMapper(ui->wedgeZmin, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1034
        connectMapSignalMapper(ui->wedgeX2min, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1035
        connectMapSignalMapper(ui->wedgeZ2min, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1036
        connectMapSignalMapper(ui->wedgeXmax, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1037
        connectMapSignalMapper(ui->wedgeYmax, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1038
        connectMapSignalMapper(ui->wedgeZmax, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1039
        connectMapSignalMapper(ui->wedgeX2max, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1040
        connectMapSignalMapper(ui->wedgeZ2max, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1041
    }
1042
}
1043

1044
const char* WedgePrimitive::getDefaultName() const
1045
{
1046
    return "Wedge";
1047
}
1048

1049
QString WedgePrimitive::create(const QString& objectName, const QString& placement) const
1050
{
1051
    return QString::fromLatin1(
1052
        "App.ActiveDocument.addObject(\"Part::Wedge\",\"%1\")\n"
1053
        "App.ActiveDocument.%1.Xmin='%2'\n"
1054
        "App.ActiveDocument.%1.Ymin='%3'\n"
1055
        "App.ActiveDocument.%1.Zmin='%4'\n"
1056
        "App.ActiveDocument.%1.X2min='%5'\n"
1057
        "App.ActiveDocument.%1.Z2min='%6'\n"
1058
        "App.ActiveDocument.%1.Xmax='%7'\n"
1059
        "App.ActiveDocument.%1.Ymax='%8'\n"
1060
        "App.ActiveDocument.%1.Zmax='%9'\n"
1061
        "App.ActiveDocument.%1.X2max='%10'\n"
1062
        "App.ActiveDocument.%1.Z2max='%11'\n"
1063
        "App.ActiveDocument.%1.Placement=%12\n"
1064
        "App.ActiveDocument.%1.Label='%13'\n")
1065
        .arg(objectName,
1066
             ui->wedgeXmin->value().getSafeUserString(),
1067
             ui->wedgeYmin->value().getSafeUserString(),
1068
             ui->wedgeZmin->value().getSafeUserString(),
1069
             ui->wedgeX2min->value().getSafeUserString(),
1070
             ui->wedgeZ2min->value().getSafeUserString(),
1071
             ui->wedgeXmax->value().getSafeUserString(),
1072
             ui->wedgeYmax->value().getSafeUserString())
1073
        .arg(ui->wedgeZmax->value().getSafeUserString(),
1074
             ui->wedgeX2max->value().getSafeUserString(),
1075
             ui->wedgeZ2max->value().getSafeUserString(),
1076
             placement,
1077
             DlgPrimitives::tr("Wedge"));
1078
}
1079

1080
QString WedgePrimitive::change(const QString& objectName, const QString& placement) const
1081
{
1082
    return QString::fromLatin1(
1083
        "%1.Xmin='%2'\n"
1084
        "%1.Ymin='%3'\n"
1085
        "%1.Zmin='%4'\n"
1086
        "%1.X2min='%5'\n"
1087
        "%1.Z2min='%6'\n"
1088
        "%1.Xmax='%7'\n"
1089
        "%1.Ymax='%8'\n"
1090
        "%1.Zmax='%9'\n"
1091
        "%1.X2max='%10'\n"
1092
        "%1.Z2max='%11'\n"
1093
        "%1.Placement=%12\n")
1094
        .arg(objectName,
1095
             ui->wedgeXmin->value().getSafeUserString(),
1096
             ui->wedgeYmin->value().getSafeUserString(),
1097
             ui->wedgeZmin->value().getSafeUserString(),
1098
             ui->wedgeX2min->value().getSafeUserString(),
1099
             ui->wedgeZ2min->value().getSafeUserString(),
1100
             ui->wedgeXmax->value().getSafeUserString(),
1101
             ui->wedgeYmax->value().getSafeUserString(),
1102
             ui->wedgeZmax->value().getSafeUserString())
1103
        .arg(ui->wedgeX2max->value().getSafeUserString(),
1104
             ui->wedgeZ2max->value().getSafeUserString(),
1105
             placement);
1106
}
1107

1108
void WedgePrimitive::changeValue(QObject* widget)
1109
{
1110
    if (featurePtr.expired())
1111
        return;
1112
    Part::Wedge* wedge = featurePtr.get<Part::Wedge>();
1113
    if (widget == ui->wedgeXmin) {
1114
        wedge->Xmin.setValue(ui->wedgeXmin->value().getValue());
1115
    }
1116
    else if (widget == ui->wedgeYmin) {
1117
        wedge->Ymin.setValue(ui->wedgeYmin->value().getValue());
1118
    }
1119
    else if (widget == ui->wedgeZmin) {
1120
        wedge->Zmin.setValue(ui->wedgeZmin->value().getValue());
1121
    }
1122
    else if (widget == ui->wedgeX2min) {
1123
        wedge->X2min.setValue(ui->wedgeX2min->value().getValue());
1124
    }
1125
    else if (widget == ui->wedgeZ2min) {
1126
        wedge->Z2min.setValue(ui->wedgeZ2min->value().getValue());
1127
    }
1128
    else if (widget == ui->wedgeXmax) {
1129
        wedge->Xmax.setValue(ui->wedgeXmax->value().getValue());
1130
    }
1131
    else if (widget == ui->wedgeYmax) {
1132
        wedge->Ymax.setValue(ui->wedgeYmax->value().getValue());
1133
    }
1134
    else if (widget == ui->wedgeZmax) {
1135
        wedge->Zmax.setValue(ui->wedgeZmax->value().getValue());
1136
    }
1137
    else if (widget == ui->wedgeX2max) {
1138
        wedge->X2max.setValue(ui->wedgeX2max->value().getValue());
1139
    }
1140
    else if (widget == ui->wedgeZ2max) {
1141
        wedge->Z2max.setValue(ui->wedgeZ2max->value().getValue());
1142
    }
1143

1144
    wedge->recomputeFeature();
1145
}
1146

1147
// ----------------------------------------------------------------------------
1148

1149
HelixPrimitive::HelixPrimitive(std::shared_ptr<Ui_DlgPrimitives> ui, Part::Helix* feature)
1150
    : AbstractPrimitive(feature)
1151
    , ui(ui)
1152
{
1153
    ui->helixPitch->setRange(0, INT_MAX);
1154
    ui->helixHeight->setRange(0, INT_MAX);
1155
    ui->helixRadius->setRange(0, INT_MAX);
1156
    ui->helixAngle->setRange(-89.9, 89.9);
1157

1158
    if (feature) {
1159
        ui->helixPitch->setValue(feature->Pitch.getQuantityValue());
1160
        ui->helixPitch->bind(feature->Pitch);
1161
        ui->helixHeight->setValue(feature->Height.getQuantityValue());
1162
        ui->helixHeight->bind(feature->Height);
1163
        ui->helixRadius->setValue(feature->Radius.getQuantityValue());
1164
        ui->helixRadius->bind(feature->Radius);
1165
        ui->helixAngle->setValue(feature->Angle.getQuantityValue());
1166
        ui->helixAngle->bind(feature->Angle);
1167
        ui->helixLocalCS->setCurrentIndex(feature->LocalCoord.getValue());
1168

1169
        QSignalMapper* mapper = new QSignalMapper(this);
1170
        connectSignalMapper(mapper);
1171
        connectMapSignalMapper(ui->helixPitch, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1172
        connectMapSignalMapper(ui->helixHeight, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1173
        connectMapSignalMapper(ui->helixRadius, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1174
        connectMapSignalMapper(ui->helixAngle, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1175
        connectMapSignalMapper(ui->helixLocalCS, qOverload<int>(&QComboBox::currentIndexChanged), mapper);
1176
    }
1177
}
1178

1179
const char* HelixPrimitive::getDefaultName() const
1180
{
1181
    return "Helix";
1182
}
1183

1184
QString HelixPrimitive::create(const QString& objectName, const QString& placement) const
1185
{
1186
    return QString::fromLatin1(
1187
        "App.ActiveDocument.addObject(\"Part::Helix\",\"%1\")\n"
1188
        "App.ActiveDocument.%1.Pitch='%2'\n"
1189
        "App.ActiveDocument.%1.Height='%3'\n"
1190
        "App.ActiveDocument.%1.Radius='%4'\n"
1191
        "App.ActiveDocument.%1.Angle='%5'\n"
1192
        "App.ActiveDocument.%1.LocalCoord=%6\n"
1193
        "App.ActiveDocument.%1.Style=1\n"
1194
        "App.ActiveDocument.%1.Placement=%7\n"
1195
        "App.ActiveDocument.%1.Label='%8'\n")
1196
        .arg(objectName,
1197
             ui->helixPitch->value().getSafeUserString(),
1198
             ui->helixHeight->value().getSafeUserString(),
1199
             ui->helixRadius->value().getSafeUserString(),
1200
             ui->helixAngle->value().getSafeUserString(),
1201
             QString::number(ui->helixLocalCS->currentIndex()),
1202
             placement,
1203
             DlgPrimitives::tr("Helix"));
1204
}
1205

1206
QString HelixPrimitive::change(const QString& objectName, const QString& placement) const
1207
{
1208
    return QString::fromLatin1(
1209
        "%1.Pitch='%2'\n"
1210
        "%1.Height='%3'\n"
1211
        "%1.Radius='%4'\n"
1212
        "%1.Angle='%5'\n"
1213
        "%1.LocalCoord=%6\n"
1214
        "%1.Placement=%7\n")
1215
        .arg(objectName,
1216
             ui->helixPitch->value().getSafeUserString(),
1217
             ui->helixHeight->value().getSafeUserString(),
1218
             ui->helixRadius->value().getSafeUserString(),
1219
             ui->helixAngle->value().getSafeUserString(),
1220
             QString::number(ui->helixLocalCS->currentIndex()),
1221
             placement);
1222
}
1223

1224
void HelixPrimitive::changeValue(QObject* widget)
1225
{
1226
    if (featurePtr.expired())
1227
        return;
1228
    Part::Helix* helix = featurePtr.get<Part::Helix>();
1229
    if (widget == ui->helixPitch) {
1230
        helix->Pitch.setValue(ui->helixPitch->value().getValue());
1231
    }
1232
    else if (widget == ui->helixHeight) {
1233
        helix->Height.setValue(ui->helixHeight->value().getValue());
1234
    }
1235
    else if (widget == ui->helixRadius) {
1236
        helix->Radius.setValue(ui->helixRadius->value().getValue());
1237
    }
1238
    else if (widget == ui->helixAngle) {
1239
        helix->Angle.setValue(ui->helixAngle->value().getValue());
1240
    }
1241
    else if (widget == ui->helixLocalCS) {
1242
        helix->LocalCoord.setValue(ui->helixLocalCS->currentIndex());
1243
    }
1244

1245
    helix->recomputeFeature();
1246
}
1247

1248
// ----------------------------------------------------------------------------
1249

1250
SpiralPrimitive::SpiralPrimitive(std::shared_ptr<Ui_DlgPrimitives> ui, Part::Spiral* feature)
1251
    : AbstractPrimitive(feature)
1252
    , ui(ui)
1253
{
1254
    ui->spiralGrowth->setRange(0, INT_MAX);
1255
    ui->spiralRotation->setRange(0, INT_MAX);
1256
    ui->spiralRadius->setRange(0, INT_MAX);
1257

1258
    if (feature) {
1259
        ui->spiralGrowth->setValue(feature->Growth.getQuantityValue());
1260
        ui->spiralGrowth->bind(feature->Growth);
1261
        ui->spiralRotation->setValue(feature->Rotations.getQuantityValue().getValue());
1262
        ui->spiralRadius->setValue(feature->Radius.getQuantityValue());
1263
        ui->spiralRadius->bind(feature->Radius);
1264

1265
        QSignalMapper* mapper = new QSignalMapper(this);
1266
        connectSignalMapper(mapper);
1267
        connectMapSignalMapper(ui->spiralGrowth, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1268
        connectMapSignalMapper(ui->spiralRotation, qOverload<double>(&QDoubleSpinBox::valueChanged), mapper);
1269
        connectMapSignalMapper(ui->spiralRadius, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1270
    }
1271
}
1272

1273
const char* SpiralPrimitive::getDefaultName() const
1274
{
1275
    return "Spiral";
1276
}
1277

1278
QString SpiralPrimitive::create(const QString& objectName, const QString& placement) const
1279
{
1280
    return QString::fromLatin1(
1281
        "App.ActiveDocument.addObject(\"Part::Spiral\",\"%1\")\n"
1282
        "App.ActiveDocument.%1.Growth='%2'\n"
1283
        "App.ActiveDocument.%1.Rotations=%3\n"
1284
        "App.ActiveDocument.%1.Radius='%4'\n"
1285
        "App.ActiveDocument.%1.Placement=%5\n"
1286
        "App.ActiveDocument.%1.Label='%6'\n")
1287
        .arg(objectName,
1288
             ui->spiralGrowth->value().getSafeUserString(),
1289
             QString::number(ui->spiralRotation->value()),
1290
             ui->spiralRadius->value().getSafeUserString(),
1291
             placement,
1292
             DlgPrimitives::tr("Spiral"));
1293
}
1294

1295
QString SpiralPrimitive::change(const QString& objectName, const QString& placement) const
1296
{
1297
    return QString::fromLatin1(
1298
        "%1.Growth='%2'\n"
1299
        "%1.Rotations=%3\n"
1300
        "%1.Radius='%4'\n"
1301
        "%1.Placement=%5\n")
1302
        .arg(objectName,
1303
             ui->spiralGrowth->value().getSafeUserString(),
1304
             QString::number(ui->spiralRotation->value()),
1305
             ui->spiralRadius->value().getSafeUserString(),
1306
             placement);
1307
}
1308

1309
void SpiralPrimitive::changeValue(QObject* widget)
1310
{
1311
    if (featurePtr.expired())
1312
        return;
1313
    Part::Spiral* spiral = featurePtr.get<Part::Spiral>();
1314
    if (widget == ui->spiralGrowth) {
1315
        spiral->Growth.setValue(ui->spiralGrowth->value().getValue());
1316
    }
1317
    else if (widget == ui->spiralRotation) {
1318
        spiral->Rotations.setValue(ui->spiralRotation->value());
1319
    }
1320
    else if (widget == ui->spiralRadius) {
1321
        spiral->Radius.setValue(ui->spiralRadius->value().getValue());
1322
    }
1323

1324
    spiral->recomputeFeature();
1325
}
1326

1327
// ----------------------------------------------------------------------------
1328

1329
CirclePrimitive::CirclePrimitive(std::shared_ptr<Ui_DlgPrimitives> ui, Part::Circle* feature)
1330
    : AbstractPrimitive(feature)
1331
    , ui(ui)
1332
{
1333
    ui->circleRadius->setRange(0, INT_MAX);
1334
    ui->circleAngle1->setRange(0, 360);
1335
    ui->circleAngle2->setRange(0, 360);
1336

1337
    if (feature) {
1338
        ui->circleRadius->setValue(feature->Radius.getQuantityValue());
1339
        ui->circleRadius->bind(feature->Radius);
1340
        ui->circleAngle1->setValue(feature->Angle1.getQuantityValue());
1341
        ui->circleAngle1->bind(feature->Angle1);
1342
        ui->circleAngle2->setValue(feature->Angle2.getQuantityValue());
1343
        ui->circleAngle2->bind(feature->Angle2);
1344

1345
        QSignalMapper* mapper = new QSignalMapper(this);
1346
        connectSignalMapper(mapper);
1347
        connectMapSignalMapper(ui->circleRadius, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1348
        connectMapSignalMapper(ui->circleAngle1, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1349
        connectMapSignalMapper(ui->circleAngle2, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1350
    }
1351
}
1352

1353
const char* CirclePrimitive::getDefaultName() const
1354
{
1355
    return "Circle";
1356
}
1357

1358
QString CirclePrimitive::create(const QString& objectName, const QString& placement) const
1359
{
1360
    return QString::fromLatin1(
1361
        "App.ActiveDocument.addObject(\"Part::Circle\",\"%1\")\n"
1362
        "App.ActiveDocument.%1.Radius='%2'\n"
1363
        "App.ActiveDocument.%1.Angle1='%3'\n"
1364
        "App.ActiveDocument.%1.Angle2='%4'\n"
1365
        "App.ActiveDocument.%1.Placement=%5\n"
1366
        "App.ActiveDocument.%1.Label='%6'\n")
1367
        .arg(objectName,
1368
             ui->circleRadius->value().getSafeUserString(),
1369
             ui->circleAngle1->value().getSafeUserString(),
1370
             ui->circleAngle2->value().getSafeUserString(),
1371
             placement,
1372
             DlgPrimitives::tr("Circle"));
1373
}
1374

1375
QString CirclePrimitive::change(const QString& objectName, const QString& placement) const
1376
{
1377
    return QString::fromLatin1(
1378
        "%1.Radius='%2'\n"
1379
        "%1.Angle1='%3'\n"
1380
        "%1.Angle2='%4'\n"
1381
        "%1.Placement=%5\n")
1382
        .arg(objectName,
1383
             ui->circleRadius->value().getSafeUserString(),
1384
             ui->circleAngle1->value().getSafeUserString(),
1385
             ui->circleAngle2->value().getSafeUserString(),
1386
             placement);
1387
}
1388

1389
void CirclePrimitive::changeValue(QObject* widget)
1390
{
1391
    if (featurePtr.expired())
1392
        return;
1393
    Part::Circle* circle = featurePtr.get<Part::Circle>();
1394
    if (widget == ui->circleRadius) {
1395
        circle->Radius.setValue(ui->circleRadius->value().getValue());
1396
    }
1397
    else if (widget == ui->circleAngle1) {
1398
        circle->Angle1.setValue(ui->circleAngle1->value().getValue());
1399
    }
1400
    else if (widget == ui->circleAngle2) {
1401
        circle->Angle2.setValue(ui->circleAngle2->value().getValue());
1402
    }
1403

1404
    circle->recomputeFeature();
1405
}
1406

1407
// ----------------------------------------------------------------------------
1408

1409
EllipsePrimitive::EllipsePrimitive(std::shared_ptr<Ui_DlgPrimitives> ui, Part::Ellipse* feature)
1410
    : AbstractPrimitive(feature)
1411
    , ui(ui)
1412
{
1413
    ui->ellipseMajorRadius->setRange(0, INT_MAX);
1414
    ui->ellipseMinorRadius->setRange(0, INT_MAX);
1415
    ui->ellipseAngle1->setRange(0, 360);
1416
    ui->ellipseAngle2->setRange(0, 360);
1417

1418
    if (feature) {
1419
        ui->ellipseMajorRadius->setValue(feature->MajorRadius.getQuantityValue());
1420
        ui->ellipseMajorRadius->bind(feature->MajorRadius);
1421
        ui->ellipseMinorRadius->setValue(feature->MinorRadius.getQuantityValue());
1422
        ui->ellipseMinorRadius->bind(feature->MinorRadius);
1423
        ui->ellipseAngle1->setValue(feature->Angle1.getQuantityValue());
1424
        ui->ellipseAngle1->bind(feature->Angle1);
1425
        ui->ellipseAngle2->setValue(feature->Angle2.getQuantityValue());
1426
        ui->ellipseAngle2->bind(feature->Angle2);
1427

1428
        QSignalMapper* mapper = new QSignalMapper(this);
1429
        connectSignalMapper(mapper);
1430
        connectMapSignalMapper(ui->ellipseMajorRadius, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1431
        connectMapSignalMapper(ui->ellipseMinorRadius, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1432
        connectMapSignalMapper(ui->ellipseAngle1, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1433
        connectMapSignalMapper(ui->ellipseAngle2, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1434
    }
1435
}
1436

1437
const char* EllipsePrimitive::getDefaultName() const
1438
{
1439
    return "Ellipse";
1440
}
1441

1442
QString EllipsePrimitive::create(const QString& objectName, const QString& placement) const
1443
{
1444
    return QString::fromLatin1(
1445
        "App.ActiveDocument.addObject(\"Part::Ellipse\",\"%1\")\n"
1446
        "App.ActiveDocument.%1.MajorRadius='%2'\n"
1447
        "App.ActiveDocument.%1.MinorRadius='%3'\n"
1448
        "App.ActiveDocument.%1.Angle1='%4'\n"
1449
        "App.ActiveDocument.%1.Angle2='%5'\n"
1450
        "App.ActiveDocument.%1.Placement=%6\n"
1451
        "App.ActiveDocument.%1.Label='%7'\n")
1452
        .arg(objectName,
1453
             ui->ellipseMajorRadius->value().getSafeUserString(),
1454
             ui->ellipseMinorRadius->value().getSafeUserString(),
1455
             ui->ellipseAngle1->value().getSafeUserString(),
1456
             ui->ellipseAngle2->value().getSafeUserString(),
1457
             placement,
1458
             DlgPrimitives::tr("Ellipse"));
1459
}
1460

1461
QString EllipsePrimitive::change(const QString& objectName, const QString& placement) const
1462
{
1463
    return QString::fromLatin1(
1464
        "%1.MajorRadius='%2'\n"
1465
        "%1.MinorRadius='%3'\n"
1466
        "%1.Angle1='%4'\n"
1467
        "%1.Angle2='%5'\n"
1468
        "%1.Placement=%6\n")
1469
        .arg(objectName,
1470
             ui->ellipseMajorRadius->value().getSafeUserString(),
1471
             ui->ellipseMinorRadius->value().getSafeUserString(),
1472
             ui->ellipseAngle1->value().getSafeUserString(),
1473
             ui->ellipseAngle2->value().getSafeUserString(),
1474
             placement);
1475
}
1476

1477
void EllipsePrimitive::changeValue(QObject* widget)
1478
{
1479
    if (featurePtr.expired())
1480
        return;
1481
    Part::Ellipse* ell = featurePtr.get<Part::Ellipse>();
1482
    if (widget == ui->ellipseMajorRadius) {
1483
        ell->MajorRadius.setValue(ui->ellipseMajorRadius->value().getValue());
1484
    }
1485
    else if (widget == ui->ellipseMinorRadius) {
1486
        ell->MinorRadius.setValue(ui->ellipseMinorRadius->value().getValue());
1487
    }
1488
    else if (widget == ui->ellipseAngle1) {
1489
        ell->Angle1.setValue(ui->ellipseAngle1->value().getValue());
1490
    }
1491
    else if (widget == ui->ellipseAngle2) {
1492
        ell->Angle2.setValue(ui->ellipseAngle2->value().getValue());
1493
    }
1494

1495
    ell->recomputeFeature();
1496
}
1497

1498
// ----------------------------------------------------------------------------
1499

1500
PolygonPrimitive::PolygonPrimitive(std::shared_ptr<Ui_DlgPrimitives> ui, Part::RegularPolygon* feature)
1501
    : AbstractPrimitive(feature)
1502
    , ui(ui)
1503
{
1504
    ui->regularPolygonCircumradius->setRange(0, INT_MAX);
1505

1506
    if (feature) {
1507
        ui->regularPolygonPolygon->setValue(feature->Polygon.getValue());
1508
        ui->regularPolygonCircumradius->setValue(feature->Circumradius.getQuantityValue());
1509
        ui->regularPolygonCircumradius->bind(feature->Circumradius);
1510

1511
        QSignalMapper* mapper = new QSignalMapper(this);
1512
        connectSignalMapper(mapper);
1513
        connectMapSignalMapper(ui->regularPolygonPolygon, qOverload<int>(&QSpinBox::valueChanged), mapper);
1514
        connectMapSignalMapper(ui->regularPolygonCircumradius, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1515
    }
1516
}
1517

1518
const char* PolygonPrimitive::getDefaultName() const
1519
{
1520
    return "RegularPolygon";
1521
}
1522

1523
QString PolygonPrimitive::create(const QString& objectName, const QString& placement) const
1524
{
1525
    return QString::fromLatin1(
1526
        "App.ActiveDocument.addObject(\"Part::RegularPolygon\",\"%1\")\n"
1527
        "App.ActiveDocument.%1.Polygon=%2\n"
1528
        "App.ActiveDocument.%1.Circumradius='%3'\n"
1529
        "App.ActiveDocument.%1.Placement=%4\n"
1530
        "App.ActiveDocument.%1.Label='%5'\n")
1531
        .arg(objectName,
1532
             QString::number(ui->regularPolygonPolygon->value()),
1533
             ui->regularPolygonCircumradius->value().getSafeUserString(),
1534
             placement,
1535
             DlgPrimitives::tr("Regular polygon"));
1536
}
1537

1538
QString PolygonPrimitive::change(const QString& objectName, const QString& placement) const
1539
{
1540
    return QString::fromLatin1(
1541
        "%1.Polygon=%2\n"
1542
        "%1.Circumradius='%3'\n"
1543
        "%1.Placement=%4\n")
1544
        .arg(objectName,
1545
             QString::number(ui->regularPolygonPolygon->value()),
1546
             ui->regularPolygonCircumradius->value().getSafeUserString(),
1547
             placement);
1548
}
1549

1550
void PolygonPrimitive::changeValue(QObject* widget)
1551
{
1552
    if (featurePtr.expired())
1553
        return;
1554
    Part::RegularPolygon* poly = featurePtr.get<Part::RegularPolygon>();
1555
    if (widget == ui->regularPolygonPolygon) {
1556
        poly->Polygon.setValue(ui->regularPolygonPolygon->value());
1557
    }
1558
    else if (widget == ui->regularPolygonCircumradius) {
1559
        poly->Circumradius.setValue(ui->regularPolygonCircumradius->value().getValue());
1560
    }
1561

1562
    poly->recomputeFeature();
1563
}
1564

1565
// ----------------------------------------------------------------------------
1566

1567
LinePrimitive::LinePrimitive(std::shared_ptr<Ui_DlgPrimitives> ui, Part::Line* feature)
1568
    : AbstractPrimitive(feature)
1569
    , ui(ui)
1570
{
1571
    ui->edgeX1->setMaximum(INT_MAX);
1572
    ui->edgeX1->setMinimum(INT_MIN);
1573
    ui->edgeY1->setMaximum(INT_MAX);
1574
    ui->edgeY1->setMinimum(INT_MIN);
1575
    ui->edgeZ1->setMaximum(INT_MAX);
1576
    ui->edgeZ1->setMinimum(INT_MIN);
1577
    ui->edgeX2->setMaximum(INT_MAX);
1578
    ui->edgeX2->setMinimum(INT_MIN);
1579
    ui->edgeY2->setMaximum(INT_MAX);
1580
    ui->edgeY2->setMinimum(INT_MIN);
1581
    ui->edgeZ2->setMaximum(INT_MAX);
1582
    ui->edgeZ2->setMinimum(INT_MIN);
1583

1584
    if (feature) {
1585
        ui->edgeX1->setValue(feature->X1.getQuantityValue());
1586
        ui->edgeX1->bind(feature->X1);
1587
        ui->edgeY1->setValue(feature->Y1.getQuantityValue());
1588
        ui->edgeY1->bind(feature->Y1);
1589
        ui->edgeZ1->setValue(feature->Z1.getQuantityValue());
1590
        ui->edgeZ1->bind(feature->Z1);
1591
        ui->edgeX2->setValue(feature->X2.getQuantityValue());
1592
        ui->edgeX2->bind(feature->X2);
1593
        ui->edgeY2->setValue(feature->Y2.getQuantityValue());
1594
        ui->edgeY2->bind(feature->Y2);
1595
        ui->edgeZ2->setValue(feature->Z2.getQuantityValue());
1596
        ui->edgeZ2->bind(feature->Z2);
1597

1598
        QSignalMapper* mapper = new QSignalMapper(this);
1599
        connectSignalMapper(mapper);
1600
        connectMapSignalMapper(ui->edgeX1, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1601
        connectMapSignalMapper(ui->edgeY1, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1602
        connectMapSignalMapper(ui->edgeZ1, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1603
        connectMapSignalMapper(ui->edgeX2, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1604
        connectMapSignalMapper(ui->edgeY2, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1605
        connectMapSignalMapper(ui->edgeZ2, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1606
    }
1607
}
1608

1609
const char* LinePrimitive::getDefaultName() const
1610
{
1611
    return "Line";
1612
}
1613

1614
QString LinePrimitive::create(const QString& objectName, const QString& placement) const
1615
{
1616
    return QString::fromLatin1(
1617
        "App.ActiveDocument.addObject(\"Part::Line\",\"%1\")\n"
1618
        "App.ActiveDocument.%1.X1='%2'\n"
1619
        "App.ActiveDocument.%1.Y1='%3'\n"
1620
        "App.ActiveDocument.%1.Z1='%4'\n"
1621
        "App.ActiveDocument.%1.X2='%5'\n"
1622
        "App.ActiveDocument.%1.Y2='%6'\n"
1623
        "App.ActiveDocument.%1.Z2='%7'\n"
1624
        "App.ActiveDocument.%1.Placement=%8\n"
1625
        "App.ActiveDocument.%1.Label='%9'\n")
1626
        .arg(objectName,
1627
             ui->edgeX1->value().getSafeUserString(),
1628
             ui->edgeY1->value().getSafeUserString(),
1629
             ui->edgeZ1->value().getSafeUserString(),
1630
             ui->edgeX2->value().getSafeUserString(),
1631
             ui->edgeY2->value().getSafeUserString(),
1632
             ui->edgeZ2->value().getSafeUserString(),
1633
             placement,
1634
             DlgPrimitives::tr("Line"));
1635
}
1636

1637
QString LinePrimitive::change(const QString& objectName, const QString& placement) const
1638
{
1639
    return QString::fromLatin1(
1640
        "%1.X1='%2'\n"
1641
        "%1.Y1='%3'\n"
1642
        "%1.Z1='%4'\n"
1643
        "%1.X2='%5'\n"
1644
        "%1.Y2='%6'\n"
1645
        "%1.Z2='%7'\n"
1646
        "%1.Placement=%8\n")
1647
        .arg(objectName,
1648
             ui->edgeX1->value().getSafeUserString(),
1649
             ui->edgeY1->value().getSafeUserString(),
1650
             ui->edgeZ1->value().getSafeUserString(),
1651
             ui->edgeX2->value().getSafeUserString(),
1652
             ui->edgeY2->value().getSafeUserString(),
1653
             ui->edgeZ2->value().getSafeUserString(),
1654
             placement);
1655
}
1656

1657
void LinePrimitive::changeValue(QObject* widget)
1658
{
1659
    if (featurePtr.expired())
1660
        return;
1661
    Part::Line* line = featurePtr.get<Part::Line>();
1662
    if (widget == ui->edgeX1) {
1663
        line->X1.setValue(ui->edgeX1->value().getValue());
1664
    }
1665
    else if (widget == ui->edgeY1) {
1666
        line->Y1.setValue(ui->edgeY1->value().getValue());
1667
    }
1668
    else if (widget == ui->edgeZ1) {
1669
        line->Z1.setValue(ui->edgeZ1->value().getValue());
1670
    }
1671
    else if (widget == ui->edgeX2) {
1672
        line->X2.setValue(ui->edgeX2->value().getValue());
1673
    }
1674
    else if (widget == ui->edgeY2) {
1675
        line->Y2.setValue(ui->edgeY2->value().getValue());
1676
    }
1677
    else if (widget == ui->edgeZ2) {
1678
        line->Z2.setValue(ui->edgeZ2->value().getValue());
1679
    }
1680

1681
    line->recomputeFeature();
1682
}
1683

1684
// ----------------------------------------------------------------------------
1685

1686
VertexPrimitive::VertexPrimitive(std::shared_ptr<Ui_DlgPrimitives> ui, Part::Vertex* feature)
1687
    : AbstractPrimitive(feature)
1688
    , ui(ui)
1689
{
1690
    ui->vertexX->setMaximum(INT_MAX);
1691
    ui->vertexY->setMaximum(INT_MAX);
1692
    ui->vertexZ->setMaximum(INT_MAX);
1693
    ui->vertexX->setMinimum(INT_MIN);
1694
    ui->vertexY->setMinimum(INT_MIN);
1695
    ui->vertexZ->setMinimum(INT_MIN);
1696

1697
    if (feature) {
1698
        ui->vertexX->setValue(feature->X.getQuantityValue());
1699
        ui->vertexX->bind(feature->X);
1700
        ui->vertexY->setValue(feature->Y.getQuantityValue());
1701
        ui->vertexY->bind(feature->Y);
1702
        ui->vertexZ->setValue(feature->Z.getQuantityValue());
1703
        ui->vertexZ->bind(feature->Z);
1704

1705
        QSignalMapper* mapper = new QSignalMapper(this);
1706
        connectSignalMapper(mapper);
1707
        connectMapSignalMapper(ui->vertexX, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1708
        connectMapSignalMapper(ui->vertexY, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1709
        connectMapSignalMapper(ui->vertexZ, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), mapper);
1710
    }
1711
}
1712

1713
const char* VertexPrimitive::getDefaultName() const
1714
{
1715
    return "Vertex";
1716
}
1717

1718
QString VertexPrimitive::create(const QString& objectName, const QString& placement) const
1719
{
1720
    return QString::fromLatin1(
1721
        "App.ActiveDocument.addObject(\"Part::Vertex\",\"%1\")\n"
1722
        "App.ActiveDocument.%1.X='%2'\n"
1723
        "App.ActiveDocument.%1.Y='%3'\n"
1724
        "App.ActiveDocument.%1.Z='%4'\n"
1725
        "App.ActiveDocument.%1.Placement=%5\n"
1726
        "App.ActiveDocument.%1.Label='%6'\n")
1727
        .arg(objectName,
1728
             ui->vertexX->value().getSafeUserString(),
1729
             ui->vertexY->value().getSafeUserString(),
1730
             ui->vertexZ->value().getSafeUserString(),
1731
             placement,
1732
             DlgPrimitives::tr("Vertex"));
1733
}
1734

1735
QString VertexPrimitive::change(const QString& objectName, const QString& placement) const
1736
{
1737
    return QString::fromLatin1(
1738
        "%1.X='%2'\n"
1739
        "%1.Y='%3'\n"
1740
        "%1.Z='%4'\n"
1741
        "%1.Placement=%5\n")
1742
        .arg(objectName,
1743
             ui->vertexX->value().getSafeUserString(),
1744
             ui->vertexY->value().getSafeUserString(),
1745
             ui->vertexZ->value().getSafeUserString(),
1746
             placement);
1747
}
1748

1749
void VertexPrimitive::changeValue(QObject* widget)
1750
{
1751
    if (featurePtr.expired())
1752
        return;
1753
    Part::Vertex* v = featurePtr.get<Part::Vertex>();
1754
    if (widget == ui->vertexX) {
1755
        v->X.setValue(ui->vertexX->value().getValue());
1756
    }
1757
    else if (widget == ui->vertexY) {
1758
        v->Y.setValue(ui->vertexY->value().getValue());
1759
    }
1760
    else if (widget == ui->vertexZ) {
1761
        v->Z.setValue(ui->vertexZ->value().getValue());
1762
    }
1763

1764
    v->recomputeFeature();
1765
}
1766

1767
// ----------------------------------------------------------------------------
1768

1769
/* TRANSLATOR PartGui::DlgPrimitives */
1770

1771
DlgPrimitives::DlgPrimitives(QWidget* parent, Part::Primitive* feature)
1772
  : QWidget(parent)
1773
  , ui(new Ui_DlgPrimitives)
1774
  , featurePtr(feature)
1775
{
1776
    ui->setupUi(this);
1777
    connect(ui->buttonCircleFromThreePoints, &QPushButton::clicked,
1778
            this, &DlgPrimitives::buttonCircleFromThreePoints);
1779
    Gui::Command::doCommand(Gui::Command::Doc, "from FreeCAD import Base");
1780
    Gui::Command::doCommand(Gui::Command::Doc, "import Part,PartGui");
1781

1782
    // must be in the same order as of the stacked widget
1783
    addPrimitive(std::make_shared<PlanePrimitive>(ui, dynamic_cast<Part::Plane*>(feature)));
1784
    addPrimitive(std::make_shared<BoxPrimitive>(ui, dynamic_cast<Part::Box*>(feature)));
1785
    addPrimitive(std::make_shared<CylinderPrimitive>(ui, dynamic_cast<Part::Cylinder*>(feature)));
1786
    addPrimitive(std::make_shared<ConePrimitive>(ui, dynamic_cast<Part::Cone*>(feature)));
1787
    addPrimitive(std::make_shared<SpherePrimitive>(ui, dynamic_cast<Part::Sphere*>(feature)));
1788
    addPrimitive(std::make_shared<EllipsoidPrimitive>(ui, dynamic_cast<Part::Ellipsoid*>(feature)));
1789
    addPrimitive(std::make_shared<TorusPrimitive>(ui, dynamic_cast<Part::Torus*>(feature)));
1790
    addPrimitive(std::make_shared<PrismPrimitive>(ui, dynamic_cast<Part::Prism*>(feature)));
1791
    addPrimitive(std::make_shared<WedgePrimitive>(ui, dynamic_cast<Part::Wedge*>(feature)));
1792
    addPrimitive(std::make_shared<HelixPrimitive>(ui, dynamic_cast<Part::Helix*>(feature)));
1793
    addPrimitive(std::make_shared<SpiralPrimitive>(ui, dynamic_cast<Part::Spiral*>(feature)));
1794
    addPrimitive(std::make_shared<CirclePrimitive>(ui, dynamic_cast<Part::Circle*>(feature)));
1795
    addPrimitive(std::make_shared<EllipsePrimitive>(ui, dynamic_cast<Part::Ellipse*>(feature)));
1796
    addPrimitive(std::make_shared<VertexPrimitive>(ui, dynamic_cast<Part::Vertex*>(feature)));
1797
    addPrimitive(std::make_shared<LinePrimitive>(ui, dynamic_cast<Part::Line*>(feature)));
1798
    addPrimitive(std::make_shared<PolygonPrimitive>(ui, dynamic_cast<Part::RegularPolygon*>(feature)));
1799

1800
    if (feature) {
1801
        activatePage();
1802
    }
1803
}
1804

1805
/*
1806
 *  Destroys the object and frees any allocated resources
1807
 */
1808
DlgPrimitives::~DlgPrimitives() = default;
1809

1810
void DlgPrimitives::activatePage()
1811
{
1812
    int index = findIndexOfValidPrimitive();
1813
    ui->PrimitiveTypeCB->setCurrentIndex(index);
1814
    ui->widgetStack2->setCurrentIndex(index);
1815
    ui->PrimitiveTypeCB->setDisabled(true);
1816
}
1817

1818
void DlgPrimitives::addPrimitive(std::shared_ptr<AbstractPrimitive> prim)
1819
{
1820
    primitive.push_back(prim);
1821
}
1822

1823
std::shared_ptr<AbstractPrimitive> DlgPrimitives::getPrimitive(int index) const
1824
{
1825
    return primitive.at(index);
1826
}
1827

1828
int DlgPrimitives::findIndexOfValidPrimitive() const
1829
{
1830
    return std::distance(primitive.begin(), std::find_if(primitive.begin(), primitive.end(),
1831
                         [](std::shared_ptr<AbstractPrimitive> prim) {
1832
        return prim->hasValidPrimitive();
1833
    }));
1834
}
1835

1836
void DlgPrimitives::pickCallback(void * ud, SoEventCallback * n)
1837
{
1838
    const SoMouseButtonEvent * mbe = static_cast<const SoMouseButtonEvent*>(n->getEvent());
1839
    Picker* pick = static_cast<Picker*>(ud);
1840
    if (pick->exitCode >= 0)
1841
        pick->loop.exit(pick->exitCode);
1842

1843
    // Mark all incoming mouse button events as handled, especially, to deactivate the selection node
1844
    n->setHandled();
1845
    if (mbe->getButton() == SoMouseButtonEvent::BUTTON1) {
1846
        if (mbe->getState() == SoButtonEvent::DOWN) {
1847
            const SoPickedPoint * point = n->getPickedPoint();
1848
            if (point) {
1849
                if (pick->pickedPoint(point)) {
1850
                    pick->exitCode = 0;
1851
                }
1852
            }
1853
        }
1854
    }
1855
    else if (mbe->getButton() == SoMouseButtonEvent::BUTTON2) {
1856
        if (mbe->getState() == SoButtonEvent::UP) {
1857
            pick->loop.exit(1);
1858
        }
1859
    }
1860
}
1861

1862
void DlgPrimitives::executeCallback(Picker* p)
1863
{
1864
    Gui::Document* doc = Gui::Application::Instance->activeDocument();
1865
    if (!doc) {
1866
        return;
1867
    }
1868

1869
    Gui::View3DInventor* view = static_cast<Gui::View3DInventor*>(doc->getActiveView());
1870
    if (view) {
1871
        Gui::View3DInventorViewer* viewer = view->getViewer();
1872
        if (!viewer->isEditing()) {
1873
            viewer->setEditing(true);
1874
            viewer->setRedirectToSceneGraph(true);
1875
            SoNode* root = viewer->getSceneGraph();
1876
            int mode = 0;
1877
            if (root && root->getTypeId().isDerivedFrom(Gui::SoFCUnifiedSelection::getClassTypeId())) {
1878
                mode = static_cast<Gui::SoFCUnifiedSelection*>(root)->selectionMode.getValue();
1879
                static_cast<Gui::SoFCUnifiedSelection*>(root)->selectionMode.setValue(Gui::SoFCUnifiedSelection::OFF);
1880
            }
1881
            viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), pickCallback, p);
1882
            this->setDisabled(true);
1883
            int ret = p->loop.exec();
1884
            if (root && root->getTypeId().isDerivedFrom(Gui::SoFCUnifiedSelection::getClassTypeId()))
1885
                static_cast<Gui::SoFCUnifiedSelection*>(root)->selectionMode.setValue(mode);
1886
            this->setEnabled(true);
1887
            viewer->setEditing(false);
1888
            viewer->setRedirectToSceneGraph(false);
1889
            viewer->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), pickCallback, p);
1890

1891
            if (ret == 0) {
1892
                p->createPrimitive(this, ui->PrimitiveTypeCB->currentText(), doc);
1893
            }
1894
        }
1895
    }
1896
}
1897

1898
void DlgPrimitives::buttonCircleFromThreePoints()
1899
{
1900
    CircleFromThreePoints pp;
1901
    executeCallback(&pp);
1902
}
1903

1904
void DlgPrimitives::tryCreatePrimitive(const QString& placement)
1905
{
1906
    QString cmd;
1907
    QString name;
1908
    App::Document* doc = App::GetApplication().getActiveDocument();
1909
    if (!doc) {
1910
        QMessageBox::warning(this, tr("Create %1")
1911
            .arg(ui->PrimitiveTypeCB->currentText()), tr("No active document"));
1912
        return;
1913
    }
1914

1915
    std::shared_ptr<AbstractPrimitive> primitive = getPrimitive(ui->PrimitiveTypeCB->currentIndex());
1916
    name = QString::fromLatin1(doc->getUniqueObjectName(primitive->getDefaultName()).c_str());
1917
    cmd = primitive->create(name, placement);
1918

1919
    // Execute the Python block
1920
    QString prim = tr("Create %1").arg(ui->PrimitiveTypeCB->currentText());
1921
    Gui::Application::Instance->activeDocument()->openCommand(prim.toUtf8());
1922
    Gui::Command::runCommand(Gui::Command::Doc, cmd.toUtf8());
1923
    Gui::Command::runCommand(Gui::Command::Doc, getAutoGroupCommandStr(name).toUtf8());
1924
    Gui::Application::Instance->activeDocument()->commitCommand();
1925
    Gui::Command::runCommand(Gui::Command::Doc, "App.ActiveDocument.recompute()");
1926
    Gui::Command::runCommand(Gui::Command::Gui, "Gui.SendMsgToActiveView(\"ViewFit\")");
1927
}
1928

1929
void DlgPrimitives::createPrimitive(const QString& placement)
1930
{
1931
    try {
1932
        tryCreatePrimitive(placement);
1933
    }
1934
    catch (const std::exception& e) {
1935
        QMessageBox::warning(this, tr("Create %1")
1936
            .arg(ui->PrimitiveTypeCB->currentText()), QCoreApplication::translate("Exception", e.what()));
1937
    }
1938
    catch (const Base::PyException& e) {
1939
        QMessageBox::warning(this, tr("Create %1")
1940
            .arg(ui->PrimitiveTypeCB->currentText()), QCoreApplication::translate("Exception", e.what()));
1941
    }
1942
}
1943

1944
void DlgPrimitives::acceptChanges(const QString& placement)
1945
{
1946
    App::Document* doc = featurePtr->getDocument();
1947
    QString objectName = QString::fromLatin1("App.getDocument(\"%1\").%2")
1948
                         .arg(QString::fromLatin1(doc->getName()),
1949
                              QString::fromLatin1(featurePtr->getNameInDocument()));
1950

1951
    // read values from the properties
1952
    std::shared_ptr<AbstractPrimitive> primitive = getPrimitive(ui->PrimitiveTypeCB->currentIndex());
1953
    QString command = primitive->change(objectName, placement);
1954

1955
    // execute command, a transaction is already opened
1956
    Gui::Command::runCommand(Gui::Command::App, command.toUtf8());
1957
}
1958

1959
void DlgPrimitives::accept(const QString& placement)
1960
{
1961
    if (featurePtr.expired())
1962
        return;
1963
    App::Document* doc = featurePtr->getDocument();
1964
    acceptChanges(placement);
1965
    doc->recompute();
1966
    // commit undo command
1967
    doc->commitTransaction();
1968
}
1969

1970
void DlgPrimitives::reject()
1971
{
1972
    if (featurePtr.expired())
1973
        return;
1974
    App::Document* doc = featurePtr->getDocument();
1975
    doc->abortTransaction();
1976
}
1977

1978
// ----------------------------------------------
1979

1980
/* TRANSLATOR PartGui::Location */
1981

1982
Location::Location(QWidget* parent, Part::Feature* feature)
1983
    : QWidget(parent)
1984
    , ui(new Ui_Location)
1985
    , featurePtr(feature)
1986
{
1987
    mode = 0;
1988
    ui->setupUi(this);
1989
    connect(ui->viewPositionButton, &QPushButton::clicked,
1990
            this, &Location::onViewPositionButton);
1991

1992
    ui->XPositionQSB->setUnit(Base::Unit::Length);
1993
    ui->YPositionQSB->setUnit(Base::Unit::Length);
1994
    ui->ZPositionQSB->setUnit(Base::Unit::Length);
1995
    ui->AngleQSB->setUnit(Base::Unit::Angle);
1996

1997
    // fill location widget if object already exists
1998
    if (feature) {
1999
        setPlacement(feature);
2000
        bindExpressions(feature);
2001
        connectSignals();
2002
    }
2003
}
2004

2005
Location::~Location()
2006
{
2007
    // no need to delete child widgets, Qt does it all for us
2008
    if (!this->activeView.isNull()) {
2009
        Gui::View3DInventorViewer* viewer = static_cast<Gui::View3DInventor*>
2010
            (this->activeView.data())->getViewer();
2011
        viewer->setEditing(false);
2012
        viewer->setRedirectToSceneGraph(false);
2013
        viewer->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), pickCallback,this);
2014
        SoNode* root = viewer->getSceneGraph();
2015
        if (root && root->getTypeId().isDerivedFrom(Gui::SoFCUnifiedSelection::getClassTypeId()))
2016
            static_cast<Gui::SoFCUnifiedSelection*>(root)->selectionMode.setValue(this->mode);
2017
    }
2018
}
2019

2020
void Location::setPlacement(Part::Feature* feature)
2021
{
2022
    // get the placement values
2023
    auto placement = feature->Placement.getValue();
2024

2025
    auto position = placement.getPosition();
2026
    ui->XPositionQSB->setValue(position.x);
2027
    ui->YPositionQSB->setValue(position.y);
2028
    ui->ZPositionQSB->setValue(position.z);
2029

2030
    double rotationAngle;
2031
    Base::Vector3d rotationAxes;
2032
    auto rotation = placement.getRotation();
2033
    rotation.getRawValue(rotationAxes, rotationAngle);
2034
    ui->XDirectionEdit->setValue(rotationAxes.x);
2035
    ui->YDirectionEdit->setValue(rotationAxes.y);
2036
    ui->ZDirectionEdit->setValue(rotationAxes.z);
2037
    // the angle is rad, transform it for display to degrees
2038
    ui->AngleQSB->setValue(Base::toDegrees<double>(rotationAngle));
2039
}
2040

2041
void Location::bindExpressions(Part::Feature* feature)
2042
{
2043
    ui->XPositionQSB->bind(App::ObjectIdentifier::parse(feature, std::string("Placement.Base.x")));
2044
    ui->YPositionQSB->bind(App::ObjectIdentifier::parse(feature, std::string("Placement.Base.y")));
2045
    ui->ZPositionQSB->bind(App::ObjectIdentifier::parse(feature, std::string("Placement.Base.z")));
2046
    ui->XDirectionEdit->bind(App::ObjectIdentifier::parse(feature, std::string("Placement.Rotation.Axis.x")));
2047
    ui->YDirectionEdit->bind(App::ObjectIdentifier::parse(feature, std::string("Placement.Rotation.Axis.y")));
2048
    ui->ZDirectionEdit->bind(App::ObjectIdentifier::parse(feature, std::string("Placement.Rotation.Axis.z")));
2049
    ui->AngleQSB->bind(App::ObjectIdentifier::parse(feature, std::string("Placement.Rotation.Angle")));
2050
}
2051

2052
void Location::connectSignals()
2053
{
2054
    connect(ui->XPositionQSB, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), this, &Location::onPlacementChanged);
2055
    connect(ui->YPositionQSB, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), this, &Location::onPlacementChanged);
2056
    connect(ui->ZPositionQSB, qOverload<double>(&Gui::QuantitySpinBox::valueChanged), this, &Location::onPlacementChanged);
2057
    connect(ui->AngleQSB,     qOverload<double>(&Gui::QuantitySpinBox::valueChanged), this, &Location::onPlacementChanged);
2058
    connect(ui->XDirectionEdit, qOverload<double>(&Gui::DoubleSpinBox::valueChanged), this, &Location::onPlacementChanged);
2059
    connect(ui->YDirectionEdit, qOverload<double>(&Gui::DoubleSpinBox::valueChanged), this, &Location::onPlacementChanged);
2060
    connect(ui->ZDirectionEdit, qOverload<double>(&Gui::DoubleSpinBox::valueChanged), this, &Location::onPlacementChanged);
2061
}
2062

2063
void Location::onPlacementChanged()
2064
{
2065
    App::GeoFeature* geom = featurePtr.get<App::GeoFeature>();
2066
    if (!geom)
2067
        return;
2068

2069
    // read dialog values
2070
    Base::Vector3d loc;
2071
    loc.x = ui->XPositionQSB->rawValue();
2072
    loc.y = ui->YPositionQSB->rawValue();
2073
    loc.z = ui->ZPositionQSB->rawValue();
2074
    double angle = ui->AngleQSB->rawValue();
2075
    // the angle is displayed in degrees, transform it to rad
2076
    angle = Base::toRadians<double>(angle);
2077
    Base::Vector3d rot;
2078
    rot.x = ui->XDirectionEdit->value();
2079
    rot.y = ui->YDirectionEdit->value();
2080
    rot.z = ui->ZDirectionEdit->value();
2081

2082
    // set placement and rotation
2083
    Base::Placement placement;
2084
    Base::Rotation rotation(rot, angle);
2085
    placement.setPosition(loc);
2086
    placement.setRotation(rotation);
2087

2088
    // apply new placement to the feature
2089
    geom->Placement.setValue(placement);
2090
    geom->recomputeFeature();
2091
}
2092

2093
void Location::onViewPositionButton()
2094
{
2095
    Gui::Document* doc = Gui::Application::Instance->activeDocument();
2096
    if (!doc) {
2097
        return;
2098
    }
2099

2100
    Gui::View3DInventor* view = static_cast<Gui::View3DInventor*>(doc->getActiveView());
2101
    if (view && !this->activeView) {
2102
        Gui::View3DInventorViewer* viewer = view->getViewer();
2103
        if (!viewer->isEditing()) {
2104
            this->activeView = view;
2105
            viewer->setEditing(true);
2106
            viewer->setRedirectToSceneGraph(true);
2107
            viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), pickCallback, this);
2108
            SoNode* root = viewer->getSceneGraph();
2109
            if (root && root->getTypeId().isDerivedFrom(Gui::SoFCUnifiedSelection::getClassTypeId())) {
2110
                this->mode = static_cast<Gui::SoFCUnifiedSelection*>(root)->selectionMode.getValue();
2111
                static_cast<Gui::SoFCUnifiedSelection*>(root)->selectionMode.setValue(Gui::SoFCUnifiedSelection::OFF);
2112
            }
2113
        }
2114
     }
2115
}
2116

2117
void Location::pickCallback(void * ud, SoEventCallback * n)
2118
{
2119
    const SoMouseButtonEvent * mbe = static_cast<const SoMouseButtonEvent*>(n->getEvent());
2120
    Gui::View3DInventorViewer* view  = static_cast<Gui::View3DInventorViewer*>(n->getUserData());
2121

2122
    // Mark all incoming mouse button events as handled, especially, to deactivate the selection node
2123
    n->getAction()->setHandled();
2124
    if (mbe->getButton() == SoMouseButtonEvent::BUTTON1) {
2125
        if (mbe->getState() == SoButtonEvent::DOWN) {
2126
            const SoPickedPoint * point = n->getPickedPoint();
2127
            if (point) {
2128
                SbVec3f pnt = point->getPoint();
2129
                SbVec3f nor = point->getNormal();
2130
                Location* dlg = static_cast<Location*>(ud);
2131
                dlg->ui->XPositionQSB->setValue(pnt[0]);
2132
                dlg->ui->YPositionQSB->setValue(pnt[1]);
2133
                dlg->ui->ZPositionQSB->setValue(pnt[2]);
2134
                dlg->ui->XDirectionEdit->setValue(nor[0]);
2135
                dlg->ui->YDirectionEdit->setValue(nor[1]);
2136
                dlg->ui->ZDirectionEdit->setValue(nor[2]);
2137
                n->setHandled();
2138
            }
2139
        }
2140
    }
2141
    else if (mbe->getButton() == SoMouseButtonEvent::BUTTON2) {
2142
        if (mbe->getState() == SoButtonEvent::UP) {
2143
            n->setHandled();
2144
            view->setEditing(false);
2145
            view->setRedirectToSceneGraph(false);
2146
            Location* dlg = static_cast<Location*>(ud);
2147
            dlg->activeView = nullptr;
2148
            view->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), pickCallback,ud);
2149
            SoNode* root = view->getSceneGraph();
2150
            if (root && root->getTypeId().isDerivedFrom(Gui::SoFCUnifiedSelection::getClassTypeId()))
2151
                static_cast<Gui::SoFCUnifiedSelection*>(root)->selectionMode.setValue(static_cast<Location*>(ud)->mode);
2152
        }
2153
    }
2154
}
2155

2156
QString Location::toPlacement() const
2157
{
2158
    // create a command to set the position and angle of the primitive object
2159

2160
    Base::Vector3d rot;
2161
    rot.x = ui->XDirectionEdit->value();
2162
    rot.y = ui->YDirectionEdit->value();
2163
    rot.z = ui->ZDirectionEdit->value();
2164

2165
    double angle = ui->AngleQSB->rawValue();
2166

2167
    Base::Vector3d loc;
2168
    loc.x = ui->XPositionQSB->rawValue();
2169
    loc.y = ui->YPositionQSB->rawValue();
2170
    loc.z = ui->ZPositionQSB->rawValue();
2171

2172
    return QString::fromLatin1("App.Placement(App.Vector(%1,%2,%3),App.Rotation(App.Vector(%4,%5,%6),%7))")
2173
        .arg(loc.x, 0, 'f', Base::UnitsApi::getDecimals())
2174
        .arg(loc.y, 0, 'f', Base::UnitsApi::getDecimals())
2175
        .arg(loc.z, 0, 'f', Base::UnitsApi::getDecimals())
2176
        .arg(rot.x, 0, 'f', Base::UnitsApi::getDecimals())
2177
        .arg(rot.y, 0, 'f', Base::UnitsApi::getDecimals())
2178
        .arg(rot.z, 0, 'f', Base::UnitsApi::getDecimals())
2179
        .arg(angle, 0, 'f', Base::UnitsApi::getDecimals());
2180
}
2181

2182
// ----------------------------------------------
2183

2184
/* TRANSLATOR PartGui::TaskPrimitives */
2185

2186
TaskPrimitives::TaskPrimitives()
2187
{
2188
    widget = new DlgPrimitives();
2189
    addTaskBox(widget);
2190

2191
    location = new Location();
2192
    addTaskBox(location);
2193
}
2194

2195
QDialogButtonBox::StandardButtons TaskPrimitives::getStandardButtons() const
2196
{
2197
    return QDialogButtonBox::Close|
2198
           QDialogButtonBox::Ok;
2199
}
2200

2201
void TaskPrimitives::modifyStandardButtons(QDialogButtonBox* box)
2202
{
2203
    QPushButton* btn = box->button(QDialogButtonBox::Ok);
2204
    btn->setText(QApplication::translate("PartGui::DlgPrimitives", "&Create"));
2205
}
2206

2207
bool TaskPrimitives::accept()
2208
{
2209
    widget->createPrimitive(location->toPlacement());
2210
    return false;
2211
}
2212

2213
bool TaskPrimitives::reject()
2214
{
2215
    return true;
2216
}
2217

2218
// ----------------------------------------------
2219

2220
/* TRANSLATOR PartGui::TaskPrimitivesEdit */
2221

2222
TaskPrimitivesEdit::TaskPrimitivesEdit(Part::Primitive* feature)
2223
{
2224
    // create and show dialog for the primitives
2225
    widget = new DlgPrimitives(nullptr, feature);
2226
    addTaskBox(widget);
2227

2228
    // create and show dialog for the location
2229
    location = new Location(nullptr, feature);
2230
    addTaskBox(location);
2231
}
2232

2233
QDialogButtonBox::StandardButtons TaskPrimitivesEdit::getStandardButtons() const
2234
{
2235
    return QDialogButtonBox::Cancel |
2236
        QDialogButtonBox::Ok;
2237
}
2238

2239
bool TaskPrimitivesEdit::accept()
2240
{
2241
    widget->accept(location->toPlacement());
2242
    std::string document = getDocumentName(); // needed because resetEdit() deletes this instance
2243
    Gui::Command::doCommand(Gui::Command::Gui, "Gui.getDocument('%s').resetEdit()", document.c_str());
2244
    return true;
2245
}
2246

2247
bool TaskPrimitivesEdit::reject()
2248
{
2249
    widget->reject();
2250
    std::string document = getDocumentName(); // needed because resetEdit() deletes this instance
2251
    Gui::Command::doCommand(Gui::Command::Gui, "Gui.getDocument('%s').resetEdit()", document.c_str());
2252
    return true;
2253
}
2254

2255
#include "moc_DlgPrimitives.cpp"
2256

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.