FreeCAD

Форк
0
/
Command.cpp 
520 строк · 18.1 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2006 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 <Inventor/events/SoMouseButtonEvent.h>
26
#include <QInputDialog>
27
#include <algorithm>
28
#endif
29

30
#include <App/Application.h>
31
#include <App/Document.h>
32
#include <Base/Exception.h>
33
#include <Base/Interpreter.h>
34
#include <Base/Tools.h>
35
#include <Base/UnitsApi.h>
36
#include <Gui/Application.h>
37
#include <Gui/Command.h>
38
#include <Gui/Document.h>
39
#include <Gui/FileDialog.h>
40
#include <Gui/MainWindow.h>
41
#include <Gui/Selection.h>
42
#include <Gui/View3DInventor.h>
43
#include <Gui/View3DInventorViewer.h>
44
#include <Gui/ViewProviderDocumentObject.h>
45
#include <Gui/WaitCursor.h>
46

47
#include "../App/PointsFeature.h"
48
#include "../App/Properties.h"
49
#include "../App/Structured.h"
50
#include "../App/Tools.h"
51

52
#include "DlgPointsReadImp.h"
53
#include "ViewProvider.h"
54

55

56
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
57

58
//===========================================================================
59
// CmdPointsImport
60
//===========================================================================
61
DEF_STD_CMD_A(CmdPointsImport)
62

63
CmdPointsImport::CmdPointsImport()
64
    : Command("Points_Import")
65
{
66
    sAppModule = "Points";
67
    sGroup = QT_TR_NOOP("Points");
68
    sMenuText = QT_TR_NOOP("Import points...");
69
    sToolTipText = QT_TR_NOOP("Imports a point cloud");
70
    sWhatsThis = "Points_Import";
71
    sStatusTip = QT_TR_NOOP("Imports a point cloud");
72
    sPixmap = "Points_Import_Point_cloud";
73
}
74

75
void CmdPointsImport::activated(int iMsg)
76
{
77
    Q_UNUSED(iMsg);
78

79
    QString fn = Gui::FileDialog::getOpenFileName(
80
        Gui::getMainWindow(),
81
        QString(),
82
        QString(),
83
        QString::fromLatin1("%1 (*.asc *.pcd *.ply);;%2 (*.*)")
84
            .arg(QObject::tr("Point formats"), QObject::tr("All Files")));
85
    if (fn.isEmpty()) {
86
        return;
87
    }
88

89
    if (!fn.isEmpty()) {
90
        fn = Base::Tools::escapeEncodeFilename(fn);
91
        Gui::Document* doc = getActiveGuiDocument();
92
        openCommand(QT_TRANSLATE_NOOP("Command", "Import points"));
93
        addModule(Command::App, "Points");
94
        doCommand(Command::Doc,
95
                  "Points.insert(\"%s\", \"%s\")",
96
                  fn.toUtf8().data(),
97
                  doc->getDocument()->getName());
98
        commitCommand();
99

100
        updateActive();
101
    }
102
}
103

104
bool CmdPointsImport::isActive()
105
{
106
    if (getActiveGuiDocument()) {
107
        return true;
108
    }
109
    else {
110
        return false;
111
    }
112
}
113

114
DEF_STD_CMD_A(CmdPointsExport)
115

116
CmdPointsExport::CmdPointsExport()
117
    : Command("Points_Export")
118
{
119
    sAppModule = "Points";
120
    sGroup = QT_TR_NOOP("Points");
121
    sMenuText = QT_TR_NOOP("Export points...");
122
    sToolTipText = QT_TR_NOOP("Exports a point cloud");
123
    sWhatsThis = "Points_Export";
124
    sStatusTip = QT_TR_NOOP("Exports a point cloud");
125
    sPixmap = "Points_Export_Point_cloud";
126
}
127

128
void CmdPointsExport::activated(int iMsg)
129
{
130
    Q_UNUSED(iMsg);
131

132
    addModule(Command::App, "Points");
133
    std::vector<App::DocumentObject*> points =
134
        getSelection().getObjectsOfType(Points::Feature::getClassTypeId());
135
    for (auto point : points) {
136
        QString fn = Gui::FileDialog::getSaveFileName(
137
            Gui::getMainWindow(),
138
            QString(),
139
            QString(),
140
            QString::fromLatin1("%1 (*.asc *.pcd *.ply);;%2 (*.*)")
141
                .arg(QObject::tr("Point formats"), QObject::tr("All Files")));
142
        if (fn.isEmpty()) {
143
            break;
144
        }
145

146
        if (!fn.isEmpty()) {
147
            fn = Base::Tools::escapeEncodeFilename(fn);
148
            doCommand(Command::Doc,
149
                      "Points.export([App.ActiveDocument.%s], \"%s\")",
150
                      point->getNameInDocument(),
151
                      fn.toUtf8().data());
152
        }
153
    }
154
}
155

156
bool CmdPointsExport::isActive()
157
{
158
    return getSelection().countObjectsOfType(Points::Feature::getClassTypeId()) > 0;
159
}
160

161
DEF_STD_CMD_A(CmdPointsTransform)
162

163
CmdPointsTransform::CmdPointsTransform()
164
    : Command("Points_Transform")
165
{
166
    sAppModule = "Points";
167
    sGroup = QT_TR_NOOP("Points");
168
    sMenuText = QT_TR_NOOP("Transform Points");
169
    sToolTipText = QT_TR_NOOP("Test to transform a point cloud");
170
    sWhatsThis = "Points_Transform";
171
    sStatusTip = QT_TR_NOOP("Test to transform a point cloud");
172
    sPixmap = "Test1";
173
}
174

175
void CmdPointsTransform::activated(int iMsg)
176
{
177
    Q_UNUSED(iMsg);
178

179
    // This is a test command to transform a point cloud directly written in C++ (not Python)
180
    Base::Placement trans;
181
    trans.setRotation(Base::Rotation(Base::Vector3d(0.0, 0.0, 1.0), 1.570796));
182

183
    openCommand(QT_TRANSLATE_NOOP("Command", "Transform points"));
184
    // std::vector<App::DocumentObject*> points =
185
    // getSelection().getObjectsOfType(Points::Feature::getClassTypeId()); for
186
    // (std::vector<App::DocumentObject*>::const_iterator it = points.begin(); it != points.end();
187
    // ++it) {
188
    //     Base::Placement p = static_cast<Points::Feature*>(*it)->Placement.getValue();
189
    //     p._rot *= Base::Rotation(Base::Vector3d(0.0, 0.0, 1.0), 1.570796);
190
    //     static_cast<Points::Feature*>(*it)->Placement.setValue(p);
191
    // }
192
    commitCommand();
193
}
194

195
bool CmdPointsTransform::isActive()
196
{
197
    return getSelection().countObjectsOfType(Points::Feature::getClassTypeId()) > 0;
198
}
199

200
DEF_STD_CMD_A(CmdPointsConvert)
201

202
CmdPointsConvert::CmdPointsConvert()
203
    : Command("Points_Convert")
204
{
205
    sAppModule = "Points";
206
    sGroup = QT_TR_NOOP("Points");
207
    sMenuText = QT_TR_NOOP("Convert to points...");
208
    sToolTipText = QT_TR_NOOP("Convert to points");
209
    sWhatsThis = "Points_Convert";
210
    sStatusTip = QT_TR_NOOP("Convert to points");
211
    sPixmap = "Points_Convert";
212
}
213

214
void CmdPointsConvert::activated(int iMsg)
215
{
216
    Q_UNUSED(iMsg);
217
    double STD_OCC_TOLERANCE = 1e-6;
218

219
    int decimals = Base::UnitsApi::getDecimals();
220
    double tolerance_from_decimals = pow(10., -decimals);
221

222
    double minimal_tolerance =
223
        tolerance_from_decimals < STD_OCC_TOLERANCE ? STD_OCC_TOLERANCE : tolerance_from_decimals;
224

225
    bool ok;
226
    double tol = QInputDialog::getDouble(Gui::getMainWindow(),
227
                                         QObject::tr("Distance"),
228
                                         QObject::tr("Enter maximum distance:"),
229
                                         0.1,
230
                                         minimal_tolerance,
231
                                         10.0,
232
                                         decimals,
233
                                         &ok,
234
                                         Qt::MSWindowsFixedSizeDialogHint);
235
    if (!ok) {
236
        return;
237
    }
238

239
    Gui::WaitCursor wc;
240
    openCommand(QT_TRANSLATE_NOOP("Command", "Convert to points"));
241
    std::vector<App::GeoFeature*> geoObject = getSelection().getObjectsOfType<App::GeoFeature>();
242

243
    auto run_python = [](const std::vector<App::GeoFeature*>& geoObject, double tol) -> bool {
244
        Py::List list;
245
        for (auto it : geoObject) {
246
            const App::PropertyComplexGeoData* prop = it->getPropertyOfGeometry();
247
            if (prop) {
248
                list.append(Py::asObject(it->getPyObject()));
249
            }
250
        }
251

252
        if (list.size() > 0) {
253
            PyObject* module = PyImport_ImportModule("pointscommands.commands");
254
            if (!module) {
255
                throw Py::Exception();
256
            }
257

258
            Py::Module commands(module, true);
259
            commands.callMemberFunction("make_points_from_geometry",
260
                                        Py::TupleN(list, Py::Float(tol)));
261
            return true;
262
        }
263

264
        return false;
265
    };
266

267
    Base::PyGILStateLocker lock;
268
    try {
269
        if (run_python(geoObject, tol)) {
270
            commitCommand();
271
        }
272
        else {
273
            abortCommand();
274
        }
275
    }
276
    catch (const Py::Exception&) {
277
        abortCommand();
278
        Base::PyException e;
279
        e.ReportException();
280
    }
281
}
282

283
bool CmdPointsConvert::isActive()
284
{
285
    return getSelection().countObjectsOfType(Base::Type::fromName("App::GeoFeature")) > 0;
286
}
287

288
DEF_STD_CMD_A(CmdPointsPolyCut)
289

290
CmdPointsPolyCut::CmdPointsPolyCut()
291
    : Command("Points_PolyCut")
292
{
293
    sAppModule = "Points";
294
    sGroup = QT_TR_NOOP("Points");
295
    sMenuText = QT_TR_NOOP("Cut point cloud");
296
    sToolTipText = QT_TR_NOOP("Cuts a point cloud with a picked polygon");
297
    sWhatsThis = "Points_PolyCut";
298
    sStatusTip = QT_TR_NOOP("Cuts a point cloud with a picked polygon");
299
    sPixmap = "PolygonPick";
300
}
301

302
void CmdPointsPolyCut::activated(int iMsg)
303
{
304
    Q_UNUSED(iMsg);
305

306
    std::vector<App::DocumentObject*> docObj =
307
        Gui::Selection().getObjectsOfType(Points::Feature::getClassTypeId());
308
    for (std::vector<App::DocumentObject*>::iterator it = docObj.begin(); it != docObj.end();
309
         ++it) {
310
        if (it == docObj.begin()) {
311
            Gui::Document* doc = getActiveGuiDocument();
312
            Gui::MDIView* view = doc->getActiveView();
313
            if (view->isDerivedFrom<Gui::View3DInventor>()) {
314
                Gui::View3DInventorViewer* viewer = ((Gui::View3DInventor*)view)->getViewer();
315
                viewer->setEditing(true);
316
                viewer->startSelection(Gui::View3DInventorViewer::Lasso);
317
                viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(),
318
                                         PointsGui::ViewProviderPoints::clipPointsCallback);
319
            }
320
            else {
321
                return;
322
            }
323
        }
324

325
        Gui::ViewProvider* pVP = getActiveGuiDocument()->getViewProvider(*it);
326
        pVP->startEditing(Gui::ViewProvider::Cutting);
327
    }
328
}
329

330
bool CmdPointsPolyCut::isActive()
331
{
332
    // Check for the selected mesh feature (all Mesh types)
333
    return getSelection().countObjectsOfType(Points::Feature::getClassTypeId()) > 0;
334
}
335

336
DEF_STD_CMD_A(CmdPointsMerge)
337

338
CmdPointsMerge::CmdPointsMerge()
339
    : Command("Points_Merge")
340
{
341
    sAppModule = "Points";
342
    sGroup = QT_TR_NOOP("Points");
343
    sMenuText = QT_TR_NOOP("Merge point clouds");
344
    sToolTipText = QT_TR_NOOP("Merge several point clouds into one");
345
    sWhatsThis = "Points_Merge";
346
    sStatusTip = QT_TR_NOOP("Merge several point clouds into one");
347
    sPixmap = "Points_Merge";
348
}
349

350
void CmdPointsMerge::activated(int iMsg)
351
{
352
    Q_UNUSED(iMsg);
353

354
    App::Document* doc = App::GetApplication().getActiveDocument();
355
    doc->openTransaction("Merge point clouds");
356
    Points::Feature* pts =
357
        static_cast<Points::Feature*>(doc->addObject("Points::Feature", "Merged Points"));
358
    Points::PointKernel* kernel = pts->Points.startEditing();
359

360
    std::vector<App::DocumentObject*> docObj =
361
        Gui::Selection().getObjectsOfType(Points::Feature::getClassTypeId());
362
    for (auto it : docObj) {
363
        const Points::PointKernel& k = static_cast<Points::Feature*>(it)->Points.getValue();
364
        std::size_t numPts = kernel->size();
365
        kernel->resize(numPts + k.size());
366
        for (std::size_t i = 0; i < k.size(); ++i) {
367
            kernel->setPoint(i + numPts, k.getPoint(i));
368
        }
369
    }
370

371
    pts->Points.finishEditing();
372

373
    // Add properties
374
    std::string displayMode = "Points";
375
    if (Points::copyProperty<App::PropertyColorList>(pts, docObj, "Color")) {
376
        displayMode = "Color";
377
    }
378
    if (Points::copyProperty<Points::PropertyNormalList>(pts, docObj, "Normal")) {
379
        displayMode = "Shaded";
380
    }
381
    if (Points::copyProperty<Points::PropertyGreyValueList>(pts, docObj, "Intensity")) {
382
        displayMode = "Intensity";
383
    }
384

385
    if (auto vp = dynamic_cast<Gui::ViewProviderDocumentObject*>(
386
            Gui::Application::Instance->getViewProvider(pts))) {
387
        vp->DisplayMode.setValue(displayMode.c_str());
388
    }
389

390
    doc->commitTransaction();
391
    updateActive();
392
}
393

394
bool CmdPointsMerge::isActive()
395
{
396
    return getSelection().countObjectsOfType(Points::Feature::getClassTypeId()) > 1;
397
}
398

399
DEF_STD_CMD_A(CmdPointsStructure)
400

401
CmdPointsStructure::CmdPointsStructure()
402
    : Command("Points_Structure")
403
{
404
    sAppModule = "Points";
405
    sGroup = QT_TR_NOOP("Points");
406
    sMenuText = QT_TR_NOOP("Structured point cloud");
407
    sToolTipText = QT_TR_NOOP("Convert points to structured point cloud");
408
    sWhatsThis = "Points_Structure";
409
    sStatusTip = QT_TR_NOOP("Convert points to structured point cloud");
410
    sPixmap = "Points_Structure";
411
}
412

413
void CmdPointsStructure::activated(int iMsg)
414
{
415
    Q_UNUSED(iMsg);
416

417
    App::Document* doc = App::GetApplication().getActiveDocument();
418
    doc->openTransaction("Structure point cloud");
419

420
    std::vector<App::DocumentObject*> docObj =
421
        Gui::Selection().getObjectsOfType(Points::Feature::getClassTypeId());
422
    for (auto it : docObj) {
423
        std::string name = it->Label.getValue();
424
        name += " (Structured)";
425
        Points::Structured* output =
426
            static_cast<Points::Structured*>(doc->addObject("Points::Structured", name.c_str()));
427
        output->Label.setValue(name);
428

429
        // Already sorted, so just make a copy
430
        if (it->isDerivedFrom<Points::Structured>()) {
431
            Points::Structured* input = static_cast<Points::Structured*>(it);
432

433
            Points::PointKernel* kernel = output->Points.startEditing();
434
            const Points::PointKernel& k = input->Points.getValue();
435

436
            kernel->resize(k.size());
437
            for (std::size_t i = 0; i < k.size(); ++i) {
438
                kernel->setPoint(i, k.getPoint(i));
439
            }
440
            output->Points.finishEditing();
441
            output->Width.setValue(input->Width.getValue());
442
            output->Height.setValue(input->Height.getValue());
443
        }
444
        // Sort the points
445
        else {
446
            Points::Feature* input = static_cast<Points::Feature*>(it);
447

448
            Points::PointKernel* kernel = output->Points.startEditing();
449
            const Points::PointKernel& k = input->Points.getValue();
450

451
            Base::BoundBox3d bbox = input->Points.getBoundingBox();
452
            double width = bbox.LengthX();
453
            double height = bbox.LengthY();
454

455
            // Count the number of different x or y values to get the size
456
            std::set<double> countX, countY;
457
            for (std::size_t i = 0; i < k.size(); ++i) {
458
                Base::Vector3d pnt = k.getPoint(i);
459
                countX.insert(pnt.x);
460
                countY.insert(pnt.y);
461
            }
462

463
            long width_l = long(countX.size());
464
            long height_l = long(countY.size());
465

466
            double dx = width / (width_l - 1);
467
            double dy = height / (height_l - 1);
468

469
            // Pre-fill the vector with <nan, nan, nan> points and afterwards replace them
470
            // with valid point coordinates
471
            double nan = std::numeric_limits<double>::quiet_NaN();
472
            std::vector<Base::Vector3d> sortedPoints(width_l * height_l,
473
                                                     Base::Vector3d(nan, nan, nan));
474

475
            for (std::size_t i = 0; i < k.size(); ++i) {
476
                Base::Vector3d pnt = k.getPoint(i);
477
                double xi = (pnt.x - bbox.MinX) / dx;
478
                double yi = (pnt.y - bbox.MinY) / dy;
479

480
                double xx = std::fabs(xi - std::round(xi));
481
                double yy = std::fabs(yi - std::round(yi));
482
                if (xx < 0.01 && yy < 0.01) {
483
                    xi = std::round(xi);
484
                    yi = std::round(yi);
485
                    long index = long(yi * width_l + xi);
486
                    sortedPoints[index] = pnt;
487
                }
488
            }
489

490
            kernel->resize(sortedPoints.size());
491
            for (std::size_t index = 0; index < sortedPoints.size(); index++) {
492
                kernel->setPoint(index, sortedPoints[index]);
493
            }
494

495
            output->Points.finishEditing();
496
            output->Width.setValue(width_l);
497
            output->Height.setValue(height_l);
498
        }
499
    }
500

501
    doc->commitTransaction();
502
    updateActive();
503
}
504

505
bool CmdPointsStructure::isActive()
506
{
507
    return getSelection().countObjectsOfType(Points::Feature::getClassTypeId()) == 1;
508
}
509

510
void CreatePointsCommands()
511
{
512
    Gui::CommandManager& rcCmdMgr = Gui::Application::Instance->commandManager();
513
    rcCmdMgr.addCommand(new CmdPointsImport());
514
    rcCmdMgr.addCommand(new CmdPointsExport());
515
    rcCmdMgr.addCommand(new CmdPointsTransform());
516
    rcCmdMgr.addCommand(new CmdPointsConvert());
517
    rcCmdMgr.addCommand(new CmdPointsPolyCut());
518
    rcCmdMgr.addCommand(new CmdPointsMerge());
519
    rcCmdMgr.addCommand(new CmdPointsStructure());
520
}
521

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

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

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

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