Exemple #1
0
/// utility non-class member functions
//! Returns the centroid of shape, as viewed according to direction and xAxis
gp_Pnt TechDrawGeometry::findCentroid(const TopoDS_Shape &shape,
                                      const Base::Vector3d &direction,
                                      const Base::Vector3d &xAxis)
{
    gp_Ax2 viewAxis;
    viewAxis = gp_Ax2(gp_Pnt(0, 0, 0),
                      gp_Dir(direction.x, -direction.y, direction.z),
                      gp_Dir(xAxis.x, -xAxis.y, xAxis.z)); // Y invert warning!

    gp_Trsf tempTransform;
    tempTransform.SetTransformation(viewAxis);
    BRepBuilderAPI_Transform builder(shape, tempTransform);

    Bnd_Box tBounds;
    BRepBndLib::Add(builder.Shape(), tBounds);

    tBounds.SetGap(0.0);
    Standard_Real xMin, yMin, zMin, xMax, yMax, zMax;
    tBounds.Get(xMin, yMin, zMin, xMax, yMax, zMax);

    Standard_Real x = (xMin + xMax) / 2.0,
                  y = (yMin + yMax) / 2.0,
                  z = (zMin + zMax) / 2.0;

    // Get centroid back into object space
    tempTransform.Inverted().Transforms(x, y, z);

    return gp_Pnt(x, y, z);
}
//! Returns the centroid of shape, as viewed according to direction
gp_Pnt TechDrawGeometry::findCentroid(const TopoDS_Shape &shape,
                                    const Base::Vector3d &direction)
{
    Base::Vector3d origin(0.0,0.0,0.0);
    gp_Ax2 viewAxis = getViewAxis(origin,direction);

    gp_Trsf tempTransform;
    tempTransform.SetTransformation(viewAxis);
    BRepBuilderAPI_Transform builder(shape, tempTransform);

    Bnd_Box tBounds;
    BRepBndLib::Add(builder.Shape(), tBounds);

    tBounds.SetGap(0.0);
    Standard_Real xMin, yMin, zMin, xMax, yMax, zMax;
    tBounds.Get(xMin, yMin, zMin, xMax, yMax, zMax);

    Standard_Real x = (xMin + xMax) / 2.0,
                  y = (yMin + yMax) / 2.0,
                  z = (zMin + zMax) / 2.0;

    // Get centroid back into object space
    tempTransform.Inverted().Transforms(x, y, z);

    return gp_Pnt(x, y, z);
}
Base::BoundBox3d PropertyPartShape::getBoundingBox() const
{
    Base::BoundBox3d box;
    if (_Shape._Shape.IsNull())
        return box;
    try {
        // If the shape is empty an exception may be thrown
        Bnd_Box bounds;
        BRepBndLib::Add(_Shape._Shape, bounds);
        bounds.SetGap(0.0);
        Standard_Real xMin, yMin, zMin, xMax, yMax, zMax;
        bounds.Get(xMin, yMin, zMin, xMax, yMax, zMax);

        box.MinX = xMin;
        box.MaxX = xMax;
        box.MinY = yMin;
        box.MaxY = yMax;
        box.MinZ = zMin;
        box.MaxZ = zMax;
    }
    catch (Standard_Failure) {
    }

    return box;
}
Exemple #4
0
void InventorShape::computeShape() {
    Bnd_Box bounds;
    BRepBndLib::Add(shape->getShape(), 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 * 0.2;
    BRepMesh::Mesh(shape->getShape(), deflection);

    SoGroup* faces = new SoGroup();

    computeFaces(faces, shape->getShape());

    separator->addChild(faces);

    SoGroup* edges = new SoGroup();
    computeEdges(edges, shape->getShape());

    separator->addChild(edges);

    SoGroup* vertices = new SoGroup();
    computeVertices(vertices, shape->getShape());

    separator->addChild(vertices);
}
void Transformed::divideTools(const std::vector<TopoDS_Shape> &toolsIn, std::vector<TopoDS_Shape> &individualsOut,
                              TopoDS_Compound &compoundOut) const
{
  typedef std::pair<TopoDS_Shape, Bnd_Box> ShapeBoundPair;
  typedef std::list<ShapeBoundPair> PairList;
  typedef std::vector<ShapeBoundPair> PairVector;
  
  PairList pairList;
  
  std::vector<TopoDS_Shape>::const_iterator it;
  for (it = toolsIn.begin(); it != toolsIn.end(); ++it)
  {
    Bnd_Box bound;
    BRepBndLib::Add(*it, bound);
    bound.SetGap(0.0);
    ShapeBoundPair temp = std::make_pair(*it, bound);
    pairList.push_back(temp);
  }
  
  BRep_Builder builder;
  builder.MakeCompound(compoundOut);
  
  while(!pairList.empty())
  {
    PairVector currentGroup;
    currentGroup.push_back(pairList.front());
    pairList.pop_front();
    PairList::iterator it = pairList.begin();
    while(it != pairList.end())
    {
      PairVector::const_iterator groupIt;
      bool found(false);
      for (groupIt = currentGroup.begin(); groupIt != currentGroup.end(); ++groupIt)
      {
	if (!(*it).second.IsOut((*groupIt).second))//touching means is out.
	{
	  found = true;
	  break;
	}
      }
      if (found)
      {
	currentGroup.push_back(*it);
	pairList.erase(it);
	it=pairList.begin();
	continue;
      }
      it++;
    }
    if (currentGroup.size() == 1)
      builder.Add(compoundOut, currentGroup.front().first);
    else
    {
      PairVector::const_iterator groupIt;
      for (groupIt = currentGroup.begin(); groupIt != currentGroup.end(); ++groupIt)
	individualsOut.push_back((*groupIt).first);
    }
  }
}
TopoDS_Shape ProjectionAlgos::invertY(const TopoDS_Shape& shape)
{
    // make sure to have the y coordinates inverted
    gp_Trsf mat;
    Bnd_Box bounds;
    BRepBndLib::Add(shape, bounds);
    bounds.SetGap(0.0);
    Standard_Real xMin, yMin, zMin, xMax, yMax, zMax;
    bounds.Get(xMin, yMin, zMin, xMax, yMax, zMax);
    mat.SetMirror(gp_Ax2(gp_Pnt((xMin+xMax)/2,(yMin+yMax)/2,(zMin+zMax)/2), gp_Dir(0,1,0)));
    BRepBuilderAPI_Transform mkTrf(shape, mat);
    return mkTrf.Shape();
}
Base::BoundBox3d GeometryObject::calcBoundingBox() const
{
    Bnd_Box testBox;
    testBox.SetGap(0.0);
    for (std::vector<BaseGeom *>::const_iterator it( edgeGeom.begin() );
            it != edgeGeom.end(); ++it) {
         BRepBndLib::Add((*it)->occEdge, testBox);
    }
    if (testBox.IsVoid()) {
        Base::Console().Log("INFO - GO::calcBoundingBox - testBox is void\n");
    }
    double xMin,xMax,yMin,yMax,zMin,zMax;
    testBox.Get(xMin,yMin,zMin,xMax,yMax,zMax);

    Base::BoundBox3d bbox(xMin,yMin,zMin,xMax,yMax,zMax);
    return bbox;
}
//this routine is the big time consumer.  gets called many times (and is slow?))
//note param gets modified here
bool DrawProjectSplit::isOnEdge(TopoDS_Edge e, TopoDS_Vertex v, double& param, bool allowEnds)
{
    bool result = false;
    bool outOfBox = false;
    param = -2;

    //eliminate obvious cases
    Bnd_Box sBox;
    BRepBndLib::Add(e, sBox);
    sBox.SetGap(0.1);
    if (sBox.IsVoid()) {
        Base::Console().Message("DPS::isOnEdge - Bnd_Box is void\n");
    } else {
        gp_Pnt pt = BRep_Tool::Pnt(v);
        if (sBox.IsOut(pt)) {
            outOfBox = true;
        }
    }
    if (!outOfBox) {
            double dist = DrawUtil::simpleMinDist(v,e);
            if (dist < 0.0) {
                Base::Console().Error("DPS::isOnEdge - simpleMinDist failed: %.3f\n",dist);
                result = false;
            } else if (dist < Precision::Confusion()) {
                const gp_Pnt pt = BRep_Tool::Pnt(v);                         //have to duplicate method 3 to get param
                BRepAdaptor_Curve adapt(e);
                const Handle_Geom_Curve c = adapt.Curve().Curve();
                double maxDist = 0.000001;     //magic number.  less than this gives false positives.
                //bool found =
                (void) GeomLib_Tool::Parameter(c,pt,maxDist,param);  //already know point it on curve
                result = true;
            }
            if (result) {
                TopoDS_Vertex v1 = TopExp::FirstVertex(e);
                TopoDS_Vertex v2 = TopExp::LastVertex(e);
                if (DrawUtil::isSamePoint(v,v1) || DrawUtil::isSamePoint(v,v2)) {
                    if (!allowEnds) {
                        result = false;
                    }
                }
            }
    } //!outofbox
    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());
        }
    }

}
Exemple #10
0
//this routine is the big time consumer.  gets called many times (and is slow?))
//note param gets modified here
bool DrawViewPart::isOnEdge(TopoDS_Edge e, TopoDS_Vertex v, double& param, bool allowEnds)
{
    bool result = false;
    bool outOfBox = false;
    param = -2;

    //eliminate obvious cases
    Bnd_Box sBox;
    BRepBndLib::Add(e, sBox);
    sBox.SetGap(0.1);
    if (sBox.IsVoid()) {
        Base::Console().Message("DVP::isOnEdge - Bnd_Box is void for %s\n",getNameInDocument());
    } else {
        gp_Pnt pt = BRep_Tool::Pnt(v);
        if (sBox.IsOut(pt)) {
            outOfBox = true;
        }
    }
    if (!outOfBox) {
        if (m_interAlgo == 1) {
            //1) using projPointOnCurve.  roughly similar to dist to shape w/ bndbox.  hangs(?) w/o bndbox
            try {
                gp_Pnt pt = BRep_Tool::Pnt(v);
                BRepAdaptor_Curve adapt(e);
                Handle_Geom_Curve c = adapt.Curve().Curve();
                GeomAPI_ProjectPointOnCurve proj(pt,c);
                int n = proj.NbPoints();
                if (n > 0) {
                    if (proj.LowerDistance() < Precision::Confusion()) {
                        param = proj.LowerDistanceParameter();
                        result = true;
                    }
                    if (result) {
                        TopoDS_Vertex v1 = TopExp::FirstVertex(e);
                        TopoDS_Vertex v2 = TopExp::LastVertex(e);
                        if (DrawUtil::isSamePoint(v,v1) || DrawUtil::isSamePoint(v,v2)) {
                            if (!allowEnds) {
                                result = false;
                            }
                        }
                    }
                }
            }
            catch (Standard_Failure) {
                Handle_Standard_Failure e = Standard_Failure::Caught();     //no perp projection
            }
        } else if (m_interAlgo == 2) {                                      //can't provide param as is
            double dist = simpleMinDist(v,e);
            if (dist < 0.0) {
                Base::Console().Error("DVP::isOnEdge - simpleMinDist failed: %.3f\n",dist);
                result = false;
            } else if (dist < Precision::Confusion()) {
                const gp_Pnt pt = BRep_Tool::Pnt(v);                         //have to duplicate method 3 to get param
                BRepAdaptor_Curve adapt(e);
                const Handle_Geom_Curve c = adapt.Curve().Curve();
                double maxDist = 0.000001;     //magic number.  less than this gives false positives.
                //bool found =
                (void) GeomLib_Tool::Parameter(c,pt,maxDist,param);  //already know point it on curve
                result = true;
            }
            if (result) {
                TopoDS_Vertex v1 = TopExp::FirstVertex(e);
                TopoDS_Vertex v2 = TopExp::LastVertex(e);
                if (DrawUtil::isSamePoint(v,v1) || DrawUtil::isSamePoint(v,v2)) {
                    if (!allowEnds) {
                        result = false;
                    }
                }
            }
        } else if (m_interAlgo == 3) {
            const gp_Pnt pt = BRep_Tool::Pnt(v);
            BRepAdaptor_Curve adapt(e);
            const Handle_Geom_Curve c = adapt.Curve().Curve();
            double par = -1;
            double maxDist = 0.000001;     //magic number.  less than this gives false positives.
            bool found = GeomLib_Tool::Parameter(c,pt,maxDist,par);
            if (found) {
                result = true;
                param = par;
                TopoDS_Vertex v1 = TopExp::FirstVertex(e);
                TopoDS_Vertex v2 = TopExp::LastVertex(e);
                if (DrawUtil::isSamePoint(v,v1) || DrawUtil::isSamePoint(v,v2)) {
                    if (!allowEnds) {
                        result = false;
                    }
                }
            }
        }
    } //!outofbox
    return result;
}
//=======================================================================
//function : DetectVertices
//purpose  :
//=======================================================================
  void GEOMAlgo_GlueAnalyser::DetectVertices()
{
  myErrorStatus=0;
  //
  Standard_Integer j, i, aNbV, aIndex, aNbVSD;
  TColStd_ListIteratorOfListOfInteger aIt;
  Handle(Bnd_HArray1OfBox) aHAB;
  Bnd_BoundSortBox aBSB;
  TopoDS_Shape aSTmp, aVF;
  TopoDS_Vertex aVnew;
  TopTools_IndexedMapOfShape aMV, aMVProcessed;
  TopTools_ListIteratorOfListOfShape aItS;
  TopTools_DataMapIteratorOfDataMapOfShapeListOfShape aItIm;
  GEOMAlgo_IndexedDataMapOfIntegerShape aMIS;
  GEOMAlgo_IndexedDataMapOfShapeBox aMSB;
  //
  TopExp::MapShapes(myShape, TopAbs_VERTEX, aMV);
  aNbV=aMV.Extent();
  if (!aNbV) {
    myErrorStatus=2; // no vertices in source shape
    return;
  }
  //
  aHAB=new Bnd_HArray1OfBox(1, aNbV);
  //
  for (i=1; i<=aNbV; ++i) {
    const TopoDS_Shape& aV=aMV(i);
    Bnd_Box aBox;
    //
    aBox.SetGap(myTol);
    BRepBndLib::Add(aV, aBox);
    aHAB->SetValue(i, aBox);
    aMIS.Add(i, aV);
    aMSB.Add(aV, aBox);
  }
  //
  aBSB.Initialize(aHAB);
  //
  for (i=1; i<=aNbV; ++i) {
    const TopoDS_Shape& aV=aMV(i);
    //
    if (aMVProcessed.Contains(aV)) {
      continue;
    }
    //
    const Bnd_Box& aBoxV=aMSB.FindFromKey(aV);
    const TColStd_ListOfInteger& aLI=aBSB.Compare(aBoxV);
    aNbVSD=aLI.Extent();
    if (!aNbVSD) {
      myErrorStatus=3; // it must not be
      return;
    }
    //
    // Images
    TopTools_ListOfShape aLVSD;
    //
    aIt.Initialize(aLI);
    for (j=0; aIt.More(); aIt.Next(), ++j) {
      aIndex=aIt.Value();
      const TopoDS_Shape& aVx=aMIS.FindFromKey(aIndex);
      if(!j) {
        aVF=aVx;
      }
      aLVSD.Append(aVx);
      aMVProcessed.Add(aVx);
    }
    myImages.Bind(aVF, aLVSD);
  }
  // Origins
  aItIm.Initialize(myImages);
  for (; aItIm.More(); aItIm.Next()) {
    const TopoDS_Shape& aV=aItIm.Key();
    const TopTools_ListOfShape& aLVSD=aItIm.Value();
    //
    aItS.Initialize(aLVSD);
    for (; aItS.More(); aItS.Next()) {
      const TopoDS_Shape& aVSD=aItS.Value();
      if (!myOrigins.IsBound(aVSD)) {
        myOrigins.Bind(aVSD, aV);
      }
    }
  }
}
//=======================================================================
// function: MakeAloneVertices
// purpose:
//=======================================================================
void NMTTools_PaveFiller::MakeAloneVertices()
{
  Standard_Integer i, aNbFFs, nF1, nF2, j, aNbPnts, nFx, aNbV;
  Standard_Real aTolF1, aTolF2, aTolSum, aTolV;
  TColStd_ListIteratorOfListOfInteger aIt;
  TColStd_ListOfInteger aLI;
  TopoDS_Vertex aV;
  TopoDS_Compound aCompound;
  BRep_Builder aBB;
  TopTools_DataMapOfShapeListOfInteger aDMVFF, aDMVFF1;
  TopTools_DataMapIteratorOfDataMapOfShapeListOfInteger aItDMVFF;
  TopTools_DataMapOfShapeShape aDMVV;
  TopTools_DataMapOfIntegerShape aDMIV;
  TopTools_DataMapOfShapeInteger aDMVI;
  TopTools_DataMapIteratorOfDataMapOfShapeInteger aItDMVI;
  TopTools_DataMapIteratorOfDataMapOfIntegerShape aItDMIV;
  //
  aBB.MakeCompound(aCompound);
  //
  myAloneVertices.Clear();
  //
  BOPTools_CArray1OfSSInterference& aFFs=myIP->SSInterferences();
  //
  // 1. Collect alone vertices from FFs
  aNbV=0;
  aNbFFs=aFFs.Extent();
  for (i=1; i<=aNbFFs; ++i) {
    BOPTools_SSInterference& aFFi=aFFs(i);
    aFFi.Indices(nF1, nF2);
    //
    const TopoDS_Face aF1=TopoDS::Face(myDS->Shape(nF1));//mpv
    const TopoDS_Face aF2=TopoDS::Face(myDS->Shape(nF2));//mpv
    //
    aTolF1=BRep_Tool::Tolerance(aF1);
    aTolF2=BRep_Tool::Tolerance(aF2);
    aTolSum=aTolF1+aTolF2;
    //
    aLI.Clear();
    aLI.Append(nF1);
    aLI.Append(nF2);
    //
    const IntTools_SequenceOfPntOn2Faces& aSeqAlonePnts=aFFi.AlonePnts();
    aNbPnts=aSeqAlonePnts.Length();
    for (j=1; j<=aNbPnts; ++j) {
      const gp_Pnt& aP=aSeqAlonePnts(j).P1().Pnt();
      BOPTools_Tools::MakeNewVertex(aP, aTolSum, aV);
      aDMVFF.Bind(aV, aLI);
      aBB.Add(aCompound, aV);
      ++aNbV;
    }
  }
  if (!aNbV) {
    return;
  }
  //
  // 2. Try to fuse alone vertices themselves;
  FuseVertices(aCompound, aDMVV);
  //
  // if some are fused, replace them by new ones
  aItDMVFF.Initialize(aDMVFF);
  for (;  aItDMVFF.More(); aItDMVFF.Next()) {
    const TopoDS_Shape& aVx=aItDMVFF.Key();
    const TColStd_ListOfInteger& aLIx=aItDMVFF.Value();
    //
    if (!aDMVV.IsBound(aVx)) {
      aDMVFF1.Bind(aVx, aLIx);
    }
    else {
      const TopoDS_Shape& aVy=aDMVV.Find(aVx);

      if (aDMVFF1.IsBound(aVy)) {
        TColStd_ListOfInteger& aLIy=aDMVFF1.ChangeFind(aVy);
        aIt.Initialize(aLIx);
        for(; aIt.More(); aIt.Next()) {
          nFx=aIt.Value();
          aLIy.Append(nFx);
        }
      }
      else {
        aDMVFF1.Bind(aVy, aLIx);
      }
    }
  }
  aDMVFF.Clear();
  //
  // refine lists of faces in aDMVFF1;
  aItDMVFF.Initialize(aDMVFF1);
  for (;  aItDMVFF.More(); aItDMVFF.Next()) {
    TColStd_MapOfInteger aMIy;
    TColStd_ListOfInteger aLIy;
    //
    const TopoDS_Shape& aVx=aItDMVFF.Key();
    TColStd_ListOfInteger& aLIx=aDMVFF1.ChangeFind(aVx);
    aIt.Initialize(aLIx);
    for(; aIt.More(); aIt.Next()) {
      nFx=aIt.Value();
      if (aMIy.Add(nFx)) {
        aLIy.Append(nFx);
      }
    }
    aLIx.Clear();
    aLIx.Append(aLIy);
  }
  //==================================
  //
  // 3. Collect vertices from DS
  Standard_Integer aNbS, nV, nVSD, aNbVDS, i1, i2, aNbVSD;
  //
  aNbS=myDS->NumberOfShapesOfTheObject();
  // old shapes
  for (i=1; i<=aNbS; ++i) {
    const TopoDS_Shape& aS=myDS->Shape(i);
    if (aS.ShapeType() != TopAbs_VERTEX){
      continue;
    }
    //
    nVSD=FindSDVertex(i);
    nV=(nVSD) ? nVSD : i;
    const TopoDS_Shape& aVx=myDS->Shape(nV);
    if (!aDMVI.IsBound(aVx)) {
      aDMVI.Bind(aVx, nV);
    }
  }
  // new shapes
  i1=myDS->NumberOfSourceShapes()+1;
  i2=myDS->NumberOfInsertedShapes();
  for (i=i1; i<=i2; ++i) {
    const TopoDS_Shape aS=myDS->Shape(i);//mpv
    if (aS.ShapeType() != TopAbs_VERTEX){
      continue;
    }
    if (!aDMVI.IsBound(aS)) {
      aDMVI.Bind(aS, i);
    }
  }
  //
  // 4. Initialize BoundSortBox on aDMVI
  //
  Handle(Bnd_HArray1OfBox) aHAB;
  Bnd_BoundSortBox aBSB;
  //
  aNbVDS=aDMVI.Extent();
  aHAB=new Bnd_HArray1OfBox(1, aNbVDS);
  //
  aItDMVI.Initialize(aDMVI);
  for (i=1; aItDMVI.More(); aItDMVI.Next(), ++i) {
    Bnd_Box aBox;
    //
    nV=aItDMVI.Value();
    aV=TopoDS::Vertex(aItDMVI.Key());
    aTolV=BRep_Tool::Tolerance(aV);
    aBox.SetGap(aTolV);
    BRepBndLib::Add(aV, aBox);
    aHAB->SetValue(i, aBox);
    //
    aDMIV.Bind(i, aV);
  }
  aBSB.Initialize(aHAB);
  //
  // 5. Compare
  aItDMVFF.Initialize(aDMVFF1);
  for (;  aItDMVFF.More(); aItDMVFF.Next()) {
    Bnd_Box aBoxV;
    //
    const TColStd_ListOfInteger& aLIFF=aItDMVFF.Value();
    aV=TopoDS::Vertex(aItDMVFF.Key());
    //
    aTolV=BRep_Tool::Tolerance(aV);
    aBoxV.SetGap(aTolV);
    BRepBndLib::Add(aV, aBoxV);
    //
    const TColStd_ListOfInteger& aLIVSD=aBSB.Compare(aBoxV);
    aNbVSD=aLIVSD.Extent();
    if (aNbVSD==0) {
      // add new vertex in DS and update map myAloneVertices
      BooleanOperations_AncestorsSeqAndSuccessorsSeq anASSeq;
      //
      myDS->InsertShapeAndAncestorsSuccessors(aV, anASSeq);
      nV=myDS->NumberOfInsertedShapes();
      //
      aIt.Initialize(aLIFF);
      for (; aIt.More(); aIt.Next()) {
        nFx=aIt.Value();
        if (myAloneVertices.Contains(nFx)) {
          TColStd_IndexedMapOfInteger& aMVx=myAloneVertices.ChangeFromKey(nFx);
          aMVx.Add(nV);
        }
        else {
          TColStd_IndexedMapOfInteger aMVx;
          aMVx.Add(nV);
          myAloneVertices.Add(nFx, aMVx);
        }
      }
    }
  }
  // qqf
  {
    Standard_Integer aNbF, aNbAV, nF, k;
    NMTTools_IndexedDataMapOfIndexedMapOfInteger aMAVF;
    //
    aNbF=myAloneVertices.Extent();
    if (aNbF<2) {
      return;
    }
    //
    // 1. fill map Alone Vertex/Face ->  aMAVF
    for (i=1; i<=aNbF; ++i) {
      nF=myAloneVertices.FindKey(i);
      const TColStd_IndexedMapOfInteger& aMAV=myAloneVertices(i);
      aNbAV=aMAV.Extent();
      for(j=1; j<=aNbAV; ++j) {
        nV=aMAV(j);
        if (aMAVF.Contains(nV)) {
          TColStd_IndexedMapOfInteger& aMF=aMAVF.ChangeFromKey(nV);
          aMF.Add(nF);
        }
        else{
          TColStd_IndexedMapOfInteger aMF;
          aMF.Add(nF);
          aMAVF.Add(nV, aMF);
        }
      }
    }
    //
    // 2 Obtain pairs of faces
    aNbAV=aMAVF.Extent();
    for (i=1; i<=aNbAV; ++i) {
      const TColStd_IndexedMapOfInteger& aMF=aMAVF(i);
      aNbF=aMF.Extent();
      for(j=1; j<aNbF; ++j) {
        nF1=aMF(j);
        for(k=j+1; k<=aNbF; ++k) {
          nF2=aMF(k);
          myIP->Add(nF1, nF2, Standard_True, NMTDS_TI_FF);
        }
      }
    }
  }
  // qqt
}
App::DocumentObjectExecReturn *DrawViewSection::execute(void)
{
    App::DocumentObject* link = Source.getValue();
    App::DocumentObject* base = BaseView.getValue();
    if (!link || !base)  {
        Base::Console().Log("INFO - DVS::execute - No Source or Link - creation?\n");
        return DrawView::execute();
    }

    if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))
        return new App::DocumentObjectExecReturn("Source object is not a Part object");
    if (!base->getTypeId().isDerivedFrom(TechDraw::DrawViewPart::getClassTypeId()))
        return new App::DocumentObjectExecReturn("BaseView object is not a DrawViewPart object");

    //Base::Console().Message("TRACE - DVS::execute() - %s/%s\n",getNameInDocument(),Label.getValue());

    const Part::TopoShape &partTopo = static_cast<Part::Feature*>(link)->Shape.getShape();

    if (partTopo.getShape().IsNull())
        return new App::DocumentObjectExecReturn("Linked shape object is empty");

    (void) DrawView::execute();          //make sure Scale is up to date

    gp_Pln pln = getSectionPlane();
    gp_Dir gpNormal = pln.Axis().Direction();
    Base::Vector3d orgPnt = SectionOrigin.getValue();

    Base::BoundBox3d bb = partTopo.getBoundBox();
    if(!isReallyInBox(orgPnt, bb)) {
        Base::Console().Warning("DVS: Section Plane doesn't intersect part in %s\n",getNameInDocument());
        Base::Console().Warning("DVS: Using center of bounding box.\n");
        orgPnt = bb.GetCenter();
        SectionOrigin.setValue(orgPnt);
    }

    // Make the extrusion face
    double dMax = bb.CalcDiagonalLength();
    BRepBuilderAPI_MakeFace mkFace(pln, -dMax,dMax,-dMax,dMax);
    TopoDS_Face aProjFace = mkFace.Face();
    if(aProjFace.IsNull())
        return new App::DocumentObjectExecReturn("DrawViewSection - Projected face is NULL");
    gp_Vec extrudeDir = dMax * gp_Vec(gpNormal);
    TopoDS_Shape prism = BRepPrimAPI_MakePrism(aProjFace, extrudeDir, false, true).Shape();

    // We need to copy the shape to not modify the BRepstructure
    BRepBuilderAPI_Copy BuilderCopy(partTopo.getShape());
    TopoDS_Shape myShape = BuilderCopy.Shape();

    BRepAlgoAPI_Cut mkCut(myShape, prism);
    if (!mkCut.IsDone())
        return new App::DocumentObjectExecReturn("Section cut has failed");

    TopoDS_Shape rawShape = mkCut.Shape();
    Bnd_Box testBox;
    BRepBndLib::Add(rawShape, testBox);
    testBox.SetGap(0.0);
    if (testBox.IsVoid()) {                        //prism & input don't intersect.  rawShape is garbage, don't bother.
        Base::Console().Log("INFO - DVS::execute - prism & input don't intersect\n");
        return DrawView::execute();
    }

    gp_Pnt inputCenter;
    try {
        inputCenter = TechDrawGeometry::findCentroid(rawShape,
                                                     Direction.getValue());
        TopoDS_Shape mirroredShape = TechDrawGeometry::mirrorShape(rawShape,
                                                    inputCenter,
                                                    Scale.getValue());
        geometryObject = buildGeometryObject(mirroredShape,inputCenter);   //this is original shape after cut by section prism

#if MOD_TECHDRAW_HANDLE_FACES
        extractFaces();
#endif //#if MOD_TECHDRAW_HANDLE_FACES
    }
    catch (Standard_Failure) {
        Handle_Standard_Failure e1 = Standard_Failure::Caught();
        Base::Console().Log("LOG - DVS::execute - base shape failed for %s - %s **\n",getNameInDocument(),e1->GetMessageString());
        return new App::DocumentObjectExecReturn(e1->GetMessageString());
    }

    try {
        TopoDS_Compound sectionCompound = findSectionPlaneIntersections(rawShape);
        TopoDS_Shape mirroredSection = TechDrawGeometry::mirrorShape(sectionCompound,
                                                                     inputCenter,
                                                                     Scale.getValue());

        TopoDS_Compound newFaces;
        BRep_Builder builder;
        builder.MakeCompound(newFaces);
        TopExp_Explorer expl(mirroredSection, TopAbs_FACE);
        for (; expl.More(); expl.Next()) {
            const TopoDS_Face& face = TopoDS::Face(expl.Current());
            TopoDS_Face pFace = projectFace(face,
                                            inputCenter,
                                            Direction.getValue());
             if (!pFace.IsNull()) {
                 builder.Add(newFaces,pFace);
             }

        }
        sectionFaces = newFaces;
    }
    catch (Standard_Failure) {
        Handle_Standard_Failure e2 = Standard_Failure::Caught();
        Base::Console().Log("LOG - DVS::execute - failed building section faces for %s - %s **\n",getNameInDocument(),e2->GetMessageString());
        return new App::DocumentObjectExecReturn(e2->GetMessageString());
    }

    return App::DocumentObject::StdReturn;
}
//! get the projected edges with all their new intersections.
std::vector<TopoDS_Edge> DrawProjectSplit::getEdges(TechDrawGeometry::GeometryObject* geometryObject)
{
    const std::vector<TechDrawGeometry::BaseGeom*>& goEdges = geometryObject->getVisibleFaceEdges(true,true);
    std::vector<TechDrawGeometry::BaseGeom*>::const_iterator itEdge = goEdges.begin();
    std::vector<TopoDS_Edge> origEdges;
    for (;itEdge != goEdges.end(); itEdge++) {
        origEdges.push_back((*itEdge)->occEdge);
    }

    std::vector<TopoDS_Edge> faceEdges;
    std::vector<TopoDS_Edge> nonZero;
    for (auto& e:origEdges) {                            //drop any zero edges (shouldn't be any by now!!!)
        if (!DrawUtil::isZeroEdge(e)) {
            nonZero.push_back(e);
        } else {
            Base::Console().Message("INFO - DPS::getEdges found ZeroEdge!\n");
        }
    }
    faceEdges = nonZero;
    origEdges = nonZero;

    //HLR algo does not provide all edge intersections for edge endpoints.
    //need to split long edges touched by Vertex of another edge
    std::vector<splitPoint> splits;
    std::vector<TopoDS_Edge>::iterator itOuter = origEdges.begin();
    int iOuter = 0;
    for (; itOuter != origEdges.end(); ++itOuter, iOuter++) {
        TopoDS_Vertex v1 = TopExp::FirstVertex((*itOuter));
        TopoDS_Vertex v2 = TopExp::LastVertex((*itOuter));
        Bnd_Box sOuter;
        BRepBndLib::Add(*itOuter, sOuter);
        sOuter.SetGap(0.1);
        if (sOuter.IsVoid()) {
            Base::Console().Message("DPS::Extract Faces - outer Bnd_Box is void\n");
            continue;
        }
        if (DrawUtil::isZeroEdge(*itOuter)) {
            Base::Console().Message("DPS::extractFaces - outerEdge: %d is ZeroEdge\n",iOuter);   //this is not finding ZeroEdges
            continue;  //skip zero length edges. shouldn't happen ;)
        }
        int iInner = 0;
        std::vector<TopoDS_Edge>::iterator itInner = faceEdges.begin();
        for (; itInner != faceEdges.end(); ++itInner,iInner++) {
            if (iInner == iOuter) {
                continue;
            }
            if (DrawUtil::isZeroEdge((*itInner))) {
                continue;  //skip zero length edges. shouldn't happen ;)
            }

            Bnd_Box sInner;
            BRepBndLib::Add(*itInner, sInner);
            sInner.SetGap(0.1);
            if (sInner.IsVoid()) {
                Base::Console().Log("INFO - DPS::Extract Faces - inner Bnd_Box is void\n");
                continue;
            }
            if (sOuter.IsOut(sInner)) {      //bboxes of edges don't intersect, don't bother
                continue;
            }

            double param = -1;
            if (isOnEdge((*itInner),v1,param,false)) {
                gp_Pnt pnt1 = BRep_Tool::Pnt(v1);
                splitPoint s1;
                s1.i = iInner;
                s1.v = Base::Vector3d(pnt1.X(),pnt1.Y(),pnt1.Z());
                s1.param = param;
                splits.push_back(s1);
            }
            if (isOnEdge((*itInner),v2,param,false)) {
                gp_Pnt pnt2 = BRep_Tool::Pnt(v2);
                splitPoint s2;
                s2.i = iInner;
                s2.v = Base::Vector3d(pnt2.X(),pnt2.Y(),pnt2.Z());
                s2.param = param;
                splits.push_back(s2);
            }
        } //inner loop
    }   //outer loop

    std::vector<splitPoint> sorted = sortSplits(splits,true);
    auto last = std::unique(sorted.begin(), sorted.end(), DrawProjectSplit::splitEqual);  //duplicates to back
    sorted.erase(last, sorted.end());                         //remove dupls
    std::vector<TopoDS_Edge> newEdges = splitEdges(faceEdges,sorted);

    if (newEdges.empty()) {
        Base::Console().Log("LOG - DPS::extractFaces - no newEdges\n");
    }
    newEdges = removeDuplicateEdges(newEdges);
    return newEdges;
}
Exemple #15
0
//! make faces from the existing edge geometry
void DrawViewPart::extractFaces()
{
    geometryObject->clearFaceGeom();
    const std::vector<TechDrawGeometry::BaseGeom*>& goEdges =
                       geometryObject->getVisibleFaceEdges(SmoothVisible.getValue(),SeamVisible.getValue());
    std::vector<TechDrawGeometry::BaseGeom*>::const_iterator itEdge = goEdges.begin();
    std::vector<TopoDS_Edge> origEdges;
    for (;itEdge != goEdges.end(); itEdge++) {
        origEdges.push_back((*itEdge)->occEdge);
    }


    std::vector<TopoDS_Edge> faceEdges;
    std::vector<TopoDS_Edge> nonZero;
    for (auto& e:origEdges) {                            //drop any zero edges (shouldn't be any by now!!!)
        if (!DrawUtil::isZeroEdge(e)) {
            nonZero.push_back(e);
        } else {
            Base::Console().Message("INFO - DVP::extractFaces for %s found ZeroEdge!\n",getNameInDocument());
        }
    }
    faceEdges = nonZero;
    origEdges = nonZero;

    //HLR algo does not provide all edge intersections for edge endpoints.
    //need to split long edges touched by Vertex of another edge
    std::vector<splitPoint> splits;
    std::vector<TopoDS_Edge>::iterator itOuter = origEdges.begin();
    int iOuter = 0;
    for (; itOuter != origEdges.end(); ++itOuter, iOuter++) {
        TopoDS_Vertex v1 = TopExp::FirstVertex((*itOuter));
        TopoDS_Vertex v2 = TopExp::LastVertex((*itOuter));
        Bnd_Box sOuter;
        BRepBndLib::Add(*itOuter, sOuter);
        sOuter.SetGap(0.1);
        if (sOuter.IsVoid()) {
            Base::Console().Message("DVP::Extract Faces - outer Bnd_Box is void for %s\n",getNameInDocument());
            continue;
        }
        if (DrawUtil::isZeroEdge(*itOuter)) {
            Base::Console().Message("DVP::extractFaces - outerEdge: %d is ZeroEdge\n",iOuter);   //this is not finding ZeroEdges
            continue;  //skip zero length edges. shouldn't happen ;)
        }
        int iInner = 0;
        std::vector<TopoDS_Edge>::iterator itInner = faceEdges.begin();
        for (; itInner != faceEdges.end(); ++itInner,iInner++) {
            if (iInner == iOuter) {
                continue;
            }
            if (DrawUtil::isZeroEdge((*itInner))) {
                continue;  //skip zero length edges. shouldn't happen ;)
            }

            Bnd_Box sInner;
            BRepBndLib::Add(*itInner, sInner);
            sInner.SetGap(0.1);
            if (sInner.IsVoid()) {
                Base::Console().Log("INFO - DVP::Extract Faces - inner Bnd_Box is void for %s\n",getNameInDocument());
                continue;
            }
            if (sOuter.IsOut(sInner)) {      //bboxes of edges don't intersect, don't bother
                continue;
            }

            double param = -1;
            if (DrawProjectSplit::isOnEdge((*itInner),v1,param,false)) {
                gp_Pnt pnt1 = BRep_Tool::Pnt(v1);
                splitPoint s1;
                s1.i = iInner;
                s1.v = Base::Vector3d(pnt1.X(),pnt1.Y(),pnt1.Z());
                s1.param = param;
                splits.push_back(s1);
            }
            if (DrawProjectSplit::isOnEdge((*itInner),v2,param,false)) {
                gp_Pnt pnt2 = BRep_Tool::Pnt(v2);
                splitPoint s2;
                s2.i = iInner;
                s2.v = Base::Vector3d(pnt2.X(),pnt2.Y(),pnt2.Z());
                s2.param = param;
                splits.push_back(s2);
            }
        } //inner loop
    }   //outer loop

    std::vector<splitPoint> sorted = DrawProjectSplit::sortSplits(splits,true);
    auto last = std::unique(sorted.begin(), sorted.end(), DrawProjectSplit::splitEqual);  //duplicates to back
    sorted.erase(last, sorted.end());                         //remove dupl splits
    std::vector<TopoDS_Edge> newEdges = DrawProjectSplit::splitEdges(faceEdges,sorted);

    if (newEdges.empty()) {
        Base::Console().Log("LOG - DVP::extractFaces - no newEdges\n");
        return;
    }

    newEdges = DrawProjectSplit::removeDuplicateEdges(newEdges);

//find all the wires in the pile of faceEdges
    EdgeWalker ew;
    ew.loadEdges(newEdges);
    bool success = ew.perform();
    if (!success) {
        Base::Console().Warning("DVP::extractFaces - input is not planar graph. No face detection\n");
        return;
    }
    std::vector<TopoDS_Wire> fw = ew.getResultNoDups();

    std::vector<TopoDS_Wire> sortedWires = ew.sortStrip(fw,true);

    std::vector<TopoDS_Wire>::iterator itWire = sortedWires.begin();
    for (; itWire != sortedWires.end(); itWire++) {
        //version 1: 1 wire/face - no voids in face
        TechDrawGeometry::Face* f = new TechDrawGeometry::Face();
        const TopoDS_Wire& wire = (*itWire);
        TechDrawGeometry::Wire* w = new TechDrawGeometry::Wire(wire);
        f->wires.push_back(w);
        geometryObject->addFaceGeom(f);
    }
}
App::DocumentObjectExecReturn *DrawViewDetail::execute(void)
{
    if (!keepUpdated()) {
        return App::DocumentObject::StdReturn;
    }

    App::DocumentObject* baseObj = BaseView.getValue();
    if (!baseObj)  {
        Base::Console().Log("INFO - DVD::execute - No BaseView - creation?\n");
        return DrawView::execute();
    }

    DrawViewPart* dvp = nullptr;
    if (!baseObj->getTypeId().isDerivedFrom(TechDraw::DrawViewPart::getClassTypeId())) {
        return new App::DocumentObjectExecReturn("BaseView object is not a DrawViewPart object");
    } else {
        dvp = static_cast<DrawViewPart*>(baseObj);
    }

    TopoDS_Shape shape = dvp->getSourceShapeFused();
    if (shape.IsNull()) {
        return new App::DocumentObjectExecReturn("DVD - Linked shape object is invalid");
    }

    Base::Vector3d anchor = AnchorPoint.getValue();    //this is a 2D point (in unrotated coords)
    Base::Vector3d dirDetail = dvp->Direction.getValue();

    double shapeRotate = dvp->Rotation.getValue();                      //degrees CW?
    if (dvp->isDerivedFrom(TechDraw::DrawProjGroupItem::getClassTypeId())) {
        DrawProjGroupItem* dpgi= static_cast<TechDraw::DrawProjGroupItem*>(dvp);
        shapeRotate += dpgi->getRotateAngle() * 180.0/M_PI;            // to degrees from radians
    }
 
    double radius = getFudgeRadius();
    double scale = getScale();

    BRepBuilderAPI_Copy BuilderCopy(shape);
    TopoDS_Shape myShape = BuilderCopy.Shape();

    //rotate the copied shape to match orientation of BaseView and center it on origin
    gp_Pnt gpCenter = TechDrawGeometry::findCentroid(myShape,           //centre of unrotated shape
                                                     dirDetail);
    Base::Vector3d shapeCenter = Base::Vector3d(gpCenter.X(),gpCenter.Y(),gpCenter.Z());
    gp_Ax2 viewAxis = getViewAxis(shapeCenter, dirDetail, false);
    myShape = TechDrawGeometry::rotateShape(myShape,                    //rotate to match Base shape
                                            viewAxis,
                                            -shapeRotate);
    myShape = TechDrawGeometry::moveShape(myShape,                     //centre on origin
                                          -shapeCenter);
//    shapeCenter = Base::Vector3d(0.0,0.0,0.0);
    gpCenter = TechDrawGeometry::findCentroid(myShape,
                                              dirDetail);
    shapeCenter = Base::Vector3d(gpCenter.X(),gpCenter.Y(),gpCenter.Z());
   
    Bnd_Box bbxSource;
    bbxSource.SetGap(0.0);
    BRepBndLib::Add(myShape, bbxSource);
    double diag = sqrt(bbxSource.SquareExtent());

    Base::Vector3d extentFar,extentNear;
    extentFar = shapeCenter + dirDetail * diag;
    extentNear = shapeCenter + dirDetail * diag * -1.0;

    anchor = Base::Vector3d(anchor.x,anchor.y, 0.0);
    viewAxis = getViewAxis(shapeCenter, dirDetail, false);                //change view axis to (0,0,0)
    Base::Vector3d offsetCenter3D = DrawUtil::toR3(viewAxis, anchor);     //displacement in R3
    Base::Vector3d stdZ(0.0,0.0,1.0);
    if (DrawUtil::checkParallel(dirDetail,stdZ)) {
        extentNear = extentNear + offsetCenter3D;
    } else {
        extentNear = extentNear - offsetCenter3D;
    }

    gp_Dir cylDir(dirDetail.x,dirDetail.y,dirDetail.z);
    gp_Pnt cylPoint(extentNear.x,extentNear.y,extentNear.z);
    gp_Ax2 cylAxis(cylPoint,cylDir);

    BRepPrimAPI_MakeCylinder mkCyl(cylAxis, radius, (extentFar-extentNear).Length());
    TopoDS_Shell sh = mkCyl.Cylinder().Shell();
    BRepBuilderAPI_MakeSolid mkSol(sh);
    TopoDS_Solid tool = mkSol.Solid();

    BRepAlgoAPI_Common mkCommon(myShape,tool);
    if (!mkCommon.IsDone()) {
        Base::Console().Log("DVD::execute - mkCommon not done\n");
        return new App::DocumentObjectExecReturn("DVD::execute - mkCommon not done");
    }
    if (mkCommon.Shape().IsNull()) {
        Base::Console().Log("DVD::execute - mkCommon.Shape is Null\n");
        return new App::DocumentObjectExecReturn("DVD::execute - mkCommon.Shape is Null");
    }

    //Did we get a solid?
    TopExp_Explorer xp;
    xp.Init(mkCommon.Shape(),TopAbs_SOLID);
    if (!(xp.More() == Standard_True)) {
        Base::Console().Message("DVD::execute - mkCommon.Shape is not a solid!\n");
    }
    TopoDS_Shape detail = mkCommon.Shape();
    Bnd_Box testBox;
    testBox.SetGap(0.0);
    BRepBndLib::Add(detail, testBox);
    if (testBox.IsVoid()) {
        Base::Console().Message("DrawViewDetail - detail area contains no geometry\n");
        return new App::DocumentObjectExecReturn("DVDetail - detail area contains no geometry");
    }

//for debugging show compound instead of common
//    BRep_Builder builder;
//    TopoDS_Compound Comp;
//    builder.MakeCompound(Comp);
//    builder.Add(Comp, tool);
//    builder.Add(Comp, myShape);

    gp_Pnt inputCenter;
    try {
        inputCenter = TechDrawGeometry::findCentroid(tool,
                                                     Direction.getValue());
        TopoDS_Shape mirroredShape = TechDrawGeometry::mirrorShape(detail,
                                                    inputCenter,
                                                    scale);
        viewAxis = getViewAxis(Base::Vector3d(inputCenter.X(),inputCenter.Y(),inputCenter.Z()),Direction.getValue());
        if (!DrawUtil::fpCompare(Rotation.getValue(),0.0)) {
            mirroredShape = TechDrawGeometry::rotateShape(mirroredShape,
                                                          viewAxis,
                                                          Rotation.getValue());         //degrees cw?
        }
        geometryObject = buildGeometryObject(mirroredShape,viewAxis);
        geometryObject->pruneVertexGeom(Base::Vector3d(0.0,0.0,0.0),Radius.getValue() * scale);      //remove vertices beyond clipradius

#if MOD_TECHDRAW_HANDLE_FACES
    if (handleFaces()) {
        try {
            extractFaces();
        }
        catch (Standard_Failure& e4) {
            Base::Console().Log("LOG - DVD::execute - extractFaces failed for %s - %s **\n",getNameInDocument(),e4.GetMessageString());
            return new App::DocumentObjectExecReturn(e4.GetMessageString());
        }
    }

#endif //#if MOD_TECHDRAW_HANDLE_FACES
    }
    catch (Standard_Failure& e1) {
        Base::Console().Log("LOG - DVD::execute - base shape failed for %s - %s **\n",getNameInDocument(),e1.GetMessageString());
        return new App::DocumentObjectExecReturn(e1.GetMessageString());
    }

    requestPaint();
    dvp->requestPaint();

    return App::DocumentObject::StdReturn;
}
std::vector<TopoDS_Wire> EdgeWalker::sortStrip(std::vector<TopoDS_Wire> fw, bool includeBiggest)
{
    std::vector<TopoDS_Wire> sortedWires = sortWiresBySize(fw,false);           //biggest 1st
    if (!sortedWires.size()) {
        Base::Console().Log("INFO - DVP::extractFaces - no sorted Wires!\n");
        return sortedWires;                                     // might happen in the middle of changes?
    }

    //find the largest wire (OuterWire of graph) using bbox
    Bnd_Box bigBox;
    if (sortedWires.size() && !sortedWires.front().IsNull()) {
        BRepBndLib::Add(sortedWires.front(), bigBox);
        bigBox.SetGap(0.0);
    }
    std::vector<std::size_t> toBeChecked;
    std::vector<TopoDS_Wire>::iterator it = sortedWires.begin() + 1;
    for (; it != sortedWires.end(); it++) {
        if (!(*it).IsNull()) {
            Bnd_Box littleBox;
            BRepBndLib::Add((*it), littleBox);
            littleBox.SetGap(0.0);
            if (bigBox.SquareExtent() > littleBox.SquareExtent()) {
                break;
            } else {
                auto position = std::distance( sortedWires.begin(), it );    //get an index from iterator
                toBeChecked.push_back(position);
            }
        }
    }

    //unfortuneately, faces can have same bbox, but not be same size.  need to weed out biggest
    if (toBeChecked.size() == 0) {
        //nobody had as big a bbox as first element of sortedWires
        if (!includeBiggest) {
            sortedWires.erase(sortedWires.begin());
        }
    } else if (toBeChecked.size() > 0) {
        BRepBuilderAPI_MakeFace mkFace(sortedWires.front());
        const TopoDS_Face& face = mkFace.Face();
        GProp_GProps props;
        BRepGProp::SurfaceProperties(face, props);
        double bigArea = props.Mass();
        unsigned int bigIndex = 0;
        for (unsigned int idx = 0; idx < toBeChecked.size(); idx++) {
            int iCheck = toBeChecked.at(idx);
            BRepBuilderAPI_MakeFace mkFace2(sortedWires.at(iCheck));
            const TopoDS_Face& face2 = mkFace2.Face();
            BRepGProp::SurfaceProperties(face2, props);
            double area = props.Mass();
            if (area > bigArea) {
                bigArea = area;
                bigIndex = iCheck;
            }
        }
        if (bigIndex == 0) {                    //first wire is the biggest
            if (!includeBiggest) {
                sortedWires.erase(sortedWires.begin());
            }
        } else {                                  //first wire is not the biggest
            TopoDS_Wire bigWire = *(sortedWires.begin() + bigIndex);
            sortedWires.erase(sortedWires.begin() + bigIndex);
            if (includeBiggest) {
                sortedWires.insert(sortedWires.begin(),bigWire);               //doesn't happen often
            }
        }

    }
    return sortedWires;
}
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;
}