// TODO: This code is taken from and duplicates code in Part2DObject::positionBySupport() // Note: We cannot return a reference, because it will become Null. // Not clear where, because we check for IsNull() here, but as soon as it is passed out of // this method, it becomes null! const TopoDS_Face SketchBased::getSupportFace() const { const App::PropertyLinkSub& Support = static_cast<Part::Part2DObject*>(Sketch.getValue())->Support; Part::Feature *part = static_cast<Part::Feature*>(Support.getValue()); if (!part || !part->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) throw Base::Exception("Sketch has no support shape"); const std::vector<std::string> &sub = Support.getSubValues(); assert(sub.size()==1); // get the selected sub shape (a Face) const Part::TopoShape &shape = part->Shape.getShape(); if (shape._Shape.IsNull()) throw Base::Exception("Sketch support shape is empty!"); TopoDS_Shape sh = shape.getSubShape(sub[0].c_str()); if (sh.IsNull()) throw Base::Exception("Null shape in SketchBased::getSupportFace()!"); const TopoDS_Face face = TopoDS::Face(sh); if (face.IsNull()) throw Base::Exception("Null face in SketchBased::getSupportFace()!"); BRepAdaptor_Surface adapt(face); if (adapt.GetType() != GeomAbs_Plane) throw Base::Exception("No planar face in SketchBased::getSupportFace()!"); return face; }
void Part2DObject::transformPlacement(const Base::Placement &transform) { Part::Feature *part = static_cast<Part::Feature*>(Support.getValue()); if (part && part->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { part->transformPlacement(transform); positionBySupport(); } else GeoFeature::transformPlacement(transform); }
const std::list<gp_Trsf> Scaled::getTransformations(const std::vector<App::DocumentObject*> originals) { double factor = Factor.getValue(); if (factor < Precision::Confusion()) throw Base::Exception("Scaling factor too small"); int occurrences = Occurrences.getValue(); if (occurrences < 2) throw Base::Exception("At least two occurrences required"); double f = (factor - 1.0) / double(occurrences - 1); // Find centre of gravity of first original // FIXME: This method will NOT give the expected result for more than one original! Part::Feature* originalFeature = static_cast<Part::Feature*>(originals.front()); TopoDS_Shape original; if (originalFeature->getTypeId().isDerivedFrom(PartDesign::Additive::getClassTypeId())) { PartDesign::Additive* addFeature = static_cast<PartDesign::Additive*>(originalFeature); original = addFeature->AddShape.getShape()._Shape; } else if (originalFeature->getTypeId().isDerivedFrom(PartDesign::Subtractive::getClassTypeId())) { PartDesign::Subtractive* subFeature = static_cast<PartDesign::Subtractive*>(originalFeature); original = subFeature->SubShape.getShape()._Shape; } GProp_GProps props; BRepGProp::VolumeProperties(original,props); gp_Pnt cog = props.CentreOfMass(); // Note: The original feature is NOT included in the list of transformations! Therefore // we start with occurrence number 1, not number 0 std::list<gp_Trsf> transformations; gp_Trsf trans; transformations.push_back(trans); // identity transformation for (int i = 1; i < occurrences; i++) { trans.SetScale(cog, 1.0 + double(i) * f); transformations.push_back(trans); } return transformations; }
void SketchBased::transformPlacement(const Base::Placement &transform) { Part::Part2DObject *sketch = static_cast<Part::Part2DObject*>(Sketch.getValue()); if (sketch && sketch->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())) { Part::Feature *part = static_cast<Part::Feature*>(sketch->Support.getValue()); if (part && part->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) part->transformPlacement(transform); else sketch->transformPlacement(transform); positionBySketch(); } }
// Note: We cannot return a reference, because it will become Null. // Not clear where, because we check for IsNull() here, but as soon as it is passed out of // this method, it becomes null! const TopoDS_Face ProfileBased::getSupportFace() const { const Part::Part2DObject* sketch = getVerifiedSketch(); if (sketch->MapMode.getValue() == Attacher::mmFlatFace && sketch->Support.getValue()) { const auto &Support = sketch->Support; App::DocumentObject* ref = Support.getValue(); Part::Feature *part = static_cast<Part::Feature*>(ref); if (part && part->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { const std::vector<std::string> &sub = Support.getSubValues(); assert(sub.size()==1); if (sub.at(0) == "") { // This seems to happen when sketch is on a datum plane return TopoDS::Face(Feature::makeShapeFromPlane(sketch)); } // get the selected sub shape (a Face) const Part::TopoShape &shape = part->Shape.getShape(); if (shape.getShape().IsNull()) throw Base::ValueError("Sketch support shape is empty!"); TopoDS_Shape sh = shape.getSubShape(sub[0].c_str()); if (sh.IsNull()) throw Base::ValueError("Null shape in SketchBased::getSupportFace()!"); const TopoDS_Face face = TopoDS::Face(sh); if (face.IsNull()) throw Base::ValueError("Null face in SketchBased::getSupportFace()!"); BRepAdaptor_Surface adapt(face); if (adapt.GetType() != GeomAbs_Plane) throw Base::TypeError("No planar face in SketchBased::getSupportFace()!"); return face; } } return TopoDS::Face(Feature::makeShapeFromPlane(sketch)); }
void Transformed::positionBySupport(void) { Part::Feature *support = static_cast<Part::Feature*>(getSupportObject()); if ((support != NULL) && support->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) this->Placement.setValue(support->Placement.getValue()); }
const std::list<gp_Trsf> MultiTransform::getTransformations(const std::vector<App::DocumentObject*> originals) { std::vector<App::DocumentObject*> transFeatures = Transformations.getValues(); // Find centre of gravity of first original // FIXME: This method will NOT give the expected result for more than one original! Part::Feature* originalFeature = static_cast<Part::Feature*>(originals.front()); TopoDS_Shape original; if (originalFeature->getTypeId().isDerivedFrom(PartDesign::FeatureAddSub::getClassTypeId())) { PartDesign::FeatureAddSub* addFeature = static_cast<PartDesign::FeatureAddSub*>(originalFeature); if(addFeature->getAddSubType() == FeatureAddSub::Additive) original = addFeature->AddSubShape.getShape()._Shape; else original = addFeature->AddSubShape.getShape()._Shape; } GProp_GProps props; BRepGProp::VolumeProperties(original,props); gp_Pnt cog = props.CentreOfMass(); std::list<gp_Trsf> result; std::list<gp_Pnt> cogs; std::vector<App::DocumentObject*>::const_iterator f; for (f = transFeatures.begin(); f != transFeatures.end(); ++f) { if (!((*f)->getTypeId().isDerivedFrom(PartDesign::Transformed::getClassTypeId()))) throw Base::Exception("Transformation features must be subclasses of Transformed"); PartDesign::Transformed* transFeature = static_cast<PartDesign::Transformed*>(*f); std::list<gp_Trsf> newTransformations = transFeature->getTransformations(originals); if (result.empty()) { // First transformation Feature result = newTransformations; for (std::list<gp_Trsf>::const_iterator nt = newTransformations.begin(); nt != newTransformations.end(); ++nt) { cogs.push_back(cog.Transformed(*nt)); } } else { // Retain a copy of the first set of transformations for iterator ot // We can't iterate through result if we are also adding elements with push_back()! std::list<gp_Trsf> oldTransformations; result.swap(oldTransformations); // empty result to receive new transformations std::list<gp_Pnt> oldCogs; cogs.swap(oldCogs); // empty cogs to receive new cogs if ((*f)->getTypeId() == PartDesign::Scaled::getClassTypeId()) { // Diagonal method // Multiply every element in the old transformations' slices with the corresponding // element in the newTransformations. Example: // a11 a12 a13 a14 b1 a11*b1 a12*b1 a13*b1 a14*b1 // a21 a22 a23 a24 diag b2 = a21*b2 a22*b2 a23*b2 a24*b1 // a31 a23 a33 a34 b3 a31*b3 a23*b3 a33*b3 a34*b1 // In other words, the length of the result vector is equal to the length of the // oldTransformations vector if (oldTransformations.size() % newTransformations.size() != 0) throw Base::Exception("Number of occurrences must be a divisor of previous number of occurrences"); unsigned sliceLength = oldTransformations.size() / newTransformations.size(); std::list<gp_Trsf>::const_iterator ot = oldTransformations.begin(); std::list<gp_Pnt>::const_iterator oc = oldCogs.begin(); for (std::list<gp_Trsf>::const_iterator nt = newTransformations.begin(); nt != newTransformations.end(); ++nt) { for (unsigned s = 0; s < sliceLength; s++) { gp_Trsf trans; double factor = nt->ScaleFactor(); // extract scale factor if (factor > Precision::Confusion()) { trans.SetScale(*oc, factor); // recreate the scaled transformation to use the correct COG trans = trans * (*ot); cogs.push_back(*oc); // Scaling does not affect the COG } else { trans = (*nt) * (*ot); cogs.push_back(oc->Transformed(*nt)); } result.push_back(trans); ++ot; ++oc; } } } else { // Multiplication method: Combine the new transformations with the old ones. // All old transformations are multiplied with all new ones, so that the length of the // result vector is the length of the old and new transformations multiplied. // a11 a12 b1 a11*b1 a12*b1 a11*b2 a12*b2 a11*b3 a12*b3 // a21 a22 mul b2 = a21*b1 a22*b1 a21*b2 a22*b2 a21*b3 a22*b3 // b3 for (std::list<gp_Trsf>::const_iterator nt = newTransformations.begin(); nt != newTransformations.end(); ++nt) { std::list<gp_Pnt>::const_iterator oc = oldCogs.begin(); for (std::list<gp_Trsf>::const_iterator ot = oldTransformations.begin(); ot != oldTransformations.end(); ++ot) { result.push_back((*nt) * (*ot)); cogs.push_back(oc->Transformed(*nt)); ++oc; } } } // What about the Additive method: Take the last (set of) transformations and use them as // "originals" for the next transformationFeature, so that something similar to a sweep // for transformations could be put together? } } return result; }
void Part2DObject::positionBySupport(void) { // recalculate support: Part::Feature *part = static_cast<Part::Feature*>(Support.getValue()); if (!part || !part->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) return; Base::Placement Place = part->Placement.getValue(); const std::vector<std::string> &sub = Support.getSubValues(); assert(sub.size()==1); // get the selected sub shape (a Face) const Part::TopoShape &shape = part->Shape.getShape(); if (shape._Shape.IsNull()) throw Base::Exception("Support shape is empty!"); TopoDS_Shape sh; try { sh = shape.getSubShape(sub[0].c_str()); } catch (Standard_Failure) { throw Base::Exception("Face in support shape doesn't exist!"); } const TopoDS_Face &face = TopoDS::Face(sh); if (face.IsNull()) throw Base::Exception("Null face in Part2DObject::positionBySupport()!"); BRepAdaptor_Surface adapt(face); if (adapt.GetType() != GeomAbs_Plane) throw Base::Exception("No planar face in Part2DObject::positionBySupport()!"); bool Reverse = false; if (face.Orientation() == TopAbs_REVERSED) Reverse = true; gp_Pln plane = adapt.Plane(); Standard_Boolean ok = plane.Direct(); if (!ok) { // toggle if plane has a left-handed coordinate system plane.UReverse(); Reverse = !Reverse; } gp_Ax1 Normal = plane.Axis(); if (Reverse) Normal.Reverse(); gp_Pnt ObjOrg(Place.getPosition().x,Place.getPosition().y,Place.getPosition().z); Handle (Geom_Plane) gPlane = new Geom_Plane(plane); GeomAPI_ProjectPointOnSurf projector(ObjOrg,gPlane); gp_Pnt SketchBasePoint = projector.NearestPoint(); gp_Dir dir = Normal.Direction(); gp_Ax3 SketchPos; Base::Vector3d dX,dY,dZ; Place.getRotation().multVec(Base::Vector3d(1,0,0),dX); Place.getRotation().multVec(Base::Vector3d(0,1,0),dY); Place.getRotation().multVec(Base::Vector3d(0,0,1),dZ); gp_Dir dirX(dX.x, dX.y, dX.z); gp_Dir dirY(dY.x, dY.y, dY.z); gp_Dir dirZ(dZ.x, dZ.y, dZ.z); double cosNX = dir.Dot(dirX); double cosNY = dir.Dot(dirY); double cosNZ = dir.Dot(dirZ); std::vector<double> cosXYZ; cosXYZ.push_back(fabs(cosNX)); cosXYZ.push_back(fabs(cosNY)); cosXYZ.push_back(fabs(cosNZ)); int pos = std::max_element(cosXYZ.begin(), cosXYZ.end()) - cosXYZ.begin(); // +X/-X if (pos == 0) { if (cosNX > 0) SketchPos = gp_Ax3(SketchBasePoint, dir, dirY); else SketchPos = gp_Ax3(SketchBasePoint, dir, -dirY); } // +Y/-Y else if (pos == 1) { if (cosNY > 0) SketchPos = gp_Ax3(SketchBasePoint, dir, -dirX); else SketchPos = gp_Ax3(SketchBasePoint, dir, dirX); } // +Z/-Z else { SketchPos = gp_Ax3(SketchBasePoint, dir, dirX); } gp_Trsf Trf; Trf.SetTransformation(SketchPos); Trf.Invert(); Base::Matrix4D mtrx; gp_Mat m = Trf._CSFDB_Getgp_Trsfmatrix(); gp_XYZ p = Trf._CSFDB_Getgp_Trsfloc(); Standard_Real scale = 1.0; // set Rotation matrix mtrx[0][0] = scale * m._CSFDB_Getgp_Matmatrix(0,0); mtrx[0][1] = scale * m._CSFDB_Getgp_Matmatrix(0,1); mtrx[0][2] = scale * m._CSFDB_Getgp_Matmatrix(0,2); mtrx[1][0] = scale * m._CSFDB_Getgp_Matmatrix(1,0); mtrx[1][1] = scale * m._CSFDB_Getgp_Matmatrix(1,1); mtrx[1][2] = scale * m._CSFDB_Getgp_Matmatrix(1,2); mtrx[2][0] = scale * m._CSFDB_Getgp_Matmatrix(2,0); mtrx[2][1] = scale * m._CSFDB_Getgp_Matmatrix(2,1); mtrx[2][2] = scale * m._CSFDB_Getgp_Matmatrix(2,2); // set pos vector mtrx[0][3] = p._CSFDB_Getgp_XYZx(); mtrx[1][3] = p._CSFDB_Getgp_XYZy(); mtrx[2][3] = p._CSFDB_Getgp_XYZz(); // check the angle against the Z Axis //Standard_Real a = Normal.Angle(gp_Ax1(gp_Pnt(0,0,0),gp_Dir(0,0,1))); Placement.setValue(Base::Placement(mtrx)); }