Files
create/src/Mod/PartDesign/App/FeatureChamfer.cpp
Markus Reitböck 88c6f176bb PartDesign: use CMake to generate precompiled headers on all platforms
"Professional CMake" book suggest the following:

"Targets should build successfully with or without compiler support for precompiled headers. It
 should be considered an optimization, not a requirement. In particular, do not explicitly include a
 precompile header (e.g. stdafx.h) in the source code, let CMake force-include an automatically
 generated precompile header on the compiler command line instead. This is more portable across
 the major compilers and is likely to be easier to maintain. It will also avoid warnings being
 generated from certain code checking tools like iwyu (include what you use)."

Therefore, removed the "#include <PreCompiled.h>" from sources, also
there is no need for the "#ifdef _PreComp_" anymore
2025-09-23 22:39:36 +02:00

261 lines
9.7 KiB
C++

/***************************************************************************
* Copyright (c) 2010 Juergen Riegel <FreeCAD@juergen-riegel.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
# include <limits>
# include <BRepAlgo.hxx>
# include <BRepFilletAPI_MakeChamfer.hxx>
# include <TopExp.hxx>
# include <TopoDS.hxx>
# include <TopoDS_Edge.hxx>
# include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
# include <TopTools_ListOfShape.hxx>
# include <ShapeFix_Shape.hxx>
# include <ShapeFix_ShapeTolerance.hxx>
# include <Standard_Version.hxx>
#include <Base/Exception.h>
#include <Base/Reader.h>
#include <Base/Tools.h>
#include <Mod/Part/App/TopoShape.h>
#include "FeatureChamfer.h"
using namespace PartDesign;
PROPERTY_SOURCE(PartDesign::Chamfer, PartDesign::DressUp)
const char* ChamferTypeEnums[] = {"Equal distance", "Two distances", "Distance and Angle", nullptr};
const App::PropertyQuantityConstraint::Constraints Chamfer::floatSize = {0.0, std::numeric_limits<float>::max(), 0.1};
const App::PropertyAngle::Constraints Chamfer::floatAngle = {0.0, 180.0, 1.0};
static App::DocumentObjectExecReturn *validateParameters(int chamferType, double size, double size2, double angle);
Chamfer::Chamfer()
{
ADD_PROPERTY_TYPE(ChamferType, (0L), "Chamfer", App::Prop_None, "Type of chamfer");
ChamferType.setEnums(ChamferTypeEnums);
ADD_PROPERTY_TYPE(Size, (1.0), "Chamfer", App::Prop_None, "Size of chamfer");
Size.setUnit(Base::Unit::Length);
Size.setConstraints(&floatSize);
ADD_PROPERTY_TYPE(Size2, (1.0), "Chamfer", App::Prop_None, "Second size of chamfer");
Size2.setUnit(Base::Unit::Length);
Size2.setConstraints(&floatSize);
ADD_PROPERTY_TYPE(Angle, (45.0), "Chamfer", App::Prop_None, "Angle of chamfer");
Angle.setUnit(Base::Unit::Angle);
Angle.setConstraints(&floatAngle);
ADD_PROPERTY_TYPE(FlipDirection, (false), "Chamfer", App::Prop_None, "Flip direction");
ADD_PROPERTY_TYPE(UseAllEdges, (false), "Chamfer", App::Prop_None,
"Chamfer all edges if true, else use only those edges in Base property.\n"
"If true, then this overrides any edge changes made to the Base property or in the dialog.\n");
updateProperties();
}
short Chamfer::mustExecute() const
{
bool touched = false;
auto chamferType = ChamferType.getValue();
switch (chamferType) {
case 0: // "Equal distance"
touched = Size.isTouched() || ChamferType.isTouched();
break;
case 1: // "Two distances"
touched = Size.isTouched() || ChamferType.isTouched() || Size2.isTouched();
break;
case 2: // "Distance and Angle"
touched = Size.isTouched() || ChamferType.isTouched() || Angle.isTouched();
break;
}
if (Placement.isTouched() || touched)
return 1;
return DressUp::mustExecute();
}
App::DocumentObjectExecReturn *Chamfer::execute()
{
if (onlyHaveRefined()) { return App::DocumentObject::StdReturn; }
// NOTE: Normally the Base property and the BaseFeature property should point to the same object.
// The only difference is that the Base property also stores the edges that are to be chamfered
Part::TopoShape TopShape;
try {
TopShape = getBaseTopoShape();
}
catch (Base::Exception& e) {
return new App::DocumentObjectExecReturn(e.what());
}
TopShape.setTransform(Base::Matrix4D());
auto edges = UseAllEdges.getValue() ? TopShape.getSubTopoShapes(TopAbs_EDGE)
: getContinuousEdges(TopShape);
if (edges.empty()) {
return new App::DocumentObjectExecReturn(
QT_TRANSLATE_NOOP("Exception", "No edges specified"));
}
const int chamferType = ChamferType.getValue();
const double size = Size.getValue();
double size2 = Size2.getValue();
const double angle = Angle.getValue();
const bool flipDirection = FlipDirection.getValue();
auto res = validateParameters(chamferType, size, size2, angle);
if (res != App::DocumentObject::StdReturn) {
return res;
}
this->positionByBaseFeature();
if ( static_cast<Part::ChamferType>(chamferType) == Part::ChamferType::distanceAngle ) {
size2 = angle;
}
try {
TopoShape shape(0);
shape.makeElementChamfer(TopShape,
edges,
static_cast<Part::ChamferType>(chamferType),
size,
size2,
nullptr,
flipDirection ? Part::Flip::flip : Part::Flip::none);
if (shape.isNull()) {
return new App::DocumentObjectExecReturn(
QT_TRANSLATE_NOOP("Exception", "Failed to create chamfer"));
}
TopTools_ListOfShape aLarg;
aLarg.Append(TopShape.getShape());
if (!BRepAlgo::IsValid(aLarg, shape.getShape(), Standard_False, Standard_False)) {
ShapeFix_ShapeTolerance aSFT;
aSFT.LimitTolerance(shape.getShape(),
Precision::Confusion(),
Precision::Confusion(),
TopAbs_SHAPE);
}
// store shape before refinement
this->rawShape = shape;
shape = refineShapeIfActive(shape);
if (!isSingleSolidRuleSatisfied(shape.getShape())) {
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Result has multiple solids: enable 'Allow Compound' in the active body."));
}
shape = getSolid(shape);
this->Shape.setValue(shape);
return App::DocumentObject::StdReturn;
}
catch (Standard_Failure& e) {
return new App::DocumentObjectExecReturn(e.GetMessageString());
}
}
void Chamfer::Restore(Base::XMLReader &reader)
{
DressUp::Restore(reader);
}
void Chamfer::handleChangedPropertyType(Base::XMLReader &reader, const char * TypeName, App::Property * prop)
{
if (prop && strcmp(TypeName,"App::PropertyFloatConstraint") == 0 &&
strcmp(prop->getTypeId().getName(), "App::PropertyQuantityConstraint") == 0) {
App::PropertyFloatConstraint p;
p.Restore(reader);
static_cast<App::PropertyQuantityConstraint*>(prop)->setValue(p.getValue());
}
else {
DressUp::handleChangedPropertyType(reader, TypeName, prop);
}
}
void Chamfer::onChanged(const App::Property* prop)
{
if (prop == &ChamferType) {
updateProperties();
}
DressUp::onChanged(prop);
}
void Chamfer::updateProperties()
{
auto chamferType = ChamferType.getValue();
auto disableproperty = [](App::Property * prop, bool on) {
prop->setStatus(App::Property::ReadOnly, on);
};
switch (chamferType) {
case 0: // "Equal distance"
disableproperty(&this->Angle, true);
disableproperty(&this->Size2, true);
break;
case 1: // "Two distances"
disableproperty(&this->Angle, true);
disableproperty(&this->Size2, false);
break;
case 2: // "Distance and Angle"
disableproperty(&this->Angle, false);
disableproperty(&this->Size2, true);
break;
}
}
static App::DocumentObjectExecReturn *validateParameters(int chamferType, double size, double size2, double angle)
{
// Size is common to all chamfer types.
if (size <= 0) {
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Size must be greater than zero"));
}
switch (chamferType) {
case 0: // Equal distance
// Nothing to do.
break;
case 1: // Two distances
if (size2 <= 0) {
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Size2 must be greater than zero"));
}
break;
case 2: // Distance and angle
if (angle <= 0 || angle >= 180.0) {
return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Angle must be greater than 0 and less than 180"));
}
break;
}
return App::DocumentObject::StdReturn;
}