void GEOM_ShadingFace:: OCC2VTK(const TopoDS_Face& theFace, vtkPolyData* thePolyData, vtkPoints* thePts) { TopLoc_Location aLoc; Handle(Poly_Triangulation) aPoly = BRep_Tool::Triangulation(theFace,aLoc); if(aPoly.IsNull()) return; else{ gp_Trsf myTransf; Standard_Boolean identity = true; if(!aLoc.IsIdentity()){ identity = false; myTransf = aLoc.Transformation(); } Standard_Integer i; int aNbOfNodes = thePts->GetNumberOfPoints(); const TColgp_Array1OfPnt& Nodes = aPoly->Nodes(); Standard_Integer nbNodesInFace = aPoly->NbNodes(); for(i = 1; i <= nbNodesInFace; i++) { gp_Pnt P = Nodes(i); if(!identity) P.Transform(myTransf); thePts->InsertNextPoint(P.X(),P.Y(),P.Z()); } const Poly_Array1OfTriangle& Triangles = aPoly->Triangles(); Standard_Integer nbTriInFace = aPoly->NbTriangles(); for(i = 1; i <= nbTriInFace; i++){ // Get the triangle Standard_Integer N1,N2,N3; Triangles(i).Get(N1,N2,N3); N1 += aNbOfNodes - 1; N2 += aNbOfNodes - 1; N3 += aNbOfNodes - 1; vtkIdType anIds[3] = {N1, N2, N3}; thePolyData->InsertNextCell(VTK_TRIANGLE,3,anIds); } } }
void ShapeGeometryBuilder::edgeConstruct(const TopoDS_Edge &edgeIn) { TopoDS_Face face = TopoDS::Face(edgeToFace.FindFromKey(edgeIn).First()); if (face.IsNull()) throw std::runtime_error("face is null in edge construction"); TopLoc_Location location; Handle(Poly_Triangulation) triangulation; triangulation = BRep_Tool::Triangulation(face, location); const Handle(Poly_PolygonOnTriangulation) &segments = BRep_Tool::PolygonOnTriangulation(edgeIn, triangulation, location); if (segments.IsNull()) throw std::runtime_error("edge triangulation is null in edge construction"); gp_Trsf transformation; bool identity = true; if(!location.IsIdentity()) { identity = false; transformation = location.Transformation(); } const TColStd_Array1OfInteger& indexes = segments->Nodes(); const TColgp_Array1OfPnt& nodes = triangulation->Nodes(); osg::Vec3Array *vertices = dynamic_cast<osg::Vec3Array *>(edgeGeometry->getVertexArray()); osg::Vec4Array *colors = dynamic_cast<osg::Vec4Array *>(edgeGeometry->getColorArray()); osg::ref_ptr<osg::DrawElementsUInt> indices = new osg::DrawElementsUInt (GL_LINE_STRIP, indexes.Length()); osg::BoundingSphere bSphere; for (int index(indexes.Lower()); index < indexes.Upper() + 1; ++index) { gp_Pnt point = nodes(indexes(index)); if(!identity) point.Transform(transformation); vertices->push_back(osg::Vec3(point.X(), point.Y(), point.Z())); colors->push_back(edgeGeometry->getColor()); (*indices)[index - 1] = vertices->size() - 1; if (!bSphere.valid()) //for first one. { bSphere.center() = vertices->back(); bSphere.radius() = 0.0; } else bSphere.expandBy(vertices->back()); } edgeGeometry->addPrimitiveSet(indices.get()); boost::uuids::uuid id = seerShape->findShapeIdRecord(edgeIn).id; std::size_t lastPrimitiveIndex = edgeGeometry->getNumPrimitiveSets() - 1; if (!idPSetWrapperEdge->hasId(id)) { IdPSetRecord record; record.id = id; record.primitiveSetIndex = lastPrimitiveIndex; record.bSphere = bSphere; idPSetWrapperEdge->idPSetContainer.insert(record); } else //ensure that edges have the same primitive index between lod calls. //asserts here prior to having lod implemented is probably duplicate ids //for different geometry. assert(lastPrimitiveIndex == idPSetWrapperEdge->findPSetFromId(id)); }
void ShapeGeometryBuilder::faceConstruct(const TopoDS_Face &faceIn) { TopLoc_Location location; Handle(Poly_Triangulation) triangulation; triangulation = BRep_Tool::Triangulation(faceIn, location); if (triangulation.IsNull()) throw std::runtime_error("null triangulation in face construction"); bool signalOrientation(false); if (faceIn.Orientation() == TopAbs_FORWARD) signalOrientation = true; gp_Trsf transformation; bool identity = true; if(!location.IsIdentity()) { identity = false; transformation = location.Transformation(); } //vertices. const TColgp_Array1OfPnt& nodes = triangulation->Nodes(); osg::Vec3Array *vertices = dynamic_cast<osg::Vec3Array *>(faceGeometry->getVertexArray()); osg::Vec3Array *normals = dynamic_cast<osg::Vec3Array *>(faceGeometry->getNormalArray()); osg::Vec4Array *colors = dynamic_cast<osg::Vec4Array *>(faceGeometry->getColorArray()); std::size_t offset = vertices->size(); for (int index(nodes.Lower()); index < nodes.Upper() + 1; ++index) { gp_Pnt point = nodes.Value(index); if(!identity) point.Transform(transformation); vertices->push_back(osg::Vec3(point.X(), point.Y(), point.Z())); normals->push_back(osg::Vec3(0.0, 0.0, 0.0)); colors->push_back(faceGeometry->getColor()); } const Poly_Array1OfTriangle& triangles = triangulation->Triangles(); osg::ref_ptr<osg::DrawElementsUInt> indices = new osg::DrawElementsUInt (GL_TRIANGLES, triangulation->NbTriangles() * 3); for (int index(triangles.Lower()); index < triangles.Upper() + 1; ++index) { int N1, N2, N3; triangles(index).Get(N1, N2, N3); int factor = (index - 1) * 3; if (!signalOrientation) { (*indices)[factor] = N3 - 1 + offset; (*indices)[factor + 1] = N2 - 1 + offset; (*indices)[factor + 2] = N1 - 1 + offset; } else { (*indices)[factor] = N1 - 1 + offset; (*indices)[factor + 1] = N2 - 1 + offset; (*indices)[factor + 2] = N3 - 1 + offset; } //store primitiveset index and vertex indes into map. PSetVertexRecord record; record.primitiveSetIndex = faceGeometry->getNumPrimitiveSets(); record.vertexIndex = (*indices)[factor]; pSetTriangleWrapper->pSetVertexContainer.insert(record); record.vertexIndex = (*indices)[factor + 1]; pSetTriangleWrapper->pSetVertexContainer.insert(record); record.vertexIndex = (*indices)[factor + 2]; pSetTriangleWrapper->pSetVertexContainer.insert(record); //now that we are combining faces into one geometry, osgUtil SmoothingVisitor //wants to 'average' out normals across faces. so we go back to manual calculation //of surface normals. osg::Vec3 pointOne(vertices->at((*indices)[factor])); osg::Vec3 pointTwo(vertices->at((*indices)[factor + 1])); osg::Vec3 pointThree(vertices->at((*indices)[factor + 2])); osg::Vec3 axisOne(pointTwo - pointOne); osg::Vec3 axisTwo(pointThree - pointOne); osg::Vec3 currentNormal(axisOne ^ axisTwo); if (currentNormal.isNaN()) continue; currentNormal.normalize(); osg::Vec3 tempNormal; tempNormal = (*normals)[(*indices)[factor]]; tempNormal += currentNormal; tempNormal.normalize(); (*normals)[(*indices)[factor]] = tempNormal; tempNormal = (*normals)[(*indices)[factor + 1]]; tempNormal += currentNormal; tempNormal.normalize(); (*normals)[(*indices)[factor + 1]] = tempNormal; tempNormal = (*normals)[(*indices)[factor + 2]]; tempNormal += currentNormal; tempNormal.normalize(); (*normals)[(*indices)[factor + 2]] = tempNormal; } faceGeometry->addPrimitiveSet(indices.get()); boost::uuids::uuid id = seerShape->findShapeIdRecord(faceIn).id; std::size_t lastPrimitiveIndex = faceGeometry->getNumPrimitiveSets() - 1; if (!idPSetWrapperFace->hasId(id)) { IdPSetRecord record; record.id = id; record.primitiveSetIndex = lastPrimitiveIndex; idPSetWrapperFace->idPSetContainer.insert(record); } else //ensure that the faces have the same primitive index between lod calls. assert(lastPrimitiveIndex == idPSetWrapperFace->findPSetFromId(id)); }
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()); } } }
void PovTools::transferToArray(const TopoDS_Face& aFace,gp_Vec** vertices,gp_Vec** vertexnormals, long** cons,int &nbNodesInFace,int &nbTriInFace ) { TopLoc_Location aLoc; // doing the meshing and checking the result //BRepMesh_IncrementalMesh MESH(aFace,fDeflection); Handle(Poly_Triangulation) aPoly = BRep_Tool::Triangulation(aFace,aLoc); if (aPoly.IsNull()) { Base::Console().Log("Empty face trianglutaion\n"); nbNodesInFace =0; nbTriInFace = 0; vertices = 0l; cons = 0l; return; } // getting the transformation of the shape/face gp_Trsf myTransf; Standard_Boolean identity = true; if (!aLoc.IsIdentity()) { identity = false; myTransf = aLoc.Transformation(); } Standard_Integer i; // getting size and create the array nbNodesInFace = aPoly->NbNodes(); nbTriInFace = aPoly->NbTriangles(); *vertices = new gp_Vec[nbNodesInFace]; *vertexnormals = new gp_Vec[nbNodesInFace]; for (i=0; i < nbNodesInFace; i++) { (*vertexnormals)[i]= gp_Vec(0.0,0.0,0.0); } *cons = new long[3*(nbTriInFace)+1]; // check orientation TopAbs_Orientation orient = aFace.Orientation(); // cycling through the poly mesh const Poly_Array1OfTriangle& Triangles = aPoly->Triangles(); const TColgp_Array1OfPnt& Nodes = aPoly->Nodes(); for (i=1; i<=nbTriInFace; i++) { // Get the triangle Standard_Integer N1,N2,N3; Triangles(i).Get(N1,N2,N3); // change orientation of the triangles if ( orient != TopAbs_FORWARD ) { Standard_Integer tmp = N1; N1 = N2; N2 = tmp; } gp_Pnt V1 = Nodes(N1); gp_Pnt V2 = Nodes(N2); gp_Pnt V3 = Nodes(N3); // transform the vertices to the place of the face if (!identity) { V1.Transform(myTransf); V2.Transform(myTransf); V3.Transform(myTransf); } // 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); //Standard_Real Area = 0.5 * Normal.Magnitude(); // add the triangle normal to the vertex normal for all points of this triangle (*vertexnormals)[N1-1] += gp_Vec(Normal.X(),Normal.Y(),Normal.Z()); (*vertexnormals)[N2-1] += gp_Vec(Normal.X(),Normal.Y(),Normal.Z()); (*vertexnormals)[N3-1] += gp_Vec(Normal.X(),Normal.Y(),Normal.Z()); (*vertices)[N1-1].SetX((float)(V1.X())); (*vertices)[N1-1].SetY((float)(V1.Y())); (*vertices)[N1-1].SetZ((float)(V1.Z())); (*vertices)[N2-1].SetX((float)(V2.X())); (*vertices)[N2-1].SetY((float)(V2.Y())); (*vertices)[N2-1].SetZ((float)(V2.Z())); (*vertices)[N3-1].SetX((float)(V3.X())); (*vertices)[N3-1].SetY((float)(V3.Y())); (*vertices)[N3-1].SetZ((float)(V3.Z())); int j = i - 1; N1--; N2--; N3--; (*cons)[3*j] = N1; (*cons)[3*j+1] = N2; (*cons)[3*j+2] = N3; } // normalize all vertex normals for (i=0; i < nbNodesInFace; i++) { gp_Dir clNormal; try { Handle(Geom_Surface) Surface = BRep_Tool::Surface(aFace); gp_Pnt vertex((*vertices)[i].XYZ()); // gp_Pnt vertex((*vertices)[i][0], (*vertices)[i][1], (*vertices)[i][2]); GeomAPI_ProjectPointOnSurf ProPntSrf(vertex, Surface); Standard_Real fU, fV; ProPntSrf.Parameters(1, fU, fV); GeomLProp_SLProps clPropOfFace(Surface, fU, fV, 2, gp::Resolution()); clNormal = clPropOfFace.Normal(); gp_Vec temp = clNormal; //Base::Console().Log("unterschied:%.2f",temp.dot((*vertexnormals)[i])); if ( temp * (*vertexnormals)[i] < 0 ) temp = -temp; (*vertexnormals)[i] = temp; } catch (...) { } (*vertexnormals)[i].Normalize(); } }
App::DocumentObjectExecReturn *RuledSurface::execute(void) { try { App::DocumentObjectExecReturn* ret; // get the first input shape TopoDS_Shape S1; ret = getShape(Curve1, S1); if (ret) return ret; // get the second input shape TopoDS_Shape S2; ret = getShape(Curve2, S2); if (ret) return ret; // check for expected type if (S1.IsNull() || S2.IsNull()) return new App::DocumentObjectExecReturn("Linked shapes are empty."); if (S1.ShapeType() != TopAbs_EDGE && S1.ShapeType() != TopAbs_WIRE) return new App::DocumentObjectExecReturn("Linked shape is neither edge nor wire."); if (S2.ShapeType() != TopAbs_EDGE && S2.ShapeType() != TopAbs_WIRE) return new App::DocumentObjectExecReturn("Linked shape is neither edge nor wire."); // https://forum.freecadweb.org/viewtopic.php?f=8&t=24052 // // if both shapes are sub-elements of one common shape then the fill algorithm // leads to problems if the shape has set a placement // The workaround is to reset the placement before calling BRepFill and then // applying the placement to the output shape TopLoc_Location Loc; if (Curve1.getValue() == Curve2.getValue()) { Loc = S1.Location(); if (!Loc.IsIdentity() && Loc == S2.Location()) { S1.Location(TopLoc_Location()); S2.Location(TopLoc_Location()); } } // make both shapes to have the same type Standard_Boolean isWire = Standard_False; if (S1.ShapeType() == TopAbs_WIRE) isWire = Standard_True; if (isWire) { if (S2.ShapeType() == TopAbs_EDGE) S2 = BRepLib_MakeWire(TopoDS::Edge(S2)); } else { // S1 is an edge, if S2 is a wire convert S1 to a wire, too if (S2.ShapeType() == TopAbs_WIRE) { S1 = BRepLib_MakeWire(TopoDS::Edge(S1)); isWire = Standard_True; } } if (Orientation.getValue() == 0) { // Automatic Handle(Adaptor3d_HCurve) a1; Handle(Adaptor3d_HCurve) a2; if (!isWire) { BRepAdaptor_Curve adapt1(TopoDS::Edge(S1)); BRepAdaptor_Curve adapt2(TopoDS::Edge(S2)); a1 = new BRepAdaptor_HCurve(adapt1); a2 = new BRepAdaptor_HCurve(adapt2); } else { BRepAdaptor_CompCurve adapt1(TopoDS::Wire(S1)); BRepAdaptor_CompCurve adapt2(TopoDS::Wire(S2)); a1 = new BRepAdaptor_HCompCurve(adapt1); a2 = new BRepAdaptor_HCompCurve(adapt2); } if (!a1.IsNull() && !a2.IsNull()) { // get end points of 1st curve Standard_Real first, last; first = a1->FirstParameter(); last = a1->LastParameter(); if (S1.Closed()) last = (first + last)/2; gp_Pnt p1 = a1->Value(first); gp_Pnt p2 = a1->Value(last); if (S1.Orientation() == TopAbs_REVERSED) { std::swap(p1, p2); } // get end points of 2nd curve first = a2->FirstParameter(); last = a2->LastParameter(); if (S2.Closed()) last = (first + last)/2; gp_Pnt p3 = a2->Value(first); gp_Pnt p4 = a2->Value(last); if (S2.Orientation() == TopAbs_REVERSED) { std::swap(p3, p4); } // Form two triangles (P1,P2,P3) and (P4,P3,P2) and check their normals. // If the dot product is negative then it's assumed that the resulting face // is twisted, hence the 2nd edge is reversed. gp_Vec v1(p1, p2); gp_Vec v2(p1, p3); gp_Vec n1 = v1.Crossed(v2); gp_Vec v3(p4, p3); gp_Vec v4(p4, p2); gp_Vec n2 = v3.Crossed(v4); if (n1.Dot(n2) < 0) { S2.Reverse(); } } } else if (Orientation.getValue() == 2) { // Reverse S2.Reverse(); } TopoDS_Shape ruledShape; if (!isWire) { ruledShape = BRepFill::Face(TopoDS::Edge(S1), TopoDS::Edge(S2)); } else { ruledShape = BRepFill::Shell(TopoDS::Wire(S1), TopoDS::Wire(S2)); } // re-apply the placement in case we reset it if (!Loc.IsIdentity()) ruledShape.Move(Loc); Loc = ruledShape.Location(); if (!Loc.IsIdentity()) { // reset the placement of the shape because the Placement // property will be changed ruledShape.Location(TopLoc_Location()); Base::Matrix4D transform; TopoShape::convertToMatrix(Loc.Transformation(), transform); this->Placement.setValue(Base::Placement(transform)); } this->Shape.setValue(ruledShape); return App::DocumentObject::StdReturn; } catch (Standard_Failure& e) { return new App::DocumentObjectExecReturn(e.GetMessageString()); } catch (...) { return new App::DocumentObjectExecReturn("General error in RuledSurface::execute()"); } }
void ViewProviderPartExt::updateVisual(const TopoDS_Shape& inputShape) { // Clear selection Gui::SoSelectionElementAction action(Gui::SoSelectionElementAction::None); action.apply(this->faceset); action.apply(this->lineset); action.apply(this->nodeset); TopoDS_Shape cShape(inputShape); if (cShape.IsNull()) { coords ->point .setNum(0); norm ->vector .setNum(0); faceset ->coordIndex .setNum(0); faceset ->partIndex .setNum(0); lineset ->coordIndex .setNum(0); VisualTouched = false; return; } // time measurement and book keeping Base::TimeInfo start_time; int nbrTriangles=0,nbrNodes=0,nbrNorms=0,nbrFaces=0,nbrEdges=0,nbrLines=0; std::set<int> faceEdges; try { // calculating the deflection value Bnd_Box bounds; BRepBndLib::Add(cShape, bounds); bounds.SetGap(0.0); Standard_Real xMin, yMin, zMin, xMax, yMax, zMax; 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 BRepMesh_IncrementalMesh myMesh(cShape,deflection); // 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 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(); nbrNorms += mesh->NbNodes(); } TopExp_Explorer xp; for (xp.Init(Ex.Current(),TopAbs_EDGE);xp.More();xp.Next()) faceEdges.insert(xp.Current().HashCode(INT_MAX)); nbrFaces++; } // get an indexed map of edges TopTools_IndexedMapOfShape M; TopExp::MapShapes(cShape, TopAbs_EDGE, M); std::set<int> edgeIdxSet; std::vector<int32_t> indxVector; std::vector<int32_t> edgeVector; // count and index the edges for (int i=1; i <= M.Extent(); i++) { edgeIdxSet.insert(i); nbrEdges++; const TopoDS_Edge& aEdge = TopoDS::Edge(M(i)); TopLoc_Location aLoc; // handling of the free edge that are not associated to a face // Note: The assumption that if for an edge BRep_Tool::Polygon3D // returns a valid object is wrong. This e.g. happens for ruled // surfaces which gets created by two edges or wires. // So, we have to store the hashes of the edges associated to a face. // If the hash of a given edge is not in this list we know it's really // a free edge. int hash = aEdge.HashCode(INT_MAX); if (faceEdges.find(hash) == faceEdges.end()) { Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D(aEdge, aLoc); if (!aPoly.IsNull()) { int nbNodesInEdge = aPoly->NbNodes(); nbrNodes += nbNodesInEdge; } } } // reserve some memory indxVector.reserve(nbrEdges*8); // handling of the vertices TopTools_IndexedMapOfShape V; TopExp::MapShapes(cShape, TopAbs_VERTEX, V); nbrNodes += V.Extent(); // create memory for the nodes and indexes coords ->point .setNum(nbrNodes); norm ->vector .setNum(nbrNorms); faceset ->coordIndex .setNum(nbrTriangles*4); faceset ->partIndex .setNum(nbrFaces); // get the raw memory for fast fill up SbVec3f* verts = coords ->point .startEditing(); SbVec3f* norms = norm ->vector .startEditing(); int32_t* index = faceset ->coordIndex .startEditing(); int32_t* parts = faceset ->partIndex .startEditing(); // preset the normal vector with null vector for (int i=0;i < nbrNorms;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; } parts[ii] = nbTriInFace; // new part // handling the edges lying on this face TopExp_Explorer Exp; for(Exp.Init(actFace,TopAbs_EDGE);Exp.More();Exp.Next()) { const TopoDS_Edge &actEdge = TopoDS::Edge(Exp.Current()); // get the overall index of this edge int idx = M.FindIndex(actEdge); edgeVector.push_back((int32_t)idx-1); // already processed this index ? if (edgeIdxSet.find(idx)!=edgeIdxSet.end()) { // this holds the indices of the edge's triangulation to the current polygon Handle(Poly_PolygonOnTriangulation) aPoly = BRep_Tool::PolygonOnTriangulation(actEdge, mesh, aLoc); if (aPoly.IsNull()) continue; // polygon does not exist // getting the indexes of the edge polygon const TColStd_Array1OfInteger& indices = aPoly->Nodes(); for (Standard_Integer i=indices.Lower();i <= indices.Upper();i++) { int inx = indices(i); indxVector.push_back(FaceNodeOffset+inx-1); // usually the coordinates for this edge are already set by the // triangles of the face this edge belongs to. However, there are // rare cases where some points are only referenced by the polygon // but not by any triangle. Thus, we must apply the coordinates to // make sure that everything is properly set. gp_Pnt p(Nodes(inx)); if (!identity) p.Transform(myTransf); verts[FaceNodeOffset+inx-1].setValue((float)(p.X()),(float)(p.Y()),(float)(p.Z())); } indxVector.push_back(-1); // remove the handled edge index from the set edgeIdxSet.erase(idx); } } edgeVector.push_back(-1); // counting up the per Face offsets FaceNodeOffset += nbNodesInFace; FaceTriaOffset += nbTriInFace; } // handling of the free edges for (int i=1; i <= M.Extent(); i++) { const TopoDS_Edge& aEdge = TopoDS::Edge(M(i)); Standard_Boolean identity = true; gp_Trsf myTransf; TopLoc_Location aLoc; // handling of the free edge that are not associated to a face int hash = aEdge.HashCode(INT_MAX); if (faceEdges.find(hash) == faceEdges.end()) { Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D(aEdge, aLoc); if (!aPoly.IsNull()) { if (!aLoc.IsIdentity()) { identity = false; myTransf = aLoc.Transformation(); } const TColgp_Array1OfPnt& aNodes = aPoly->Nodes(); int nbNodesInEdge = aPoly->NbNodes(); gp_Pnt pnt; for (Standard_Integer j=1;j <= nbNodesInEdge;j++) { pnt = aNodes(j); if (!identity) pnt.Transform(myTransf); verts[FaceNodeOffset+j-1].setValue((float)(pnt.X()),(float)(pnt.Y()),(float)(pnt.Z())); indxVector.push_back(FaceNodeOffset+j-1); } indxVector.push_back(-1); FaceNodeOffset += nbNodesInEdge; } } } nodeset->startIndex.setValue(FaceNodeOffset); for (int i=0; i<V.Extent(); i++) { const TopoDS_Vertex& aVertex = TopoDS::Vertex(V(i+1)); gp_Pnt pnt = BRep_Tool::Pnt(aVertex); verts[FaceNodeOffset+i].setValue((float)(pnt.X()),(float)(pnt.Y()),(float)(pnt.Z())); } // normalize all normals for (int i = 0; i< nbrNorms ;i++) norms[i].normalize(); // preset the index vector size nbrLines = indxVector.size(); lineset ->coordIndex .setNum(nbrLines); int32_t* lines = lineset ->coordIndex .startEditing(); int l=0; for (std::vector<int32_t>::const_iterator it=indxVector.begin();it!=indxVector.end();++it,l++) lines[l] = *it; // end the editing of the nodes coords ->point .finishEditing(); norm ->vector .finishEditing(); faceset ->coordIndex .finishEditing(); faceset ->partIndex .finishEditing(); lineset ->coordIndex .finishEditing(); } catch (...) { Base::Console().Error("Cannot compute Inventor representation for the shape of %s.\n",pcObject->getNameInDocument()); } // printing some informations Base::Console().Log("ViewProvider update time: %f s\n",Base::TimeInfo::diffTimeF(start_time,Base::TimeInfo())); Base::Console().Log("Shape tria info: Faces:%d Edges:%d Nodes:%d Triangles:%d IdxVec:%d\n",nbrFaces,nbrEdges,nbrNodes,nbrTriangles,nbrLines); VisualTouched = false; }
//======================================================================= // profile // command to build a profile //======================================================================= Sketcher_Profile::Sketcher_Profile(const char* aCmd) { enum {line, circle, point, none} move; Standard_Integer i = 1; Standard_Real x0, y0, x, y, dx, dy; x0 = y0 = x = y = dy = 0; dx = 1; Standard_Boolean first, stayfirst, face, close; first = Standard_True; stayfirst = face = close = Standard_False; Standard_Integer reversed = 0; Standard_Integer control_Tolerance = 0; TopoDS_Shape S; TopoDS_Vertex MP; BRepBuilderAPI_MakeWire MW; gp_Ax3 DummyHP(gp::XOY()); gp_Pln P(DummyHP); TopLoc_Location TheLocation; Handle(Geom_Surface) Surface; myOK = Standard_False; myError = 0; //TCollection_AsciiString aCommand(CORBA::string_dup(aCmd)); TCollection_AsciiString aCommand ((char*)aCmd); TCollection_AsciiString aToken = aCommand.Token(":", 1); int n = 0; // porting to WNT TColStd_Array1OfAsciiString aTab (0, aCommand.Length() - 1); if ( aCommand.Length() ) { while(aToken.Length() != 0) { if(aCommand.Token(":", n + 1).Length() > 0) aTab(n) = aCommand.Token(":", n + 1); aToken = aCommand.Token(":", ++n); } n = n - 1; } if ( aTab.Length() && aTab(0).Length() ) while(i < n) { Standard_Real length = 0, radius = 0, angle = 0; move = point; int n1 = 0; TColStd_Array1OfAsciiString a (0, aTab(0).Length()); aToken = aTab(i).Token(" ", 1); while (aToken.Length() != 0) { if (aTab(i).Token(" ", n1 + 1).Length() > 0) a(n1) = aTab(i).Token(" ", n1 + 1); aToken = aTab(i).Token(" ", ++n1); } n1 = n1 - 1; switch(a(0).Value(1)) { case 'F': { if (n1 != 3) goto badargs; if (!first) { MESSAGE("profile : The F instruction must precede all moves"); return; } x0 = x = a(1).RealValue(); y0 = y = a(2).RealValue(); stayfirst = Standard_True; break; } case 'O': { if (n1 != 4) goto badargs; P.SetLocation(gp_Pnt(a(1).RealValue(), a(2).RealValue(), a(3).RealValue())); stayfirst = Standard_True; break; } case 'P': { if (n1 != 7) goto badargs; gp_Vec vn(a(1).RealValue(), a(2).RealValue(), a(3).RealValue()); gp_Vec vx(a(4).RealValue(), a(5).RealValue(), a(6).RealValue()); if (vn.Magnitude() <= Precision::Confusion() || vx.Magnitude() <= Precision::Confusion()) { MESSAGE("profile : null direction"); return; } gp_Ax2 ax(P.Location(), vn, vx); P.SetPosition(ax); stayfirst = Standard_True; break; } case 'X': { if (n1 != 2) goto badargs; length = a(1).RealValue(); if (a(0) == "XX") length -= x; dx = 1; dy = 0; move = line; break; } case 'Y': { if (n1 != 2) goto badargs; length = a(1).RealValue(); if (a(0) == "YY") length -= y; dx = 0; dy = 1; move = line; break; } case 'L': { if (n1 != 2) goto badargs; length = a(1).RealValue(); if (Abs(length) > Precision::Confusion()) move = line; else move = none; break; } case 'T': { if (n1 != 3) goto badargs; Standard_Real vx = a(1).RealValue(); Standard_Real vy = a(2).RealValue(); if (a(0) == "TT") { vx -= x; vy -= y; } length = Sqrt(vx * vx + vy * vy); if (length > Precision::Confusion()) { move = line; dx = vx / length; dy = vy / length; } else move = none; break; } case 'R': { if (n1 != 2) goto badargs; angle = a(1).RealValue() * PI180; if (a(0) == "RR") { dx = Cos(angle); dy = Sin(angle); } else { Standard_Real c = Cos(angle); Standard_Real s = Sin(angle); Standard_Real t = c * dx - s * dy; dy = s * dx + c * dy; dx = t; } break; } case 'D': { if (n1 != 3) goto badargs; Standard_Real vx = a(1).RealValue(); Standard_Real vy = a(2).RealValue(); length = Sqrt(vx * vx + vy * vy); if (length > Precision::Confusion()) { dx = vx / length; dy = vy / length; } else move = none; break; } case 'C': { if (n1 != 3) goto badargs; radius = a(1).RealValue(); if (Abs(radius) > Precision::Confusion()) { angle = a(2).RealValue() * PI180; move = circle; } else move = none; break; } case 'A': // TAngential arc by end point { if (n1 != 3) goto badargs; Standard_Real vx = a(1).RealValue(); Standard_Real vy = a(2).RealValue(); if (a(0) == "AA") { vx -= x; vy -= y; } Standard_Real det = dx * vy - dy * vx; if ( Abs(det) > Precision::Confusion()) { Standard_Real c = (dx * vx + dy * vy) / Sqrt((dx * dx + dy * dy) * (vx * vx + vy * vy)); // Cosine of alpha = arc of angle / 2 , alpha in [0,Pi] radius = (vx * vx + vy * vy)* Sqrt(dx * dx + dy * dy) // radius = distance between start and end point / 2 * sin(alpha) / (2.0 * det); // radius is > 0 or < 0 if (Abs(radius) > Precision::Confusion()) { angle = 2.0 * acos(c); // angle in [0,2Pi] move = circle; } else move = none; break; } else move = none; break; } case 'U': // Arc by end point and radiUs { if (n1 != 5) goto badargs; Standard_Real vx = a(1).RealValue(); Standard_Real vy = a(2).RealValue(); radius = a(3).RealValue(); reversed = a(4).IntegerValue(); if (a(0) == "UU") { // Absolute vx -= x; vy -= y; } Standard_Real length = Sqrt(vx * vx + vy * vy); if ( (4.0 - (vx * vx + vy * vy) / (radius * radius) >= 0.0 ) && (length > Precision::Confusion()) ) { Standard_Real c = 0.5 * Sqrt(4.0 - (vx * vx + vy * vy) / (radius * radius)); // Cosine of alpha = arc angle / 2 , alpha in [0,Pi/2] angle = 2.0 * acos(c); // angle in [0,Pi] if ( reversed == 2 ) angle = angle - 2 * PI; dx = 0.5 * ( vy * 1.0/radius + vx * Sqrt(4.0 / (vx * vx + vy * vy) - 1.0 / (radius * radius))); dy = - 0.5 * ( vx * 1.0/radius - vy * Sqrt(4.0 / (vx * vx + vy * vy) - 1.0 / (radius * radius))); move = circle; } else{ move = none; } break; } case 'E': // Arc by end point and cEnter { if (n1 != 7) goto badargs; Standard_Real vx = a(1).RealValue(); Standard_Real vy = a(2).RealValue(); Standard_Real vxc = a(3).RealValue(); Standard_Real vyc = a(4).RealValue(); reversed = a(5).IntegerValue(); control_Tolerance = a(6).IntegerValue(); if (a(0) == "EE") { // Absolute vx -= x; vy -= y; vxc -= x; vyc -= y; } radius = Sqrt( vxc * vxc + vyc * vyc ); Standard_Real det = vx * vyc - vy * vxc; Standard_Real length = Sqrt(vx * vx + vy * vy); Standard_Real length2 = Sqrt((vx-vxc) * (vx-vxc) + (vy-vyc) * (vy-vyc)); Standard_Real length3 = Sqrt(vxc * vxc + vyc * vyc); Standard_Real error = Abs(length2 - radius); myError = error; if ( error > Precision::Confusion() ){ MESSAGE("Warning : The specified end point is not on the Arc, distance = "<<error); } if ( error > Precision::Confusion() && control_Tolerance == 1) // Don't create the arc if the end point move = none; // is too far from it else if ( (length > Precision::Confusion()) && (length2 > Precision::Confusion()) && (length3 > Precision::Confusion()) ) { Standard_Real c = ( radius * radius - (vx * vxc + vy * vyc) ) / ( radius * Sqrt((vx-vxc) * (vx-vxc) + (vy-vyc) * (vy-vyc)) ) ; // Cosine of arc angle angle = acos(c); // angle in [0,Pi] if ( reversed == 2 ) angle = angle - 2 * PI; if (det < 0) angle = -angle; dx = vyc / radius; dy = -vxc / radius; move = circle; } else { move = none; } break; } case 'I': { if (n1 != 2) goto badargs; length = a(1).RealValue(); if (a(0) == "IX") { if (Abs(dx) < Precision::Confusion()) { MESSAGE("profile : cannot intersect, arg "<<i-1); return; } length = (length - x) / dx; } else if (a(0) == "IY") { if (Abs(dy) < Precision::Confusion()) { MESSAGE("profile : cannot intersect, arg "<<i-1); return; } length = (length - y) / dy; } if (Abs(length) > Precision::Confusion()) move = line; else move = none; break; } case 'W': { if (a(0) == "WW") close = Standard_True; else if(a(0) == "WF") { close = Standard_True; face = Standard_True; } i = n - 1; break; } default: { MESSAGE("profile : unknown code " << a(i)); return; } } again : switch (move) { case line : { if (length < 0) { length = -length; dx = -dx; dy = -dy; } Handle(Geom2d_Line) l = new Geom2d_Line(gp_Pnt2d(x,y),gp_Dir2d(dx,dy)); BRepBuilderAPI_MakeEdge ME (GeomAPI::To3d(l,P),0,length); if (!ME.IsDone()) return; MW.Add(ME); x += length*dx; y += length*dy; break; } case circle : { Standard_Boolean sense = Standard_True; if (radius < 0) { radius = -radius; sense = !sense; dx = -dx; dy = -dy; } gp_Ax2d ax(gp_Pnt2d(x-radius*dy,y+radius*dx),gp_Dir2d(dy,-dx)); if (angle < 0) { angle = -angle; sense = !sense; } Handle(Geom2d_Circle) c = new Geom2d_Circle(ax,radius,sense); BRepBuilderAPI_MakeEdge ME (GeomAPI::To3d(c,P),0,angle); if (!ME.IsDone()) return; MW.Add(ME); gp_Pnt2d p; gp_Vec2d v; c->D1(angle,p,v); x = p.X(); y = p.Y(); dx = v.X() / radius; dy = v.Y() / radius; break; } case point: { MP = BRepBuilderAPI_MakeVertex(gp_Pnt(x, y, 0.0)); break; } case none: { i = n - 1; break; } } // update first first = stayfirst; stayfirst = Standard_False; if(!(dx == 0 && dy == 0)) myLastDir.SetCoord(dx, dy, 0.0); else return; myLastPoint.SetX(x); myLastPoint.SetY(y); // next segment.... i++; if ((i == n) && close) { // the closing segment dx = x0 - x; dy = y0 - y; length = Sqrt(dx * dx + dy * dy); move = line; if (length > Precision::Confusion()) { dx = dx / length; dy = dy / length; goto again; } } } // get the result, face or wire if (move == none) { return; } else if (move == point) { S = MP; } else if (face) { if (!MW.IsDone()) { return; } BRepBuilderAPI_MakeFace MF (P, MW.Wire()); if (!MF.IsDone()) { return; } S = MF; } else { if (!MW.IsDone()) { return; } S = MW; } if(!TheLocation.IsIdentity()) S.Move(TheLocation); myShape = S; myOK = true; return; badargs : MESSAGE("profile : bad number of arguments"); return; }