| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | #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"
|
| |
|
| | #include <Base/ProgramVersion.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:
|
| | touched = Size.isTouched() || ChamferType.isTouched();
|
| | break;
|
| | case 1:
|
| | touched = Size.isTouched() || ChamferType.isTouched() || Size2.isTouched();
|
| | break;
|
| | case 2:
|
| | 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;
|
| | }
|
| |
|
| |
|
| |
|
| | 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
|
| | );
|
| | }
|
| |
|
| |
|
| | 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);
|
| |
|
| | migrateFlippedProperties(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);
|
| | }
|
| | }
|
| |
|
| | bool Chamfer::requiresSizeSwapping(const Base::XMLReader& reader) const
|
| | {
|
| | return Base::getVersion(reader.ProgramVersion) < Base::Version::v1_0
|
| | && (ChamferType.getValue() == 1 || ChamferType.getValue() == 2);
|
| | }
|
| |
|
| | void Chamfer::migrateFlippedProperties(const Base::XMLReader& reader)
|
| | {
|
| | if (!requiresSizeSwapping(reader)) {
|
| | return;
|
| | }
|
| |
|
| | Base::Console().warning(
|
| | "The 'FlipDirection' property of the chamfer of %s is being adjusted to maintain"
|
| | "the same geometry in this FreeCAD version. If the re-saved file is later opened "
|
| | "in FreeCAD 0.21.x the chamfer result may differ due to the changed parameter "
|
| | "interpretation.\n",
|
| | getFullName()
|
| | );
|
| |
|
| | FlipDirection.setValue(!FlipDirection.getValue());
|
| | }
|
| |
|
| | 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:
|
| | disableproperty(&this->Angle, true);
|
| | disableproperty(&this->Size2, true);
|
| | break;
|
| | case 1:
|
| | disableproperty(&this->Angle, true);
|
| | disableproperty(&this->Size2, false);
|
| | break;
|
| | case 2:
|
| | disableproperty(&this->Angle, false);
|
| | disableproperty(&this->Size2, true);
|
| | break;
|
| | }
|
| | }
|
| |
|
| | static App::DocumentObjectExecReturn* validateParameters(
|
| | int chamferType,
|
| | double size,
|
| | double size2,
|
| | double angle
|
| | )
|
| | {
|
| |
|
| | if (size <= 0) {
|
| | return new App::DocumentObjectExecReturn(
|
| | QT_TRANSLATE_NOOP("Exception", "Size must be greater than zero")
|
| | );
|
| | }
|
| |
|
| | switch (chamferType) {
|
| | case 0:
|
| |
|
| | break;
|
| | case 1:
|
| | if (size2 <= 0) {
|
| | return new App::DocumentObjectExecReturn(
|
| | QT_TRANSLATE_NOOP("Exception", "Size2 must be greater than zero")
|
| | );
|
| | }
|
| | break;
|
| | case 2:
|
| | 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;
|
| | }
|
| |
|