/****************************************************************************** * Copyright (c)2012 Jan Rheinlaender * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ******************************************************************************/ #include "PreCompiled.h" #ifndef _PreComp_ # include # include # include #endif #include "FeatureMultiTransform.h" #include "FeatureScaled.h" #include "FeatureAdditive.h" #include "FeatureSubtractive.h" #include #include #include using namespace PartDesign; namespace PartDesign { PROPERTY_SOURCE(PartDesign::MultiTransform, PartDesign::Transformed) MultiTransform::MultiTransform() { ADD_PROPERTY(Transformations,(0)); Transformations.setSize(0); } void MultiTransform::positionBySupport(void) { PartDesign::Transformed::positionBySupport(); std::vector transFeatures = Transformations.getValues(); for (std::vector::const_iterator 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(*f); transFeature->Placement.setValue(this->Placement.getValue()); } } short MultiTransform::mustExecute() const { if (Transformations.isTouched()) return 1; return Transformed::mustExecute(); } const std::list MultiTransform::getTransformations(const std::vector originals) { std::vector 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(originals.front()); TopoDS_Shape original; if (originalFeature->getTypeId().isDerivedFrom(PartDesign::Additive::getClassTypeId())) { PartDesign::Additive* addFeature = static_cast(originalFeature); original = addFeature->AddShape.getShape()._Shape; } else if (originalFeature->getTypeId().isDerivedFrom(PartDesign::Subtractive::getClassTypeId())) { PartDesign::Subtractive* subFeature = static_cast(originalFeature); original = subFeature->SubShape.getShape()._Shape; } GProp_GProps props; BRepGProp::VolumeProperties(original,props); gp_Pnt cog = props.CentreOfMass(); std::list result; std::list cogs; std::vector::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(*f); std::list newTransformations = transFeature->getTransformations(originals); if (result.empty()) { // First transformation Feature result = newTransformations; for (std::list::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 oldTransformations; result.swap(oldTransformations); // empty result to receive new transformations std::list 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::const_iterator ot = oldTransformations.begin(); std::list::const_iterator oc = oldCogs.begin(); for (std::list::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::const_iterator nt = newTransformations.begin(); nt != newTransformations.end(); nt++) { std::list::const_iterator oc = oldCogs.begin(); for (std::list::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; } }