void ViewProviderTransformed::recomputeFeature(void) { PartDesign::Transformed* pcTransformed = static_cast<PartDesign::Transformed*>(getObject()); pcTransformed->getDocument()->recomputeFeature(pcTransformed); const std::vector<App::DocumentObjectExecReturn*> log = pcTransformed->getDocument()->getRecomputeLog(); unsigned rejected = pcTransformed->getRejectedTransformations().size(); QString msg = QString::fromAscii("%1"); if (rejected > 0) { msg = QString::fromLatin1("<font color='orange'>%1<br/></font>\r\n%2"); if (rejected == 1) msg = msg.arg(QObject::tr("One transformed shape does not intersect support")); else { msg = msg.arg(QObject::tr("%1 transformed shapes do not intersect support")); msg = msg.arg(rejected); } } if (log.size() > 0) { msg = msg.arg(QString::fromLatin1("<font color='red'>%1<br/></font>")); msg = msg.arg(QString::fromStdString(log.back()->Why)); } else { msg = msg.arg(QString::fromLatin1("<font color='green'>%1<br/></font>")); msg = msg.arg(QObject::tr("Transformation succeeded")); } signalDiagnosis(msg); }
const bool TaskTransformedParameters::originalSelected(const Gui::SelectionChanges& msg) { if (msg.Type == Gui::SelectionChanges::AddSelection && ( (selectionMode == addFeature) || (selectionMode == removeFeature))) { if (strcmp(msg.pDocName, getObject()->getDocument()->getName()) != 0) return false; PartDesign::Transformed* pcTransformed = getObject(); App::DocumentObject* selectedObject = pcTransformed->getDocument()->getObject(msg.pObjectName); if (selectedObject->isDerivedFrom(PartDesign::FeatureAddSub::getClassTypeId())) { // Do the same like in TaskDlgTransformedParameters::accept() but without doCommand std::vector<App::DocumentObject*> originals = pcTransformed->Originals.getValues(); std::vector<App::DocumentObject*>::iterator o = std::find(originals.begin(), originals.end(), selectedObject); if (selectionMode == addFeature) { if (o == originals.end()) originals.push_back(selectedObject); else return false; // duplicate selection } else { if (o != originals.end()) originals.erase(o); else return false; } pcTransformed->Originals.setValues(originals); recomputeFeature(); return true; } } return false; }
App::DocumentObject* TaskTransformedParameters::getSupportObject() const { if (insideMultiTransform) { return parentTask->getSupportObject(); } else { PartDesign::Transformed* pcTransformed = static_cast<PartDesign::Transformed*>(TransformedView->getObject()); return pcTransformed->getSupportObject(); } }
void MultiTransform::positionBySupport(void) { PartDesign::Transformed::positionBySupport(); std::vector<App::DocumentObject*> transFeatures = Transformations.getValues(); for (std::vector<App::DocumentObject*>::const_iterator f = transFeatures.begin(); f != transFeatures.end(); ++f) { if (!((*f)->getTypeId().isDerivedFrom(PartDesign::Transformed::getClassTypeId()))) throw Base::TypeError("Transformation features must be subclasses of Transformed"); PartDesign::Transformed* transFeature = static_cast<PartDesign::Transformed*>(*f); transFeature->Placement.setValue(this->Placement.getValue()); // To avoid that a linked transform feature stays touched after a recompute // we have to purge the touched state if (this->isRecomputing()) { transFeature->purgeTouched(); } } }
const bool TaskTransformedParameters::originalSelected(const Gui::SelectionChanges& msg) { if (msg.Type == Gui::SelectionChanges::AddSelection && originalSelectionMode) { if (strcmp(msg.pDocName, getObject()->getDocument()->getName()) != 0) return false; PartDesign::Transformed* pcTransformed = getObject(); App::DocumentObject* selectedObject = pcTransformed->getDocument()->getObject(msg.pObjectName); if (selectedObject->isDerivedFrom(PartDesign::Additive::getClassTypeId()) || selectedObject->isDerivedFrom(PartDesign::Subtractive::getClassTypeId())) { // Do the same like in TaskDlgTransformedParameters::accept() but without doCommand std::vector<App::DocumentObject*> originals(1,selectedObject); pcTransformed->Originals.setValues(originals); recomputeFeature(); originalSelectionMode = false; return true; } } return false; }
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 ViewProviderTransformed::recomputeFeature(void) { PartDesign::Transformed* pcTransformed = static_cast<PartDesign::Transformed*>(getObject()); pcTransformed->getDocument()->recomputeFeature(pcTransformed); const std::vector<App::DocumentObjectExecReturn*> log = pcTransformed->getDocument()->getRecomputeLog(); PartDesign::Transformed::rejectedMap rejected_trsf = pcTransformed->getRejectedTransformations(); unsigned rejected = 0; for (PartDesign::Transformed::rejectedMap::const_iterator r = rejected_trsf.begin(); r != rejected_trsf.end(); r++) rejected += r->second.size(); QString msg = QString::fromLatin1("%1"); if (rejected > 0) { msg = QString::fromLatin1("<font color='orange'>%1<br/></font>\r\n%2"); if (rejected == 1) msg = msg.arg(QObject::tr("One transformed shape does not intersect support")); else { msg = msg.arg(QObject::tr("%1 transformed shapes do not intersect support")); msg = msg.arg(rejected); } } if (log.size() > 0) { msg = msg.arg(QString::fromLatin1("<font color='red'>%1<br/></font>")); msg = msg.arg(QString::fromStdString(log.back()->Why)); } else { msg = msg.arg(QString::fromLatin1("<font color='green'>%1<br/></font>")); msg = msg.arg(QObject::tr("Transformation succeeded")); } signalDiagnosis(msg); // Clear all the rejected stuff while (pcRejectedRoot->getNumChildren() > 7) { SoSeparator* sep = static_cast<SoSeparator*>(pcRejectedRoot->getChild(7)); SoMultipleCopy* rejectedTrfms = static_cast<SoMultipleCopy*>(sep->getChild(2)); rejectedTrfms ->removeAllChildren(); sep->removeChild(1); sep->removeChild(0); pcRejectedRoot ->removeChild(7); } for (PartDesign::Transformed::rejectedMap::const_iterator o = rejected_trsf.begin(); o != rejected_trsf.end(); o++) { if (o->second.empty()) continue; TopoDS_Shape shape; if ((o->first)->getTypeId().isDerivedFrom(PartDesign::FeatureAddSub::getClassTypeId())) { PartDesign::FeatureAddSub* feature = static_cast<PartDesign::FeatureAddSub*>(o->first); shape = feature->AddSubShape.getShape().getShape(); } if (shape.IsNull()) continue; // Display the rejected transformations in red TopoDS_Shape cShape(shape); try { // calculating the deflection value Standard_Real xMin, yMin, zMin, xMax, yMax, zMax; { Bnd_Box bounds; BRepBndLib::Add(cShape, bounds); bounds.SetGap(0.0); bounds.Get(xMin, yMin, zMin, xMax, yMax, zMax); } Standard_Real deflection = ((xMax-xMin)+(yMax-yMin)+(zMax-zMin))/300.0 * Deviation.getValue(); // create or use the mesh on the data structure // Note: This DOES have an effect on cShape #if OCC_VERSION_HEX >= 0x060600 Standard_Real AngDeflectionRads = AngularDeflection.getValue() / 180.0 * M_PI; BRepMesh_IncrementalMesh(cShape,deflection,Standard_False, AngDeflectionRads,Standard_True); #else BRepMesh_IncrementalMesh(cShape,deflection); #endif // We must reset the location here because the transformation data // are set in the placement property TopLoc_Location aLoc; cShape.Location(aLoc); // count triangles and nodes in the mesh int nbrTriangles=0, nbrNodes=0; TopExp_Explorer Ex; for (Ex.Init(cShape,TopAbs_FACE);Ex.More();Ex.Next()) { Handle (Poly_Triangulation) mesh = BRep_Tool::Triangulation(TopoDS::Face(Ex.Current()), aLoc); // Note: we must also count empty faces if (!mesh.IsNull()) { nbrTriangles += mesh->NbTriangles(); nbrNodes += mesh->NbNodes(); } } // create memory for the nodes and indexes SoCoordinate3* rejectedCoords = new SoCoordinate3(); rejectedCoords ->point .setNum(nbrNodes); SoNormal* rejectedNorms = new SoNormal(); rejectedNorms ->vector .setNum(nbrNodes); SoIndexedFaceSet* rejectedFaceSet = new SoIndexedFaceSet(); rejectedFaceSet ->coordIndex .setNum(nbrTriangles*4); // get the raw memory for fast fill up SbVec3f* verts = rejectedCoords ->point .startEditing(); SbVec3f* norms = rejectedNorms ->vector .startEditing(); int32_t* index = rejectedFaceSet ->coordIndex .startEditing(); // preset the normal vector with null vector for (int i=0; i < nbrNodes; i++) norms[i]= SbVec3f(0.0,0.0,0.0); int ii = 0,FaceNodeOffset=0,FaceTriaOffset=0; for (Ex.Init(cShape, TopAbs_FACE); Ex.More(); Ex.Next(),ii++) { TopLoc_Location aLoc; const TopoDS_Face &actFace = TopoDS::Face(Ex.Current()); // get the mesh of the shape Handle (Poly_Triangulation) mesh = BRep_Tool::Triangulation(actFace,aLoc); if (mesh.IsNull()) continue; // getting the transformation of the shape/face gp_Trsf myTransf; Standard_Boolean identity = true; if (!aLoc.IsIdentity()) { identity = false; myTransf = aLoc.Transformation(); } // getting size of node and triangle array of this face int nbNodesInFace = mesh->NbNodes(); int nbTriInFace = mesh->NbTriangles(); // check orientation TopAbs_Orientation orient = actFace.Orientation(); // cycling through the poly mesh const Poly_Array1OfTriangle& Triangles = mesh->Triangles(); const TColgp_Array1OfPnt& Nodes = mesh->Nodes(); for (int g=1; g <= nbTriInFace; g++) { // Get the triangle Standard_Integer N1,N2,N3; Triangles(g).Get(N1,N2,N3); // change orientation of the triangle if the face is reversed if ( orient != TopAbs_FORWARD ) { Standard_Integer tmp = N1; N1 = N2; N2 = tmp; } // get the 3 points of this triangle gp_Pnt V1(Nodes(N1)), V2(Nodes(N2)), V3(Nodes(N3)); // transform the vertices to the place of the face if (!identity) { V1.Transform(myTransf); V2.Transform(myTransf); V3.Transform(myTransf); } // calculating per vertex normals // Calculate triangle normal gp_Vec v1(V1.X(),V1.Y(),V1.Z()),v2(V2.X(),V2.Y(),V2.Z()),v3(V3.X(),V3.Y(),V3.Z()); gp_Vec Normal = (v2-v1)^(v3-v1); // add the triangle normal to the vertex normal for all points of this triangle norms[FaceNodeOffset+N1-1] += SbVec3f(Normal.X(),Normal.Y(),Normal.Z()); norms[FaceNodeOffset+N2-1] += SbVec3f(Normal.X(),Normal.Y(),Normal.Z()); norms[FaceNodeOffset+N3-1] += SbVec3f(Normal.X(),Normal.Y(),Normal.Z()); // set the vertices verts[FaceNodeOffset+N1-1].setValue((float)(V1.X()),(float)(V1.Y()),(float)(V1.Z())); verts[FaceNodeOffset+N2-1].setValue((float)(V2.X()),(float)(V2.Y()),(float)(V2.Z())); verts[FaceNodeOffset+N3-1].setValue((float)(V3.X()),(float)(V3.Y()),(float)(V3.Z())); // set the index vector with the 3 point indexes and the end delimiter index[FaceTriaOffset*4+4*(g-1)] = FaceNodeOffset+N1-1; index[FaceTriaOffset*4+4*(g-1)+1] = FaceNodeOffset+N2-1; index[FaceTriaOffset*4+4*(g-1)+2] = FaceNodeOffset+N3-1; index[FaceTriaOffset*4+4*(g-1)+3] = SO_END_FACE_INDEX; } // counting up the per Face offsets FaceNodeOffset += nbNodesInFace; FaceTriaOffset += nbTriInFace; } // normalize all normals for (int i=0; i < nbrNodes; i++) norms[i].normalize(); // end the editing of the nodes rejectedCoords ->point .finishEditing(); rejectedNorms ->vector .finishEditing(); rejectedFaceSet ->coordIndex .finishEditing(); // fill in the transformation matrices SoMultipleCopy* rejectedTrfms = new SoMultipleCopy(); rejectedTrfms->matrix.setNum((o->second).size()); SbMatrix* mats = rejectedTrfms->matrix.startEditing(); std::list<gp_Trsf>::const_iterator trsf = (o->second).begin(); for (unsigned int i=0; i < (o->second).size(); i++,trsf++) { Base::Matrix4D mat; Part::TopoShape::convertToMatrix(*trsf,mat); mats[i] = convert(mat); } rejectedTrfms->matrix.finishEditing(); rejectedTrfms->addChild(rejectedFaceSet); SoSeparator* sep = new SoSeparator(); sep->addChild(rejectedCoords); sep->addChild(rejectedNorms); sep->addChild(rejectedTrfms); pcRejectedRoot->addChild(sep); } catch (...) { Base::Console().Error("Cannot compute Inventor representation for the rejected transformations of shape of %s.\n", pcTransformed->getNameInDocument()); } } }