1
/***************************************************************************
2
* Copyright (c) 2023 Pierre-Louis Boyer <development@Ondsel.com> *
4
* This file is part of the FreeCAD CAx development system. *
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. *
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. *
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 *
21
***************************************************************************/
23
#include "PreCompiled.h"
31
#include <App/Document.h>
32
#include <App/DocumentObject.h>
35
#include <Base/UnitsApi.h>
36
#include <Gui/Application.h>
37
#include <Gui/MainWindow.h>
38
#include <Gui/Selection.h>
39
#include <Gui/ViewProvider.h>
41
#include <Mod/Part/App/PartFeature.h>
42
#include <Mod/Part/App/TopoShape.h>
44
#include <Mod/Measure/App/Measurement.h>
46
#include "QuickMeasure.h"
48
using namespace Measure;
49
using namespace MeasureGui;
51
QuickMeasure::QuickMeasure(QObject* parent)
53
, measurement {new Measure::Measurement()}
55
selectionTimer = new QTimer(this);
56
pendingProcessing = false;
57
connect(selectionTimer, &QTimer::timeout, this, &QuickMeasure::processSelection);
60
QuickMeasure::~QuickMeasure()
62
delete selectionTimer;
66
void QuickMeasure::onSelectionChanged(const Gui::SelectionChanges& msg)
68
if (canMeasureSelection(msg)) {
69
if (!pendingProcessing) {
70
selectionTimer->start(100);
72
pendingProcessing = true;
76
void QuickMeasure::processSelection()
78
if (pendingProcessing) {
79
pendingProcessing = false;
81
tryMeasureSelection();
83
catch (const Base::IndexError&) {
84
// ignore this exception because it can be caused by trying to access a non-existing
85
// sub-element e.g. when selecting a construction geometry in sketcher
87
catch (const Base::ValueError&) {
88
// ignore this exception because it can be caused by trying to access a non-existing
89
// sub-element e.g. when selecting a constraint in sketcher
91
catch (const Base::Exception& e) {
97
void QuickMeasure::tryMeasureSelection()
100
addSelectionToMeasurement();
104
bool QuickMeasure::canMeasureSelection(const Gui::SelectionChanges& msg) const
106
if (msg.Type == Gui::SelectionChanges::SetPreselect
107
|| msg.Type == Gui::SelectionChanges::RmvPreselect) {
111
Gui::Document* doc = Gui::Application::Instance->activeDocument();
112
return doc != nullptr;
115
void QuickMeasure::addSelectionToMeasurement()
120
for (auto& selObj : Gui::Selection().getSelectionEx()) {
121
App::DocumentObject* obj = selObj.getObject();
123
std::string vpType = obj->getViewProviderName();
124
auto* vp = Gui::Application::Instance->getViewProvider(obj);
125
if ((vpType == "SketcherGui::ViewProviderSketch" && vp->isEditing())
126
|| vpType.find("Gui::ViewProviderOrigin") != std::string::npos
127
|| vpType.find("Gui::ViewProviderPart") != std::string::npos
128
|| vpType.find("SpreadsheetGui") != std::string::npos
129
|| vpType.find("TechDrawGui") != std::string::npos) {
133
const std::vector<std::string> subNames = selObj.getSubNames();
135
// Check that there's not too many selection
136
count += subNames.empty() ? 1 : subNames.size();
138
measurement->clear();
142
if (subNames.empty()) {
143
measurement->addReference3D(obj, "");
146
for (auto& subName : subNames) {
147
measurement->addReference3D(obj, subName);
153
void QuickMeasure::printResult()
155
MeasureType mtype = measurement->getType();
156
if (mtype == MeasureType::Surfaces) {
157
Base::Quantity area(measurement->area(), Base::Unit::Area);
158
print(tr("Total area: %1").arg(area.getUserString()));
160
/* deactivated because computing the volumes/area of solids makes a significant
161
slow down in selection of complex solids.
162
else if (mtype == MeasureType::Volumes) {
163
Base::Quantity area(measurement->area(), Base::Unit::Area);
164
Base::Quantity vol(measurement->volume(), Base::Unit::Volume);
165
print(tr("Volume: %1, Area:
166
%2").arg(vol.getSafeUserString()).arg(area.getSafeUserString()));
168
else if (mtype == MeasureType::TwoPlanes) {
169
Base::Quantity dist(measurement->planePlaneDistance(), Base::Unit::Length);
170
print(tr("Nominal distance: %1").arg(dist.getSafeUserString()));
172
else if (mtype == MeasureType::Cone || mtype == MeasureType::Plane) {
173
Base::Quantity area(measurement->area(), Base::Unit::Area);
174
print(tr("Area: %1").arg(area.getUserString()));
176
else if (mtype == MeasureType::Cylinder || mtype == MeasureType::Sphere
177
|| mtype == MeasureType::Torus) {
178
Base::Quantity area(measurement->area(), Base::Unit::Area);
179
Base::Quantity rad(measurement->radius(), Base::Unit::Length);
180
print(tr("Area: %1, Radius: %2").arg(area.getSafeUserString(), rad.getSafeUserString()));
182
else if (mtype == MeasureType::Edges) {
183
Base::Quantity dist(measurement->length(), Base::Unit::Length);
184
print(tr("Total length: %1").arg(dist.getSafeUserString()));
186
else if (mtype == MeasureType::TwoParallelLines) {
187
Base::Quantity dist(measurement->lineLineDistance(), Base::Unit::Length);
188
print(tr("Nominal distance: %1").arg(dist.getSafeUserString()));
190
else if (mtype == MeasureType::TwoLines) {
191
Base::Quantity angle(measurement->angle(), Base::Unit::Length);
192
Base::Quantity dist(measurement->length(), Base::Unit::Length);
193
print(tr("Angle: %1, Total length: %2")
194
.arg(angle.getSafeUserString(), dist.getSafeUserString()));
196
else if (mtype == MeasureType::Line) {
197
Base::Quantity dist(measurement->length(), Base::Unit::Length);
198
print(tr("Length: %1").arg(dist.getSafeUserString()));
200
else if (mtype == MeasureType::Circle) {
201
Base::Quantity dist(measurement->radius(), Base::Unit::Length);
202
print(tr("Radius: %1").arg(dist.getSafeUserString()));
204
else if (mtype == MeasureType::PointToPoint) {
205
Base::Quantity dist(measurement->length(), Base::Unit::Length);
206
print(tr("Distance: %1").arg(dist.getSafeUserString()));
208
else if (mtype == MeasureType::PointToEdge || mtype == MeasureType::PointToSurface) {
209
Base::Quantity dist(measurement->length(), Base::Unit::Length);
210
print(tr("Minimum distance: %1").arg(dist.getSafeUserString()));
213
print(QString::fromLatin1(""));
217
void QuickMeasure::print(const QString& message)
219
Gui::getMainWindow()->setRightSideMessage(message);
223
#include "moc_QuickMeasure.cpp"