1
/***************************************************************************
2
* Copyright (c) 2023 WandererFan <wandererfan@gmail.com> *
4
* This file is part of FreeCAD. *
6
* FreeCAD is free software: you can redistribute it and/or modify it *
7
* under the terms of the GNU Lesser General Public License as *
8
* published by the Free Software Foundation, either version 2.1 of the *
9
* License, or (at your option) any later version. *
11
* FreeCAD is distributed in the hope that it will be useful, but *
12
* WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14
* Lesser General Public License for more details. *
16
* You should have received a copy of the GNU Lesser General Public *
17
* License along with FreeCAD. If not, see *
18
* <https://www.gnu.org/licenses/>. *
20
**************************************************************************/
22
#include "PreCompiled.h"
25
#include <TopExp_Explorer.hxx>
27
#include <TopoDS_Edge.hxx>
28
#include <TopoDS_Wire.hxx>
29
#include <BRepAdaptor_Curve.hxx>
30
#include <BRepLProp_CLProps.hxx>
32
#include <App/Application.h>
33
#include <App/Document.h>
34
#include <App/MeasureManager.h>
36
#include <Mod/Part/App/PartFeature.h>
38
#include "MeasureRadius.h"
41
using namespace Measure;
43
PROPERTY_SOURCE(Measure::MeasureRadius, Measure::MeasureBase)
46
MeasureRadius::MeasureRadius()
48
ADD_PROPERTY_TYPE(Element,
52
"Element to get the radius from");
53
Element.setScope(App::LinkScope::Global);
54
Element.setAllowExternal(true);
56
ADD_PROPERTY_TYPE(Radius,
59
App::PropertyType(App::Prop_ReadOnly | App::Prop_Output),
60
"Radius of selection");
63
MeasureRadius::~MeasureRadius() = default;
65
//! validate all the object+subelement pairs in the selection. Must be circle or arc
66
//! and have a geometry handler available. We only calculate radius if there is a
67
//! single valid item in the selection
68
bool MeasureRadius::isValidSelection(const App::MeasureSelection& selection)
71
if (selection.empty() || selection.size() > 1) {
72
// too few or too many selections
76
auto element = selection.front();
77
auto type = App::MeasureManager::getMeasureElementType(element);
79
if (type == App::MeasureElementType::INVALID) {
83
if (type != App::MeasureElementType::CIRCLE && type != App::MeasureElementType::ARC) {
90
//! return true if the selection is particularly interesting to MeasureRadius.
91
//! In this case we claim circles and arcs.
92
bool MeasureRadius::isPrioritizedSelection(const App::MeasureSelection& selection)
94
if (selection.size() != 1) {
98
auto element = selection.front();
99
auto type = App::MeasureManager::getMeasureElementType(element);
101
if (type == App::MeasureElementType::CIRCLE || type == App::MeasureElementType::ARC) {
109
//! Set properties from first item in selection. assumes a valid selection.
110
void MeasureRadius::parseSelection(const App::MeasureSelection& selection)
112
auto element = selection.front();
113
auto objT = element.object;
115
std::vector<std::string> subElementList {objT.getSubName()};
116
Element.setValue(objT.getObject(), subElementList);
120
App::DocumentObjectExecReturn* MeasureRadius::execute()
122
auto info = getMeasureInfoFirst();
123
if (!info || !info->valid) {
124
return new App::DocumentObjectExecReturn("Cannot calculate radius");
127
Radius.setValue(info->radius);
128
return DocumentObject::StdReturn;
132
void MeasureRadius::onChanged(const App::Property* prop)
134
if (isRestoring() || isRemoving()) {
138
if (prop == &Element) {
139
auto ret = recompute();
143
MeasureBase::onChanged(prop);
147
//! return a placement (location + orientation) for the first element
148
Base::Placement MeasureRadius::getPlacement()
150
auto loc = getMeasureInfoFirst()->pointOnCurve;
151
auto p = Base::Placement();
157
//! return the pointOnCurve element in MeasureRadiusInfo for the first element
158
Base::Vector3d MeasureRadius::getPointOnCurve() const
160
return getMeasureInfoFirst()->pointOnCurve;
163
//! get the handler's result for the first element
164
Part::MeasureRadiusInfoPtr MeasureRadius::getMeasureInfoFirst() const
166
const App::DocumentObject* object = Element.getValue();
167
const std::vector<std::string>& subElements = Element.getSubValues();
169
if (!object || subElements.empty()) {
170
// NOLINTNEXTLINE(modernize-return-braced-init-list)
171
return std::make_shared<Part::MeasureRadiusInfo>();
174
App::SubObjectT subject {object, subElements.front().c_str()};
175
auto info = getMeasureInfo(subject);
176
if (!info || !info->valid) {
177
// NOLINTNEXTLINE(modernize-return-braced-init-list)
178
return std::make_shared<Part::MeasureRadiusInfo>();
181
auto radiusInfo = std::dynamic_pointer_cast<Part::MeasureRadiusInfo>(info);
185
//! Return the object we are measuring
186
//! used by the viewprovider in determining visibility
187
std::vector<App::DocumentObject*> MeasureRadius::getSubject() const
189
return {Element.getValue()};