Part: changes to Part Module

* Added Part::Feature::getTopoShape/getShape() function that can obtain
  shape from any object with proper implementation of getSubObject(). It
  can even construct compound from group object with proper implementation
  of getSubObjects().

* Modified ViewProviderExt to work on any object, because it now obtain
  the shape using Part::Feature::getShape()

* Modified various Part features to obtain base/tool shapes using
  Part::getShape(), which allows them to be any type of object,
  including Link and groups.

* Modified various Part command to relax type requirement on selected
  objects.

* Add support of link and group to dimension, and add dimension refresh
  command

* Support link and group in simple command command, and add a few more
  copy command variations.

* Add special handling of 'Shape' attribute in PropertyContainerPy and
  use Part::Feature::getShape() to return shape for any object without
  Shape property. This allows many python feature work with any object
  without modification.

* GeometrySurface/CurvePy, add convenience attribute 'Rotation'

* TopoShapePy:

    * Extended support of sub shape attribute, e.g. Compound1, Solid2,
      SubShape3 ('SubShape' is used to access child shape of a compound)

    * makeWires(), new API to sort and return wires given a list of edges.

    * transformed/translated/rotated/scaled(), return a new shape with
      some transformation.

    * findPlane(), find the plane of a planar shape

    * isCoplanar(), check if two shape are coplanar
This commit is contained in:
Zheng, Lei
2019-07-12 10:10:03 +08:00
committed by wmayer
parent ebd60c8595
commit f028ba42ff
58 changed files with 3250 additions and 727 deletions

View File

@@ -515,6 +515,8 @@ public:
*/
virtual int canLoadPartial() const {return 0;}
virtual void onUpdateElementReference(const Property *) {}
/** Allow object to redirect a subname path
*
* @param ss: input as the current subname path from \a topParent leading

View File

@@ -506,6 +506,27 @@ PyObject *PropertyContainerPy::getCustomAttributes(const char* attr) const
}
}
return dict;
} else if(Base::streq(attr,"Shape")
&& getPropertyContainerPtr()->isDerivedFrom(App::DocumentObject::getClassTypeId()))
{
// Special treatment of Shape property
static PyObject *_getShape = 0;
if(!_getShape) {
_getShape = Py_None;
PyObject *mod = PyImport_ImportModule("Part");
if(!mod) {
PyErr_Clear();
} else {
Py::Object pyMod = Py::asObject(mod);
if(pyMod.hasAttr("getShape"))
_getShape = Py::new_reference_to(pyMod.getAttr("getShape"));
}
}
if(_getShape != Py_None) {
Py::Tuple args(1);
args.setItem(0,Py::Object(const_cast<PropertyContainerPy*>(this)));
return PyObject_CallObject(_getShape, args.ptr());
}
}
return 0;

View File

@@ -452,6 +452,7 @@ PyMOD_INIT_FUNC(Part)
Part::Fillet ::init();
Part::Chamfer ::init();
Part::Compound ::init();
Part::Compound2 ::init();
Part::Extrusion ::init();
Part::Revolution ::init();
Part::Mirroring ::init();

View File

@@ -126,7 +126,9 @@
#include "ImportStep.h"
#include "edgecluster.h"
#include "FaceMaker.h"
#include "PartFeature.h"
#include "PartPyCXX.h"
#include "modelRefine.h"
#ifdef FCUseFreeType
# include "FT2FC.h"
@@ -134,10 +136,6 @@
extern const char* BRepBuilderAPI_FaceErrorText(BRepBuilderAPI_FaceError fe);
namespace Part {
extern Py::Object shape2pyshape(const TopoDS_Shape &shape);
}
#ifndef M_PI
#define M_PI 3.14159265358979323846 /* pi */
#endif
@@ -147,6 +145,35 @@ extern Py::Object shape2pyshape(const TopoDS_Shape &shape);
#endif
namespace Part {
PartExport void getPyShapes(PyObject *obj, std::vector<TopoShape> &shapes) {
if(!obj)
return;
if(PyObject_TypeCheck(obj,&Part::TopoShapePy::Type))
shapes.push_back(*static_cast<TopoShapePy*>(obj)->getTopoShapePtr());
else if (PyObject_TypeCheck(obj, &GeometryPy::Type))
shapes.push_back(TopoShape(static_cast<GeometryPy*>(obj)->getGeometryPtr()->toShape()));
else if(PySequence_Check(obj)) {
Py::Sequence list(obj);
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
if (PyObject_TypeCheck((*it).ptr(), &(Part::TopoShapePy::Type)))
shapes.push_back(*static_cast<TopoShapePy*>((*it).ptr())->getTopoShapePtr());
else if (PyObject_TypeCheck((*it).ptr(), &GeometryPy::Type))
shapes.push_back(TopoShape(static_cast<GeometryPy*>(
(*it).ptr())->getGeometryPtr()->toShape()));
else
throw Py::TypeError("expect shape in sequence");
}
}else
throw Py::TypeError("expect shape or sequence of shapes");
}
PartExport std::vector<TopoShape> getPyShapes(PyObject *obj) {
std::vector<TopoShape> ret;
getPyShapes(obj,ret);
return ret;
}
struct EdgePoints {
gp_Pnt v1, v2;
std::list<TopoDS_Edge>::iterator it;
@@ -425,12 +452,74 @@ public:
add_varargs_method("__fromPythonOCC__",&Module::fromPythonOCC,
"__fromPythonOCC__(occ) -- Helper method to convert a pythonocc shape to an internal shape"
);
add_varargs_method("clearShapeCache",&Module::clearShapeCache,
"clearShapeCache() -- Clears internal shape cache"
);
add_keyword_method("getShape",&Module::getShape,
"getShape(obj,subname=None,mat=None,needSubElement=False,transform=True,retType=0):\n"
"Obtain the the TopoShape of a given object with SubName reference\n\n"
"* obj: the input object\n"
"* subname: dot separated sub-object reference\n"
"* mat: the current transformation matrix\n"
"* needSubElement: if False, ignore the sub-element (e.g. Face1, Edge1) reference in 'subname'\n"
"* transform: if False, then skip obj's transformation. Use this if mat already include obj's\n"
" transformation matrix\n"
"* retType: 0: return TopoShape,\n"
" 1: return (shape,subObj,mat), where subObj is the object referenced in 'subname',\n"
" and 'mat' is the accumulated transformation matrix of that sub-object.\n"
" 2: same as 1, but make sure 'subObj' is resolved if it is a link.\n"
"* refine: refine the returned shape"
);
add_varargs_method("splitSubname",&Module::splitSubname,
"splitSubname(subname) -> list(sub,mapped,subElement)\n"
"Split the given subname into a list\n\n"
"sub: subname without any sub-element reference\n"
"mapped: mapped element name, or '' if none\n"
"subElement: old style element name, or '' if none"
);
add_varargs_method("joinSubname",&Module::joinSubname,
"joinSubname(sub,mapped,subElement) -> subname\n"
);
initialize("This is a module working with shapes."); // register with Python
}
virtual ~Module() {}
private:
virtual Py::Object invoke_method_keyword( void *method_def,
const Py::Tuple &args, const Py::Dict &keywords ) override
{
try {
return Py::ExtensionModule<Module>::invoke_method_keyword(method_def, args, keywords);
}
catch (const Standard_Failure &e) {
std::string str;
Standard_CString msg = e.GetMessageString();
str += typeid(e).name();
str += " ";
if (msg) {str += msg;}
else {str += "No OCCT Exception Message";}
Base::Console().Error("%s\n", str.c_str());
throw Py::Exception(Part::PartExceptionOCCError, str);
}
catch (const Base::Exception &e) {
std::string str;
str += "FreeCAD exception thrown (";
str += e.what();
str += ")";
e.ReportException();
throw Py::RuntimeError(str);
}
catch (const std::exception &e) {
std::string str;
str += "C++ exception thrown (";
str += e.what();
str += ")";
Base::Console().Error("%s\n", str.c_str());
throw Py::RuntimeError(str);
}
}
virtual Py::Object invoke_method_varargs(void *method_def, const Py::Tuple &args)
{
try {
@@ -638,21 +727,13 @@ private:
TopoDS_Compound Comp;
builder.MakeCompound(Comp);
try {
Py::Sequence list(pcObj);
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
if (PyObject_TypeCheck((*it).ptr(), &(Part::TopoShapePy::Type))) {
const TopoDS_Shape& sh = static_cast<TopoShapePy*>((*it).ptr())->
getTopoShapePtr()->getShape();
if (!sh.IsNull())
builder.Add(Comp, sh);
}
PY_TRY {
for(auto &s : getPyShapes(pcObj)) {
const auto &sh = s.getShape();
if (!sh.IsNull())
builder.Add(Comp, sh);
}
}
catch (Standard_Failure& e) {
throw Py::Exception(PartExceptionOCCError, e.GetMessageString());
}
} _PY_CATCH_OCC(throw Py::Exception())
return Py::asObject(new TopoShapeCompoundPy(new TopoShape(Comp)));
}
Py::Object makeShell(const Py::Tuple& args)
@@ -1980,6 +2061,95 @@ private:
throw Py::Exception(PartExceptionOCCError, e.what());
}
}
Py::Object getShape(const Py::Tuple& args, const Py::Dict &kwds) {
PyObject *pObj;
const char *subname = 0;
PyObject *pyMat = 0;
PyObject *needSubElement = Py_False;
PyObject *transform = Py_True;
PyObject *noElementMap = Py_False;
PyObject *refine = Py_False;
short retType = 0;
static char* kwd_list[] = {"obj", "subname", "mat",
"needSubElement","transform","retType","noElementMap","refine",0};
if(!PyArg_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), "O!|sO!OOhOO", kwd_list,
&App::DocumentObjectPy::Type, &pObj, &subname, &Base::MatrixPy::Type, &pyMat,
&needSubElement,&transform,&retType,&noElementMap,&refine))
throw Py::Exception();
App::DocumentObject *obj =
static_cast<App::DocumentObjectPy*>(pObj)->getDocumentObjectPtr();
App::DocumentObject *subObj = 0;
Base::Matrix4D mat;
if(pyMat)
mat = *static_cast<Base::MatrixPy*>(pyMat)->getMatrixPtr();
auto shape = Feature::getTopoShape(obj,subname,PyObject_IsTrue(needSubElement),
&mat,&subObj,retType==2,PyObject_IsTrue(transform),PyObject_IsTrue(noElementMap));
if(PyObject_IsTrue(refine)) {
// shape = TopoShape(0,shape.Hasher).makERefine(shape);
BRepBuilderAPI_RefineModel mkRefine(shape.getShape());
shape.setShape(mkRefine.Shape());
}
Py::Object sret(shape2pyshape(shape));
if(retType==0)
return sret;
return Py::TupleN(sret,Py::Object(new Base::MatrixPy(new Base::Matrix4D(mat))),
subObj?Py::Object(subObj->getPyObject(),true):Py::Object());
}
Py::Object clearShapeCache(const Py::Tuple &args) {
if (!PyArg_ParseTuple(args.ptr(),""))
throw Py::Exception();
Part::Feature::clearShapeCache();
return Py::Object();
}
Py::Object splitSubname(const Py::Tuple& args) {
const char *subname;
if (!PyArg_ParseTuple(args.ptr(), "s",&subname))
throw Py::Exception();
auto element = Data::ComplexGeoData::findElementName(subname);
std::string sub(subname,element-subname);
Py::List list;
list.append(Py::String(sub));
const char *dot = strchr(element,'.');
if(!dot)
dot = element+strlen(element);
const char *mapped = Data::ComplexGeoData::isMappedElement(element);
if(mapped)
list.append(Py::String(std::string(mapped,dot-mapped)));
else
list.append(Py::String());
if(*dot=='.')
list.append(Py::String(dot+1));
else if(!mapped)
list.append(Py::String(element));
else
list.append(Py::String());
return list;
}
Py::Object joinSubname(const Py::Tuple& args) {
const char *sub;
const char *mapped;
const char *element;
if (!PyArg_ParseTuple(args.ptr(), "sss",&sub,&mapped,&element))
throw Py::Exception();
std::string subname(sub);
if(subname.size() && subname[subname.size()-1]!='.')
subname += '.';
if(mapped && mapped[0]) {
if(!Data::ComplexGeoData::isMappedElement(mapped))
subname += Data::ComplexGeoData::elementMapPrefix();
subname += mapped;
if(element && element[0] && subname[subname.size()-1]!='.')
subname += '.';
}
subname += element;
return Py::String(subname);
}
};
PyObject* initModule()

View File

@@ -51,16 +51,14 @@ App::DocumentObjectExecReturn *Chamfer::execute(void)
App::DocumentObject* link = Base.getValue();
if (!link)
return new App::DocumentObjectExecReturn("No object linked");
if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))
return new App::DocumentObjectExecReturn("Linked object is not a Part object");
Part::Feature *base = static_cast<Part::Feature*>(Base.getValue());
try {
BRepFilletAPI_MakeChamfer mkChamfer(base->Shape.getValue());
auto baseShape = Feature::getShape(link);
BRepFilletAPI_MakeChamfer mkChamfer(baseShape);
TopTools_IndexedMapOfShape mapOfEdges;
TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace;
TopExp::MapShapesAndAncestors(base->Shape.getValue(), TopAbs_EDGE, TopAbs_FACE, mapEdgeFace);
TopExp::MapShapes(base->Shape.getValue(), TopAbs_EDGE, mapOfEdges);
TopExp::MapShapesAndAncestors(baseShape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace);
TopExp::MapShapes(baseShape, TopAbs_EDGE, mapOfEdges);
std::vector<FilletElement> values = Edges.getValues();
for (std::vector<FilletElement>::iterator it = values.begin(); it != values.end(); ++it) {
@@ -75,7 +73,7 @@ App::DocumentObjectExecReturn *Chamfer::execute(void)
TopoDS_Shape shape = mkChamfer.Shape();
if (shape.IsNull())
return new App::DocumentObjectExecReturn("Resulting shape is null");
ShapeHistory history = buildHistory(mkChamfer, TopAbs_FACE, shape, base->Shape.getValue());
ShapeHistory history = buildHistory(mkChamfer, TopAbs_FACE, shape, baseShape);
this->Shape.setValue(shape);
// make sure the 'PropertyShapeHistory' is not safed in undo/redo (#0001889)

View File

@@ -72,12 +72,10 @@ App::DocumentObjectExecReturn *Compound::execute(void)
const std::vector<DocumentObject*>& links = Links.getValues();
for (std::vector<DocumentObject*>::const_iterator it = links.begin(); it != links.end(); ++it) {
if (*it && (*it)->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) {
Part::Feature* fea = static_cast<Part::Feature*>(*it);
auto pos = tempLinks.insert(fea);
if (*it) {
auto pos = tempLinks.insert(*it);
if (pos.second) {
const TopoDS_Shape& sh = fea->Shape.getValue();
const TopoDS_Shape& sh = Feature::getShape(*it);
if (!sh.IsNull()) {
builder.Add(comp, sh);
TopTools_IndexedMapOfShape faceMap;
@@ -108,3 +106,15 @@ App::DocumentObjectExecReturn *Compound::execute(void)
}
}
////////////////////////////////////////////////////////////////////////
PROPERTY_SOURCE(Part::Compound2, Part::Compound)
Compound2::Compound2() {
Shape.setStatus(App::Property::Transient,true);
}
void Compound2::onDocumentRestored() {
auto res = execute();
delete res;
}

View File

@@ -52,6 +52,14 @@ public:
//@}
};
/// Same as Part::Compound, except it marks the Shape as transient, and rebuild it during restore
class Compound2 : public Compound {
PROPERTY_HEADER(Part::Compound2);
public:
Compound2();
virtual void onDocumentRestored() override;
};
} //namespace Part

View File

@@ -102,16 +102,13 @@ bool Extrusion::fetchAxisLink(const App::PropertyLinkSub& axisLink, Base::Vector
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());
auto linked = 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());
axEdge = Feature::getTopoShape(linked).getSubShape(axisLink.getSubValues()[0].c_str());
} else {
axEdge = linked->Shape.getValue();
axEdge = Feature::getShape(linked);
}
if (axEdge.IsNull())
@@ -196,25 +193,21 @@ Extrusion::ExtrusionParameters Extrusion::computeFinalParameters()
Base::Vector3d Extrusion::calculateShapeNormal(const App::PropertyLink& shapeLink)
{
if (!shapeLink.getValue())
App::DocumentObject* docobj = 0;
Base::Matrix4D mat;
TopoDS_Shape sh = Feature::getShape(shapeLink.getValue(),0,false, &mat,&docobj);
if (!docobj)
throw Base::ValueError("calculateShapeNormal: link is empty");
const App::DocumentObject* docobj = shapeLink.getValue();
//special case for sketches and the like: no matter what shape they have, use their local Z axis.
if (docobj->isDerivedFrom(Part::Part2DObject::getClassTypeId())){
const Part::Part2DObject* p2do = static_cast<const Part::Part2DObject*>(docobj);
Base::Vector3d OZ (0.0, 0.0, 1.0);
Base::Vector3d result;
p2do->Placement.getValue().getRotation().multVec(OZ, result);
Base::Rotation(mat).multVec(OZ, result);
return result;
}
//extract the shape
if (! docobj->isDerivedFrom(Part::Feature::getClassTypeId()))
throw Base::TypeError("Linked object doesn't have shape.");
const TopoShape &tsh = static_cast<const Part::Feature*>(docobj)->Shape.getShape();
TopoDS_Shape sh = tsh.getShape();
if (sh.IsNull())
throw NullShapeException("calculateShapeNormal: link points to a valid object, but its shape is null.");
@@ -327,13 +320,10 @@ App::DocumentObjectExecReturn *Extrusion::execute(void)
App::DocumentObject* link = Base.getValue();
if (!link)
return new App::DocumentObjectExecReturn("No object linked");
if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))
return new App::DocumentObjectExecReturn("Linked object is not a Part object");
Part::Feature *base = static_cast<Part::Feature*>(Base.getValue());
try {
Extrusion::ExtrusionParameters params = computeFinalParameters();
TopoShape result = extrudeShape(base->Shape.getShape(),params);
TopoShape result = extrudeShape(Feature::getShape(link),params);
this->Shape.setValue(result);
return App::DocumentObject::StdReturn;
}

View File

@@ -84,9 +84,9 @@ App::DocumentObjectExecReturn *Face::execute(void)
std::unique_ptr<FaceMaker> facemaker = FaceMaker::ConstructFromType(this->FaceMakerClass.getValue());
for (std::vector<App::DocumentObject*>::iterator it = links.begin(); it != links.end(); ++it) {
if (!(*it && (*it)->isDerivedFrom(Part::Feature::getClassTypeId())))
if (!(*it))
return new App::DocumentObjectExecReturn("Linked object is not a Part object (has no Shape).");
TopoDS_Shape shape = static_cast<Part::Part2DObject*>(*it)->Shape.getShape().getShape();
TopoDS_Shape shape = Feature::getShape(*it);
if (shape.IsNull())
return new App::DocumentObjectExecReturn("Linked shape object is empty");

View File

@@ -50,17 +50,16 @@ App::DocumentObjectExecReturn *Fillet::execute(void)
App::DocumentObject* link = Base.getValue();
if (!link)
return new App::DocumentObjectExecReturn("No object linked");
if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))
return new App::DocumentObjectExecReturn("Linked object is not a Part object");
Part::Feature *base = static_cast<Part::Feature*>(Base.getValue());
auto baseShape = Feature::getShape(link);
try {
#if defined(__GNUC__) && defined (FC_OS_LINUX)
Base::SignalException se;
#endif
BRepFilletAPI_MakeFillet mkFillet(base->Shape.getValue());
BRepFilletAPI_MakeFillet mkFillet(baseShape);
TopTools_IndexedMapOfShape mapOfShape;
TopExp::MapShapes(base->Shape.getValue(), TopAbs_EDGE, mapOfShape);
TopExp::MapShapes(baseShape, TopAbs_EDGE, mapOfShape);
std::vector<FilletElement> values = Edges.getValues();
for (std::vector<FilletElement>::iterator it = values.begin(); it != values.end(); ++it) {
@@ -74,7 +73,7 @@ App::DocumentObjectExecReturn *Fillet::execute(void)
TopoDS_Shape shape = mkFillet.Shape();
if (shape.IsNull())
return new App::DocumentObjectExecReturn("Resulting shape is null");
ShapeHistory history = buildHistory(mkFillet, TopAbs_FACE, shape, base->Shape.getValue());
ShapeHistory history = buildHistory(mkFillet, TopAbs_FACE, shape, baseShape);
this->Shape.setValue(shape);
// make sure the 'PropertyShapeHistory' is not safed in undo/redo (#0001889)

View File

@@ -95,14 +95,11 @@ App::DocumentObjectExecReturn *Mirroring::execute(void)
App::DocumentObject* link = Source.getValue();
if (!link)
return new App::DocumentObjectExecReturn("No object linked");
if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))
return new App::DocumentObjectExecReturn("Linked object is not a Part object");
Part::Feature *source = static_cast<Part::Feature*>(link);
Base::Vector3d base = Base.getValue();
Base::Vector3d norm = Normal.getValue();
try {
const TopoDS_Shape& shape = source->Shape.getValue();
const TopoDS_Shape& shape = Feature::getShape(link);
if (shape.IsNull())
Standard_Failure::Raise("Cannot mirroR empty shape");
gp_Ax2 ax2(gp_Pnt(base.x,base.y,base.z), gp_Dir(norm.x,norm.y,norm.z));

View File

@@ -77,7 +77,7 @@ short Offset::mustExecute() const
App::DocumentObjectExecReturn *Offset::execute(void)
{
App::DocumentObject* source = Source.getValue();
if (!(source && source->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())))
if (!source)
return new App::DocumentObjectExecReturn("No source shape linked.");
double offset = Value.getValue();
double tol = Precision::Confusion();
@@ -86,7 +86,7 @@ App::DocumentObjectExecReturn *Offset::execute(void)
short mode = (short)Mode.getValue();
short join = (short)Join.getValue();
bool fill = Fill.getValue();
const TopoShape& shape = static_cast<Part::Feature*>(source)->Shape.getShape();
const TopoShape& shape = Feature::getShape(source);
if (fabs(offset) > 2*tol)
this->Shape.setValue(shape.makeOffsetShape(offset, tol, inter, self, mode, join, fill));
else

View File

@@ -73,17 +73,17 @@ App::DocumentObjectExecReturn *Boolean::execute(void)
#if defined(__GNUC__) && defined (FC_OS_LINUX)
Base::SignalException se;
#endif
Part::Feature *base = dynamic_cast<Part::Feature*>(Base.getValue());
Part::Feature *tool = dynamic_cast<Part::Feature*>(Tool.getValue());
auto base = Base.getValue();
auto tool = Tool.getValue();
if (!base || !tool)
return new App::DocumentObjectExecReturn("Linked object is not a Part object");
// Now, let's get the TopoDS_Shape
TopoDS_Shape BaseShape = base->Shape.getValue();
TopoDS_Shape BaseShape = Feature::getShape(base);
if (BaseShape.IsNull())
throw NullShapeException("Base shape is null");
TopoDS_Shape ToolShape = tool->Shape.getValue();
TopoDS_Shape ToolShape = Feature::getShape(tool);
if (ToolShape.IsNull())
throw NullShapeException("Tool shape is null");

View File

@@ -91,6 +91,16 @@ void Box::Restore(Base::XMLReader &reader)
{
reader.readElement("Properties");
int Cnt = reader.getAttributeAsInteger("Count");
int transientCount = 0;
if(reader.hasAttribute("TransientCount"))
transientCount = reader.getAttributeAsUnsigned("TransientCount");
for (int i=0;i<transientCount; ++i) {
reader.readElement("_Property");
App::Property* prop = getPropertyByName(reader.getAttribute("name"));
if(prop && reader.hasAttribute("status"))
prop->setStatusValue(reader.getAttributeAsUnsigned("status"));
}
bool location_xyz = false;
bool location_axis = false;
@@ -104,7 +114,27 @@ void Box::Restore(Base::XMLReader &reader)
reader.readElement("Property");
const char* PropName = reader.getAttribute("name");
const char* TypeName = reader.getAttribute("type");
App::Property* prop = getPropertyByName(PropName);
auto prop = dynamicProps.restore(*this,PropName,TypeName,reader);
if(!prop)
prop = getPropertyByName(PropName);
std::bitset<32> status;
if(reader.hasAttribute("status")) {
status = reader.getAttributeAsUnsigned("status");
if(prop)
prop->setStatusValue(status.to_ulong());
}
if (prop && strcmp(prop->getTypeId().getName(), TypeName) == 0) {
if (!prop->testStatus(App::Property::Transient)
&& !status.test(App::Property::Transient)
&& !status.test(App::Property::PropTransient)
&& !(getPropertyType(prop) & App::Prop_Transient))
{
prop->Restore(reader);
}
reader.readEndElement("Property");
continue;
}
if (!prop) {
// in case this comes from an old document we must use the new properties
if (strcmp(PropName, "l") == 0) {

View File

@@ -89,9 +89,7 @@ App::DocumentObjectExecReturn *MultiCommon::execute(void)
std::vector<App::DocumentObject*>::iterator it;
for (it = obj.begin(); it != obj.end(); ++it) {
if ((*it)->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) {
s.push_back(static_cast<Part::Feature*>(*it)->Shape.getValue());
}
s.push_back(Feature::getShape(*it));
}
bool argumentsAreInCompound = false;

View File

@@ -89,9 +89,7 @@ App::DocumentObjectExecReturn *MultiFuse::execute(void)
std::vector<App::DocumentObject*>::iterator it;
for (it = obj.begin(); it != obj.end(); ++it) {
if ((*it)->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) {
s.push_back(static_cast<Part::Feature*>(*it)->Shape.getValue());
}
s.push_back(Feature::getShape(*it));
}
bool argumentsAreInCompound = false;

View File

@@ -90,16 +90,13 @@ bool Revolution::fetchAxisLink(const App::PropertyLinkSub &axisLink,
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());
auto linked = 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());
axEdge = Feature::getTopoShape(linked).getSubShape(axisLink.getSubValues()[0].c_str());
} else {
axEdge = linked->Shape.getValue();
axEdge = Feature::getShape(linked);
}
if (axEdge.IsNull())
@@ -133,9 +130,6 @@ App::DocumentObjectExecReturn *Revolution::execute(void)
App::DocumentObject* link = Source.getValue();
if (!link)
return new App::DocumentObjectExecReturn("No object linked");
if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))
return new App::DocumentObjectExecReturn("Linked object is not a Part object");
Part::Feature *base = static_cast<Part::Feature*>(Source.getValue());
try {
//read out axis link
@@ -158,7 +152,7 @@ App::DocumentObjectExecReturn *Revolution::execute(void)
angle = angle_edge;
//apply "midplane" symmetry
TopoShape sourceShape = base->Shape.getShape();
TopoShape sourceShape = Feature::getShape(link);
if (Symmetric.getValue()) {
//rotate source shape backwards by half angle, to make resulting revolution symmetric to the profile
gp_Trsf mov;

View File

@@ -217,5 +217,11 @@ or raises an exception if it is not periodic.</UserDocu>
</Documentation>
<Parameter Name="LastParameter" Type="Float"/>
</Attribute>
<Attribute Name="Rotation" ReadOnly="true">
<Documentation>
<UserDocu>Returns a rotation object to describe the orientation for curve that supports it</UserDocu>
</Documentation>
<Parameter Name="Rotation" Type="Object"/>
</Attribute>
</PythonExport>
</GenerateModel>

View File

@@ -28,6 +28,7 @@
# include <gp_Dir.hxx>
# include <gp_Vec.hxx>
# include <gp_Pln.hxx>
# include <gp_Quaternion.hxx>
# include <GCPnts_UniformAbscissa.hxx>
# include <GCPnts_UniformDeflection.hxx>
# include <GCPnts_TangentialDeflection.hxx>
@@ -851,6 +852,17 @@ PyObject* GeometryCurvePy::intersect(PyObject *args)
return 0;
}
Py::Object GeometryCurvePy::getRotation(void) const
{
Handle(Geom_Conic) s = Handle(Geom_Conic)::DownCast(getGeometryPtr()->handle());
if(!s)
return Py::Object();
gp_Trsf trsf;
trsf.SetTransformation(s->Position(),gp_Ax3());
auto q = trsf.GetRotation();
return Py::Rotation(Base::Rotation(q.X(),q.Y(),q.Z(),q.W()));
}
PyObject* GeometryCurvePy::reverse(PyObject *args)
{
if (!PyArg_ParseTuple(args, ""))

View File

@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
<PythonExport
Father="PyObjectBase"
Father="PersistencePy"
Name="GeometryPy"
Twin="Geometry"
TwinPointer="Geometry"
Include="Mod/Part/App/Geometry.h"
Namespace="Part"
FatherInclude="Base/PyObjectBase.h"
FatherInclude="Base/PersistencePy.h"
FatherNamespace="Base"
Constructor="true"
Delete="true">

View File

@@ -87,6 +87,12 @@ Checks if the surface is planar within a certain tolerance.
</Documentation>
<Parameter Name="Continuity" Type="String"/>
</Attribute>
<Attribute Name="Rotation" ReadOnly="true">
<Documentation>
<UserDocu>Returns a rotation object to describe the orientation for surface that supports it</UserDocu>
</Documentation>
<Parameter Name="Rotation" Type="Object"/>
</Attribute>
<Methode Name="uIso" Const="true">
<Documentation>
<UserDocu>Builds the U isoparametric curve</UserDocu>

View File

@@ -31,6 +31,7 @@
# include <gp_Parab.hxx>
# include <gp_Vec.hxx>
# include <gp_Lin.hxx>
# include <gp_Quaternion.hxx>
# include <Geom_Geometry.hxx>
# include <Geom_Surface.hxx>
# include <GeomConvert_ApproxSurface.hxx>
@@ -855,3 +856,16 @@ PyObject* GeometrySurfacePy::intersect(PyObject *args)
PyErr_SetString(PyExc_TypeError, "intersect(): Geometry is not a surface");
return 0;
}
Py::Object GeometrySurfacePy::getRotation(void) const
{
Handle(Geom_ElementarySurface) s = Handle(Geom_ElementarySurface)::DownCast
(getGeometryPtr()->handle());
if(!s)
return Py::Object();
gp_Trsf trsf;
trsf.SetTransformation(s->Position().Ax2(),gp_Ax3());
auto q = trsf.GetRotation();
return Py::Rotation(Base::Rotation(q.X(),q.Y(),q.Z(),q.W()));
}

View File

@@ -70,9 +70,9 @@ PartExport extern PyObject* PartExceptionOCCDimensionError;
#define PY_TRY try
#ifndef DONT_CATCH_CXX_EXCEPTIONS
/// see docu of PY_TRY
# define PY_CATCH_OCC catch (Standard_Failure &e) \
# define _PY_CATCH_OCC(R) \
catch (Standard_Failure &e) \
{ \
std::string str; \
Standard_CString msg = e.GetMessageString(); \
@@ -81,80 +81,11 @@ PartExport extern PyObject* PartExceptionOCCDimensionError;
if (msg) {str += msg;} \
else {str += "No OCCT Exception Message";} \
Base::Console().Error(str.c_str()); \
Py_Error(Part::PartExceptionOCCError,str.c_str()); \
_Py_Error(R,Part::PartExceptionOCCError,str.c_str()); \
} \
catch(Base::Exception &e) \
{ \
std::string str; \
str += "FreeCAD exception thrown ("; \
str += e.what(); \
str += ")"; \
e.ReportException(); \
Py_Error(Base::BaseExceptionFreeCADError,str.c_str()); \
} \
catch(std::exception &e) \
{ \
std::string str; \
str += "STL exception thrown ("; \
str += e.what(); \
str += ")"; \
Base::Console().Error(str.c_str()); \
Py_Error(Base::BaseExceptionFreeCADError,str.c_str()); \
} \
catch(const Py::Exception&) \
{ \
return NULL; \
} \
catch(const char *e) \
{ \
Py_Error(Base::BaseExceptionFreeCADError,e); \
} \
catch(...) \
{ \
Py_Error(Base::BaseExceptionFreeCADError,"Unknown C++ exception"); \
}
#else
/// see docu of PY_TRY
# define PY_CATCH_OCC catch (Standard_Failure &e) \
{ \
std::string str; \
Standard_CString msg = e.GetMessageString(); \
str += typeid(e).name(); \
str += " "; \
if (msg) {str += msg;} \
else {str += "No OCCT Exception Message";} \
Base::Console().Error(str.c_str()); \
Py_Error(Part::PartExceptionOCCError,str.c_str()); \
} \
catch(Base::Exception &e) \
{ \
std::string str; \
str += "FreeCAD exception thrown ("; \
str += e.what(); \
str += ")"; \
e.ReportException(); \
Py_Error(Base::BaseExceptionFreeCADError,str.c_str()); \
} \
catch(std::exception &e) \
{ \
std::string str; \
str += "STL exception thrown ("; \
str += e.what(); \
str += ")"; \
Base::Console().Error(str.c_str()); \
Py_Error(Base::BaseExceptionFreeCADError,str.c_str()); \
} \
catch(const Py::Exception&) \
{ \
return NULL; \
} \
catch(const char *e) \
{ \
Py_Error(Base::BaseExceptionFreeCADError,e); \
}
#endif // DONT_CATCH_CXX_EXCEPTIONS
_PY_CATCH(R)
} //namespace Part
#define PY_CATCH_OCC _PY_CATCH_OCC(return(NULL))
#endif // _OCCError_h_

View File

@@ -234,6 +234,7 @@
#include <BRepExtrema_ShapeProximity.hxx>
#endif
#include <BRepFeat_SplitShape.hxx>
#include <BRepFeat_MakePrism.hxx>
#include <BRepFilletAPI_MakeChamfer.hxx>
#include <BRepFilletAPI_MakeFillet.hxx>
#include <BRepFill.hxx>
@@ -252,6 +253,7 @@
#include <BRepOffsetAPI_MakeThickSolid.hxx>
#include <BRepOffsetAPI_ThruSections.hxx>
#include <BRepBuilderAPI_NurbsConvert.hxx>
#include <BRepOffsetAPI_DraftAngle.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <BRepPrimAPI_MakeCone.hxx>
#include <BRepPrimAPI_MakeCylinder.hxx>
@@ -419,6 +421,7 @@
#include <gp_Trsf.hxx>
#include <gp_Vec.hxx>
#include <gp_Vec2d.hxx>
#include <gp_Quaternion.hxx>
// Adaptors
#include <Adaptor3d_HCurve.hxx>

View File

@@ -52,6 +52,8 @@
# include <gce_MakeDir.hxx>
#endif
#include <boost/algorithm/string/predicate.hpp>
#include <boost/bind.hpp>
#include <Base/Console.h>
#include <Base/Writer.h>
#include <Base/Reader.h>
@@ -63,6 +65,8 @@
#include <App/Application.h>
#include <App/FeaturePythonPyImp.h>
#include <App/Document.h>
#include <App/Link.h>
#include <App/GeoFeatureGroupExtension.h>
#include "PartPyCXX.h"
#include "PartFeature.h"
@@ -126,8 +130,10 @@ App::DocumentObject *Feature::getSubObject(const char *subname,
if(subname && !Data::ComplexGeoData::isMappedElement(subname) && strchr(subname,'.'))
return App::DocumentObject::getSubObject(subname,pyObj,pmat,transform,depth);
if(pmat && transform)
*pmat *= Placement.getValue().toMatrix();
Base::Matrix4D _mat;
auto &mat = pmat?*pmat:_mat;
if(transform)
mat *= Placement.getValue().toMatrix();
if(!pyObj) {
#if 0
@@ -142,13 +148,11 @@ App::DocumentObject *Feature::getSubObject(const char *subname,
try {
TopoShape ts(Shape.getShape());
bool doTransform = pmat && *pmat!=ts.getTransform();
if(doTransform) {
ts.setShape(ts.getShape().Located(TopLoc_Location()),false);
ts.initCache(1);
}
bool doTransform = mat!=ts.getTransform();
if(doTransform)
ts.setShape(ts.getShape().Located(TopLoc_Location()));
if(subname && *subname && !ts.isNull())
ts = ts.getSubTopoShape(subname,true);
ts = ts.getSubShape(subname);
if(doTransform && !ts.isNull()) {
static int sCopy = -1;
if(sCopy<0) {
@@ -171,7 +175,7 @@ App::DocumentObject *Feature::getSubObject(const char *subname,
}
}
}
ts.transformShape(*pmat,copy,true);
ts.transformShape(mat,copy,true);
}
*pyObj = Py::new_reference_to(shape2pyshape(ts));
return const_cast<Feature*>(this);
@@ -189,6 +193,330 @@ App::DocumentObject *Feature::getSubObject(const char *subname,
}
}
TopoDS_Shape Feature::getShape(const App::DocumentObject *obj, const char *subname,
bool needSubElement, Base::Matrix4D *pmat, App::DocumentObject **powner,
bool resolveLink, bool transform)
{
return getTopoShape(obj,subname,needSubElement,pmat,powner,resolveLink,transform,true).getShape();
}
struct ShapeCache {
std::unordered_map<const App::Document*,
std::map<std::pair<const App::DocumentObject*, std::string> ,TopoShape> > cache;
bool inited = false;
void init() {
if(inited)
return;
inited = true;
App::GetApplication().signalDeleteDocument.connect(
boost::bind(&ShapeCache::slotDeleteDocument, this, _1));
App::GetApplication().signalDeletedObject.connect(
boost::bind(&ShapeCache::slotClear, this, _1));
App::GetApplication().signalChangedObject.connect(
boost::bind(&ShapeCache::slotChanged, this, _1,_2));
}
void slotDeleteDocument(const App::Document &doc) {
cache.erase(&doc);
}
void slotChanged(const App::DocumentObject &obj, const App::Property &prop) {
const char *propName = prop.getName();
if(!propName)
return;
if(strcmp(propName,"Shape")==0
|| strcmp(propName,"Group")==0
|| strstr(propName,"Touched")!=0)
slotClear(obj);
}
void slotClear(const App::DocumentObject &obj) {
auto it = cache.find(obj.getDocument());
if(it==cache.end())
return;
auto &map = it->second;
for(auto it2=map.lower_bound(std::make_pair(&obj,std::string()));
it2!=map.end() && it2->first.first==&obj;)
{
it2 = map.erase(it2);
}
}
bool getShape(const App::DocumentObject *obj, TopoShape &shape, const char *subname=0) {
init();
auto &entry = cache[obj->getDocument()];
if(!subname) subname = "";
auto it = entry.find(std::make_pair(obj,std::string(subname)));
if(it!=entry.end()) {
shape = it->second;
return !shape.isNull();
}
return false;
}
void setShape(const App::DocumentObject *obj, const TopoShape &shape, const char *subname=0) {
init();
if(!subname) subname = "";
cache[obj->getDocument()][std::make_pair(obj,std::string(subname))] = shape;
}
};
static ShapeCache _ShapeCache;
void Feature::clearShapeCache() {
_ShapeCache.cache.clear();
}
static TopoShape _getTopoShape(const App::DocumentObject *obj, const char *subname,
bool needSubElement, Base::Matrix4D *pmat, App::DocumentObject **powner,
bool resolveLink, bool noElementMap, std::vector<App::DocumentObject*> &linkStack)
{
TopoShape shape;
if(!obj) return shape;
PyObject *pyobj = 0;
Base::Matrix4D mat;
if(powner) *powner = 0;
std::string _subname;
auto subelement = Data::ComplexGeoData::findElementName(subname);
if(!needSubElement && subname) {
// strip out element name if not needed
if(subelement && *subelement) {
_subname = std::string(subname,subelement);
subname = _subname.c_str();
}
}
if(_ShapeCache.getShape(obj,shape,subname)) {
if(noElementMap) {
// shape.resetElementMap();
// shape.Tag = 0;
// shape.Hasher.reset();
}
}
App::DocumentObject *linked = 0;
App::DocumentObject *owner = 0;
Base::Matrix4D linkMat;
// App::StringHasherRef hasher;
// long tag;
{
Base::PyGILStateLocker lock;
owner = obj->getSubObject(subname,shape.isNull()?&pyobj:0,&mat,false);
if(!owner)
return shape;
// tag = owner->getID();
// hasher = owner->getDocument()->getStringHasher();
linked = owner->getLinkedObject(true,&linkMat,false);
if(pmat) {
if(resolveLink && obj!=owner)
*pmat = mat * linkMat;
else
*pmat = mat;
}
if(!linked)
linked = owner;
if(powner)
*powner = resolveLink?linked:owner;
if(!shape.isNull())
return shape;
if(pyobj && PyObject_TypeCheck(pyobj,&TopoShapePy::Type)) {
shape = *static_cast<TopoShapePy*>(pyobj)->getTopoShapePtr();
if(!shape.isNull()) {
if(obj->getDocument() != linked->getDocument())
_ShapeCache.setShape(obj,shape,subname);
if(noElementMap) {
// shape.resetElementMap();
// shape.Tag = 0;
// shape.Hasher.reset();
}
Py_DECREF(pyobj);
return shape;
}
}
Py_XDECREF(pyobj);
}
// nothing can be done if there is sub-element references
if(needSubElement && subelement && *subelement)
return shape;
bool scaled = false;
if(obj!=owner) {
if(_ShapeCache.getShape(owner,shape)) {
auto scaled = shape.transformShape(mat,false,true);
if(owner->getDocument()!=obj->getDocument()) {
// shape.reTagElementMap(obj->getID(),obj->getDocument()->getStringHasher());
_ShapeCache.setShape(obj,shape,subname);
} else if(scaled)
_ShapeCache.setShape(obj,shape,subname);
}
if(!shape.isNull()) {
if(noElementMap) {
// shape.resetElementMap();
// shape.Tag = 0;
// shape.Hasher.reset();
}
return shape;
}
}
auto link = owner->getExtensionByType<App::LinkBaseExtension>(true);
if(owner!=linked && (!link || !link->_ChildCache.getSize())) {
// if there is a linked object, and there is no child cache (which is used
// for special handling of plain group), obtain shape from the linked object
shape = Feature::getTopoShape(linked,0,false,0,0,false,false);
if(shape.isNull())
return shape;
if(owner==obj)
shape.transformShape(mat*linkMat,false,true);
else
shape.transformShape(linkMat,false,true);
// shape.reTagElementMap(tag,hasher);
} else {
if(link || owner->getExtensionByType<App::GeoFeatureGroupExtension>(true))
linkStack.push_back(owner);
// Construct a compound of sub objects
std::vector<TopoShape> shapes;
// Acceleration for link array. Unlike non-array link, a link array does
// not return the linked object when calling getLinkedObject().
// Therefore, it should be handled here.
TopoShape baseShape;
std::string op;
if(link && link->getElementCountValue()) {
linked = link->getTrueLinkedObject(false);
if(linked && linked!=owner) {
baseShape = Feature::getTopoShape(linked,0,false,0,0,false,false);
// if(!link->getShowElementValue())
// baseShape.reTagElementMap(owner->getID(),owner->getDocument()->getStringHasher());
}
}
for(auto &sub : owner->getSubObjects()) {
if(sub.empty()) continue;
int visible;
if(sub[sub.size()-1] != '.')
sub += '.';
std::string childName;
App::DocumentObject *parent=0;
Base::Matrix4D mat;
auto subObj = owner->resolve(sub.c_str(), &parent, &childName,0,0,&mat,false);
if(!parent || !subObj)
continue;
if(linkStack.size()
&& parent->getExtensionByType<App::GroupExtension>(true,false))
{
visible = linkStack.back()->isElementVisible(childName.c_str());
}else
visible = parent->isElementVisible(childName.c_str());
if(visible==0)
continue;
TopoShape shape;
if(baseShape.isNull()) {
shape = _getTopoShape(owner,sub.c_str(),false,0,&subObj,false,false,linkStack);
if(shape.isNull())
continue;
if(visible<0 && subObj && !subObj->Visibility.getValue())
continue;
}else{
if(link && !link->getShowElementValue())
shape = baseShape.makETransform(mat,(TopoShape::indexPostfix()+childName).c_str());
else {
shape = baseShape.makETransform(mat);
// shape.reTagElementMap(subObj->getID(),subObj->getDocument()->getStringHasher());
}
}
shapes.push_back(shape);
}
if(linkStack.size() && linkStack.back()==owner)
linkStack.pop_back();
if(shapes.empty())
return shape;
// shape.Tag = tag;
// shape.Hasher = hasher;
shape.makECompound(shapes);
}
_ShapeCache.setShape(owner,shape);
if(owner!=obj) {
scaled = shape.transformShape(mat,false,true);
if(owner->getDocument()!=obj->getDocument()) {
// shape.reTagElementMap(obj->getID(),obj->getDocument()->getStringHasher());
_ShapeCache.setShape(obj,shape,subname);
}else if(scaled)
_ShapeCache.setShape(obj,shape,subname);
}
if(noElementMap) {
// shape.resetElementMap();
// shape.Tag = 0;
// shape.Hasher.reset();
}
return shape;
}
TopoShape Feature::getTopoShape(const App::DocumentObject *obj, const char *subname,
bool needSubElement, Base::Matrix4D *pmat, App::DocumentObject **powner,
bool resolveLink, bool transform, bool noElementMap)
{
if(!obj || !obj->getNameInDocument())
return TopoShape();
std::vector<App::DocumentObject*> linkStack;
// NOTE! _getTopoShape() always return shape without top level
// transformation for easy shape caching, i.e. with `transform` set
// to false. So we manually apply the top level transform if asked.
Base::Matrix4D mat;
auto shape = _getTopoShape(obj, subname, needSubElement, &mat,
powner, resolveLink, noElementMap, linkStack);
Base::Matrix4D topMat;
if(pmat || transform) {
// Obtain top level transformation
if(pmat)
topMat = *pmat;
if(transform)
obj->getSubObject(0,0,&topMat);
// Apply the top level transformation
if(!shape.isNull())
shape.transformShape(topMat,false,true);
if(pmat)
*pmat = topMat * mat;
}
return shape;
}
App::DocumentObject *Feature::getShapeOwner(const App::DocumentObject *obj, const char *subname)
{
if(!obj) return 0;
auto owner = obj->getSubObject(subname);
if(owner) {
auto linked = owner->getLinkedObject(true);
if(linked)
owner = linked;
}
return owner;
}
void Feature::onChanged(const App::Property* prop)
{
// if the placement has changed apply the change to the point data as well

View File

@@ -71,6 +71,44 @@ public:
virtual DocumentObject *getSubObject(const char *subname, PyObject **pyObj,
Base::Matrix4D *mat, bool transform, int depth) const override;
/** Convenience function to extract shape from fully qualified subname
*
* @param obj: the parent object
*
* @param subname: dot separated full qualified subname
*
* @param needSubElement: whether to ignore the non-object subelement
* reference inside \c subname
*
* @param pmat: used as current transformation on input, and return the
* accumulated transformation on output
*
* @param owner: return the owner of the shape returned
*
* @param resolveLink: if true, resolve link(s) of the returned 'owner'
* by calling its getLinkedObject(true) function
*
* @param transform: if true, apply obj's transformation. Set to false
* if pmat already include obj's transformation matrix.
*/
static TopoDS_Shape getShape(const App::DocumentObject *obj,
const char *subname=0, bool needSubElement=false, Base::Matrix4D *pmat=0,
App::DocumentObject **owner=0, bool resolveLink=true, bool transform=true);
static TopoShape getTopoShape(const App::DocumentObject *obj,
const char *subname=0, bool needSubElement=false, Base::Matrix4D *pmat=0,
App::DocumentObject **owner=0, bool resolveLink=true, bool transform=true,
bool noElementMap=false);
static void clearShapeCache();
static App::DocumentObject *getShapeOwner(const App::DocumentObject *obj, const char *subname=0);
static bool hasShapeOwner(const App::DocumentObject *obj, const char *subname=0) {
auto owner = getShapeOwner(obj,subname);
return owner && owner->isDerivedFrom(getClassTypeId());
}
protected:
/// recompute only this object
virtual App::DocumentObjectExecReturn *recompute(void);

View File

@@ -84,20 +84,20 @@ App::DocumentObjectExecReturn* RuledSurface::getShape(const App::PropertyLinkSub
TopoDS_Shape& shape) const
{
App::DocumentObject* obj = link.getValue();
if (!(obj && obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())))
if(!obj)
return new App::DocumentObjectExecReturn("No shape linked.");
// if no explicit sub-shape is selected use the whole part
const std::vector<std::string>& element = link.getSubValues();
if (element.empty()) {
shape = static_cast<Part::Feature*>(obj)->Shape.getValue();
shape = Feature::getShape(obj);
return nullptr;
}
else if (element.size() != 1) {
return new App::DocumentObjectExecReturn("Not exactly one sub-shape linked.");
}
const Part::TopoShape& part = static_cast<Part::Feature*>(obj)->Shape.getValue();
const Part::TopoShape& part = Feature::getTopoShape(obj);
if (!part.getShape().IsNull()) {
if (!element[0].empty()) {
shape = part.getSubShape(element[0].c_str());
@@ -311,9 +311,7 @@ App::DocumentObjectExecReturn *Loft::execute(void)
const std::vector<App::DocumentObject*>& shapes = Sections.getValues();
std::vector<App::DocumentObject*>::const_iterator it;
for (it = shapes.begin(); it != shapes.end(); ++it) {
if (!(*it)->isDerivedFrom(Part::Feature::getClassTypeId()))
return new App::DocumentObjectExecReturn("Linked object is not a shape.");
TopoDS_Shape shape = static_cast<Part::Feature*>(*it)->Shape.getValue();
TopoDS_Shape shape = Feature::getShape(*it);
if (shape.IsNull())
return new App::DocumentObjectExecReturn("Linked shape is invalid.");
@@ -424,12 +422,12 @@ App::DocumentObjectExecReturn *Sweep::execute(void)
if (Sections.getSize() == 0)
return new App::DocumentObjectExecReturn("No sections linked.");
App::DocumentObject* spine = Spine.getValue();
if (!(spine && spine->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())))
if (!spine)
return new App::DocumentObjectExecReturn("No spine linked.");
const std::vector<std::string>& subedge = Spine.getSubValues();
TopoDS_Shape path;
const Part::TopoShape& shape = static_cast<Part::Feature*>(spine)->Shape.getValue();
const Part::TopoShape& shape = Feature::getTopoShape(spine);
if (!shape.getShape().IsNull()) {
try {
if (!subedge.empty()) {
@@ -483,9 +481,7 @@ App::DocumentObjectExecReturn *Sweep::execute(void)
const std::vector<App::DocumentObject*>& shapes = Sections.getValues();
std::vector<App::DocumentObject*>::const_iterator it;
for (it = shapes.begin(); it != shapes.end(); ++it) {
if (!(*it)->isDerivedFrom(Part::Feature::getClassTypeId()))
return new App::DocumentObjectExecReturn("Linked object is not a shape.");
TopoDS_Shape shape = static_cast<Part::Feature*>(*it)->Shape.getValue();
TopoDS_Shape shape = Feature::getShape(*it);
if (shape.IsNull())
return new App::DocumentObjectExecReturn("Linked shape is invalid.");
@@ -638,9 +634,9 @@ void Thickness::handleChangedPropertyType(Base::XMLReader &reader, const char *T
App::DocumentObjectExecReturn *Thickness::execute(void)
{
App::DocumentObject* source = Faces.getValue();
if (!(source && source->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())))
if (!source)
return new App::DocumentObjectExecReturn("No source shape linked.");
const TopoShape& shape = static_cast<Part::Feature*>(source)->Shape.getShape();
const TopoShape& shape = Feature::getTopoShape(source);
if (shape.isNull())
return new App::DocumentObjectExecReturn("Source shape is empty.");

View File

@@ -33,11 +33,11 @@
#include <Mod/Part/App/TopoShapeCompoundPy.h>
namespace Part {
PartExport Py::Object shape2pyshape(const TopoDS_Shape &shape)
PartExport Py::Object shape2pyshape(const TopoShape &shape)
{
PyObject* ret = 0;
if (!shape.IsNull()) {
TopAbs_ShapeEnum type = shape.ShapeType();
if (!shape.isNull()) {
TopAbs_ShapeEnum type = shape.getShape().ShapeType();
switch (type)
{
case TopAbs_COMPOUND:
@@ -79,6 +79,11 @@ PartExport Py::Object shape2pyshape(const TopoDS_Shape &shape)
return Py::asObject(ret);
}
PartExport Py::Object shape2pyshape(const TopoDS_Shape &shape) {
return shape2pyshape(TopoShape(shape));
}
} //namespace Part

View File

@@ -32,4 +32,11 @@ namespace Py {
bool TopoShape::accepts (PyObject *pyob) const;
}
namespace Part {
PartExport Py::Object shape2pyshape(const TopoShape &shape);
PartExport Py::Object shape2pyshape(const TopoDS_Shape &shape);
PartExport void getPyShapes(PyObject *obj, std::vector<TopoShape> &shapes);
PartExport std::vector<TopoShape> getPyShapes(PyObject *obj);
}
#endif //PART_PYCXX_H

View File

@@ -181,6 +181,8 @@
#endif
#endif // _PreComp_
#include <boost/algorithm/string/predicate.hpp>
#include <Base/Builder3D.h>
#include <Base/FileInfo.h>
#include <Base/Exception.h>
@@ -188,6 +190,7 @@
#include <Base/Console.h>
#include <App/Material.h>
#include "PartPyCXX.h"
#include "TopoShape.h"
#include "CrossSection.h"
#include "TopoShapeFacePy.h"
@@ -200,6 +203,8 @@
#include "FaceMakerBullseye.h"
#include "BRepOffsetAPI_MakeOffsetFix.h"
FC_LOG_LEVEL_INIT("TopoShape",true,true);
using namespace Part;
const char* BRepBuilderAPI_FaceErrorText(BRepBuilderAPI_FaceError et)
@@ -298,6 +303,7 @@ TopoShape::TopoShape(const TopoDS_Shape& shape)
TopoShape::TopoShape(const TopoShape& shape)
: _Shape(shape._Shape)
{
Tag = shape.Tag;
}
std::vector<const char*> TopoShape::getElementTypes(void) const
@@ -323,88 +329,188 @@ Data::Segment* TopoShape::getSubElement(const char* Type, unsigned long n) const
return new ShapeSegment(getSubShape(temp.c_str()));
}
TopoDS_Shape TopoShape::getSubShape(const char* Type) const
TopoDS_Shape TopoShape::getSubShape(const char* Type, bool silent) const
{
if (!Type)
Standard_Failure::Raise("No sub-shape type given");
if (this->_Shape.IsNull())
auto res = shapeTypeAndIndex(Type);
return getSubShape(res.first,res.second,silent);
}
TopoDS_Shape TopoShape::getSubShape(TopAbs_ShapeEnum type, int index, bool silent) const
{
if(index <= 0) {
if(silent)
return TopoDS_Shape();
Standard_Failure::Raise("Unsupported sub-shape type");
}
if (this->_Shape.IsNull()) {
if(silent)
return TopoDS_Shape();
Standard_Failure::Raise("Cannot get sub-shape from empty shape");
std::string shapetype(Type);
if (shapetype.size() > 4 && shapetype.substr(0,4) == "Face") {
int index=std::atoi(&shapetype[4]);
TopTools_IndexedMapOfShape anIndices;
TopExp::MapShapes(this->_Shape, TopAbs_FACE, anIndices);
// To avoid a segmentation fault we have to check if container is empty
if (anIndices.IsEmpty())
Standard_Failure::Raise("Shape has no faces");
return anIndices.FindKey(index);
}
else if (shapetype.size() > 4 && shapetype.substr(0,4) == "Edge") {
int index=std::atoi(&shapetype[4]);
TopTools_IndexedMapOfShape anIndices;
TopExp::MapShapes(this->_Shape, TopAbs_EDGE, anIndices);
// To avoid a segmentation fault we have to check if container is empty
if (anIndices.IsEmpty())
Standard_Failure::Raise("Shape has no edges");
return anIndices.FindKey(index);
}
else if (shapetype.size() > 6 && shapetype.substr(0,6) == "Vertex") {
int index=std::atoi(&shapetype[6]);
TopTools_IndexedMapOfShape anIndices;
TopExp::MapShapes(this->_Shape, TopAbs_VERTEX, anIndices);
// To avoid a segmentation fault we have to check if container is empty
if (anIndices.IsEmpty())
Standard_Failure::Raise("Shape has no vertexes");
return anIndices.FindKey(index);
}
Standard_Failure::Raise("Unsupported sub-shape type");
return TopoDS_Shape(); // avoid compiler warning
try {
if(type == TopAbs_SHAPE) {
int i=1;
for(TopoDS_Iterator it(_Shape);it.More();it.Next(),++i) {
if(i == index)
return it.Value();
}
} else {
TopTools_IndexedMapOfShape anIndices;
TopExp::MapShapes(this->_Shape, type, anIndices);
if(index <= anIndices.Extent())
return anIndices.FindKey(index);
}
} catch(Standard_Failure &) {
if(silent)
return TopoDS_Shape();
throw;
}
if(!silent)
Standard_Failure::Raise("Index out of bound");
return TopoDS_Shape();
}
unsigned long TopoShape::countSubShapes(const char* Type) const
{
std::string shapetype(Type);
if (shapetype == "Face") {
TopTools_IndexedMapOfShape anIndices;
TopExp::MapShapes(this->_Shape, TopAbs_FACE, anIndices);
return anIndices.Extent();
}
else if (shapetype == "Edge") {
TopTools_IndexedMapOfShape anIndices;
TopExp::MapShapes(this->_Shape, TopAbs_EDGE, anIndices);
return anIndices.Extent();
}
else if (shapetype == "Vertex") {
TopTools_IndexedMapOfShape anIndices;
TopExp::MapShapes(this->_Shape, TopAbs_VERTEX, anIndices);
return anIndices.Extent();
}
return 0;
if(!Type) return 0;
if(strcmp(Type,"SubShape")==0)
return countSubShapes(TopAbs_SHAPE);
auto type = shapeType(Type,true);
if(type == TopAbs_SHAPE)
return 0;
return countSubShapes(type);
}
PyObject * TopoShape::getPySubShape(const char* Type) const
unsigned long TopoShape::countSubShapes(TopAbs_ShapeEnum Type) const
{
// get the shape
TopoDS_Shape Shape = getSubShape(Type);
// destinquish the return type
std::string shapetype(Type);
if (shapetype.size() > 4 && shapetype.substr(0,4) == "Face")
return new TopoShapeFacePy(new TopoShape(Shape));
else if (shapetype.size() > 4 && shapetype.substr(0,4) == "Edge")
return new TopoShapeEdgePy(new TopoShape(Shape));
else if (shapetype.size() > 6 && shapetype.substr(0,6) == "Vertex")
return new TopoShapeVertexPy(new TopoShape(Shape));
else
return 0;
if(Type == TopAbs_SHAPE) {
int count = 0;
for(TopoDS_Iterator it(_Shape);it.More();it.Next())
++count;
return count;
}
TopTools_IndexedMapOfShape anIndices;
TopExp::MapShapes(this->_Shape, Type, anIndices);
return anIndices.Extent();
}
bool TopoShape::hasSubShape(TopAbs_ShapeEnum type) const {
if(type == TopAbs_SHAPE) {
TopoDS_Iterator it(_Shape);
return !!it.More();
}
TopExp_Explorer exp(_Shape,type);
return !!exp.More();
}
bool TopoShape::hasSubShape(const char *Type) const {
auto idx = shapeTypeAndIndex(Type);
return idx.second>0 && idx.second<=(int)countSubShapes(idx.first);
}
static std::array<std::string,TopAbs_SHAPE> _ShapeNames;
static void initShapeNameMap() {
if(_ShapeNames[TopAbs_VERTEX].empty()) {
_ShapeNames[TopAbs_VERTEX] = "Vertex";
_ShapeNames[TopAbs_EDGE] = "Edge";
_ShapeNames[TopAbs_FACE] = "Face";
_ShapeNames[TopAbs_WIRE] = "Wire";
_ShapeNames[TopAbs_SHELL] = "Shell";
_ShapeNames[TopAbs_SOLID] = "Solid";
_ShapeNames[TopAbs_COMPOUND] = "Compound";
_ShapeNames[TopAbs_COMPSOLID] = "CompSolid";
}
}
std::pair<TopAbs_ShapeEnum,int> TopoShape::shapeTypeAndIndex(const char *name) {
int idx = 0;
TopAbs_ShapeEnum type = TopAbs_SHAPE;
static const std::string _subshape("SubShape");
if(boost::starts_with(name,_subshape)) {
std::istringstream iss(name+_subshape.size());
iss >> idx;
if(!iss.eof())
idx = 0;
} else {
type = shapeType(name,true);
if(type != TopAbs_SHAPE) {
std::istringstream iss(name+shapeName(type).size());
iss >> idx;
if(!iss.eof()) {
idx = 0;
type = TopAbs_SHAPE;
}
}
}
return std::make_pair(type,idx);
}
TopAbs_ShapeEnum TopoShape::shapeType(const char *type, bool silent) {
if(type) {
initShapeNameMap();
for(size_t idx=0;idx<_ShapeNames.size();++idx) {
if(_ShapeNames[idx].size() && boost::starts_with(type,_ShapeNames[idx]))
return (TopAbs_ShapeEnum)idx;
}
}
if(!silent) {
if(Data::ComplexGeoData::hasMissingElement(type))
FC_THROWM(Base::CADKernelError,"missing shape element: " << (type?type:"?"));
FC_THROWM(Base::CADKernelError,"invalid shape type: " << (type?type:"?"));
}
return TopAbs_SHAPE;
}
TopAbs_ShapeEnum TopoShape::shapeType(char type, bool silent) {
switch(type) {
case 'E':
return TopAbs_EDGE;
case 'V':
return TopAbs_VERTEX;
case 'F':
return TopAbs_FACE;
default:
if(!silent)
FC_THROWM(Base::CADKernelError, "invalid shape type '" << type << "'");
return TopAbs_SHAPE;
}
}
TopAbs_ShapeEnum TopoShape::shapeType(bool silent) const {
if(isNull()) {
if(!silent)
FC_THROWM(NullShapeException, "Input shape is null");
return TopAbs_SHAPE;
}
return getShape().ShapeType();
}
const std::string &TopoShape::shapeName(TopAbs_ShapeEnum type, bool silent) {
initShapeNameMap();
if(type>=0 && type<_ShapeNames.size() && _ShapeNames[type].size())
return _ShapeNames[type];
if(!silent)
FC_THROWM(Base::CADKernelError, "invalid shape type '" << type << "'");
static std::string ret("");
return ret;
}
const std::string &TopoShape::shapeName(bool silent) const {
return shapeName(shapeType(silent),silent);
}
PyObject * TopoShape::getPySubShape(const char* Type, bool silent) const
{
return Py::new_reference_to(shape2pyshape(getSubShape(Type,silent)));
}
void TopoShape::operator = (const TopoShape& sh)
{
if (this != &sh) {
this->Tag = sh.Tag;
this->_Shape = sh._Shape;
}
}
@@ -470,6 +576,18 @@ void TopoShape::convertToMatrix(const gp_Trsf& trsf, Base::Matrix4D& mtrx)
#endif
}
Base::Matrix4D TopoShape::convert(const gp_Trsf& trsf) {
Base::Matrix4D mat;
convertToMatrix(trsf,mat);
return mat;
}
gp_Trsf TopoShape::convert(const Base::Matrix4D& mtrx) {
gp_Trsf trsf;
convertTogpTrsf(mtrx,trsf);
return trsf;
}
void TopoShape::setTransform(const Base::Matrix4D& rclTrf)
{
gp_Trsf mov;
@@ -2841,7 +2959,10 @@ TopoDS_Shape TopoShape::makeThickSolid(const TopTools_ListOfShape& remFace,
void TopoShape::transformGeometry(const Base::Matrix4D &rclMat)
{
this->_Shape = transformGShape(rclMat);
if (this->_Shape.IsNull())
Standard_Failure::Raise("Cannot transform null shape");
*this = makEGTransform(rclMat);
}
TopoDS_Shape TopoShape::transformGShape(const Base::Matrix4D& rclTrf) const
@@ -2868,23 +2989,12 @@ TopoDS_Shape TopoShape::transformGShape(const Base::Matrix4D& rclTrf) const
return mkTrf.Shape();
}
void TopoShape::transformShape(const Base::Matrix4D& rclTrf, bool copy)
bool TopoShape::transformShape(const Base::Matrix4D& rclTrf, bool copy, bool checkScale)
{
if (this->_Shape.IsNull())
Standard_Failure::Raise("Cannot transform null shape");
gp_Trsf mat;
mat.SetValues(rclTrf[0][0],rclTrf[0][1],rclTrf[0][2],rclTrf[0][3],
rclTrf[1][0],rclTrf[1][1],rclTrf[1][2],rclTrf[1][3],
rclTrf[2][0],rclTrf[2][1],rclTrf[2][2],rclTrf[2][3]
#if OCC_VERSION_HEX < 0x060800
, 0.00001,0.00001
#endif
); //precision was removed in OCCT CR0025194
// location transformation
BRepBuilderAPI_Transform mkTrf(this->_Shape, mat, copy ? Standard_True : Standard_False);
this->_Shape = mkTrf.Shape();
return _makETransform(TopoShape(*this),rclTrf,0,checkScale,copy);
}
TopoDS_Shape TopoShape::mirror(const gp_Ax2& ax2) const
@@ -3428,6 +3538,10 @@ void TopoShape::getLinesFromSubelement(const Data::Segment* element,
return;
}
// build up map edge->face
TopTools_IndexedDataMapOfShapeListOfShape edge2Face;
TopExp::MapShapesAndAncestors(this->_Shape, TopAbs_EDGE, TopAbs_FACE, edge2Face);
for(TopExp_Explorer exp(shape,TopAbs_EDGE);exp.More();exp.Next()) {
TopoDS_Edge aEdge = TopoDS::Edge(exp.Current());
@@ -3460,12 +3574,16 @@ void TopoShape::getLinesFromSubelement(const Data::Segment* element,
// must provide this triangulation
// Look for one face in our map (it doesn't care which one we take)
auto aFace = findAncestorShape(aEdge, TopAbs_FACE);
if(aFace.IsNull())
int index = edge2Face.FindIndex(aEdge);
if(!index)
continue;
const auto &faces = edge2Face.FindFromIndex(index);
if(!faces.Extent())
continue;
const TopoDS_Face& aFace = TopoDS::Face(faces.First());
// take the face's triangulation instead
Handle(Poly_Triangulation) aPolyTria = BRep_Tool::Triangulation(TopoDS::Face(aFace),aLoc);
Handle(Poly_Triangulation) aPolyTria = BRep_Tool::Triangulation(aFace,aLoc);
if (!aLoc.IsIdentity()) {
myTransf = aLoc.Transformation();
}
@@ -3691,3 +3809,286 @@ TopoDS_Shape TopoShape::makeShell(const TopoDS_Shape& input) const
return input;
}
}
#define _HANDLE_NULL_SHAPE(_msg,_throw) do {\
if(_throw) {\
FC_THROWM(NullShapeException,_msg);\
}\
FC_WARN(_msg);\
}while(0)
#define HANDLE_NULL_SHAPE _HANDLE_NULL_SHAPE("Null shape",true)
#define HANDLE_NULL_INPUT _HANDLE_NULL_SHAPE("Null input shape",true)
#define WARN_NULL_INPUT _HANDLE_NULL_SHAPE("Null input shape",false)
TopoShape &TopoShape::makEWires(const TopoShape &shape, const char *op, bool fix, double tol)
{
_Shape.Nullify();
if(shape.isNull())
HANDLE_NULL_INPUT;
if(tol<Precision::Confusion()) tol = Precision::Confusion();
(void)op;
(void)fix;
std::vector<TopoShape> edges;
std::list<TopoShape> edge_list;
std::vector<TopoShape> wires;
TopTools_IndexedMapOfShape anIndices;
TopExp::MapShapes(shape.getShape(), TopAbs_EDGE, anIndices);
for(int i=1;i<=anIndices.Extent();++i)
edge_list.push_back(anIndices.FindKey(i));
edges.reserve(edge_list.size());
wires.reserve(edge_list.size());
// sort them together to wires
while (edge_list.size() > 0) {
BRepBuilderAPI_MakeWire mkWire;
// add and erase first edge
edges.push_back(edge_list.front());
edge_list.pop_front();
mkWire.Add(TopoDS::Edge(edges.back().getShape()));
edges.back().setShape(mkWire.Edge());
TopoDS_Wire new_wire = mkWire.Wire(); // current new wire
// try to connect each edge to the wire, the wire is complete if no more edges are connectible
bool found = false;
do {
found = false;
for (auto it=edge_list.begin();it!=edge_list.end();++it) {
mkWire.Add(TopoDS::Edge(it->getShape()));
if (mkWire.Error() != BRepBuilderAPI_DisconnectedWire) {
// edge added ==> remove it from list
found = true;
edges.push_back(*it);
edges.back().setShape(mkWire.Edge());
edge_list.erase(it);
new_wire = mkWire.Wire();
break;
}
}
} while (found);
// Fix any topological issues of the wire
ShapeFix_Wire aFix;
aFix.SetPrecision(tol);
aFix.Load(new_wire);
aFix.FixReorder();
// Assuming FixReorder() just reorder and don't change the underlying
// edges, we get the wire and do a name mapping now, as the following
// two operations (FixConnected and FixClosed) may change the edges.
wires.push_back(aFix.Wire());
aFix.FixConnected();
aFix.FixClosed();
// Now retrieve the shape and set it without touching element map
wires.back().setShape(aFix.Wire());
}
return makECompound(wires,0,false);
}
TopoShape &TopoShape::makECompound(const std::vector<TopoShape> &shapes, const char *op, bool force)
{
(void)op;
_Shape.Nullify();
if(shapes.empty())
HANDLE_NULL_INPUT;
if(!force && shapes.size()==1) {
*this = shapes[0];
return *this;
}
BRep_Builder builder;
TopoDS_Compound comp;
builder.MakeCompound(comp);
int count = 0;
for(auto &s : shapes) {
if(s.isNull()) {
WARN_NULL_INPUT;
continue;
}
builder.Add(comp,s.getShape());
++count;
}
if(!count)
HANDLE_NULL_SHAPE;
_Shape = comp;
return *this;
}
TopoShape &TopoShape::makEFace(const TopoShape &shape, const char *op, const char *maker)
{
std::vector<TopoShape> shapes;
if(shape.getShape().ShapeType() == TopAbs_COMPOUND) {
for(TopoDS_Iterator it(_Shape);it.More();it.Next())
shapes.push_back(it.Value());
} else
shapes.push_back(shape);
return makEFace(shapes,op,maker);
}
TopoShape &TopoShape::makEFace(const std::vector<TopoShape> &shapes, const char *op, const char *maker)
{
(void)op;
_Shape.Nullify();
if(!maker || !maker[0]) maker = "Part::FaceMakerBullseye";
std::unique_ptr<FaceMaker> mkFace = FaceMaker::ConstructFromType(maker);
for(auto &s : shapes) {
if (s.getShape().ShapeType() == TopAbs_COMPOUND)
mkFace->useCompound(TopoDS::Compound(s.getShape()));
else
mkFace->addShape(s.getShape());
}
mkFace->Build();
_Shape = mkFace->Shape();
return *this;
}
TopoShape &TopoShape::makERefine(const TopoShape &shape, const char *op, bool no_fail) {
(void)op;
_Shape.Nullify();
if(shape.isNull()) {
if(!no_fail)
HANDLE_NULL_SHAPE;
return *this;
}
try {
BRepBuilderAPI_RefineModel mkRefine(shape.getShape());
_Shape = mkRefine.Shape();
return *this;
}catch (Standard_Failure &) {
if(!no_fail) throw;
}
*this = shape;
return *this;
}
bool TopoShape::findPlane(gp_Pln &pln, double tol) const {
if(_Shape.IsNull())
return false;
TopoDS_Shape shape = _Shape;
TopExp_Explorer exp(_Shape,TopAbs_FACE);
if(exp.More()) {
auto face = exp.Current();
exp.Next();
if(!exp.More()) {
BRepAdaptor_Surface adapt(TopoDS::Face(face));
if(adapt.GetType() != GeomAbs_Plane)
return false;
pln = adapt.Plane();
return true;
}
}else{
TopExp_Explorer exp(_Shape,TopAbs_EDGE);
if(exp.More()) {
TopoDS_Shape edge = exp.Current();
exp.Next();
if(!exp.More()) {
// To deal with OCCT bug of wrong edge transformation
shape = BRepBuilderAPI_Copy(edge).Shape();
}
}
}
try {
BRepLib_FindSurface finder(shape,tol,Standard_True);
if (!finder.Found())
return false;
pln = GeomAdaptor_Surface(finder.Surface()).Plane();
return true;
}catch (Standard_Failure &e) {
// For some reason the above BRepBuilderAPI_Copy failed to copy
// the geometry of some edge, causing exception with message
// BRepAdaptor_Curve::No geometry. However, without the above
// copy, circular edges often have the wrong transformation!
FC_LOG("failed to find surface: " << e.GetMessageString());
return false;
}
}
bool TopoShape::isCoplanar(const TopoShape &other, double tol) const {
if(isNull() || other.isNull())
return false;
if(_Shape.IsEqual(other._Shape))
return true;
gp_Pln pln1,pln2;
if(!findPlane(pln1,tol) || !other.findPlane(pln2,tol))
return false;
if(tol<0.0)
tol = Precision::Confusion();
return pln1.Position().IsCoplanar(pln2.Position(),tol,tol);
}
bool TopoShape::_makETransform(const TopoShape &shape,
const Base::Matrix4D &rclTrf, const char *op, bool checkScale, bool copy)
{
if(checkScale) {
if(rclTrf.hasScale()<0) {
makEGTransform(shape,rclTrf,op,copy);
return true;
}
}
makETransform(shape,convert(rclTrf),op,copy);
return false;
}
TopoShape &TopoShape::makETransform(const TopoShape &shape, const gp_Trsf &trsf, const char *op, bool copy) {
// resetElementMap();
if(!copy) {
// OCCT checks the ScaleFactor against gp::Resolution() which is DBL_MIN!!!
copy = trsf.ScaleFactor()*trsf.HVectorialPart().Determinant() < 0. ||
Abs(Abs(trsf.ScaleFactor()) - 1) > Precision::Confusion();
}
TopoShape tmp(shape);
if(copy) {
BRepBuilderAPI_Transform mkTrf(shape.getShape(), trsf, Standard_True);
// TODO: calling Moved() is to make sure the shape has some Location,
// which is necessary for STEP export to work. However, if we reach
// here, it porabably means BRepBuilderAPI_Transform has modified
// underlying shapes (because of scaling), it will break compound child
// parent relationship anyway. In short, STEP import/export will most
// likely break badly if there is any scaling involved
tmp._Shape = mkTrf.Shape().Moved(gp_Trsf());
}else
tmp._Shape.Move(trsf);
if(op || (shape.Tag && shape.Tag!=Tag)) {
_Shape = tmp._Shape;
// tmp.initCache(1);
// mapSubElement(tmp,op);
} else
*this = tmp;
return *this;
}
TopoShape &TopoShape::makEGTransform(const TopoShape &shape,
const Base::Matrix4D &rclTrf, const char *op, bool copy)
{
(void)op;
gp_GTrsf mat;
mat.SetValue(1,1,rclTrf[0][0]);
mat.SetValue(2,1,rclTrf[1][0]);
mat.SetValue(3,1,rclTrf[2][0]);
mat.SetValue(1,2,rclTrf[0][1]);
mat.SetValue(2,2,rclTrf[1][1]);
mat.SetValue(3,2,rclTrf[2][1]);
mat.SetValue(1,3,rclTrf[0][2]);
mat.SetValue(2,3,rclTrf[1][2]);
mat.SetValue(3,3,rclTrf[2][2]);
mat.SetValue(1,4,rclTrf[0][3]);
mat.SetValue(2,4,rclTrf[1][3]);
mat.SetValue(3,4,rclTrf[2][3]);
// geometric transformation
BRepBuilderAPI_GTransform mkTrf(shape.getShape(), mat, copy);
_Shape = mkTrf.Shape();
return *this;
}

View File

@@ -123,6 +123,8 @@ public:
virtual bool getCenterOfGravity(Base::Vector3d& center) const;
static void convertTogpTrsf(const Base::Matrix4D& mtrx, gp_Trsf& trsf);
static void convertToMatrix(const gp_Trsf& trsf, Base::Matrix4D& mtrx);
static Base::Matrix4D convert(const gp_Trsf& trsf);
static gp_Trsf convert(const Base::Matrix4D& mtrx);
//@}
/** @name Subelement management */
@@ -148,10 +150,14 @@ public:
std::vector<Facet> &faces) const;
//@}
/// get the Topo"sub"Shape with the given name
TopoDS_Shape getSubShape(const char* Type) const;
TopoDS_Shape getSubShape(const char* Type, bool silent=false) const;
TopoDS_Shape getSubShape(TopAbs_ShapeEnum type, int idx, bool silent=false) const;
unsigned long countSubShapes(const char* Type) const;
unsigned long countSubShapes(TopAbs_ShapeEnum type) const;
bool hasSubShape(const char *Type) const;
bool hasSubShape(TopAbs_ShapeEnum type) const;
/// get the Topo"sub"Shape with the given name
PyObject * getPySubShape(const char* Type) const;
PyObject * getPySubShape(const char* Type, bool silent=false) const;
/** @name Save/restore */
//@{
@@ -189,6 +195,8 @@ public:
bool isValid() const;
bool analyze(bool runBopCheck, std::ostream&) const;
bool isClosed() const;
bool isCoplanar(const TopoShape &other, double tol=-1) const;
bool findPlane(gp_Pln &pln, double tol=-1) const;
//@}
/** @name Boolean operation*/
@@ -263,7 +271,7 @@ public:
//@{
void transformGeometry(const Base::Matrix4D &rclMat);
TopoDS_Shape transformGShape(const Base::Matrix4D&) const;
void transformShape(const Base::Matrix4D&, bool copy);
bool transformShape(const Base::Matrix4D&, bool copy, bool checkScale=false);
TopoDS_Shape mirror(const gp_Ax2&) const;
TopoDS_Shape toNurbs() const;
TopoDS_Shape replaceShape(const std::vector< std::pair<TopoDS_Shape,TopoDS_Shape> >& s) const;
@@ -289,6 +297,68 @@ public:
void getDomains(std::vector<Domain>&) const;
//@}
/** @name Element name mapping aware shape maker
*
* To be complete in next batch of patches
*/
//@{
TopoShape &makECompound(const std::vector<TopoShape> &shapes, const char *op=0, bool force=true);
TopoShape &makEWires(const TopoShape &shape, const char *op=0, bool fix=false, double tol=0.0);
TopoShape makEWires(const char *op=0, bool fix=false, double tol=0.0) const {
return TopoShape().makEWires(*this,op,fix,tol);
}
TopoShape &makEFace(const std::vector<TopoShape> &shapes, const char *op=0, const char *maker=0);
TopoShape &makEFace(const TopoShape &shape, const char *op=0, const char *maker=0);
TopoShape makEFace(const char *op=0, const char *maker=0) const {
return TopoShape().makEFace(*this,op,maker);
}
bool _makETransform(const TopoShape &shape, const Base::Matrix4D &mat,
const char *op=0, bool checkScale=false, bool copy=false);
TopoShape &makETransform(const TopoShape &shape, const Base::Matrix4D &mat,
const char *op=0, bool checkScale=false, bool copy=false) {
_makETransform(shape,mat,op,checkScale,copy);
return *this;
}
TopoShape makETransform(const Base::Matrix4D &mat, const char *op=0,
bool checkScale=false, bool copy=false) const {
return TopoShape().makETransform(*this,mat,op,checkScale,copy);
}
TopoShape &makETransform(const TopoShape &shape, const gp_Trsf &trsf,
const char *op=0, bool copy=false);
TopoShape makETransform(const gp_Trsf &trsf, const char *op=0, bool copy=false) const {
return TopoShape().makETransform(*this,trsf,op,copy);
}
void move(const TopLoc_Location &loc) {
_Shape.Move(loc);
}
TopoShape moved(const TopLoc_Location &loc) const {
TopoShape ret(*this);
ret._Shape.Move(loc);
return ret;
}
TopoShape &makEGTransform(const TopoShape &shape, const Base::Matrix4D &mat,
const char *op=0, bool copy=false);
TopoShape makEGTransform(const Base::Matrix4D &mat, const char *op=0, bool copy=false) const {
return TopoShape().makEGTransform(*this,mat,op,copy);
}
TopoShape &makERefine(const TopoShape &shape, const char *op=0, bool no_fail=true);
TopoShape makERefine(const char *op=0, bool no_fail=true) const {
return TopoShape().makERefine(*this,op,no_fail);
}
//@}
static TopAbs_ShapeEnum shapeType(const char *type,bool silent=false);
static TopAbs_ShapeEnum shapeType(char type,bool silent=false);
TopAbs_ShapeEnum shapeType(bool silent=false) const;
static const std::string &shapeName(TopAbs_ShapeEnum type,bool silent=false);
const std::string &shapeName(bool silent=false) const;
static std::pair<TopAbs_ShapeEnum,int> shapeTypeAndIndex(const char *name);
private:
TopoDS_Shape _Shape;
};

View File

@@ -335,7 +335,19 @@ transformGeometry(Matrix) -> Shape
<Documentation>
<UserDocu>Apply transformation on a shape without changing
the underlying geometry.
transformShape(Matrix,[boolean copy=False]) -> None</UserDocu>
transformShape(Matrix,[boolean copy=False, checkScale=False]) -> None
If checkScale is True, it will use transformGeometry if non-uniform
scaling is detected.</UserDocu>
</Documentation>
</Methode>
<Methode Name="transformed" Const="true" Keyword="true">
<Documentation>
<UserDocu>
transformed(Matrix,copy=False,checkScale=False,op=None) -> shape
Create a new transformed shape
</UserDocu>
</Documentation>
</Methode>
<Methode Name="translate">
@@ -343,11 +355,29 @@ transformShape(Matrix,[boolean copy=False]) -> None</UserDocu>
<UserDocu>Apply the translation to the current location of this shape.</UserDocu>
</Documentation>
</Methode>
<Methode Name="translated">
<Documentation>
<UserDocu>
translated(vector) -> shape
Create a new shape with translation
</UserDocu>
</Documentation>
</Methode>
<Methode Name="rotate">
<Documentation>
<UserDocu>
Apply the rotation (degree) to the current location of this shape
Shp.rotate(Vector(0,0,0),Vector(0,0,1),180) - rotate the shape around the Z Axis 180 degrees.
Apply the rotation (base,dir,degree) to the current location of this shape
Shp.rotate(Vector(0,0,0),Vector(0,0,1),180) - rotate the shape around the Z Axis 180 degrees.
</UserDocu>
</Documentation>
</Methode>
<Methode Name="rotated">
<Documentation>
<UserDocu>
rotated(base,dir,degree) -> shape
Create a new shape with rotation.
</UserDocu>
</Documentation>
</Methode>
@@ -356,6 +386,15 @@ transformShape(Matrix,[boolean copy=False]) -> None</UserDocu>
<UserDocu>Apply scaling with point and factor to this shape.</UserDocu>
</Documentation>
</Methode>
<Methode Name="scaled">
<Documentation>
<UserDocu>
scaled(factor,base=Vector(0,0,0)) -> shape
Create a new shape with scale.
</UserDocu>
</Documentation>
</Methode>
<Methode Name="makeFillet" Const="true">
<Documentation>
<UserDocu>Make fillet.</UserDocu>
@@ -428,6 +467,23 @@ Returns: result of offsetting (wire or face or compound of those). Compounding
structure follows that of source shape.</UserDocu>
</Documentation>
</Methode>
<Methode Name="makeWires">
<Documentation>
<UserDocu>
makeWires(op=None): make wire(s) using the edges of this shape
The function will sort any edges inside the current shape, and connect them
into wire. If more than one wire is found, then it will make a compound out of
all found wires.
This function is element mapping aware. If the input shape has non-zero Tag,
it will map any edge and vertex element name inside the input shape into the
itself.
op: an optional string to be appended when auto generates element mapping.
</UserDocu>
</Documentation>
</Methode>
<Methode Name="reverse">
<Documentation>
<UserDocu>Reverses the orientation of this shape.</UserDocu>
@@ -486,6 +542,16 @@ If the shape is an edge it returns True if its vertices are the same.
<UserDocu>Checks if the shape is valid, i.e. neither null, nor empty nor corrupted.</UserDocu>
</Documentation>
</Methode>
<Methode Name="isCoplanar" Const="true">
<Documentation>
<UserDocu>isCoplanar(shape,tol=None) -- Checks if this shape is coplanar with the given shape.</UserDocu>
</Documentation>
</Methode>
<Methode Name="findPlane" Const="true">
<Documentation>
<UserDocu>findPlane(tol=None) -- return a plane if the shape is planar</UserDocu>
</Documentation>
</Methode>
<Methode Name="fix">
<Documentation>
<UserDocu>Tries to fix a broken shape. True is returned if the operation succeeded, False otherwise.
@@ -635,6 +701,11 @@ infos contains additional info on the solutions. It is a list of tuples:
<UserDocu>Returns a SubElement</UserDocu>
</Documentation>
</Methode>
<Methode Name="countElement" Const="true">
<Documentation>
<UserDocu>Returns the count of a type of element</UserDocu>
</Documentation>
</Methode>
<Methode Name="getTolerance" Const="true">
<Documentation>
<UserDocu>
@@ -796,6 +867,12 @@ infos contains additional info on the solutions. It is a list of tuples:
</Documentation>
<Parameter Name="Compounds" Type="List"/>
</Attribute>
<Attribute Name="SubShapes" ReadOnly="true">
<Documentation>
<UserDocu>List of sub-shapes in this shape.</UserDocu>
</Documentation>
<Parameter Name="SubShapes" Type="List"/>
</Attribute>
<Attribute Name="Length" ReadOnly="true">
<Documentation>
<UserDocu>Total length of the edges of the shape.</UserDocu>

View File

@@ -47,6 +47,7 @@
# include <gp_Dir.hxx>
# include <gp_Pnt.hxx>
# include <gp_Trsf.hxx>
# include <gp_Pln.hxx>
# include <Poly_Polygon3D.hxx>
# include <Poly_Triangulation.hxx>
# include <TopExp_Explorer.hxx>
@@ -58,6 +59,7 @@
# include <TopLoc_Location.hxx>
# include <TopExp.hxx>
# include <Precision.hxx>
# include <Geom_Plane.hxx>
# include <HLRAppli_ReflectLines.hxx>
# include <BRepGProp.hxx>
# include <GProp_GProps.hxx>
@@ -91,6 +93,7 @@
#include <Mod/Part/App/TopoShapeShellPy.h>
#include <Mod/Part/App/TopoShapeCompSolidPy.h>
#include <Mod/Part/App/TopoShapeCompoundPy.h>
#include <Mod/Part/App/PlanePy.h>
using namespace Part;
@@ -102,10 +105,6 @@ using namespace Part;
#define M_PI_2 1.57079632679489661923 /* pi/2 */
#endif
namespace Part {
extern Py::Object shape2pyshape(const TopoDS_Shape &shape);
}
// returns a string which represents the object e.g. when printed in python
std::string TopoShapePy::representation(void) const
{
@@ -127,29 +126,31 @@ int TopoShapePy::PyInit(PyObject* args, PyObject*)
if (!PyArg_ParseTuple(args, "|O", &pcObj))
return -1;
auto shapes = getPyShapes(pcObj);
if (pcObj) {
TopoShape shape;
try {
Py::Sequence list(pcObj);
bool first = true;
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
if (PyObject_TypeCheck((*it).ptr(), &(Part::GeometryPy::Type))) {
TopoDS_Shape sh = static_cast<GeometryPy*>((*it).ptr())->
getGeometryPtr()->toShape();
if (first) {
first = false;
shape.setShape(sh);
}
else {
shape.setShape(shape.fuse(sh));
PY_TRY {
if(PyObject_TypeCheck(pcObj,&TopoShapePy::Type)) {
shape = *static_cast<TopoShapePy*>(pcObj)->getTopoShapePtr();
}else{
Py::Sequence list(pcObj);
bool first = true;
for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) {
if (PyObject_TypeCheck((*it).ptr(), &(Part::GeometryPy::Type))) {
TopoDS_Shape sh = static_cast<GeometryPy*>((*it).ptr())->
getGeometryPtr()->toShape();
if (first) {
first = false;
shape.setShape(sh);
}
else {
shape.setShape(shape.fuse(sh));
}
}
}
}
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return -1;
}
}_PY_CATCH_OCC(return(-1))
getTopoShapePtr()->setShape(shape.getShape());
}
@@ -1399,19 +1400,35 @@ PyObject* TopoShapePy::transformShape(PyObject *args)
{
PyObject *obj;
PyObject *copy = Py_False;
if (!PyArg_ParseTuple(args, "O!|O!", &(Base::MatrixPy::Type),&obj,&(PyBool_Type), &copy))
PyObject *checkScale = Py_False;
if (!PyArg_ParseTuple(args, "O!|O!O", &(Base::MatrixPy::Type),&obj,&(PyBool_Type), &copy,&checkScale))
return NULL;
Base::Matrix4D mat = static_cast<Base::MatrixPy*>(obj)->value();
try {
this->getTopoShapePtr()->transformShape(mat, PyObject_IsTrue(copy) ? true : false);
Py_Return;
}
catch (Standard_Failure& e) {
PY_TRY {
this->getTopoShapePtr()->transformShape(mat, PyObject_IsTrue(copy) ? true : false,
PyObject_IsTrue(checkScale));
return IncRef();
} PY_CATCH_OCC
}
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return NULL;
}
PyObject* TopoShapePy::transformed(PyObject *args, PyObject *keywds)
{
static char *kwlist[] = {"matrix", "copy", "checkScale", "op", NULL};
PyObject* pymat;
PyObject* copy = Py_False;
PyObject* checkScale = Py_False;
const char *op = 0;
if (!PyArg_ParseTupleAndKeywords(args, keywds, "O!|OOs", kwlist,
&Base::MatrixPy::Type, &pymat,&copy,&checkScale,&op))
return 0;
Base::Matrix4D mat = static_cast<Base::MatrixPy*>(pymat)->value();
(void)op;
PY_TRY {
TopoShape s(*getTopoShapePtr());
s.transformShape(mat,PyObject_IsTrue(copy),PyObject_IsTrue(checkScale));
return Py::new_reference_to(shape2pyshape(s));
}PY_CATCH_OCC
}
PyObject* TopoShapePy::translate(PyObject *args)
@@ -1438,7 +1455,7 @@ PyObject* TopoShapePy::translate(PyObject *args)
TopoDS_Shape shape = getTopoShapePtr()->getShape();
shape.Move(loc);
getTopoShapePtr()->setShape(shape);
Py_Return;
return IncRef();
}
PyObject* TopoShapePy::rotate(PyObject *args)
@@ -1448,7 +1465,7 @@ PyObject* TopoShapePy::rotate(PyObject *args)
if (!PyArg_ParseTuple(args, "OOd", &obj1, &obj2, &angle))
return NULL;
try {
PY_TRY {
// Vector also supports sequence
Py::Sequence p1(obj1), p2(obj2);
// Convert into OCC representation
@@ -1466,11 +1483,8 @@ PyObject* TopoShapePy::rotate(PyObject *args)
TopoDS_Shape shape = getTopoShapePtr()->getShape();
shape.Move(loc);
getTopoShapePtr()->setShape(shape);
Py_Return;
}
catch (const Py::Exception&) {
return NULL;
}
return IncRef();
} PY_CATCH_OCC
}
PyObject* TopoShapePy::scale(PyObject *args)
@@ -1492,20 +1506,30 @@ PyObject* TopoShapePy::scale(PyObject *args)
return NULL;
}
try {
PY_TRY {
gp_Trsf scl;
scl.SetScale(pos, factor);
BRepBuilderAPI_Transform BRepScale(scl);
bool bCopy = true;
BRepScale.Perform(getTopoShapePtr()->getShape(),bCopy);
getTopoShapePtr()->setShape(BRepScale.Shape());
Py_Return;
}
catch (Standard_Failure& e) {
return IncRef();
} PY_CATCH_OCC
}
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return NULL;
}
PyObject* TopoShapePy::translated(PyObject *args) {
Py::Object pyobj(shape2pyshape(*getTopoShapePtr()));
return static_cast<TopoShapePy*>(pyobj.ptr())->translate(args);
}
PyObject* TopoShapePy::rotated(PyObject *args) {
Py::Object pyobj(shape2pyshape(*getTopoShapePtr()));
return static_cast<TopoShapePy*>(pyobj.ptr())->rotate(args);
}
PyObject* TopoShapePy::scaled(PyObject *args) {
Py::Object pyobj(shape2pyshape(*getTopoShapePtr()));
return static_cast<TopoShapePy*>(pyobj.ptr())->scale(args);
}
PyObject* TopoShapePy::makeFillet(PyObject *args)
@@ -1827,13 +1851,34 @@ PyObject* TopoShapePy::isValid(PyObject *args)
{
if (!PyArg_ParseTuple(args, ""))
return NULL;
try {
PY_TRY {
return Py_BuildValue("O", (getTopoShapePtr()->isValid() ? Py_True : Py_False));
}
catch (...) {
PyErr_SetString(PyExc_RuntimeError, "check failed, shape may be empty");
} PY_CATCH_OCC
}
PyObject* TopoShapePy::isCoplanar(PyObject *args)
{
PyObject *pyObj;
double tol = -1;
if (!PyArg_ParseTuple(args, "O!|d", &TopoShapePy::Type, &pyObj, &tol))
return NULL;
}
PY_TRY {
return Py::new_reference_to(Py::Boolean(getTopoShapePtr()->isCoplanar(
*static_cast<TopoShapePy*>(pyObj)->getTopoShapePtr(),tol)));
}PY_CATCH_OCC
}
PyObject* TopoShapePy::findPlane(PyObject *args)
{
double tol = -1;
if (!PyArg_ParseTuple(args, "|d", &tol))
return NULL;
PY_TRY {
gp_Pln pln;
if(getTopoShapePtr()->findPlane(pln,tol))
return new PlanePy(new GeomPlane(new Geom_Plane(pln)));
Py_Return;
}PY_CATCH_OCC
}
PyObject* TopoShapePy::fix(PyObject *args)
@@ -2052,10 +2097,16 @@ PyObject* TopoShapePy::makeShapeFromMesh(PyObject *args)
getTopoShapePtr()->setFaces(Points, Facets,tolerance);
Py_Return;
}
catch (const Py::Exception&) {
return 0;
}
} PY_CATCH_OCC
}
PyObject* TopoShapePy::makeWires(PyObject *args) {
const char *op = 0;
if (!PyArg_ParseTuple(args, "s", &op))
return NULL;
PY_TRY {
return Py::new_reference_to(shape2pyshape(getTopoShapePtr()->makEWires(op)));
}PY_CATCH_OCC
}
PyObject* TopoShapePy::toNurbs(PyObject *args)
@@ -2157,6 +2208,16 @@ PyObject* TopoShapePy::getElement(PyObject *args)
return 0;
}
PyObject* TopoShapePy::countElement(PyObject *args)
{
char* input;
if (!PyArg_ParseTuple(args, "s", &input))
return NULL;
PY_TRY {
return Py::new_reference_to(Py::Int((long)getTopoShapePtr()->countSubShapes(input)));
} PY_CATCH_OCC
}
PyObject* TopoShapePy::getTolerance(PyObject *args)
{
int mode;
@@ -2900,6 +2961,14 @@ void TopoShapePy::setOrientation(Py::String arg)
getTopoShapePtr()->setShape(sh);
}
Py::List TopoShapePy::getSubShapes(void) const
{
Py::List ret;
for(TopoDS_Iterator it(getTopoShapePtr()->getShape());it.More();it.Next())
ret.append(shape2pyshape(it.Value()));
return ret;
}
Py::List TopoShapePy::getFaces(void) const
{
Py::List ret;
@@ -3117,38 +3186,11 @@ Py::Float TopoShapePy::getVolume(void) const
PyObject *TopoShapePy::getCustomAttributes(const char* attr) const
{
if (!attr) return 0;
std::string name(attr);
try {
if (name.size() > 4 && name.substr(0,4) == "Face" && name[4]>=48 && name[4]<=57) {
std::unique_ptr<Part::ShapeSegment> s(static_cast<Part::ShapeSegment*>
(getTopoShapePtr()->getSubElementByName(attr)));
TopoDS_Shape Shape = s->Shape;
TopoShapeFacePy* face = new TopoShapeFacePy(new TopoShape(Shape));
face->setNotTracking();
return face;
}
else if (name.size() > 4 && name.substr(0,4) == "Edge" && name[4]>=48 && name[4]<=57) {
std::unique_ptr<Part::ShapeSegment> s(static_cast<Part::ShapeSegment*>
(getTopoShapePtr()->getSubElementByName(attr)));
TopoDS_Shape Shape = s->Shape;
TopoShapeEdgePy* edge = new TopoShapeEdgePy(new TopoShape(Shape));
edge->setNotTracking();
return edge;
}
else if (name.size() > 6 && name.substr(0,6) == "Vertex" && name[6]>=48 && name[6]<=57) {
std::unique_ptr<Part::ShapeSegment> s(static_cast<Part::ShapeSegment*>
(getTopoShapePtr()->getSubElementByName(attr)));
TopoDS_Shape Shape = s->Shape;
TopoShapeVertexPy* vertex = new TopoShapeVertexPy(new TopoShape(Shape));
vertex->setNotTracking();
return vertex;
}
}
catch (Standard_Failure& e) {
PyErr_SetString(PartExceptionOCCError, e.GetMessageString());
return 0;
}
PY_TRY {
TopoDS_Shape res = getTopoShapePtr()->getSubShape(attr,true);
if(!res.IsNull())
return Py::new_reference_to(shape2pyshape(res));
}PY_CATCH_OCC
return 0;
}

View File

@@ -280,7 +280,8 @@ CmdPartCut::CmdPartCut()
void CmdPartCut::activated(int iMsg)
{
Q_UNUSED(iMsg);
std::vector<Gui::SelectionObject> Sel = getSelection().getSelectionEx(0, Part::Feature::getClassTypeId());
std::vector<Gui::SelectionObject> Sel =
getSelection().getSelectionEx(0, App::DocumentObject::getClassTypeId(),3);
if (Sel.size() != 2) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Select two shapes please."));
@@ -290,16 +291,14 @@ void CmdPartCut::activated(int iMsg)
bool askUser = false;
for (std::vector<Gui::SelectionObject>::iterator it = Sel.begin(); it != Sel.end(); ++it) {
App::DocumentObject* obj = it->getObject();
if (obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) {
const TopoDS_Shape& shape = static_cast<Part::Feature*>(obj)->Shape.getValue();
if (!PartGui::checkForSolids(shape) && !askUser) {
int ret = QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Non-solids selected"),
QObject::tr("The use of non-solids for boolean operations may lead to unexpected results.\n"
"Do you want to continue?"), QMessageBox::Yes, QMessageBox::No);
if (ret == QMessageBox::No)
return;
askUser = true;
}
const TopoDS_Shape& shape = Part::Feature::getShape(obj);
if (!PartGui::checkForSolids(shape) && !askUser) {
int ret = QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Non-solids selected"),
QObject::tr("The use of non-solids for boolean operations may lead to unexpected results.\n"
"Do you want to continue?"), QMessageBox::Yes, QMessageBox::No);
if (ret == QMessageBox::No)
return;
askUser = true;
}
}
@@ -335,7 +334,8 @@ void CmdPartCut::activated(int iMsg)
bool CmdPartCut::isActive(void)
{
return getSelection().countObjectsOfType(Part::Feature::getClassTypeId())==2;
return getSelection().countObjectsOfType(
App::DocumentObject::getClassTypeId(),0,3)==2;
}
//===========================================================================
@@ -358,21 +358,20 @@ CmdPartCommon::CmdPartCommon()
void CmdPartCommon::activated(int iMsg)
{
Q_UNUSED(iMsg);
std::vector<Gui::SelectionObject> Sel = getSelection().getSelectionEx(0, Part::Feature::getClassTypeId());
std::vector<Gui::SelectionObject> Sel =
getSelection().getSelectionEx(0, App::DocumentObject::getClassTypeId(), 3);
//test if selected object is a compound, and if it is, look how many children it has...
std::size_t numShapes = 0;
if (Sel.size() == 1){
numShapes = 1; //to be updated later in code, if
Gui::SelectionObject selobj = Sel[0];
if (selobj.getObject()->isDerivedFrom(Part::Feature::getClassTypeId())){
TopoDS_Shape sh = static_cast<Part::Feature*>(selobj.getObject())->Shape.getValue();
if (sh.ShapeType() == TopAbs_COMPOUND) {
numShapes = 0;
TopoDS_Iterator it(sh);
for (; it.More(); it.Next()) {
++numShapes;
}
TopoDS_Shape sh = Part::Feature::getShape(selobj.getObject());
if (sh.ShapeType() == TopAbs_COMPOUND) {
numShapes = 0;
TopoDS_Iterator it(sh);
for (; it.More(); it.Next()) {
++numShapes;
}
}
} else {
@@ -392,19 +391,17 @@ void CmdPartCommon::activated(int iMsg)
str << "App.activeDocument()." << FeatName << ".Shapes = [";
for (std::vector<Gui::SelectionObject>::iterator it = Sel.begin(); it != Sel.end(); ++it) {
App::DocumentObject* obj = it->getObject();
if (obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) {
const TopoDS_Shape& shape = static_cast<Part::Feature*>(obj)->Shape.getValue();
if (!PartGui::checkForSolids(shape) && !askUser) {
int ret = QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Non-solids selected"),
QObject::tr("The use of non-solids for boolean operations may lead to unexpected results.\n"
"Do you want to continue?"), QMessageBox::Yes, QMessageBox::No);
if (ret == QMessageBox::No)
return;
askUser = true;
}
str << "App.activeDocument()." << it->getFeatName() << ",";
partObjects.push_back(*it);
const TopoDS_Shape& shape = Part::Feature::getShape(obj);
if (!PartGui::checkForSolids(shape) && !askUser) {
int ret = QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Non-solids selected"),
QObject::tr("The use of non-solids for boolean operations may lead to unexpected results.\n"
"Do you want to continue?"), QMessageBox::Yes, QMessageBox::No);
if (ret == QMessageBox::No)
return;
askUser = true;
}
str << "App.activeDocument()." << it->getFeatName() << ",";
partObjects.push_back(*it);
}
str << "]";
@@ -437,7 +434,8 @@ void CmdPartCommon::activated(int iMsg)
bool CmdPartCommon::isActive(void)
{
return getSelection().countObjectsOfType(Part::Feature::getClassTypeId())>=1;
return getSelection().countObjectsOfType(
App::DocumentObject::getClassTypeId(),0,3)>=1;
}
//===========================================================================
@@ -460,21 +458,20 @@ CmdPartFuse::CmdPartFuse()
void CmdPartFuse::activated(int iMsg)
{
Q_UNUSED(iMsg);
std::vector<Gui::SelectionObject> Sel = getSelection().getSelectionEx(0, Part::Feature::getClassTypeId());
std::vector<Gui::SelectionObject> Sel =
getSelection().getSelectionEx(0, App::DocumentObject::getClassTypeId(),3);
//test if selected object is a compound, and if it is, look how many children it has...
std::size_t numShapes = 0;
if (Sel.size() == 1){
numShapes = 1; //to be updated later in code
Gui::SelectionObject selobj = Sel[0];
if (selobj.getObject()->isDerivedFrom(Part::Feature::getClassTypeId())){
TopoDS_Shape sh = static_cast<Part::Feature*>(selobj.getObject())->Shape.getValue();
if (sh.ShapeType() == TopAbs_COMPOUND) {
numShapes = 0;
TopoDS_Iterator it(sh);
for (; it.More(); it.Next()) {
++numShapes;
}
TopoDS_Shape sh = Part::Feature::getShape(selobj.getObject());
if (sh.ShapeType() == TopAbs_COMPOUND) {
numShapes = 0;
TopoDS_Iterator it(sh);
for (; it.More(); it.Next()) {
++numShapes;
}
}
} else {
@@ -494,19 +491,17 @@ void CmdPartFuse::activated(int iMsg)
str << "App.activeDocument()." << FeatName << ".Shapes = [";
for (std::vector<Gui::SelectionObject>::iterator it = Sel.begin(); it != Sel.end(); ++it) {
App::DocumentObject* obj = it->getObject();
if (obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) {
const TopoDS_Shape& shape = static_cast<Part::Feature*>(obj)->Shape.getValue();
if (!PartGui::checkForSolids(shape) && !askUser) {
int ret = QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Non-solids selected"),
QObject::tr("The use of non-solids for boolean operations may lead to unexpected results.\n"
"Do you want to continue?"), QMessageBox::Yes, QMessageBox::No);
if (ret == QMessageBox::No)
return;
askUser = true;
}
str << "App.activeDocument()." << it->getFeatName() << ",";
partObjects.push_back(*it);
const TopoDS_Shape& shape = Part::Feature::getShape(obj);
if (!PartGui::checkForSolids(shape) && !askUser) {
int ret = QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Non-solids selected"),
QObject::tr("The use of non-solids for boolean operations may lead to unexpected results.\n"
"Do you want to continue?"), QMessageBox::Yes, QMessageBox::No);
if (ret == QMessageBox::No)
return;
askUser = true;
}
str << "App.activeDocument()." << it->getFeatName() << ",";
partObjects.push_back(*it);
}
str << "]";
@@ -539,7 +534,8 @@ void CmdPartFuse::activated(int iMsg)
bool CmdPartFuse::isActive(void)
{
return getSelection().countObjectsOfType(Part::Feature::getClassTypeId())>=1;
return getSelection().countObjectsOfType(
App::DocumentObject::getClassTypeId(),0,3)>=1;
}
//===========================================================================
@@ -898,7 +894,8 @@ CmdPartCompound::CmdPartCompound()
void CmdPartCompound::activated(int iMsg)
{
Q_UNUSED(iMsg);
unsigned int n = getSelection().countObjectsOfType(Part::Feature::getClassTypeId());
unsigned int n = getSelection().countObjectsOfType(
App::DocumentObject::getClassTypeId(),0,3);
if (n < 1) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Select one shape or more, please."));
@@ -930,7 +927,8 @@ void CmdPartCompound::activated(int iMsg)
bool CmdPartCompound::isActive(void)
{
return getSelection().countObjectsOfType(Part::Feature::getClassTypeId())>=1;
return getSelection().countObjectsOfType(
App::DocumentObject::getClassTypeId(),0,3)>=1;
}
//===========================================================================
@@ -953,7 +951,8 @@ CmdPartSection::CmdPartSection()
void CmdPartSection::activated(int iMsg)
{
Q_UNUSED(iMsg);
std::vector<Gui::SelectionObject> Sel = getSelection().getSelectionEx(0, Part::Feature::getClassTypeId());
std::vector<Gui::SelectionObject> Sel =
getSelection().getSelectionEx(0, App::DocumentObject::getClassTypeId(),3);
if (Sel.size() != 2) {
QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"),
QObject::tr("Select two shapes please."));
@@ -977,7 +976,7 @@ void CmdPartSection::activated(int iMsg)
bool CmdPartSection::isActive(void)
{
return getSelection().countObjectsOfType(Part::Feature::getClassTypeId())==2;
return getSelection().countObjectsOfType(App::DocumentObject::getClassTypeId(),0,3)==2;
}
//===========================================================================
@@ -1084,7 +1083,7 @@ void CmdPartExport::activated(int iMsg)
bool CmdPartExport::isActive(void)
{
return Gui::Selection().countObjectsOfType(Part::Feature::getClassTypeId()) > 0;
return Gui::Selection().countObjectsOfType(App::DocumentObject::getClassTypeId(),0,3) > 0;
}
//===========================================================================
@@ -1155,10 +1154,10 @@ void CmdPartMakeSolid::activated(int iMsg)
{
Q_UNUSED(iMsg);
std::vector<App::DocumentObject*> objs = Gui::Selection().getObjectsOfType
(Part::Feature::getClassTypeId());
(App::DocumentObject::getClassTypeId(),0,3);
runCommand(Doc, "import Part");
for (std::vector<App::DocumentObject*>::iterator it = objs.begin(); it != objs.end(); ++it) {
const TopoDS_Shape& shape = static_cast<Part::Feature*>(*it)->Shape.getValue();
const TopoDS_Shape& shape = Part::Feature::getShape(*it);
if (!shape.IsNull()) {
TopAbs_ShapeEnum type = shape.ShapeType();
QString str;
@@ -1210,7 +1209,7 @@ void CmdPartMakeSolid::activated(int iMsg)
bool CmdPartMakeSolid::isActive(void)
{
return Gui::Selection().countObjectsOfType
(Part::Feature::getClassTypeId()) > 0;
(App::DocumentObject::getClassTypeId(),0,3) > 0;
}
//===========================================================================
@@ -1236,7 +1235,7 @@ void CmdPartReverseShape::activated(int iMsg)
(Part::Feature::getClassTypeId());
runCommand(Doc, "import Part");
for (std::vector<App::DocumentObject*>::iterator it = objs.begin(); it != objs.end(); ++it) {
const TopoDS_Shape& shape = static_cast<Part::Feature*>(*it)->Shape.getValue();
const TopoDS_Shape& shape = Part::Feature::getShape(*it);
if (!shape.IsNull()) {
QString str = QString::fromLatin1(
"__s__=App.ActiveDocument.%1.Shape.copy()\n"
@@ -1345,7 +1344,7 @@ CmdPartMakeFace::CmdPartMakeFace()
void CmdPartMakeFace::activated(int iMsg)
{
Q_UNUSED(iMsg);
std::vector<Part::Feature*> sketches = Gui::Selection().getObjectsOfType<Part::Feature>();
auto sketches = Gui::Selection().getObjectsOfType(App::DocumentObject::getClassTypeId(),0,3);
openCommand("Make face");
try {
@@ -1353,9 +1352,8 @@ void CmdPartMakeFace::activated(int iMsg)
std::stringstream str;
str << doc.getDocumentPython()
<< ".addObject(\"Part::Face\", \"Face\").Sources = (";
for (std::vector<Part::Feature*>::iterator it = sketches.begin(); it != sketches.end(); ++it) {
App::DocumentObjectT obj(*it);
str << obj.getObjectPython() << ", ";
for (auto &obj : sketches) {
str << App::DocumentObjectT(obj).getObjectPython() << ", ";
}
str << ")";
@@ -1372,7 +1370,7 @@ void CmdPartMakeFace::activated(int iMsg)
bool CmdPartMakeFace::isActive(void)
{
return (Gui::Selection().countObjectsOfType(Part::Feature::getClassTypeId()) > 0 &&
return (Gui::Selection().countObjectsOfType(App::DocumentObject::getClassTypeId(),0,3) > 0 &&
!Gui::Control().activeDialog());
}
@@ -1643,7 +1641,6 @@ void CmdPartOffset::activated(int iMsg)
doCommand(Doc,"App.ActiveDocument.%s.Source = App.ActiveDocument.%s" ,offset.c_str(), shape->getNameInDocument());
doCommand(Doc,"App.ActiveDocument.%s.Value = 1.0",offset.c_str());
updateActive();
doCommand(Gui,"Gui.ActiveDocument.%s.DisplayMode = 'Wireframe'", shape->getNameInDocument());
//if (isActiveObjectValid())
// doCommand(Gui,"Gui.ActiveDocument.hide(\"%s\")",shape->getNameInDocument());
doCommand(Gui,"Gui.ActiveDocument.setEdit('%s')",offset.c_str());
@@ -1659,7 +1656,7 @@ void CmdPartOffset::activated(int iMsg)
bool CmdPartOffset::isActive(void)
{
Base::Type partid = Base::Type::fromName("Part::Feature");
bool objectsSelected = Gui::Selection().countObjectsOfType(partid) == 1;
bool objectsSelected = Gui::Selection().countObjectsOfType(partid,0,3) == 1;
return (objectsSelected && !Gui::Control().activeDialog());
}
@@ -1685,7 +1682,7 @@ CmdPartOffset2D::CmdPartOffset2D()
void CmdPartOffset2D::activated(int iMsg)
{
Q_UNUSED(iMsg);
App::DocumentObject* shape = getSelection().getObjectsOfType(Part::Feature::getClassTypeId()).front();
App::DocumentObject* shape = getSelection().getObjectsOfType(Part::Feature::getClassTypeId(),0,3).front();
std::string offset = getUniqueObjectName("Offset2D");
openCommand("Make 2D Offset");
@@ -1708,7 +1705,7 @@ void CmdPartOffset2D::activated(int iMsg)
bool CmdPartOffset2D::isActive(void)
{
Base::Type partid = Base::Type::fromName("Part::Feature");
bool objectsSelected = Gui::Selection().countObjectsOfType(partid) == 1;
bool objectsSelected = Gui::Selection().countObjectsOfType(partid,0,3) == 1;
return (objectsSelected && !Gui::Control().activeDialog());
}
@@ -1801,7 +1798,7 @@ void CmdPartCompOffset::languageChange()
bool CmdPartCompOffset::isActive(void)
{
Base::Type partid = Base::Type::fromName("Part::Feature");
bool objectsSelected = Gui::Selection().countObjectsOfType(partid) == 1;
bool objectsSelected = Gui::Selection().countObjectsOfType(partid,0,3) == 1;
return (objectsSelected && !Gui::Control().activeDialog());
}
@@ -2225,6 +2222,35 @@ bool CmdMeasureAngular::isActive(void)
return hasActiveDocument();
}
//===========================================================================
// Part_Measure_Refresh
//===========================================================================
DEF_STD_CMD_A(CmdMeasureRefresh);
CmdMeasureRefresh::CmdMeasureRefresh()
: Command("Part_Measure_Refresh")
{
sAppModule = "Part";
sGroup = QT_TR_NOOP("Part");
sMenuText = QT_TR_NOOP("Refresh");
sToolTipText = QT_TR_NOOP("Refresh");
sWhatsThis = "Part_Measure_Refresh";
sStatusTip = sToolTipText;
sPixmap = "Part_Measure_Refresh";
}
void CmdMeasureRefresh::activated(int iMsg)
{
Q_UNUSED(iMsg);
PartGui::refreshDimensions();
}
bool CmdMeasureRefresh::isActive(void)
{
return hasActiveDocument();
}
//===========================================================================
// Part_Measure_Clear_All
//===========================================================================
@@ -2449,6 +2475,7 @@ void CreatePartCommands(void)
rcCmdMgr.addCommand(new CmdColorPerFace());
rcCmdMgr.addCommand(new CmdMeasureLinear());
rcCmdMgr.addCommand(new CmdMeasureAngular());
rcCmdMgr.addCommand(new CmdMeasureRefresh());
rcCmdMgr.addCommand(new CmdMeasureClearAll());
rcCmdMgr.addCommand(new CmdMeasureToggleAll());
rcCmdMgr.addCommand(new CmdMeasureToggle3d());

View File

@@ -186,33 +186,114 @@ CmdPartSimpleCopy::CmdPartSimpleCopy()
sPixmap = "Tree_Part";
}
static void _copyShape(const char *cmdName, bool resolve,bool needElement=false, bool refine=false) {
Gui::WaitCursor wc;
Gui::Command::openCommand(cmdName);
for(auto &sel : Gui::Selection().getSelectionEx("*",App::DocumentObject::getClassTypeId(),resolve)) {
std::map<std::string,App::DocumentObject*> subMap;
auto obj = sel.getObject();
if(!obj) continue;
if(resolve || !sel.hasSubNames())
subMap.emplace("",obj);
else {
for(const auto &sub : sel.getSubNames()) {
const char *element = 0;
auto sobj = obj->resolve(sub.c_str(),0,0,&element);
if(!sobj) continue;
if(!needElement && element)
subMap.emplace(sub.substr(0,element-sub.c_str()),sobj);
else
subMap.emplace(sub,sobj);
}
if(subMap.empty())
continue;
}
auto parentName = Gui::Command::getObjectCmd(obj);
for(auto &v : subMap) {
Gui::Command::doCommand(Gui::Command::Doc,
"__shape = Part.getShape(%s,'%s',needSubElement=%s,refine=%s)%s\n"
"App.ActiveDocument.addObject('Part::Feature','%s').Shape=__shape\n"
"App.ActiveDocument.ActiveObject.Label=%s.Label\n",
parentName.c_str(), v.first.c_str(),
needElement?"True":"False", refine?"True":"False",
needElement?".copy()":"",
v.second->getNameInDocument(),
Gui::Command::getObjectCmd(v.second).c_str());
auto newObj = App::GetApplication().getActiveDocument()->getActiveObject();
Gui::Command::copyVisual(newObj, "ShapeColor", v.second);
Gui::Command::copyVisual(newObj, "LineColor", v.second);
Gui::Command::copyVisual(newObj, "PointColor", v.second);
}
}
Gui::Command::commitCommand();
Gui::Command::updateActive();
}
void CmdPartSimpleCopy::activated(int iMsg)
{
Q_UNUSED(iMsg);
Base::Type partid = Base::Type::fromName("Part::Feature");
std::vector<Gui::SelectionObject> objs = Gui::Selection().getSelectionEx(0, partid);
openCommand("Create Copy");
for (std::vector<Gui::SelectionObject>::iterator it = objs.begin(); it != objs.end(); ++it) {
doCommand(Doc,"App.ActiveDocument.addObject('Part::Feature','%s').Shape="
"App.ActiveDocument.%s.Shape\n"
"App.ActiveDocument.ActiveObject.Label="
"App.ActiveDocument.%s.Label\n",
it->getFeatName(),
it->getFeatName(),
it->getFeatName());
copyVisual("ActiveObject", "ShapeColor", it->getFeatName());
copyVisual("ActiveObject", "LineColor", it->getFeatName());
copyVisual("ActiveObject", "PointColor", it->getFeatName());
copyVisual("ActiveObject", "DiffuseColor", it->getFeatName());
}
commitCommand();
updateActive();
_copyShape("Simple copy",true);
}
bool CmdPartSimpleCopy::isActive(void)
{
Base::Type partid = Base::Type::fromName("Part::Feature");
return Gui::Selection().countObjectsOfType(partid) > 0;
return Gui::Selection().hasSelection();
}
//===========================================================================
// Part_TransformedCopy
//===========================================================================
DEF_STD_CMD_A(CmdPartTransformedCopy);
CmdPartTransformedCopy::CmdPartTransformedCopy()
: Command("Part_TransformedCopy")
{
sAppModule = "Part";
sGroup = QT_TR_NOOP("Part");
sMenuText = QT_TR_NOOP("Create transformed copy");
sToolTipText = QT_TR_NOOP("Create a non-parametric copy with transformed placement");
sWhatsThis = "Part_TransformCopy";
sStatusTip = sToolTipText;
sPixmap = "Part_Transformed_Copy.svg";
}
void CmdPartTransformedCopy::activated(int iMsg)
{
Q_UNUSED(iMsg);
_copyShape("Transformed copy",false);
}
bool CmdPartTransformedCopy::isActive(void)
{
return Gui::Selection().hasSelection();
}
//===========================================================================
// Part_ElementCopy
//===========================================================================
DEF_STD_CMD_A(CmdPartElementCopy);
CmdPartElementCopy::CmdPartElementCopy()
: Command("Part_ElementCopy")
{
sAppModule = "Part";
sGroup = QT_TR_NOOP("Part");
sMenuText = QT_TR_NOOP("Create shape element copy");
sToolTipText = QT_TR_NOOP("Create a non-parametric copy of the selected shape element");
sWhatsThis = "Part_ElementCopy";
sStatusTip = sToolTipText;
sPixmap = "Part_Element_Copy.svg";
}
void CmdPartElementCopy::activated(int iMsg)
{
Q_UNUSED(iMsg);
_copyShape("Element copy",false,true);
}
bool CmdPartElementCopy::isActive(void)
{
return Gui::Selection().hasSelection();
}
//===========================================================================
@@ -235,53 +316,12 @@ CmdPartRefineShape::CmdPartRefineShape()
void CmdPartRefineShape::activated(int iMsg)
{
Q_UNUSED(iMsg);
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Part");
bool parametric = hGrp->GetBool("ParametricRefine", true);
Gui::WaitCursor wc;
Base::Type partid = Base::Type::fromName("Part::Feature");
std::vector<App::DocumentObject*> objs = Gui::Selection().getObjectsOfType(partid);
openCommand("Refine shape");
for (std::vector<App::DocumentObject*>::iterator it = objs.begin(); it != objs.end(); ++it) {
try {
if (parametric) {
doCommand(Doc,"App.ActiveDocument.addObject('Part::Refine','%s').Source="
"App.ActiveDocument.%s\n"
"App.ActiveDocument.ActiveObject.Label="
"App.ActiveDocument.%s.Label\n"
"Gui.ActiveDocument.%s.hide()\n",
(*it)->getNameInDocument(),
(*it)->getNameInDocument(),
(*it)->getNameInDocument(),
(*it)->getNameInDocument());
}
else {
doCommand(Doc,"App.ActiveDocument.addObject('Part::Feature','%s').Shape="
"App.ActiveDocument.%s.Shape.removeSplitter()\n"
"App.ActiveDocument.ActiveObject.Label="
"App.ActiveDocument.%s.Label\n"
"Gui.ActiveDocument.%s.hide()\n",
(*it)->getNameInDocument(),
(*it)->getNameInDocument(),
(*it)->getNameInDocument(),
(*it)->getNameInDocument());
}
copyVisual("ActiveObject", "ShapeColor", (*it)->getNameInDocument());
copyVisual("ActiveObject", "LineColor", (*it)->getNameInDocument());
copyVisual("ActiveObject", "PointColor", (*it)->getNameInDocument());
}
catch (const Base::Exception& e) {
Base::Console().Warning("%s: %s\n", (*it)->Label.getValue(), e.what());
}
}
commitCommand();
updateActive();
_copyShape("Refined copy",true,false,true);
}
bool CmdPartRefineShape::isActive(void)
{
Base::Type partid = Base::Type::fromName("Part::Feature");
return Gui::Selection().countObjectsOfType(partid) > 0;
return Gui::Selection().hasSelection();
}
//===========================================================================
@@ -381,6 +421,8 @@ void CreateSimplePartCommands(void)
rcCmdMgr.addCommand(new CmdPartSimpleCylinder());
rcCmdMgr.addCommand(new CmdPartShapeFromMesh());
rcCmdMgr.addCommand(new CmdPartSimpleCopy());
rcCmdMgr.addCommand(new CmdPartElementCopy());
rcCmdMgr.addCommand(new CmdPartTransformedCopy());
rcCmdMgr.addCommand(new CmdPartRefineShape());
rcCmdMgr.addCommand(new CmdPartDefeaturing());
}

View File

@@ -57,6 +57,8 @@
#include <Gui/WaitCursor.h>
#include <Gui/Utilities.h>
FC_LOG_LEVEL_INIT("Part",true,true);
using namespace PartGui;
class DlgExtrusion::EdgeSelection : public Gui::SelectionFilterGate
@@ -433,9 +435,8 @@ void DlgExtrusion::apply()
assert(sourceObj);
if (!sourceObj->isDerivedFrom(Part::Feature::getClassTypeId())){
std::stringstream errmsg;
errmsg << "Object " << sourceObj->getNameInDocument() << " is not Part object (has no OCC shape). Can't extrude it.\n";
Base::Console().Error(errmsg.str().c_str());
FC_ERR("Object " << sourceObj->getFullName()
<< " is not Part object (has no OCC shape). Can't extrude it.");
continue;
}
@@ -447,16 +448,16 @@ void DlgExtrusion::apply()
//label = QString::fromLatin1("%1_Extrude").arg((*it)->text(0));
}
Gui::Command::doCommand(Gui::Command::Doc, "f = FreeCAD.getDocument('%s').addObject('Part::Extrusion', '%s')", sourceObj->getDocument()->getName(), name.c_str());
FCMD_OBJ_DOC_CMD(sourceObj,"addObject('Part::Extrusion','" << name << "')");
auto newObj = sourceObj->getDocument()->getObject(name.c_str());
this->writeParametersToFeature(*(sourceObj->getDocument()->getObject(name.c_str())), sourceObj);
this->writeParametersToFeature(*newObj, sourceObj);
std::string sourceObjectName = sourceObj->getNameInDocument();
Gui::Command::copyVisual(name.c_str(), "ShapeColor", sourceObjectName.c_str());
Gui::Command::copyVisual(name.c_str(), "LineColor", sourceObjectName.c_str());
Gui::Command::copyVisual(name.c_str(), "PointColor", sourceObjectName.c_str());
Gui::Command::copyVisual(newObj, "ShapeColor", sourceObj);
Gui::Command::copyVisual(newObj, "LineColor", sourceObj);
Gui::Command::copyVisual(newObj, "PointColor", sourceObj);
Gui::Command::doCommand(Gui::Command::Gui,"f.Base.ViewObject.hide()");
FCMD_OBJ_HIDE(sourceObj);
}
activeDoc->commitTransaction();

View File

@@ -632,6 +632,11 @@ void DlgFilletEdges::setupFillet(const std::vector<App::DocumentObject*>& objs)
std::vector<Gui::SelectionObject>::iterator selIt = std::find_if(selObj.begin(), selObj.end(),
Private::SelectionObjectCompare(d->object));
/*
* Edit: the following check is no longer necessary, as Gui::Selection
* will do the check
*
// If sub-objects are already selected then only add the un-selected parts.
// This is impotant to avoid recursive calls of rmvSelection() which
// invalidates the internal iterator (#0002200).
@@ -645,9 +650,12 @@ void DlgFilletEdges::setupFillet(const std::vector<App::DocumentObject*>& objs)
std::set_difference(subElements.begin(), subElements.end(), selElements.begin(), selElements.end(), biit);
subElements = complementary;
}
*/
Gui::Selection().clearSelection(doc->getName());
if (!subElements.empty()) {
Gui::Selection().addSelection(doc->getName(),
Gui::Selection().addSelections(doc->getName(),
d->object->getNameInDocument(),
subElements);
}
@@ -795,7 +803,7 @@ void DlgFilletEdges::on_selectAllButton_clicked()
if (d->object) {
App::Document* doc = d->object->getDocument();
Gui::Selection().addSelection(doc->getName(),
Gui::Selection().addSelections(doc->getName(),
d->object->getNameInDocument(),
subElements);
}

View File

@@ -59,7 +59,10 @@
<file>icons/Part_Measure_Toggle_Delta.svg</file>
<file>icons/Part_Measure_Step_Active.svg</file>
<file>icons/Part_Measure_Step_Done.svg</file>
<file>icons/Part_Measure_Refresh.svg</file>
<file>icons/Part_Refine_Shape.svg</file>
<file>icons/Part_Element_Copy.svg</file>
<file>icons/Part_Transformed_Copy.svg</file>
<file>icons/Tree_Part_Box_Parametric.svg</file>
<file>icons/Tree_Part_Cylinder_Parametric.svg</file>
<file>icons/Tree_Part_Cone_Parametric.svg</file>

View File

@@ -0,0 +1,246 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg2980"
sodipodi:version="0.32"
inkscape:version="0.91 r13725"
sodipodi:docname="Part_Element_Copy.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1">
<defs
id="defs2982">
<linearGradient
inkscape:collect="always"
id="linearGradient3794">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop3796" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop3798" />
</linearGradient>
<linearGradient
id="linearGradient3864">
<stop
id="stop3866"
offset="0"
style="stop-color:#71b2f8;stop-opacity:1;" />
<stop
id="stop3868"
offset="1"
style="stop-color:#002795;stop-opacity:1;" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="64 : 32 : 1"
inkscape:persp3d-origin="32 : 21.333333 : 1"
id="perspective2988" />
<linearGradient
gradientTransform="translate(0,-4)"
inkscape:collect="always"
xlink:href="#linearGradient3767"
id="linearGradient3773"
x1="22.116516"
y1="55.717518"
x2="17.328547"
y2="21.31134"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
id="linearGradient3767">
<stop
style="stop-color:#3465a4;stop-opacity:1"
offset="0"
id="stop3769" />
<stop
style="stop-color:#729fcf;stop-opacity:1"
offset="1"
id="stop3771" />
</linearGradient>
<linearGradient
gradientTransform="translate(0,-4)"
inkscape:collect="always"
xlink:href="#linearGradient3777"
id="linearGradient3783"
x1="53.896763"
y1="51.179787"
x2="47.502235"
y2="21.83742"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
id="linearGradient3777">
<stop
style="stop-color:#204a87;stop-opacity:1"
offset="0"
id="stop3779" />
<stop
style="stop-color:#3465a4;stop-opacity:1"
offset="1"
id="stop3781" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3794"
id="radialGradient3800"
cx="1"
cy="45"
fx="1"
fy="45"
r="41"
gradientTransform="matrix(0.93348213,-2.2905276e-8,0,0.28687573,0.06651751,32.090592)"
gradientUnits="userSpaceOnUse" />
<linearGradient
gradientTransform="translate(72,0)"
inkscape:collect="always"
xlink:href="#linearGradient3777-6"
id="linearGradient3783-3"
x1="53.896763"
y1="51.179787"
x2="47.502235"
y2="21.83742"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
id="linearGradient3777-6">
<stop
style="stop-color:#c4a000;stop-opacity:1"
offset="0"
id="stop3779-7" />
<stop
style="stop-color:#edd400;stop-opacity:1"
offset="1"
id="stop3781-5" />
</linearGradient>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="3.4052734"
inkscape:cx="16.869406"
inkscape:cy="47.934459"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1375"
inkscape:window-height="876"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:snap-bbox="true"
inkscape:snap-nodes="false"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid2991"
empspacing="2"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<metadata
id="metadata2985">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:creator>
<cc:Agent>
<dc:title>[wmayer]</dc:title>
</cc:Agent>
</dc:creator>
<dc:title>Tree_Part</dc:title>
<dc:date>2011-10-10</dc:date>
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
<dc:publisher>
<cc:Agent>
<dc:title>FreeCAD</dc:title>
</cc:Agent>
</dc:publisher>
<dc:identifier>FreeCAD/src/Mod/Part/Gui/Resources/icons/Tree_Part.svg</dc:identifier>
<dc:rights>
<cc:Agent>
<dc:title>FreeCAD LGPL2+</dc:title>
</cc:Agent>
</dc:rights>
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
<dc:contributor>
<cc:Agent>
<dc:title>[agryson] Alexander Gryson</dc:title>
</cc:Agent>
</dc:contributor>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<path
style="fill:#729fcf;stroke:#0b1521;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="M 3,13 37,19 61,11 31,7 z"
id="path2993"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:url(#linearGradient3783);fill-opacity:1;stroke:#0b1521;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="M 61,11 61,47 37,57 37,19 z"
id="path2995"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc"
id="path3825"
d="M 3,13 37,19 37,57 3,51 z"
style="fill:url(#linearGradient3773);fill-opacity:1;fill-rule:evenodd;stroke:#0b1521;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<path
style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 5,15.42772 0.00867,33.919116 30.008671,5.268799 -0.0087,-33.933614 z"
id="path3765"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:none;stroke:#3465a4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 39.01243,20.433833 -0.01226,33.535301 20.001105,-8.300993 3.6e-4,-31.867363 z"
id="path3775"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<g
id="g5368"
transform="translate(-71.997618,-3.9896317)">
<path
inkscape:connector-curvature="0"
id="path2995-3"
d="m 133,15 0,36 -24,10 0,-38 z"
style="fill:url(#linearGradient3783-3);fill-opacity:1;stroke:#302b00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path3775-5"
d="m 111.01243,24.433833 -0.0123,33.535301 20.0011,-8.300993 3.6e-4,-31.867363 z"
style="fill:none;stroke:#edd400;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.1 KiB

View File

@@ -0,0 +1,659 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg2943"
sodipodi:version="0.32"
inkscape:version="0.91 r13725"
sodipodi:docname="Part_Measure_Refresh.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1">
<defs
id="defs2945">
<linearGradient
inkscape:collect="always"
id="linearGradient3961">
<stop
style="stop-color:#babdb6;stop-opacity:1"
offset="0"
id="stop3963" />
<stop
style="stop-color:#d3d7cf;stop-opacity:1"
offset="1"
id="stop3965" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient3953">
<stop
style="stop-color:#babdb6;stop-opacity:1"
offset="0"
id="stop3955" />
<stop
style="stop-color:#555753;stop-opacity:1"
offset="1"
id="stop3957" />
</linearGradient>
<linearGradient
id="linearGradient4158">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop4160" />
<stop
style="stop-color:#f6f6f6;stop-opacity:0;"
offset="1"
id="stop4162" />
</linearGradient>
<linearGradient
id="linearGradient4122">
<stop
style="stop-color:#e3d328;stop-opacity:1;"
offset="0"
id="stop4124" />
<stop
style="stop-color:#e1dec3;stop-opacity:1;"
offset="1"
id="stop4126" />
</linearGradient>
<linearGradient
id="linearGradient4088">
<stop
style="stop-color:#e9cd23;stop-opacity:1;"
offset="0"
id="stop4090" />
<stop
style="stop-color:#040000;stop-opacity:0;"
offset="1"
id="stop4092" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient4060">
<stop
style="stop-color:#ada9a9;stop-opacity:1;"
offset="0"
id="stop4062" />
<stop
style="stop-color:#ada9a9;stop-opacity:0;"
offset="1"
id="stop4064" />
</linearGradient>
<linearGradient
id="linearGradient4052">
<stop
style="stop-color:#ada9a9;stop-opacity:1;"
offset="0"
id="stop4054" />
<stop
style="stop-color:#ada9a9;stop-opacity:0;"
offset="1"
id="stop4056" />
</linearGradient>
<linearGradient
id="linearGradient4349">
<stop
style="stop-color:#898709;stop-opacity:1;"
offset="0"
id="stop4351" />
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="1"
id="stop4353" />
</linearGradient>
<linearGradient
id="linearGradient5241">
<stop
style="stop-color:#212c45;stop-opacity:1;"
offset="0"
id="stop5243" />
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="1"
id="stop5245" />
</linearGradient>
<linearGradient
id="linearGradient5227"
osb:paint="solid">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop5229" />
</linearGradient>
<linearGradient
id="linearGradient3902">
<stop
style="stop-color:#000000;stop-opacity:0.58823532;"
offset="0"
id="stop3904" />
<stop
style="stop-color:#000000;stop-opacity:0.39215687;"
offset="1"
id="stop3906" />
</linearGradient>
<linearGradient
id="linearGradient3894">
<stop
style="stop-color:#45351d;stop-opacity:1;"
offset="0"
id="stop3896" />
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="1"
id="stop3898" />
</linearGradient>
<linearGradient
id="linearGradient3886">
<stop
style="stop-color:#45351d;stop-opacity:1;"
offset="0"
id="stop3888" />
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="1"
id="stop3890" />
</linearGradient>
<linearGradient
id="linearGradient3792">
<stop
style="stop-color:#aaaaaa;stop-opacity:1;"
offset="0"
id="stop3794" />
<stop
style="stop-color:#d2d2d2;stop-opacity:1;"
offset="1"
id="stop3796" />
</linearGradient>
<linearGradient
id="linearGradient3784">
<stop
style="stop-color:#bebebe;stop-opacity:1;"
offset="0"
id="stop3786" />
<stop
style="stop-color:#ffffff;stop-opacity:0.39215687;"
offset="1"
id="stop3788" />
</linearGradient>
<linearGradient
id="linearGradient3377">
<stop
id="stop3379"
offset="0"
style="stop-color:#71b2f8;stop-opacity:1;" />
<stop
id="stop3381"
offset="1"
style="stop-color:#002795;stop-opacity:1;" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="64 : 32 : 1"
inkscape:persp3d-origin="32 : 21.333333 : 1"
id="perspective2951" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4158"
id="linearGradient3092"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-129.22376,-0.88388348)"
x1="419.99387"
y1="102.77802"
x2="458.7193"
y2="69.431564" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4052"
id="linearGradient3094"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(168.6744,65.825928)"
x1="138.99986"
y1="44.863674"
x2="92.497559"
y2="-14.356517" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4122"
id="linearGradient3096"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-88.034794,-1.0606602)"
x1="391.3074"
y1="120.81136"
x2="394.43201"
y2="112.43636" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4060"
id="linearGradient3098"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(168.6744,65.825928)"
x1="103.93729"
y1="49.179436"
x2="120.49899"
y2="0.21229285" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3953"
id="linearGradient3959"
x1="214.70918"
y1="80.886589"
x2="218.70918"
y2="104.88659"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(80,0)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3961"
id="linearGradient3967"
x1="196.70918"
y1="106.88659"
x2="190.70918"
y2="80.886589"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(80,0)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3953-5"
id="linearGradient3959-3"
x1="214.70918"
y1="80.886589"
x2="218.70918"
y2="104.88659"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(80,0)" />
<linearGradient
inkscape:collect="always"
id="linearGradient3953-5">
<stop
style="stop-color:#babdb6;stop-opacity:1"
offset="0"
id="stop3955-6" />
<stop
style="stop-color:#555753;stop-opacity:1"
offset="1"
id="stop3957-2" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2831-2"
id="linearGradient4585"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.370336,0,0,1.3589114,0.02150968,-18.214919)"
x1="13.478554"
y1="10.612206"
x2="15.419417"
y2="19.115122" />
<linearGradient
id="linearGradient2831-2">
<stop
style="stop-color:#3465a4;stop-opacity:1;"
offset="0"
id="stop2833-3" />
<stop
id="stop2855-1"
offset="0.33333334"
style="stop-color:#5b86be;stop-opacity:1;" />
<stop
style="stop-color:#83a8d8;stop-opacity:0;"
offset="1"
id="stop2835-6" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2871"
id="linearGradient1488"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-1.370336,0,0,-1.3589114,64.512944,44.464873)"
x1="37.128052"
y1="29.729605"
x2="37.065414"
y2="26.194071" />
<linearGradient
id="linearGradient2871"
inkscape:collect="always">
<stop
id="stop2873"
offset="0"
style="stop-color:#3465a4;stop-opacity:1;" />
<stop
id="stop2875"
offset="1"
style="stop-color:#3465a4;stop-opacity:1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3063-2"
id="linearGradient4587"
gradientUnits="userSpaceOnUse"
x1="42.703487"
y1="20.547306"
x2="26.605606"
y2="33.634254" />
<linearGradient
id="linearGradient3063-2">
<stop
id="stop3065-6"
offset="0"
style="stop-color:#729fcf;stop-opacity:1" />
<stop
id="stop3067-0"
offset="1"
style="stop-color:#204a87;stop-opacity:1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2380-9"
id="linearGradient3034"
gradientUnits="userSpaceOnUse"
x1="41.791897"
y1="20.134634"
x2="23.705669"
y2="34.083359" />
<linearGradient
id="linearGradient2380-9">
<stop
style="stop-color:#729fcf;stop-opacity:1"
offset="0"
id="stop2382-4" />
<stop
style="stop-color:#3465a4;stop-opacity:1"
offset="1"
id="stop2384-6" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2380-9"
id="linearGradient3034-4"
gradientUnits="userSpaceOnUse"
x1="26.221533"
y1="31.125586"
x2="46.731483"
y2="21.766298" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2831-2"
id="linearGradient4295"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.370336,0,0,1.3589114,0.02150968,-18.214919)"
x1="13.478554"
y1="10.612206"
x2="15.419417"
y2="19.115122" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2871"
id="linearGradient4297"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-1.370336,0,0,-1.3589114,64.512944,44.464873)"
x1="37.128052"
y1="29.729605"
x2="37.065414"
y2="26.194071" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3063-2"
id="linearGradient4299"
gradientUnits="userSpaceOnUse"
x1="42.703487"
y1="20.547306"
x2="26.605606"
y2="33.634254" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="7.6761244"
inkscape:cx="44.088329"
inkscape:cy="36.738683"
inkscape:current-layer="g3629"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1375"
inkscape:window-height="876"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:snap-bbox="false"
inkscape:snap-nodes="true">
<inkscape:grid
type="xygrid"
id="grid3059"
empspacing="2"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<metadata
id="metadata2948">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:creator>
<cc:Agent>
<dc:title>[blobfish]</dc:title>
</cc:Agent>
</dc:creator>
<dc:title>Part_Measure_Linear</dc:title>
<dc:date>2013-12-17</dc:date>
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
<dc:publisher>
<cc:Agent>
<dc:title>FreeCAD</dc:title>
</cc:Agent>
</dc:publisher>
<dc:identifier>FreeCAD/src/Mod/Part/Gui/Resources/icons/Part_Measure_Linear.svg</dc:identifier>
<dc:rights>
<cc:Agent>
<dc:title>FreeCAD LGPL2+</dc:title>
</cc:Agent>
</dc:rights>
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
<dc:contributor>
<cc:Agent>
<dc:title>[agryson] Alexander Gryson</dc:title>
</cc:Agent>
</dc:contributor>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
id="g3629"
transform="translate(-256.70919,-66.886588)">
<path
style="fill:#e3d328;fill-opacity:1;stroke:#040400;stroke-width:0.08838835;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d=""
id="path4102"
inkscape:connector-curvature="0"
transform="translate(256.70919,66.886588)" />
<path
style="fill:#babdb6;stroke:#2e3436;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 285.70919,77.886588 -26,-4 c 0,11 0,26 2,36.000002 l 30,12 0,-6 -2,-4 c 8,-12.000002 0,-24.000002 -4,-34.000002 z"
id="path3100"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc" />
<path
style="fill:#555753;stroke:#2e3436;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 291.70919,121.88659 12,-4 0,-6 -12,4 z"
id="path3890"
inkscape:connector-curvature="0" />
<path
style="fill:#d3d7cf;stroke:#2e3436;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 301.70919,107.88659 -12,4 2,4 12,-4 z"
id="path3892"
inkscape:connector-curvature="0" />
<path
style="fill:#888a85;stroke:#2e3436;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 285.70919,77.886588 c 4,10 12,22 4,34.000002 l 12,-4 c 8,-12.000002 0,-24.000002 -4,-34.000002 z"
id="path3894"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:#d3d7cf;stroke:#2e3436;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 259.70919,73.886588 12,-4 26,4 -12,4 z"
id="path3888"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:url(#linearGradient3967);fill-opacity:1;stroke:#d3d7cf;stroke-width:1.99999975999999990;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 284.30919,79.786588 -22.6,-3.9 c 0,10.043478 -0.0125,23.469561 1.8,32.600002 l 26.2,10.4 0,-2.5 -2.2,-4.5 c 8,-12.000002 1.2,-22.000002 -3.2,-32.100002 z"
id="path3100-6"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc" />
<path
style="fill:url(#linearGradient3959);fill-opacity:1;stroke:#babdb6;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 288.30919,79.086588 c 4,10 9.4,18.3 5.4,29.300002 l 6.6,-2.2 c 6,-9.000002 1.4,-19.300002 -3.8,-29.900002 z"
id="path3894-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
sodipodi:type="arc"
style="fill:#555753;fill-opacity:1;stroke:#2e3436;stroke-width:2.25831866;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:1.6"
id="path3932"
sodipodi:cx="-93"
sodipodi:cy="39"
sodipodi:rx="15"
sodipodi:ry="15"
d="m -78,39 a 15,15 0 0 1 -15,15 15,15 0 0 1 -15,-15 15,15 0 0 1 15,-15 15,15 0 0 1 15,15 z"
transform="matrix(0.79999998,0.19607832,0,0.9803916,350.10919,74.8866)" />
<path
style="fill:#edd400;fill-opacity:1;stroke:#302b00;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:1.6"
d="m 287.70919,97.827762 -24,-5.882349 c 0,0 -0.82229,-14.095015 12,-11.764699 11.12322,2.021527 12,17.647048 12,17.647048 z"
id="path3932-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccsc" />
<path
style="fill:#edd400;fill-opacity:1;stroke:#302b00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 294.70919,90.886588 c 2,4 3,11.000002 1,15.000002 l 4,-1 c 2,-4 2,-11.000002 0,-15.000002 z"
id="path3894-7-9"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:#edd400;stroke:#302b00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 37,51 8,-3 16,5 -6,4 z"
id="path4003"
inkscape:connector-curvature="0"
transform="translate(256.70919,66.886588)"
sodipodi:nodetypes="ccccc" />
<path
style="fill:#d3d7cf;stroke:#2e3436;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
d="m 61,53 0,4 -6,4 0,-4 z"
id="path4005"
inkscape:connector-curvature="0"
transform="translate(256.70919,66.886588)"
sodipodi:nodetypes="ccccc" />
<g
id="g4314">
<g
id="g3863"
transform="matrix(0.59299466,0,0,0.59299466,283.4333,77.218635)">
<path
style="color:#000000;display:block;overflow:visible;visibility:visible;fill:url(#linearGradient4295);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient4297);stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
d="m 27,-3.6915582 c 0,0 -12.247378,-0.8493196 -8.478954,13.4192502 l -10.534458,0 c 0,0 0.685168,-16.137073 19.013412,-13.4192502 z"
id="path2865-9"
inkscape:r_cx="true"
inkscape:r_cy="true"
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0" />
<g
id="g1878-1"
transform="matrix(-0.79349441,-0.66481753,-0.67040672,0.78687903,77.66003,0.94046451)"
inkscape:r_cx="true"
inkscape:r_cy="true"
style="fill:url(#linearGradient4299);fill-opacity:1;stroke:#204a87;stroke-width:0.73280919;stroke-opacity:1">
<path
sodipodi:nodetypes="ccccccc"
id="path1880-27"
d="M 44.306783,50.229694 C 62.821497,35.818859 49.664587,13.411704 22.462411,12.49765 L 22.113843,3.1515478 7.6245439,20.496754 22.714328,33.219189 c 0,0 -0.251917,-9.88122 -0.251917,-9.88122 18.82976,0.998977 32.981627,14.071729 21.844372,26.891725 z"
style="color:#000000;display:block;overflow:visible;visibility:visible;fill:url(#linearGradient3034);fill-opacity:1;fill-rule:nonzero;stroke:#0b1521;stroke-width:3.26039815;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
inkscape:r_cx="true"
inkscape:r_cy="true"
inkscape:connector-curvature="0" />
</g>
<g
style="fill:none;stroke:#729fcf;stroke-width:0.73280919;stroke-opacity:1"
inkscape:r_cy="true"
inkscape:r_cx="true"
transform="matrix(-0.69686517,-0.58385766,-0.58876622,0.69105539,72.350404,1.0127423)"
id="g2805-0">
<path
inkscape:r_cy="true"
inkscape:r_cx="true"
style="color:#000000;display:block;overflow:visible;visibility:visible;fill:none;stroke:#729fcf;stroke-width:2.20148993;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:21;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
d="M 52.368857,42.344789 C 57.336994,33.465615 49.176003,12.601866 19.05552,12.672851 L 18.677956,5.6633463 7.4378077,19.282655 19.129354,29.167094 18.807724,20.554957 c 18.244937,0.381972 33.804002,9.457851 33.561133,21.789832 z"
id="path2807-9"
sodipodi:nodetypes="ccccccc"
inkscape:connector-curvature="0" />
</g>
</g>
<g
id="g3863-0"
transform="matrix(-0.59299466,0,0,-0.59299466,322.563,94.41548)">
<path
style="color:#000000;display:block;overflow:visible;visibility:visible;fill:url(#linearGradient4585);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient1488);stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
d="m 27,-3.6915582 c 0,0 -12.247378,-0.8493196 -8.478954,13.4192502 l -10.534458,0 c 0,0 0.685168,-16.137073 19.013412,-13.4192502 z"
id="path2865-3"
inkscape:r_cx="true"
inkscape:r_cy="true"
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0" />
<g
id="g1878-6"
transform="matrix(-0.79349441,-0.66481753,-0.67040672,0.78687903,77.66003,0.94046451)"
inkscape:r_cx="true"
inkscape:r_cy="true"
style="fill:url(#linearGradient4587);fill-opacity:1;stroke:#204a87;stroke-width:0.73280919;stroke-opacity:1">
<path
sodipodi:nodetypes="ccccccc"
id="path1880-2"
d="M 44.306783,50.229694 C 62.821497,35.818859 49.664587,13.411704 22.462411,12.49765 L 22.113843,3.1515478 7.6245439,20.496754 22.714328,33.219189 c 0,0 -0.251917,-9.88122 -0.251917,-9.88122 18.82976,0.998977 32.981627,14.071729 21.844372,26.891725 z"
style="color:#000000;display:block;overflow:visible;visibility:visible;fill:url(#linearGradient3034-4);fill-opacity:1;fill-rule:nonzero;stroke:#0b1521;stroke-width:3.26039815;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
inkscape:r_cx="true"
inkscape:r_cy="true"
inkscape:connector-curvature="0" />
</g>
<g
style="fill:none;stroke:#729fcf;stroke-width:0.73280919;stroke-opacity:1"
inkscape:r_cy="true"
inkscape:r_cx="true"
transform="matrix(-0.69686517,-0.58385766,-0.58876622,0.69105539,72.350404,1.0127423)"
id="g2805-4">
<path
inkscape:r_cy="true"
inkscape:r_cx="true"
style="color:#000000;display:block;overflow:visible;visibility:visible;fill:none;stroke:#729fcf;stroke-width:2.20148993;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:21;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
d="M 52.368857,42.344789 C 57.864671,33.591679 49.176003,12.601866 19.05552,12.672851 L 18.677956,5.6633463 7.4378077,19.282655 19.129354,29.167094 18.807724,20.554957 c 18.244937,0.381972 33.804002,9.457851 33.561133,21.789832 z"
id="path2807-5"
sodipodi:nodetypes="ccccccc"
inkscape:connector-curvature="0" />
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -0,0 +1,290 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg2980"
sodipodi:version="0.32"
inkscape:version="0.91 r13725"
sodipodi:docname="Part_Transformed_Copy.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.1">
<defs
id="defs2982">
<linearGradient
inkscape:collect="always"
id="linearGradient3794">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop3796" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop3798" />
</linearGradient>
<linearGradient
id="linearGradient3864">
<stop
id="stop3866"
offset="0"
style="stop-color:#71b2f8;stop-opacity:1;" />
<stop
id="stop3868"
offset="1"
style="stop-color:#002795;stop-opacity:1;" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 32 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="64 : 32 : 1"
inkscape:persp3d-origin="32 : 21.333333 : 1"
id="perspective2988" />
<linearGradient
gradientTransform="translate(0,-4)"
inkscape:collect="always"
xlink:href="#linearGradient3767"
id="linearGradient3773"
x1="22.116516"
y1="55.717518"
x2="17.328547"
y2="21.31134"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
id="linearGradient3767">
<stop
style="stop-color:#edd400;stop-opacity:1"
offset="0"
id="stop3769" />
<stop
style="stop-color:#fce94f;stop-opacity:1"
offset="1"
id="stop3771" />
</linearGradient>
<linearGradient
gradientTransform="translate(0,-4)"
inkscape:collect="always"
xlink:href="#linearGradient3777"
id="linearGradient3783"
x1="53.896763"
y1="51.179787"
x2="47.502235"
y2="21.83742"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
id="linearGradient3777">
<stop
style="stop-color:#c4a000;stop-opacity:1"
offset="0"
id="stop3779" />
<stop
style="stop-color:#edd400;stop-opacity:1"
offset="1"
id="stop3781" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3794"
id="radialGradient3800"
cx="1"
cy="45"
fx="1"
fy="45"
r="41"
gradientTransform="matrix(0.93348213,-2.2905276e-8,0,0.28687573,0.06651751,32.090592)"
gradientUnits="userSpaceOnUse" />
<linearGradient
gradientTransform="translate(-32,-36)"
inkscape:collect="always"
xlink:href="#linearGradient3767-6"
id="linearGradient3773-3"
x1="22.116516"
y1="55.717518"
x2="17.328547"
y2="21.31134"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
id="linearGradient3767-6">
<stop
style="stop-color:#3465a4;stop-opacity:1"
offset="0"
id="stop3769-7" />
<stop
style="stop-color:#729fcf;stop-opacity:1"
offset="1"
id="stop3771-5" />
</linearGradient>
<linearGradient
gradientTransform="translate(-32,-36)"
inkscape:collect="always"
xlink:href="#linearGradient3777-5"
id="linearGradient3783-3"
x1="53.896763"
y1="51.179787"
x2="47.502235"
y2="21.83742"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
id="linearGradient3777-5">
<stop
style="stop-color:#204a87;stop-opacity:1"
offset="0"
id="stop3779-6" />
<stop
style="stop-color:#3465a4;stop-opacity:1"
offset="1"
id="stop3781-2" />
</linearGradient>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="4.2166862"
inkscape:cx="-19.30221"
inkscape:cy="11.865722"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:window-width="1375"
inkscape:window-height="876"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:snap-bbox="true"
inkscape:snap-nodes="false"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid2991"
empspacing="2"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<metadata
id="metadata2985">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:creator>
<cc:Agent>
<dc:title>[wmayer]</dc:title>
</cc:Agent>
</dc:creator>
<dc:title>Part_Box</dc:title>
<dc:date>2011-10-10</dc:date>
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
<dc:publisher>
<cc:Agent>
<dc:title>FreeCAD</dc:title>
</cc:Agent>
</dc:publisher>
<dc:identifier>FreeCAD/src/Mod/Part/Gui/Resources/icons/Part_Box.svg</dc:identifier>
<dc:rights>
<cc:Agent>
<dc:title>FreeCAD LGPL2+</dc:title>
</cc:Agent>
</dc:rights>
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
<dc:contributor>
<cc:Agent>
<dc:title>[agryson] Alexander Gryson</dc:title>
</cc:Agent>
</dc:contributor>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
id="g4185"
transform="matrix(0.66,0,0,0.66,24.009277,20.913856)">
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path2993-9"
d="m -29,-19 34,6 24,-8 -30,-4 z"
style="fill:#729fcf;stroke:#0b1521;stroke-width:3.03030303;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" />
<path
inkscape:connector-curvature="0"
id="path2995-1"
d="M 29,-21 29,15 5,25 5,-13 Z"
style="fill:url(#linearGradient3783-3);fill-opacity:1;stroke:#0b1521;stroke-width:3.03030303;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" />
<path
style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient3773-3);fill-opacity:1;fill-rule:evenodd;stroke:#0b1521;stroke-width:3.030303;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="M -29,-19 4.5508465,-13.089831 4.3711851,24.820339 -29,19 Z"
id="path3825-2"
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path3765-7"
d="m -26.237761,-16.064121 -0.24538,33.029838 28.400747,5.06734 -0.07222,-32.996227 z"
style="fill:none;stroke:#729fcf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path3775-0"
d="M 7.01243,-11.058008 7.00017,21.969134 27.001275,13.668141 26.620516,-17.564023 Z"
style="fill:none;stroke:#3465a4;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
<g
id="g4192"
transform="matrix(0.66,0,0,0.66,19.293871,22.570766)">
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path2993"
d="M 3,13 37,19 61,11 31,7 Z"
style="fill:#fce94f;stroke:#302b00;stroke-width:3.03030303;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" />
<path
inkscape:connector-curvature="0"
id="path2995"
d="M 61,11 61,47 37,57 37,19 Z"
style="fill:url(#linearGradient3783);fill-opacity:1;stroke:#302b00;stroke-width:3.03030303;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" />
<path
style="display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient3773);fill-opacity:1;fill-rule:evenodd;stroke:#302b00;stroke-width:3.030303;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="M 3,13 36.364801,19.25408 36.281354,56.820339 3,51 Z"
id="path3825"
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path3765"
d="M 5.4491535,15.966704 5.6374849,48.987513 33.58005,53.896989 33.751011,21.310836 Z"
style="fill:none;stroke:#fce94f;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccccc"
inkscape:connector-curvature="0"
id="path3775"
d="m 39.01243,20.433833 -0.01226,33.535301 20.001105,-8.300993 3.6e-4,-31.867363 z"
style="fill:none;stroke:#edd400;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -109,6 +109,7 @@ void TaskAttacher::makeRefStrings(std::vector<QString>& refstrings, std::vector<
TaskAttacher::TaskAttacher(Gui::ViewProviderDocumentObject *ViewProvider,QWidget *parent, QString picture, QString text)
: TaskBox(Gui::BitmapFactory().pixmap(picture.toLatin1()), text, true, parent),
SelectionObserver(ViewProvider),
ViewProvider(ViewProvider)
{
//check if we are attachable
@@ -348,8 +349,8 @@ void TaskAttacher::onSelectionChanged(const Gui::SelectionChanges& msg)
std::vector<App::DocumentObject*> refs = pcAttach->Support.getValues();
std::vector<std::string> refnames = pcAttach->Support.getSubValues();
App::DocumentObject* selObj = ViewProvider->getObject()->getDocument()->getObject(msg.pObjectName);
if (selObj == ViewProvider->getObject()) return;//prevent self-referencing
if (!selObj || selObj == ViewProvider->getObject()) return;//prevent self-referencing
std::string subname = msg.pSubName;
// Remove subname for planes and datum features
@@ -1021,36 +1022,28 @@ bool TaskDlgAttacher::accept()
return true;
Part::AttachExtension* pcAttach = ViewProvider->getObject()->getExtensionByType<Part::AttachExtension>();
std::string name = ViewProvider->getObject()->getNameInDocument();
std::string appDocument = doc.getAppDocumentPython();
std::string guiDocument = doc.getGuiDocumentPython();
auto obj = ViewProvider->getObject();
//DeepSOIC: changed this to heavily rely on dialog constantly updating feature properties
if (pcAttach->AttachmentOffset.isTouched()){
Base::Placement plm = pcAttach->AttachmentOffset.getValue();
double yaw, pitch, roll;
plm.getRotation().getYawPitchRoll(yaw,pitch,roll);
Gui::Command::doCommand(Gui::Command::Doc,"%s.%s.AttachmentOffset = App.Placement(App.Vector(%.10f, %.10f, %.10f), App.Rotation(%.10f, %.10f, %.10f))",
appDocument.c_str(), name.c_str(),
FCMD_OBJ_CMD2("AttachmentOffset = App.Placement(App.Vector(%.10f, %.10f, %.10f), App.Rotation(%.10f, %.10f, %.10f))",
obj,
plm.getPosition().x, plm.getPosition().y, plm.getPosition().z,
yaw, pitch, roll);
}
Gui::Command::doCommand(Gui::Command::Doc,"%s.%s.MapReversed = %s",
appDocument.c_str(), name.c_str(),
pcAttach->MapReversed.getValue() ? "True" : "False");
FCMD_OBJ_CMD2("MapReversed = %s", obj, pcAttach->MapReversed.getValue() ? "True" : "False");
Gui::Command::doCommand(Gui::Command::Doc,"%s.%s.Support = %s",
appDocument.c_str(), name.c_str(),
pcAttach->Support.getPyReprString().c_str());
FCMD_OBJ_CMD2("Support = %s", obj, pcAttach->Support.getPyReprString().c_str());
Gui::Command::doCommand(Gui::Command::Doc,"%s.%s.MapMode = '%s'",
appDocument.c_str(), name.c_str(),
AttachEngine::getModeName(eMapMode(pcAttach->MapMode.getValue())).c_str());
FCMD_OBJ_CMD2("MapMode = '%s'", obj, AttachEngine::getModeName(eMapMode(pcAttach->MapMode.getValue())).c_str());
Gui::Command::doCommand(Gui::Command::Doc,"%s.recompute()", appDocument.c_str());
FCMD_OBJ_DOC_CMD(obj, "recompute()");
Gui::Command::doCommand(Gui::Command::Gui, "%s.resetEdit()", guiDocument.c_str());
FCMD_VOBJ_DOC_CMD(obj,"resetEdit()");
document->commitCommand();
}
catch (const Base::Exception& e) {

View File

@@ -415,38 +415,25 @@ void TaskCheckGeometryResults::goCheck()
{
Gui::WaitCursor wc;
int selectedCount(0), checkedCount(0), invalidShapes(0);
std::vector<Gui::SelectionSingleton::SelObj> selection = Gui::Selection().getSelection();
std::vector<Gui::SelectionSingleton::SelObj>::iterator it;
ResultEntry *theRoot = new ResultEntry();
Handle(Message_ProgressIndicator) theProgress = new BOPProgressIndicator(tr("Check geometry"), Gui::getMainWindow());
theProgress->NewScope("BOP check...");
#if OCC_VERSION_HEX >= 0x060900
theProgress->Show();
#endif
selectedCount = static_cast<int>(selection.size());
for (it = selection.begin(); it != selection.end(); ++it)
{
Part::Feature *feature = dynamic_cast<Part::Feature *>((*it).pObject);
if (!feature)
continue;
currentSeparator = Gui::Application::Instance->activeDocument()->getViewProvider(feature)->getRoot();
if (!currentSeparator)
continue;
TopoDS_Shape shape = feature->Shape.getValue();
QString baseName;
QTextStream baseStream(&baseName);
baseStream << (*it).DocName;
baseStream << "." << (*it).FeatName;
if (strlen((*it).SubName) > 0)
{
shape = feature->Shape.getShape().getSubShape((*it).SubName);
baseStream << "." << (*it).SubName;
}
for(const auto &sel : Gui::Selection().getSelection()) {
selectedCount++;
TopoDS_Shape shape = Part::Feature::getShape(sel.pObject,sel.SubName,true);
if (shape.IsNull())
continue;
currentSeparator = Gui::Application::Instance->getViewProvider(sel.pObject)->getRoot();
if (!currentSeparator)
continue;
QString baseName;
QTextStream baseStream(&baseName);
baseStream << sel.DocName;
baseStream << "." << sel.FeatName;
checkedCount++;
checkedMap.Clear();
@@ -483,7 +470,7 @@ void TaskCheckGeometryResults::goCheck()
group->SetBool("RunBOPCheck", runSignal);
if (runSignal) {
std::string label = "Checking ";
label += feature->Label.getStrValue();
label += sel.pObject->Label.getStrValue();
label += "...";
theProgress->NewScope(label.c_str());
invalidShapes += goBOPSingleCheck(shape, theRoot, baseName, theProgress);

View File

@@ -78,7 +78,30 @@
#include "TaskDimension.h"
bool PartGui::getShapeFromStrings(TopoDS_Shape &shapeOut, const std::string &doc, const std::string &object, const std::string &sub)
static bool _MeasureInfoInited;
static void slotDeleteDocument(const App::Document &doc);
struct MeasureInfo {
PartGui::DimSelections sel1;
PartGui::DimSelections sel2;
bool linear;
MeasureInfo(const PartGui::DimSelections &sel1, const PartGui::DimSelections &sel2, bool linear)
:sel1(sel1),sel2(sel2),linear(linear)
{
if(!_MeasureInfoInited) {
_MeasureInfoInited = true;
App::GetApplication().signalDeleteDocument.connect(boost::bind(slotDeleteDocument, _1));
}
}
};
static std::map<std::string, std::list<MeasureInfo> > _Measures;
static void slotDeleteDocument(const App::Document &doc) {
_Measures.erase(doc.getName());
}
bool PartGui::getShapeFromStrings(TopoDS_Shape &shapeOut, const std::string &doc, const std::string &object, const std::string &sub, Base::Matrix4D *mat)
{
App::Document *docPointer = App::GetApplication().getDocument(doc.c_str());
if (!docPointer)
@@ -86,15 +109,7 @@ bool PartGui::getShapeFromStrings(TopoDS_Shape &shapeOut, const std::string &doc
App::DocumentObject *objectPointer = docPointer->getObject(object.c_str());
if (!objectPointer)
return false;
Part::Feature *feature = dynamic_cast<Part::Feature *>(objectPointer);
if (!feature)
return false;
Base::Placement placement = feature->globalPlacement();
Part::TopoShape topoShape = feature->Shape.getShape();
topoShape.setPlacement(placement);
shapeOut = topoShape.getShape();
if (sub.size() > 0)
shapeOut = topoShape.getSubShape(sub.c_str());
shapeOut = Part::Feature::getShape(objectPointer,sub.c_str(),true,mat);
if (shapeOut.IsNull())
return false;
return true;
@@ -102,23 +117,26 @@ bool PartGui::getShapeFromStrings(TopoDS_Shape &shapeOut, const std::string &doc
bool PartGui::evaluateLinearPreSelection(TopoDS_Shape &shape1, TopoDS_Shape &shape2)
{
std::vector<Gui::SelectionSingleton::SelObj> selections = Gui::Selection().getSelection();
std::vector<Gui::SelectionSingleton::SelObj> selections = Gui::Selection().getSelection(0,false);
if (selections.size() != 2)
return false;
std::vector<Gui::SelectionSingleton::SelObj>::iterator it;
std::vector<TopoDS_Shape> shapes;
DimSelections sels[2];
int i=0;
for (it = selections.begin(); it != selections.end(); ++it)
{
Part::Feature *feature = dynamic_cast<Part::Feature *>((*it).pObject);
if (!feature)
break;
TopoDS_Shape shape = feature->Shape.getValue();
if (strlen((*it).SubName) > 0)
shape = feature->Shape.getShape().getSubShape((*it).SubName);
TopoDS_Shape shape = Part::Feature::getShape(it->pObject,it->SubName,true);
if (shape.IsNull())
break;
shapes.push_back(shape);
sels[i].selections.push_back(DimSelections::DimSelection());
auto &sel = sels[i].selections[0];
++i;
sel.documentName = it->DocName;
sel.objectName = it->FeatName;
sel.subObjectName = it->SubName;
}
if (shapes.size() != 2)
@@ -126,7 +144,10 @@ bool PartGui::evaluateLinearPreSelection(TopoDS_Shape &shape1, TopoDS_Shape &sha
shape1 = shapes.front();
shape2 = shapes.back();
auto doc = App::GetApplication().getActiveDocument();
if(doc)
_Measures[doc->getName()].emplace_back(sels[0],sels[1],true);
return true;
}
@@ -266,6 +287,7 @@ void PartGui::eraseAllDimensions()
Gui::Document *doc = Gui::Application::Instance->activeDocument();
if (!doc)
return;
_Measures.erase(doc->getDocument()->getName());
Gui::View3DInventor *view = dynamic_cast<Gui::View3DInventor*>(doc->getActiveView());
if (!view)
return;
@@ -275,6 +297,24 @@ void PartGui::eraseAllDimensions()
viewer->eraseAllDimensions();
}
void PartGui::refreshDimensions() {
auto doc = App::GetApplication().getActiveDocument();
if(!doc)
return;
auto it = _Measures.find(doc->getName());
if(it == _Measures.end())
return;
std::list<MeasureInfo> measures;
measures.swap(it->second);
eraseAllDimensions();
for(auto &info : measures) {
if(info.linear)
PartGui::TaskMeasureLinear::buildDimension(info.sel1,info.sel2);
else
PartGui::TaskMeasureAngular::buildDimension(info.sel1,info.sel2);
}
}
void PartGui::toggle3d()
{
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
@@ -470,7 +510,9 @@ void PartGui::DimensionLinear::setupDimension()
textSep->addChild(rTrans);
}
PartGui::TaskMeasureLinear::TaskMeasureLinear(): selections1(), selections2(), buttonSelectedIndex(0)
PartGui::TaskMeasureLinear::TaskMeasureLinear()
: Gui::SelectionObserver(true,false)
, selections1(), selections2(), buttonSelectedIndex(0)
{
setUpGui();
}
@@ -535,14 +577,18 @@ void PartGui::TaskMeasureLinear::selectionClearDelayedSlot()
this->blockConnection(false);
}
void PartGui::TaskMeasureLinear::buildDimension()
void PartGui::TaskMeasureLinear::buildDimension() {
buildDimension(selections1,selections2);
}
void PartGui::TaskMeasureLinear::buildDimension(const DimSelections &sel1, const DimSelections &sel2)
{
if(selections1.selections.size() != 1 || selections2.selections.size() != 1)
if(sel1.selections.size() != 1 || sel2.selections.size() != 1)
return;
DimSelections::DimSelection current1 = selections1.selections.at(0);
DimSelections::DimSelection current2 = selections2.selections.at(0);
DimSelections::DimSelection current1 = sel1.selections.at(0);
DimSelections::DimSelection current2 = sel2.selections.at(0);
TopoDS_Shape shape1, shape2;
if (!getShapeFromStrings(shape1, current1.documentName, current1.objectName, current1.subObjectName))
{
@@ -554,6 +600,9 @@ void PartGui::TaskMeasureLinear::buildDimension()
Base::Console().Message("\nFailed to get shape\n\n");
return;
}
auto doc = App::GetApplication().getActiveDocument();
if(doc)
_Measures[doc->getName()].emplace_back(sel1,sel2,true);
goDimensionLinearNoTask(shape1, shape2);
}
@@ -771,25 +820,41 @@ void PartGui::goDimensionAngularRoot()
bool PartGui::evaluateAngularPreSelection(VectorAdapter &vector1Out, VectorAdapter &vector2Out)
{
std::vector<Gui::SelectionSingleton::SelObj> selections = Gui::Selection().getSelection();
std::vector<Gui::SelectionSingleton::SelObj> selections = Gui::Selection().getSelection(0,false);
if (selections.size() > 4 || selections.size() < 2)
return false;
std::vector<Gui::SelectionSingleton::SelObj>::iterator it;
std::vector<VectorAdapter> adapters;
std::vector<DimSelections> sels;
TopoDS_Vertex lastVertex;
for (it = selections.begin(); it != selections.end(); ++it)
{
Part::Feature *feature = dynamic_cast<Part::Feature *>((*it).pObject);
if (!feature)
break;
TopoDS_Shape shape = feature->Shape.getValue();
if (strlen((*it).SubName) > 0)
shape = feature->Shape.getShape().getSubShape((*it).SubName);
Base::Matrix4D mat;
TopoDS_Shape shape = Part::Feature::getShape(it->pObject,it->SubName,true,&mat);
if (shape.IsNull())
break;
mat.inverse();
if (shape.ShapeType() == TopAbs_VERTEX)
{
if(sels.empty() ||
sels.back().selections.back().shapeType!=DimSelections::Vertex ||
sels.back().selections.size()==1)
{
sels.push_back(PartGui::DimSelections());
}
sels.back().selections.push_back(DimSelections::DimSelection());
auto &sel = sels.back().selections.back();
sel.documentName = it->DocName;
sel.objectName = it->FeatName;
sel.subObjectName = it->SubName;
sel.shapeType = DimSelections::Vertex;
Base::Vector3d v(it->x,it->y,it->z);
v = mat*v;
sel.x = v.x;
sel.y = v.y;
sel.z = v.z;
TopoDS_Vertex currentVertex = TopoDS::Vertex(shape);
if (!lastVertex.IsNull())
{
@@ -815,8 +880,21 @@ bool PartGui::evaluateAngularPreSelection(VectorAdapter &vector1Out, VectorAdapt
continue;
}
sels.push_back(PartGui::DimSelections());
sels.back().selections.push_back(DimSelections::DimSelection());
auto &sel = sels.back().selections.back();
sel.documentName = it->DocName;
sel.objectName = it->FeatName;
sel.subObjectName = it->SubName;
Base::Vector3d v(it->x,it->y,it->z);
v = mat*v;
sel.x = v.x;
sel.y = v.y;
sel.z = v.z;
if (shape.ShapeType() == TopAbs_EDGE)
{
sel.shapeType = DimSelections::Edge;
TopoDS_Edge edge = TopoDS::Edge(shape);
// make edge orientation so that end of edge closest to pick is head of vector.
gp_Vec firstPoint = PartGui::convert(TopExp::FirstVertex(edge, Standard_True));
@@ -836,6 +914,7 @@ bool PartGui::evaluateAngularPreSelection(VectorAdapter &vector1Out, VectorAdapt
if (shape.ShapeType() == TopAbs_FACE)
{
sel.shapeType = DimSelections::Face;
TopoDS_Face face = TopoDS::Face(shape);
adapters.push_back(VectorAdapter(face, pickPoint));
continue;
@@ -857,6 +936,9 @@ bool PartGui::evaluateAngularPreSelection(VectorAdapter &vector1Out, VectorAdapt
return false;
}
auto doc = App::GetApplication().getActiveDocument();
if(doc)
_Measures[doc->getName()].emplace_back(sels[0],sels[1],false);
return true;
}
@@ -1401,7 +1483,9 @@ void PartGui::DimensionControl::clearAllSlot(bool)
PartGui::eraseAllDimensions();
}
PartGui::TaskMeasureAngular::TaskMeasureAngular(): selections1(), selections2(), buttonSelectedIndex(0)
PartGui::TaskMeasureAngular::TaskMeasureAngular()
: Gui::SelectionObserver(true,false)
, selections1(), selections2(), buttonSelectedIndex(0)
{
setUpGui();
}
@@ -1414,16 +1498,21 @@ PartGui::TaskMeasureAngular::~TaskMeasureAngular()
void PartGui::TaskMeasureAngular::onSelectionChanged(const Gui::SelectionChanges& msg)
{
TopoDS_Shape shape;
if (!getShapeFromStrings(shape, std::string(msg.pDocName), std::string(msg.pObjectName), std::string(msg.pSubName)))
Base::Matrix4D mat;
if (!getShapeFromStrings(shape, std::string(msg.pDocName),
std::string(msg.pObjectName), std::string(msg.pSubName),&mat))
return;
mat.inverse();
DimSelections::DimSelection newSelection;
newSelection.documentName = msg.pDocName;
newSelection.objectName = msg.pObjectName;
newSelection.subObjectName = msg.pSubName;
newSelection.x = msg.x;
newSelection.y = msg.y;
newSelection.z = msg.z;
gp_Vec pickPoint(msg.x, msg.y, msg.z);
Base::Vector3d v(msg.x,msg.y,msg.z);
v = mat*v;
newSelection.x = v.x;
newSelection.y = v.y;
newSelection.z = v.z;
if (buttonSelectedIndex == 0)
{
if (msg.Type == Gui::SelectionChanges::AddSelection)
@@ -1544,8 +1633,9 @@ void PartGui::TaskMeasureAngular::selectionClearDelayedSlot()
this->blockConnection(false);
}
PartGui::VectorAdapter PartGui::TaskMeasureAngular::buildAdapter(const PartGui::DimSelections& selection) const
PartGui::VectorAdapter PartGui::TaskMeasureAngular::buildAdapter(const PartGui::DimSelections& selection)
{
Base::Matrix4D mat;
assert(selection.selections.size() > 0 && selection.selections.size() < 3);
if (selection.selections.size() == 1)
{
@@ -1553,7 +1643,7 @@ PartGui::VectorAdapter PartGui::TaskMeasureAngular::buildAdapter(const PartGui::
if (current.shapeType == DimSelections::Edge)
{
TopoDS_Shape edgeShape;
if (!getShapeFromStrings(edgeShape, current.documentName, current.objectName, current.subObjectName))
if (!getShapeFromStrings(edgeShape, current.documentName, current.objectName, current.subObjectName,&mat))
return VectorAdapter();
TopoDS_Edge edge = TopoDS::Edge(edgeShape);
// make edge orientation so that end of edge closest to pick is head of vector.
@@ -1563,7 +1653,9 @@ PartGui::VectorAdapter PartGui::TaskMeasureAngular::buildAdapter(const PartGui::
return VectorAdapter();
gp_Vec firstPoint = PartGui::convert(firstVertex);
gp_Vec lastPoint = PartGui::convert(lastVertex);
gp_Vec pickPoint(current.x, current.y, current.z);
Base::Vector3d v(current.x,current.y,current.z);
v = mat*v;
gp_Vec pickPoint(v.x, v.y, v.z);
double firstDistance = (firstPoint - pickPoint).Magnitude();
double lastDistance = (lastPoint - pickPoint).Magnitude();
if (lastDistance > firstDistance)
@@ -1578,11 +1670,13 @@ PartGui::VectorAdapter PartGui::TaskMeasureAngular::buildAdapter(const PartGui::
if (current.shapeType == DimSelections::Face)
{
TopoDS_Shape faceShape;
if (!getShapeFromStrings(faceShape, current.documentName, current.objectName, current.subObjectName))
if (!getShapeFromStrings(faceShape, current.documentName, current.objectName, current.subObjectName,&mat))
return VectorAdapter();
TopoDS_Face face = TopoDS::Face(faceShape);
gp_Vec pickPoint(current.x, current.y, current.z);
Base::Vector3d v(current.x,current.y,current.z);
v = mat*v;
gp_Vec pickPoint(v.x, v.y, v.z);
return VectorAdapter(face, pickPoint);
}
}
@@ -1604,17 +1698,24 @@ PartGui::VectorAdapter PartGui::TaskMeasureAngular::buildAdapter(const PartGui::
return VectorAdapter(PartGui::convert(vertex2), PartGui::convert(vertex1));
}
void PartGui::TaskMeasureAngular::buildDimension()
void PartGui::TaskMeasureAngular::buildDimension() {
buildDimension(selections1,selections2);
}
void PartGui::TaskMeasureAngular::buildDimension(const DimSelections &sel1, const DimSelections &sel2)
{
//build adapters.
VectorAdapter adapt1 = buildAdapter(selections1);
VectorAdapter adapt2 = buildAdapter(selections2);
VectorAdapter adapt1 = buildAdapter(sel1);
VectorAdapter adapt2 = buildAdapter(sel2);
if (!adapt1.isValid() || !adapt2.isValid())
{
Base::Console().Message("\ncouldn't build adapter\n\n");
return;
}
auto doc = App::GetApplication().getActiveDocument();
if(doc)
_Measures[doc->getName()].emplace_back(sel1,sel2,false);
goDimensionAngularNoTask(adapt1, adapt2);
}

View File

@@ -38,6 +38,7 @@
#include <Gui/TaskView/TaskDialog.h>
#include <Gui/TaskView/TaskView.h>
#include <Base/Matrix.h>
class TopoDS_Shape;
class TopoDS_Face;
@@ -61,7 +62,7 @@ namespace PartGui
* @param sub sub-object name to search.
* @return signal if the search was successful.
*/
bool getShapeFromStrings(TopoDS_Shape &shapeOut, const std::string &doc, const std::string &object, const std::string &sub);
bool getShapeFromStrings(TopoDS_Shape &shapeOut, const std::string &doc, const std::string &object, const std::string &sub, Base::Matrix4D *mat=0);
/*!examine pre selection
* @param shape1 first shape in current selection
* @param shape2 second shape in current selection
@@ -95,6 +96,8 @@ namespace PartGui
SoNode* createLinearDimension(const gp_Pnt &point1, const gp_Pnt &point2, const SbColor &color);
/*!erases all the dimensions in the viewer.*/
void eraseAllDimensions();
/*!refresh all the dimensions in the viewer.*/
void refreshDimensions();
/*!toggles the display status of the 3d dimensions*/
void toggle3d();
/*!toggles the display status of the delta dimensions*/
@@ -259,6 +262,9 @@ protected Q_SLOTS:
void clearAllSlot(bool);
void selectionClearDelayedSlot();
public:
static void buildDimension(const DimSelections &sel1, const DimSelections &sel2);
private:
void setUpGui();
void buildDimension();
@@ -335,15 +341,18 @@ protected Q_SLOTS:
void clearAllSlot(bool);
void selectionClearDelayedSlot();
public:
static void buildDimension(const DimSelections &sel1, const DimSelections &sel2);
private:
void setUpGui();
void buildDimension();
void setUpGui();
void clearSelection();
DimSelections selections1;
DimSelections selections2;
uint buttonSelectedIndex;
SteppedSelection *stepped;
VectorAdapter buildAdapter(const DimSelections &selection) const;
static VectorAdapter buildAdapter(const DimSelections &selection);
};
/*!start of the measure angular command*/

View File

@@ -178,21 +178,14 @@ void OffsetWidget::on_updateView_toggled(bool on)
bool OffsetWidget::accept()
{
std::string name = d->offset->getNameInDocument();
try {
double offsetValue = d->ui.spinOffset->value().getValue();
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Value = %f",
name.c_str(),offsetValue);
FCMD_OBJ_CMD2("Value = %f", d->offset,offsetValue);
d->ui.spinOffset->apply();
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Mode = %i",
name.c_str(),d->ui.modeType->currentIndex());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Join = %i",
name.c_str(),d->ui.joinType->currentIndex());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Intersection = %s",
name.c_str(),d->ui.intersection->isChecked() ? "True" : "False");
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.SelfIntersection = %s",
name.c_str(),d->ui.selfIntersection->isChecked() ? "True" : "False");
FCMD_OBJ_CMD2("Mode = %i", d->offset,d->ui.modeType->currentIndex());
FCMD_OBJ_CMD2("Join = %i", d->offset,d->ui.joinType->currentIndex());
FCMD_OBJ_CMD2("Intersection = %s", d->offset,d->ui.intersection->isChecked() ? "True" : "False");
FCMD_OBJ_CMD2("SelfIntersection = %s", d->offset,d->ui.selfIntersection->isChecked() ? "True" : "False");
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()");
if (!d->offset->isValid())

View File

@@ -225,22 +225,17 @@ bool ThicknessWidget::accept()
if (d->loop.isRunning())
return false;
std::string name = d->thickness->getNameInDocument();
try {
if (!d->selection.empty()) {
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Faces = %s",
name.c_str(),d->selection.c_str());
FCMD_OBJ_CMD2("Faces = %s", d->thickness,d->selection.c_str());
}
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Value = %f",
name.c_str(),d->ui.spinOffset->value().getValue());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Mode = %i",
name.c_str(),d->ui.modeType->currentIndex());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Join = %i",
name.c_str(),d->ui.joinType->currentIndex());
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Intersection = %s",
name.c_str(),d->ui.intersection->isChecked() ? "True" : "False");
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.SelfIntersection = %s",
name.c_str(),d->ui.selfIntersection->isChecked() ? "True" : "False");
FCMD_OBJ_CMD2("Value = %f", d->thickness,d->ui.spinOffset->value().getValue());
FCMD_OBJ_CMD2("Mode = %i", d->thickness,d->ui.modeType->currentIndex());
FCMD_OBJ_CMD2("Join = %i", d->thickness,d->ui.joinType->currentIndex());
FCMD_OBJ_CMD2("Intersection = %s",
d->thickness,d->ui.intersection->isChecked() ? "True" : "False");
FCMD_OBJ_CMD2("SelfIntersection = %s",
d->thickness,d->ui.selfIntersection->isChecked() ? "True" : "False");
Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()");
if (!d->thickness->isValid())

View File

@@ -28,6 +28,7 @@
#include <Base/Console.h>
#include <Base/Exception.h>
#include <App/Document.h>
#include <Gui/Command.h>
#include <Mod/Part/App/PartFeature.h>
@@ -54,8 +55,7 @@ bool ViewProviderPart::doubleClicked(void)
Msg += this->pcObject->Label.getValue();
try {
Gui::Command::openCommand(Msg.c_str());
Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.setEdit('%s',0)",
this->pcObject->getNameInDocument());
FCMD_SET_EDIT(pcObject);
return true;
}
catch (const Base::Exception& e) {

View File

@@ -34,6 +34,7 @@
# include <Inventor/nodes/SoPickStyle.h>
# include <Inventor/nodes/SoSeparator.h>
# include <Inventor/nodes/SoVertexProperty.h>
# include <Inventor/nodes/SoAnnotation.h>
# include <cfloat>
#endif
@@ -69,7 +70,7 @@ ViewProvider2DObject::ViewProvider2DObject()
ADD_PROPERTY_TYPE(TightGrid,(true),"Grid",(App::PropertyType)(App::Prop_None),"Switch the tight grid mode on/off");
ADD_PROPERTY_TYPE(GridSnap,(false),"Grid",(App::PropertyType)(App::Prop_None),"Switch the grid snap on/off");
GridRoot = new SoSeparator();
GridRoot = new SoAnnotation();
GridRoot->ref();
GridRoot->setName("GridRoot");
MinX = MinY = -100;
@@ -150,9 +151,18 @@ SoSeparator* ViewProvider2DObject::createGrid(void)
carpet->vertexProperty = vts;
parent->addChild(carpet);*/
// It seems that SoDepthBuffer will mess up with other object's
// pre-selection highlight. No idea why the setting can leak out of a
// separator.
//
// What's the purpose of using SoDepthBuffer here anyway? If the intension
// is to render grid always on top, shouldn't it be better to use
// SoAnnotation?
#if 0
SoDepthBuffer *depth = new SoDepthBuffer;
depth->function = SoDepthBuffer::ALWAYS;
parent->addChild(depth);
#endif
// gridlines
mycolor = new SoBaseColor;

View File

@@ -88,8 +88,10 @@ void ViewProviderBoolean::updateData(const App::Property* prop)
Part::Boolean* objBool = dynamic_cast<Part::Boolean*>(getObject());
if (!objBool)
return;
Part::Feature* objBase = dynamic_cast<Part::Feature*>(objBool->Base.getValue());
Part::Feature* objTool = dynamic_cast<Part::Feature*>(objBool->Tool.getValue());
Part::Feature* objBase = dynamic_cast<Part::Feature*>(
Part::Feature::getShapeOwner(objBool->Base.getValue()));
Part::Feature* objTool = dynamic_cast<Part::Feature*>(
Part::Feature::getShapeOwner(objBool->Tool.getValue()));
if (objBase && objTool) {
const TopoDS_Shape& baseShape = objBase->Shape.getValue();
const TopoDS_Shape& toolShape = objTool->Shape.getValue();
@@ -152,18 +154,6 @@ bool ViewProviderBoolean::onDelete(const std::vector<std::string> &)
return true;
}
void ViewProviderBoolean::replaceObject(App::DocumentObject* oldValue, App::DocumentObject* newValue)
{
Part::Boolean* pBool = static_cast<Part::Boolean*>(getObject());
if (oldValue == pBool->Base.getValue()) {
pBool->Base.setValue(newValue);
}
else if (oldValue == pBool->Tool.getValue()) {
pBool->Tool.setValue(newValue);
}
}
PROPERTY_SOURCE(PartGui::ViewProviderMultiFuse,PartGui::ViewProviderPart)
ViewProviderMultiFuse::ViewProviderMultiFuse()
@@ -204,7 +194,7 @@ void ViewProviderMultiFuse::updateData(const App::Property* prop)
int index=0;
for (std::vector<App::DocumentObject*>::iterator it = sources.begin(); it != sources.end(); ++it, ++index) {
Part::Feature* objBase = dynamic_cast<Part::Feature*>(*it);
Part::Feature* objBase = dynamic_cast<Part::Feature*>(Part::Feature::getShapeOwner(*it));
if (!objBase)
continue;
const TopoDS_Shape& baseShape = objBase->Shape.getValue();
@@ -257,7 +247,9 @@ bool ViewProviderMultiFuse::canDragObjects() const
bool ViewProviderMultiFuse::canDragObject(App::DocumentObject* obj) const
{
return obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId());
(void)obj;
// return Part::Feature::hasShapeOwner(obj);
return true;
}
void ViewProviderMultiFuse::dragObject(App::DocumentObject* obj)
@@ -280,7 +272,9 @@ bool ViewProviderMultiFuse::canDropObjects() const
bool ViewProviderMultiFuse::canDropObject(App::DocumentObject* obj) const
{
return obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId());
(void)obj;
// return Part::Feature::hasShapeOwner(obj);
return true;
}
void ViewProviderMultiFuse::dropObject(App::DocumentObject* obj)
@@ -291,14 +285,6 @@ void ViewProviderMultiFuse::dropObject(App::DocumentObject* obj)
pBool->Shapes.setValues(pShapes);
}
void ViewProviderMultiFuse::replaceObject(App::DocumentObject* oldValue, App::DocumentObject* newValue)
{
Part::MultiFuse* pBool = static_cast<Part::MultiFuse*>(getObject());
std::vector<App::DocumentObject*> pShapes = pBool->Shapes.getValues();
std::replace(pShapes.begin(), pShapes.end(), oldValue, newValue);
pBool->Shapes.setValues(pShapes);
}
PROPERTY_SOURCE(PartGui::ViewProviderMultiCommon,PartGui::ViewProviderPart)
ViewProviderMultiCommon::ViewProviderMultiCommon()
@@ -339,7 +325,7 @@ void ViewProviderMultiCommon::updateData(const App::Property* prop)
int index=0;
for (std::vector<App::DocumentObject*>::iterator it = sources.begin(); it != sources.end(); ++it, ++index) {
Part::Feature* objBase = dynamic_cast<Part::Feature*>(*it);
Part::Feature* objBase = dynamic_cast<Part::Feature*>(Part::Feature::getShapeOwner(*it));
if (!objBase)
continue;
const TopoDS_Shape& baseShape = objBase->Shape.getValue();
@@ -392,7 +378,9 @@ bool ViewProviderMultiCommon::canDragObjects() const
bool ViewProviderMultiCommon::canDragObject(App::DocumentObject* obj) const
{
return obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId());
(void)obj;
// return Part::Feature::hasShapeOwner(obj);
return true;
}
void ViewProviderMultiCommon::dragObject(App::DocumentObject* obj)
@@ -415,7 +403,9 @@ bool ViewProviderMultiCommon::canDropObjects() const
bool ViewProviderMultiCommon::canDropObject(App::DocumentObject* obj) const
{
return obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId());
(void)obj;
// return Part::Feature::hasShapeOwner(obj);
return true;
}
void ViewProviderMultiCommon::dropObject(App::DocumentObject* obj)
@@ -426,10 +416,3 @@ void ViewProviderMultiCommon::dropObject(App::DocumentObject* obj)
pBool->Shapes.setValues(pShapes);
}
void ViewProviderMultiCommon::replaceObject(App::DocumentObject* oldValue, App::DocumentObject* newValue)
{
Part::MultiFuse* pBool = static_cast<Part::MultiFuse*>(getObject());
std::vector<App::DocumentObject*> pShapes = pBool->Shapes.getValues();
std::replace(pShapes.begin(), pShapes.end(), oldValue, newValue);
pBool->Shapes.setValues(pShapes);
}

View File

@@ -44,7 +44,6 @@ public:
QIcon getIcon(void) const;
void updateData(const App::Property*);
bool onDelete(const std::vector<std::string> &);
virtual void replaceObject(App::DocumentObject*, App::DocumentObject*);
};
/// ViewProvider for the MultiFuse feature
@@ -71,8 +70,6 @@ public:
bool canDropObjects() const;
bool canDropObject(App::DocumentObject*) const;
void dropObject(App::DocumentObject*);
/** Replace an object to the view provider by drag and drop */
virtual void replaceObject(App::DocumentObject*, App::DocumentObject*);
};
/// ViewProvider for the MultiFuse feature
@@ -99,8 +96,6 @@ public:
bool canDropObjects() const;
bool canDropObject(App::DocumentObject*) const;
void dropObject(App::DocumentObject*);
/** Replace an object to the view provider by drag and drop */
virtual void replaceObject(App::DocumentObject*, App::DocumentObject*);
};

View File

@@ -102,7 +102,7 @@ void ViewProviderCompound::updateData(const App::Property* prop)
int index=0;
for (std::vector<App::DocumentObject*>::iterator it = sources.begin(); it != sources.end(); ++it, ++index) {
Part::Feature* objBase = dynamic_cast<Part::Feature*>(*it);
Part::Feature* objBase = dynamic_cast<Part::Feature*>(Part::Feature::getShapeOwner(*it));
if (!objBase)
continue;
@@ -174,10 +174,3 @@ void ViewProviderCompound::dropObject(App::DocumentObject* obj)
pComp->Links.setValues(pShapes);
}
void ViewProviderCompound::replaceObject(App::DocumentObject* oldValue, App::DocumentObject* newValue)
{
Part::Compound* pBool = static_cast<Part::Compound*>(getObject());
std::vector<App::DocumentObject*> pShapes = pBool->Links.getValues();
std::replace(pShapes.begin(), pShapes.end(), oldValue, newValue);
pBool->Links.setValues(pShapes);
}

View File

@@ -48,8 +48,6 @@ public:
bool canDropObjects() const;
bool canDropObject(App::DocumentObject*) const;
void dropObject(App::DocumentObject*);
/** Replace an object to the view provider by drag and drop */
virtual void replaceObject(App::DocumentObject*, App::DocumentObject*);
protected:
void updateData(const App::Property*);

View File

@@ -112,7 +112,9 @@
#include <Gui/View3DInventorViewer.h>
#include <Gui/Utilities.h>
#include <Gui/Control.h>
#include <Gui/ViewProviderLink.h>
#include <Gui/ViewParams.h>
#include "ViewProviderExt.h"
#include "SoBrepPointSet.h"
#include "SoBrepEdgeSet.h"
@@ -122,6 +124,7 @@
#include <Mod/Part/App/PartFeature.h>
#include <Mod/Part/App/PrimitiveFeature.h>
FC_LOG_LEVEL_INIT("Part", true, true);
using namespace PartGui;
@@ -228,14 +231,13 @@ const char* ViewProviderPartExt::DrawStyleEnums[]= {"Solid","Dashed","Dotted","D
ViewProviderPartExt::ViewProviderPartExt()
{
VisualTouched = true;
forceUpdateCount = 0;
NormalsFromUV = true;
ParameterGrp::handle hView = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");
unsigned long lcol = hView->GetUnsigned("DefaultShapeLineColor",421075455UL); // dark grey (25,25,25)
unsigned long lcol = Gui::ViewParams::instance()->getDefaultShapeLineColor(); // dark grey (25,25,25)
float r,g,b;
r = ((lcol >> 24) & 0xff) / 255.0; g = ((lcol >> 16) & 0xff) / 255.0; b = ((lcol >> 8) & 0xff) / 255.0;
int lwidth = hView->GetInt("DefaultShapeLineWidth",2);
int lwidth = Gui::ViewParams::instance()->getDefaultShapeLineWidth();
ParameterGrp::handle hPart = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Mod/Part");
@@ -346,16 +348,15 @@ void ViewProviderPartExt::onChanged(const App::Property* prop)
// The lower limit of the deviation has been increased to avoid
// to freeze the GUI
// https://forum.freecadweb.org/viewtopic.php?f=3&t=24912&p=195613
Part::Feature* feature = dynamic_cast<Part::Feature*>(pcObject);
if (prop == &Deviation) {
if(Visibility.getValue() && feature && !feature->Shape.getValue().IsNull())
updateVisual(feature->Shape.getValue());
if(isUpdateForced()||Visibility.getValue())
updateVisual();
else
VisualTouched = true;
}
if (prop == &AngularDeflection) {
if(Visibility.getValue() && feature && !feature->Shape.getValue().IsNull())
updateVisual(feature->Shape.getValue());
if(isUpdateForced()||Visibility.getValue())
updateVisual();
else
VisualTouched = true;
}
@@ -456,8 +457,8 @@ void ViewProviderPartExt::onChanged(const App::Property* prop)
}
else {
// if the object was invisible and has been changed, recreate the visual
if (prop == &Visibility && Visibility.getValue() && VisualTouched) {
updateVisual(feature->Shape.getValue());
if (prop == &Visibility && (isUpdateForced() || Visibility.getValue()) && VisualTouched) {
updateVisual();
// The material has to be checked again (#0001736)
onChanged(&DiffuseColor);
}
@@ -472,10 +473,19 @@ void ViewProviderPartExt::attach(App::DocumentObject *pcFeat)
ViewProviderGeometryObject::attach(pcFeat);
// Workaround for #0000433, i.e. use SoSeparator instead of SoGroup
SoGroup* pcNormalRoot = new SoSeparator();
SoGroup* pcFlatRoot = new SoSeparator();
SoGroup* pcWireframeRoot = new SoSeparator();
SoGroup* pcPointsRoot = new SoSeparator();
auto* pcNormalRoot = new SoSeparator();
auto* pcFlatRoot = new SoSeparator();
auto* pcWireframeRoot = new SoSeparator();
auto* pcPointsRoot = new SoSeparator();
auto* wireframe = new SoSeparator();
// Must turn off all intermediate render caching, and let pcRoot to handle
// cache without interference.
pcNormalRoot->renderCaching =
pcFlatRoot->renderCaching =
pcWireframeRoot->renderCaching =
pcPointsRoot->renderCaching =
wireframe->renderCaching = SoSeparator::OFF;
// enable two-side rendering
pShapeHints->vertexOrdering = SoShapeHints::COUNTERCLOCKWISE;
@@ -486,7 +496,6 @@ void ViewProviderPartExt::attach(App::DocumentObject *pcFeat)
SoPolygonOffset* offset = new SoPolygonOffset();
// wireframe node
SoSeparator* wireframe = new SoSeparator();
wireframe->setName("Edge");
wireframe->addChild(pcLineBind);
wireframe->addChild(pcLineMaterial);
@@ -494,10 +503,10 @@ void ViewProviderPartExt::attach(App::DocumentObject *pcFeat)
wireframe->addChild(lineset);
// normal viewing with edges and points
pcNormalRoot->addChild(pcPointsRoot);
pcNormalRoot->addChild(wireframe);
pcNormalRoot->addChild(offset);
pcNormalRoot->addChild(pcFlatRoot);
pcNormalRoot->addChild(pcPointsRoot);
// just faces with no edges or points
pcFlatRoot->addChild(pShapeHints);
@@ -616,7 +625,7 @@ std::vector<Base::Vector3d> ViewProviderPartExt::getModelPoints(const SoPickedPo
try {
std::vector<Base::Vector3d> pts;
std::string element = this->getElement(pp->getDetail());
const Part::TopoShape& shape = static_cast<Part::Feature*>(getObject())->Shape.getShape();
const auto &shape = Part::Feature::getTopoShape(getObject());
TopoDS_Shape subShape = shape.getSubShape(element.c_str());
@@ -663,6 +672,9 @@ std::vector<Base::Vector3d> ViewProviderPartExt::getSelectionShape(const char* /
void ViewProviderPartExt::setHighlightedFaces(const std::vector<App::Color>& colors)
{
Gui::SoUpdateVBOAction action;
action.apply(this->faceset);
int size = static_cast<int>(colors.size());
if (size > 1 && size == this->faceset->partIndex.getNum()) {
pcFaceBind->value = SoMaterialBinding::PER_PART;
@@ -766,7 +778,7 @@ void ViewProviderPartExt::setHighlightedPoints(const std::vector<App::Color>& co
{
int size = static_cast<int>(colors.size());
if (size > 1) {
#ifdef FC_DEBUG
#if 0
int numPoints = coords->point.getNum() - nodeset->startIndex.getValue();
if (numPoints != size) {
SoDebugError::postWarning("ViewProviderPartExt::setHighlightedPoints",
@@ -813,22 +825,19 @@ bool ViewProviderPartExt::loadParameter()
void ViewProviderPartExt::reload()
{
if (loadParameter()) {
App::Property* shape = pcObject->getPropertyByName("Shape");
if (shape) update(shape);
}
if (loadParameter())
updateVisual();
}
void ViewProviderPartExt::updateData(const App::Property* prop)
{
if (prop->getTypeId() == Part::PropertyPartShape::getClassTypeId()) {
// get the shape to show
const TopoDS_Shape &cShape = static_cast<const Part::PropertyPartShape*>(prop)->getValue();
const char *propName = prop?prop->getName():"";
if(propName && (strcmp(propName,"Shape")==0 || strstr(propName,"Touched")!=0))
{
// calculate the visual only if visible
if (Visibility.getValue())
updateVisual(cShape);
else
if (isUpdateForced()||Visibility.getValue())
updateVisual();
else
VisualTouched = true;
if (!VisualTouched) {
@@ -878,7 +887,7 @@ void ViewProviderPartExt::unsetEdit(int ModNum)
}
}
void ViewProviderPartExt::updateVisual(const TopoDS_Shape& inputShape)
void ViewProviderPartExt::updateVisual()
{
Gui::SoUpdateVBOAction action;
action.apply(this->faceset);
@@ -895,7 +904,7 @@ void ViewProviderPartExt::updateVisual(const TopoDS_Shape& inputShape)
haction.apply(this->lineset);
haction.apply(this->nodeset);
TopoDS_Shape cShape(inputShape);
TopoDS_Shape cShape = Part::Feature::getShape(getObject());
if (cShape.IsNull()) {
coords ->point .setNum(0);
norm ->vector .setNum(0);
@@ -1214,7 +1223,7 @@ void ViewProviderPartExt::updateVisual(const TopoDS_Shape& inputShape)
lineset ->coordIndex .finishEditing();
}
catch (...) {
Base::Console().Error("Cannot compute Inventor representation for the shape of %s.\n",pcObject->getNameInDocument());
FC_ERR("Cannot compute Inventor representation for the shape of " << pcObject->getFullName());
}
# ifdef FC_DEBUG
@@ -1224,3 +1233,13 @@ void ViewProviderPartExt::updateVisual(const TopoDS_Shape& inputShape)
# endif
VisualTouched = false;
}
void ViewProviderPartExt::forceUpdate(bool enable) {
if(enable) {
if(++forceUpdateCount == 1) {
if(!isShow())
Visibility.touch();
}
}else if(forceUpdateCount)
--forceUpdateCount;
}

View File

@@ -33,6 +33,7 @@
#include <App/PropertyUnits.h>
#include <Gui/ViewProviderGeometryObject.h>
#include <map>
#include <Mod/Part/App/PartFeature.h>
class TopoDS_Shape;
class TopoDS_Edge;
@@ -128,9 +129,15 @@ public:
void unsetHighlightedPoints();
//@}
virtual bool isUpdateForced() const override {
return forceUpdateCount>0;
}
virtual void forceUpdate(bool enable = true) override;
/** @name Edit methods */
//@{
void setupContextMenu(QMenu*, QObject*, const char*);
protected:
bool setEdit(int ModNum);
void unsetEdit(int ModNum);
@@ -140,7 +147,7 @@ protected:
/// get called by the container whenever a property has been changed
virtual void onChanged(const App::Property* prop);
bool loadParameter();
void updateVisual(const TopoDS_Shape &);
void updateVisual();
void getNormals(const TopoDS_Face& theFace, const Handle(Poly_Triangulation)& aPolyTri,
TColgp_Array1OfDir& theNormals);
@@ -166,6 +173,7 @@ protected:
private:
// settings stuff
int forceUpdateCount;
static App::PropertyFloatConstraint::Constraints sizeRange;
static App::PropertyFloatConstraint::Constraints tessRange;
static App::PropertyQuantityConstraint::Constraints angDeflectionRange;

View File

@@ -242,7 +242,8 @@ void ViewProviderFillet::updateData(const App::Property* prop)
Part::Fillet* objFill = dynamic_cast<Part::Fillet*>(getObject());
if (!objFill)
return;
Part::Feature* objBase = dynamic_cast<Part::Feature*>(objFill->Base.getValue());
Part::Feature* objBase = dynamic_cast<Part::Feature*>(
Part::Feature::getShapeOwner(objFill->Base.getValue()));
if (objBase) {
const TopoDS_Shape& baseShape = objBase->Shape.getValue();
const TopoDS_Shape& fillShape = objFill->Shape.getValue();
@@ -345,7 +346,8 @@ void ViewProviderChamfer::updateData(const App::Property* prop)
Part::Chamfer* objCham = dynamic_cast<Part::Chamfer*>(getObject());
if (!objCham)
return;
Part::Feature* objBase = dynamic_cast<Part::Feature*>(objCham->Base.getValue());
Part::Feature* objBase = dynamic_cast<Part::Feature*>(
Part::Feature::getShapeOwner(objCham->Base.getValue()));
if (objBase) {
const TopoDS_Shape& baseShape = objBase->Shape.getValue();
const TopoDS_Shape& chamShape = objCham->Shape.getValue();
@@ -493,7 +495,11 @@ ViewProviderSweep::~ViewProviderSweep()
std::vector<App::DocumentObject*> ViewProviderSweep::claimChildren() const
{
return static_cast<Part::Sweep*>(getObject())->Sections.getValues();
auto obj = static_cast<Part::Sweep*>(getObject());
auto children = obj->Sections.getValues();
if(obj->Spine.getValue())
children.push_back(obj->Spine.getValue());
return children;
}
bool ViewProviderSweep::onDelete(const std::vector<std::string> &)

View File

@@ -88,12 +88,9 @@ bool ViewProviderFace::canDragObjects() const
bool ViewProviderFace::canDragObject(App::DocumentObject* obj) const
{
if (!obj)
return false;
if (obj->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId()))
return true;
else
return false;
(void)obj;
// return Part::Feature::hasShapeOwner(obj);
return true;
}
void ViewProviderFace::dragObject(App::DocumentObject* obj)

View File

@@ -72,6 +72,13 @@ Gui::MenuItem* Workbench::setupMenuBar() const
<< "Separator"
<< "Part_MakeTube";
Gui::MenuItem* copy = new Gui::MenuItem;
copy->setCommand("Create a copy");
*copy << "Part_SimpleCopy"
<< "Part_TransformedCopy"
<< "Part_ElementCopy"
<< "Part_RefineShape";
Gui::MenuItem* bop = new Gui::MenuItem;
bop->setCommand("Boolean");
*bop << "Part_Boolean"
@@ -113,8 +120,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const
<< "Part_ShapeFromMesh"
<< "Part_MakeSolid"
<< "Part_ReverseShape"
<< "Part_SimpleCopy"
<< "Part_RefineShape"
<< copy
<< "Part_CheckGeometry"
<< "Part_Defeaturing"
<< "Separator"
@@ -144,6 +150,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const
*measure << "Part_Measure_Linear"
<< "Part_Measure_Angular"
<< "Separator"
<< "Part_Measure_Refresh"
<< "Part_Measure_Clear_All"
<< "Part_Measure_Toggle_All"
<< "Part_Measure_Toggle_3d"
@@ -211,6 +218,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
*measure << "Part_Measure_Linear"
<< "Part_Measure_Angular"
<< "Separator"
<< "Part_Measure_Refresh"
<< "Part_Measure_Clear_All"
<< "Part_Measure_Toggle_All"
<< "Part_Measure_Toggle_3d"