Part: Revolve: add support for axis link and midplane

Changes on the App side only.
Added two properties:
* AxisLink (accepts an edge - line or arc of circle)
* Symmetric (for distributing the revolution symmetrically in both
directions)
This commit is contained in:
DeepSOIC 2016-08-08 16:57:22 +03:00
parent 8b3f8cc9e6
commit 779b7eedb2
2 changed files with 135 additions and 19 deletions

View File

@ -24,11 +24,17 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <gp_Ax1.hxx>
# include <TopoDS.hxx>
# include <BRepAdaptor_Curve.hxx>
# include <gp_Lin.hxx>
# include <gp_Circ.hxx>
#endif
#include "FeatureRevolution.h"
#include <Base/Tools.h>
#include <Base/Exception.h>
#include <App/Application.h>
using namespace Part;
@ -38,13 +44,14 @@ PROPERTY_SOURCE(Part::Revolution, Part::Feature)
Revolution::Revolution()
{
//*** why not ADD_PROPERTY_TYPE??
ADD_PROPERTY(Source,(0));
ADD_PROPERTY(Base,(Base::Vector3d(0.0,0.0,0.0)));
ADD_PROPERTY(Axis,(Base::Vector3d(0.0,0.0,1.0)));
ADD_PROPERTY(Angle,(360.0));
ADD_PROPERTY_TYPE(Solid,(false),"Base",App::Prop_None,"Make revolution a solid if possible");
ADD_PROPERTY_TYPE(Source,(0), "Revolve", App::Prop_None, "Shape to revolve");
ADD_PROPERTY_TYPE(Base,(Base::Vector3d(0.0,0.0,0.0)), "Revolve", App::Prop_None, "Base point of revolution axis");
ADD_PROPERTY_TYPE(Axis,(Base::Vector3d(0.0,0.0,1.0)), "Revolve", App::Prop_None, "Direction of revolution axis");
ADD_PROPERTY_TYPE(AxisLink,(0),"Revolve",App::Prop_None,"Link to edge to use as revolution axis.");
ADD_PROPERTY_TYPE(Angle,(360.0), "Revolve", App::Prop_None, "Angle span of revolution. If angle is zero, and an arc is used for axis link, angle span of arc will be used.");
Angle.setConstraints(&angleRangeU);
ADD_PROPERTY_TYPE(Symmetric,(false),"Revolve",App::Prop_None,"Extend revolution symmetrically from the profile.");
ADD_PROPERTY_TYPE(Solid,(false),"Revolve",App::Prop_None,"Make revolution a solid if possible");
}
short Revolution::mustExecute() const
@ -53,11 +60,75 @@ short Revolution::mustExecute() const
Axis.isTouched() ||
Angle.isTouched() ||
Source.isTouched() ||
Solid.isTouched())
Solid.isTouched() ||
AxisLink.isTouched() ||
Symmetric.isTouched())
return 1;
return 0;
}
void setReadonlyness(App::Property &prop, bool on)
{
unsigned long status = prop.getStatus();
prop.setStatus(App::Property::ReadOnly, on);
if (status != prop.getStatus())
App::GetApplication().signalChangePropertyEditor(prop);
}
void Revolution::onChanged(const App::Property* prop)
{
if(! this->isRestoring()){
if(prop == &AxisLink){
setReadonlyness(Base, AxisLink.getValue() != nullptr);
setReadonlyness(Axis, AxisLink.getValue() != nullptr);
}
}
Part::Feature::onChanged(prop);
}
bool Revolution::fetchAxisLink(const App::PropertyLinkSub &axisLink,
Base::Vector3d& center,
Base::Vector3d& dir,
double& angle)
{
if (!axisLink.getValue())
return false;
if (!axisLink.getValue()->isDerivedFrom(Part::Feature::getClassTypeId()))
throw Base::TypeError("AxisLink has no OCC shape");
Part::Feature* linked = static_cast<Part::Feature*>(axisLink.getValue());
TopoDS_Shape axEdge;
if (axisLink.getSubValues().size() > 0 && axisLink.getSubValues()[0].length() > 0){
axEdge = linked->Shape.getShape().getSubShape(axisLink.getSubValues()[0].c_str());
} else {
axEdge = linked->Shape.getValue();
}
if (axEdge.IsNull())
throw Base::ValueError("AxisLink shape is null");
if (axEdge.ShapeType() != TopAbs_EDGE)
throw Base::TypeError("AxisLink shape is not an edge");
BRepAdaptor_Curve crv(TopoDS::Edge(axEdge));
gp_Pnt base;
gp_Dir occdir;
if (crv.GetType() == GeomAbs_Line){
base = crv.Value(crv.FirstParameter());
occdir = crv.Line().Direction();
} else if (crv.GetType() == GeomAbs_Circle) {
base = crv.Circle().Axis().Location();
occdir = crv.Circle().Axis().Direction();
angle = crv.LastParameter() - crv.FirstParameter();
} else {
throw Base::TypeError("AxisLink edge is neither line nor arc of circle.");
}
center.Set(base.X(), base.Y(),base.Z());
dir.Set(occdir.X(), occdir.Y(), occdir.Z());
return true;
}
App::DocumentObjectExecReturn *Revolution::execute(void)
{
App::DocumentObject* link = Source.getValue();
@ -67,18 +138,40 @@ App::DocumentObjectExecReturn *Revolution::execute(void)
return new App::DocumentObjectExecReturn("Linked object is not a Part object");
Part::Feature *base = static_cast<Part::Feature*>(Source.getValue());
Base::Vector3d b = Base.getValue();
Base::Vector3d v = Axis.getValue();
gp_Pnt pnt(b.x,b.y,b.z);
gp_Dir dir(v.x,v.y,v.z);
Standard_Boolean isSolid = Solid.getValue() ? Standard_True : Standard_False;
try {
// Now, let's get the TopoDS_Shape
//TopoDS_Shape revolve = base->Shape.getShape().revolve(gp_Ax1(pnt, dir),
// Angle.getValue()/180.0f*M_PI);
TopoDS_Shape revolve = base->Shape.getShape().revolve(gp_Ax1(pnt, dir),
Angle.getValue()/180.0f*M_PI,isSolid);
//read out axis link
double angle_edge = 0;
Base::Vector3d b = Base.getValue();
Base::Vector3d v = Axis.getValue();
bool linkFetched = this->fetchAxisLink(this->AxisLink, b, v, angle_edge);
if (linkFetched){
this->Base.setValue(b);
this->Axis.setValue(v);
}
gp_Pnt pnt(b.x,b.y,b.z);
gp_Dir dir(v.x,v.y,v.z);
gp_Ax1 revAx(pnt, dir);
//read out revolution angle
double angle = Angle.getValue()/180.0f*M_PI;
if (fabs(angle) < Precision::Angular())
angle = angle_edge;
//apply "midplane" symmetry
TopoShape sourceShape = base->Shape.getShape();
if (Symmetric.getValue()) {
//rotate source shape backwards by half angle, to make resulting revolution symmetric to the profile
gp_Trsf mov;
mov.SetRotation(revAx, angle * (-0.5));
TopLoc_Location loc(mov);
sourceShape.setShape(sourceShape.getShape().Moved(loc));
}
//do it!
Standard_Boolean makeSolid = Solid.getValue() ? Standard_True : Standard_False;
TopoDS_Shape revolve = sourceShape.revolve(revAx, angle, makeSolid);
if (revolve.IsNull())
return new App::DocumentObjectExecReturn("Resulting shape is null");
this->Shape.setValue(revolve);

View File

@ -26,11 +26,12 @@
#include <App/PropertyStandard.h>
#include "PartFeature.h"
#include <Base/Vector3D.h>
namespace Part
{
class Revolution : public Part::Feature
class PartExport Revolution : public Part::Feature
{
PROPERTY_HEADER(Part::Revolution);
@ -40,7 +41,9 @@ public:
App::PropertyLink Source;
App::PropertyVector Base;
App::PropertyVector Axis;
App::PropertyLinkSub AxisLink;
App::PropertyFloatConstraint Angle;
App::PropertyBool Symmetric; //like "Midplane" in PartDesign
App::PropertyBool Solid;
/** @name methods override feature */
@ -48,12 +51,32 @@ public:
/// recalculate the feature
App::DocumentObjectExecReturn *execute(void);
short mustExecute() const;
void onChanged(const App::Property* prop) override;
/// returns the type name of the view provider
const char* getViewProviderName(void) const {
return "PartGui::ViewProviderRevolution";
}
//@}
/**
* @brief fetchAxisLink: read AxisLink to obtain the axis parameters and
* angle span. Note: this routine is re-used in Revolve dialog, hence it
* is static.
* @param axisLink (input): the link
* @param center (output): base point of axis
* @param dir (output): direction of axis
* @param angle (output): if edge is an arc of circle, this argument is
* used to return the angle span of the arc.
* @return true if link was fetched. false if link was empty. Throws if the
* link is wrong.
*/
static bool fetchAxisLink(const App::PropertyLinkSub& axisLink,
Base::Vector3d &center,
Base::Vector3d &dir,
double &angle);
private:
static App::PropertyFloatConstraint::Constraints angleRangeU;
};