void ViewProviderFemConstraintFixed::updateData(const App::Property* prop)
{
    // Gets called whenever a property of the attached object changes
    Fem::ConstraintFixed* pcConstraint = static_cast<Fem::ConstraintFixed*>(this->getObject());

#ifdef USE_MULTIPLE_COPY
    if (pShapeSep->getNumChildren() == 0) {
        // Set up the nodes
        SoMultipleCopy* cp = new SoMultipleCopy();
        cp->matrix.setNum(0);
        cp->addChild((SoNode*)createFixed(HEIGHT, WIDTH));
        pShapeSep->addChild(cp);
    }
#endif

    if (strcmp(prop->getName(),"Points") == 0) {
        const std::vector<Base::Vector3d>& points = pcConstraint->Points.getValues();
        const std::vector<Base::Vector3d>& normals = pcConstraint->Normals.getValues();
        if (points.size() != normals.size())
            return;
        std::vector<Base::Vector3d>::const_iterator n = normals.begin();

#ifdef USE_MULTIPLE_COPY
        SoMultipleCopy* cp = static_cast<SoMultipleCopy*>(pShapeSep->getChild(0));
        cp->matrix.setNum(points.size());
        SbMatrix* matrices = cp->matrix.startEditing();
        int idx = 0;
#else
        // Note: Points and Normals are always updated together
        pShapeSep->removeAllChildren();
#endif

        for (std::vector<Base::Vector3d>::const_iterator p = points.begin(); p != points.end(); p++) {
            SbVec3f base(p->x, p->y, p->z);
            SbVec3f dir(n->x, n->y, n->z);
            SbRotation rot(SbVec3f(0,-1,0), dir);
#ifdef USE_MULTIPLE_COPY
            SbMatrix m;
            m.setTransform(base, rot, SbVec3f(1,1,1));
            matrices[idx] = m;
            idx++;
#else
            SoSeparator* sep = new SoSeparator();
            createPlacement(sep, base, rot);
            createFixed(sep, HEIGHT, WIDTH);
            pShapeSep->addChild(sep);
#endif
            n++;
        }
#ifdef USE_MULTIPLE_COPY
        cp->matrix.finishEditing();
#endif
    }

    ViewProviderFemConstraint::updateData(prop);
}
void ViewProviderFemConstraintFluidBoundary::updateData(const App::Property* prop)
{
    // Gets called whenever a property of the attached object changes
    Fem::ConstraintFluidBoundary* pcConstraint = static_cast<Fem::ConstraintFluidBoundary*>(this->getObject());
    float scaledwidth = WIDTH * pcConstraint->Scale.getValue(); //OvG: Calculate scaled values once only
    float scaledheight = HEIGHT * pcConstraint->Scale.getValue();

    float scaledheadradius = ARROWHEADRADIUS * pcConstraint->Scale.getValue(); //OvG: Calculate scaled values once only
    float scaledlength = ARROWLENGTH * pcConstraint->Scale.getValue();

    std::string boundaryType = pcConstraint->BoundaryType.getValueAsString();
    if (strcmp(prop->getName(),"BoundaryType") == 0)
    {
        if (boundaryType == "wall")
        {
            FaceColor.setValue(0.0,1.0,1.0);
        }
        else if (boundaryType == "interface")
        {
            FaceColor.setValue(0.0,1.0,0.0);
        }
        else if (boundaryType == "freestream")
        {
            FaceColor.setValue(1.0,1.0,0.0);
        }
        else if(boundaryType == "inlet")
        {
            FaceColor.setValue(1.0,0.0,0.0);
        }
        else //(boundaryType == "outlet")
        {
            FaceColor.setValue(0.0,0.0,1.0);
        }
    }
        
    if (boundaryType == "inlet" || boundaryType == "outlet"){
#ifdef USE_MULTIPLE_COPY
        //OvG: need access to cp for scaling
        SoMultipleCopy* cp = new SoMultipleCopy();
        if (pShapeSep->getNumChildren() == 0) {
            // Set up the nodes
            cp->matrix.setNum(0);
            cp->addChild((SoNode*)createArrow(scaledlength , scaledheadradius)); //OvG: Scaling
            pShapeSep->addChild(cp);
        }
#endif

        if (strcmp(prop->getName(),"Points") == 0) {
            const std::vector<Base::Vector3d>& points = pcConstraint->Points.getValues();

#ifdef USE_MULTIPLE_COPY
            cp = static_cast<SoMultipleCopy*>(pShapeSep->getChild(0));
            cp->matrix.setNum(points.size());
            SbMatrix* matrices = cp->matrix.startEditing();
            int idx = 0;
#else
            // Redraw all arrows
            pShapeSep->removeAllChildren();
#endif
            // This should always point outside of the solid
            Base::Vector3d normal = pcConstraint->NormalDirection.getValue();

            // Get default direction (on first call to method)
            Base::Vector3d forceDirection = pcConstraint->DirectionVector.getValue();
            if (forceDirection.Length() < Precision::Confusion())
                forceDirection = normal;

            SbVec3f dir(forceDirection.x, forceDirection.y, forceDirection.z);
            SbRotation rot(SbVec3f(0,1,0), dir);

            for (std::vector<Base::Vector3d>::const_iterator p = points.begin(); p != points.end(); p++) {
                SbVec3f base(p->x, p->y, p->z);
                if (forceDirection.GetAngle(normal) < M_PI_2) // Move arrow so it doesn't disappear inside the solid
                    base = base + dir * scaledlength; //OvG: Scaling
#ifdef USE_MULTIPLE_COPY
                SbMatrix m;
                m.setTransform(base, rot, SbVec3f(1,1,1));
                matrices[idx] = m;
                idx++;
#else
                SoSeparator* sep = new SoSeparator();
                createPlacement(sep, base, rot);
                createArrow(sep, scaledlength, scaledheadradius); //OvG: Scaling
                pShapeSep->addChild(sep);
#endif
            }
#ifdef USE_MULTIPLE_COPY
            cp->matrix.finishEditing();
#endif
        }
        else if (strcmp(prop->getName(),"DirectionVector") == 0) { // Note: "Reversed" also triggers "DirectionVector"
            // Re-orient all arrows
            Base::Vector3d normal = pcConstraint->NormalDirection.getValue();
            Base::Vector3d forceDirection = pcConstraint->DirectionVector.getValue();
            if (forceDirection.Length() < Precision::Confusion())
                forceDirection = normal;

            SbVec3f dir(forceDirection.x, forceDirection.y, forceDirection.z);
            SbRotation rot(SbVec3f(0,1,0), dir);

            const std::vector<Base::Vector3d>& points = pcConstraint->Points.getValues();

#ifdef USE_MULTIPLE_COPY
            SoMultipleCopy* cp = static_cast<SoMultipleCopy*>(pShapeSep->getChild(0));
            cp->matrix.setNum(points.size());
            SbMatrix* matrices = cp->matrix.startEditing();
#endif
            int idx = 0;

            for (std::vector<Base::Vector3d>::const_iterator p = points.begin(); p != points.end(); p++) {
                SbVec3f base(p->x, p->y, p->z);
                if (forceDirection.GetAngle(normal) < M_PI_2)
                    base = base + dir * scaledlength; //OvG: Scaling
#ifdef USE_MULTIPLE_COPY
                SbMatrix m;
                m.setTransform(base, rot, SbVec3f(1,1,1));
                matrices[idx] = m;
#else
                SoSeparator* sep = static_cast<SoSeparator*>(pShapeSep->getChild(idx));
                updatePlacement(sep, 0, base, rot);
                updateArrow(sep, 2, scaledlength, scaledheadradius); //OvG: Scaling
#endif
                idx++;
            }
#ifdef USE_MULTIPLE_COPY
            cp->matrix.finishEditing();
#endif
        }
    }
    else{// not inlet or outlet boundary type

#ifdef USE_MULTIPLE_COPY
        //OvG: always need access to cp for scaling
        SoMultipleCopy* cp = new SoMultipleCopy();
        if (pShapeSep->getNumChildren() == 0) {
            // Set up the nodes
            cp->matrix.setNum(0);
            cp->addChild((SoNode*)createFixed(scaledheight, scaledwidth)); //OvG: Scaling
            pShapeSep->addChild(cp);
        }
#endif

        if (strcmp(prop->getName(),"Points") == 0) {
            const std::vector<Base::Vector3d>& points = pcConstraint->Points.getValues();
            const std::vector<Base::Vector3d>& normals = pcConstraint->Normals.getValues();
            if (points.size() != normals.size())
                return;
            std::vector<Base::Vector3d>::const_iterator n = normals.begin();

#ifdef USE_MULTIPLE_COPY
            cp = static_cast<SoMultipleCopy*>(pShapeSep->getChild(0));
            cp->matrix.setNum(points.size());
            SbMatrix* matrices = cp->matrix.startEditing();
            int idx = 0;
#else
            // Note: Points and Normals are always updated together
            pShapeSep->removeAllChildren();
#endif

            for (std::vector<Base::Vector3d>::const_iterator p = points.begin(); p != points.end(); p++) {
                SbVec3f base(p->x, p->y, p->z);
                SbVec3f dir(n->x, n->y, n->z);
                SbRotation rot(SbVec3f(0,-1,0), dir);
#ifdef USE_MULTIPLE_COPY
                SbMatrix m;
                m.setTransform(base, rot, SbVec3f(1,1,1));
                matrices[idx] = m;
                idx++;
#else
                SoSeparator* sep = new SoSeparator();
                createPlacement(sep, base, rot);
                createFixed(sep, scaledheight, scaledwidth); //OvG: Scaling
                pShapeSep->addChild(sep);
#endif
                n++;
            }
#ifdef USE_MULTIPLE_COPY
            cp->matrix.finishEditing();
#endif
        }
    }

    ViewProviderFemConstraint::updateData(prop);
}
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 ViewProviderFemConstraintPressure::updateData(const App::Property* prop)
{
    // Gets called whenever a property of the attached object changes
    Fem::ConstraintPressure* pcConstraint = static_cast<Fem::ConstraintPressure*>(this->getObject());
    float scaledheadradius = ARROWHEADRADIUS * pcConstraint->Scale.getValue(); //OvG: Calculate scaled values once only
    float scaledlength = ARROWLENGTH * pcConstraint->Scale.getValue();

#ifdef USE_MULTIPLE_COPY
    //OvG: always need access to cp for scaling
    SoMultipleCopy* cp = new SoMultipleCopy();
    if (pShapeSep->getNumChildren() == 0) {
        // Set up the nodes
        cp->matrix.setNum(0);
        cp->addChild((SoNode*)createArrow(scaledlength , scaledheadradius)); //OvG: Scaling
        pShapeSep->addChild(cp);
    }
#endif

    if (strcmp(prop->getName(),"Points") == 0) {
        const std::vector<Base::Vector3d>& points = pcConstraint->Points.getValues();
        const std::vector<Base::Vector3d>& normals = pcConstraint->Normals.getValues();
        if (points.size() != normals.size()) {
            return;
        }
        std::vector<Base::Vector3d>::const_iterator n = normals.begin();

#ifdef USE_MULTIPLE_COPY      
        cp = static_cast<SoMultipleCopy*>(pShapeSep->getChild(0)); //OvG: Use top cp
        cp->matrix.setNum(points.size());
        SbMatrix* matrices = cp->matrix.startEditing();
        int idx = 0;
#else
        // Redraw all arrows
        pShapeSep->removeAllChildren();
#endif

        for (std::vector<Base::Vector3d>::const_iterator p = points.begin(); p != points.end(); p++) {
            SbVec3f base(p->x, p->y, p->z);
            SbVec3f dir(n->x, n->y, n->z);
            double rev;
            if (pcConstraint->Reversed.getValue()) {
                base = base + dir * scaledlength; //OvG: Scaling
                rev = 1;
            } else {
                rev = -1;
            }
            SbRotation rot(SbVec3f(0, rev, 0), dir);
#ifdef USE_MULTIPLE_COPY
            SbMatrix m;
            m.setTransform(base, rot, SbVec3f(1,1,1));
            matrices[idx] = m;
            idx++;
#else
            SoSeparator* sep = new SoSeparator();
            createPlacement(sep, base, rot);
            createArrow(sep, scaledlength , scaledheadradius); //OvG: Scaling
            pShapeSep->addChild(sep);
#endif
            n++;
        }
#ifdef USE_MULTIPLE_COPY
        cp->matrix.finishEditing();
#endif
    }

    ViewProviderFemConstraint::updateData(prop);
}