From 56ab9d8cb9eb165d1ecb7adca2aff891086d8bd9 Mon Sep 17 00:00:00 2001 From: Abdullah Tahiri Date: Mon, 13 Mar 2017 22:32:54 +0100 Subject: [PATCH] Sketcher: Curvature comb general representation scale fix --- src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 698 +++++++++++--------- 1 file changed, 371 insertions(+), 327 deletions(-) diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index b04e748eb2..b85855e4e5 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -3213,10 +3213,14 @@ void ViewProviderSketch::draw(bool temp /*=false*/, bool rebuildinformationlayer ParameterGrp::handle hGrpsk = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Sketcher/General"); + std::vector bsplineGeoIds; + + double combrepscale = 0; + // end information layer int GeoId = 0; - + int stdcountsegments = hGrp->GetInt("SegmentsPerGeometry", 50); // RootPoint @@ -3410,6 +3414,7 @@ void ViewProviderSketch::draw(bool temp /*=false*/, bool rebuildinformationlayer Points.push_back(center); } else if ((*it)->getTypeId() == Part::GeomBSplineCurve::getClassTypeId()) { // add a bspline + bsplineGeoIds.push_back(GeoId); const Part::GeomBSplineCurve *spline = static_cast(*it); Handle_Geom_BSplineCurve curve = Handle_Geom_BSplineCurve::DownCast(spline->handle()); @@ -3439,178 +3444,34 @@ void ViewProviderSketch::draw(bool temp /*=false*/, bool rebuildinformationlayer edit->CurvIdToGeoId.push_back(GeoId); Points.push_back(startp); Points.push_back(endp); - - //---------------------------------------------------------- - // geometry information layer - - // polynom degree -------------------------------------------------------- + + //*************************************************************************************************************** + // global information gathering for geometry information layer + std::vector poles = spline->getPoles(); - + Base::Vector3d midp = Base::Vector3d(0,0,0); - + for (std::vector::iterator it = poles.begin(); it != poles.end(); ++it) { midp += (*it); } - - midp /= poles.size(); - - if(rebuildinformationlayer) { - SoSwitch *sw = new SoSwitch(); - - sw->whichChild = hGrpsk->GetBool("BSplineDegreeVisible", true)?SO_SWITCH_ALL:SO_SWITCH_NONE; - - SoSeparator *sep = new SoSeparator(); - sep->ref(); - // no caching for fluctuand data structures - sep->renderCaching = SoSeparator::OFF; - - // every information visual node gets its own material for to-be-implemented preselection and selection - SoMaterial *mat = new SoMaterial; - mat->ref(); - mat->diffuseColor = InformationColor; - - SoTranslation *translate = new SoTranslation; - - translate->translation.setValue(midp.x,midp.y,zInfo); - - SoFont *font = new SoFont; - font->name.setValue("Helvetica"); - font->size.setValue(fontSize); - - SoText2 *degreetext = new SoText2; - degreetext->string = SbString(spline->getDegree()); - - sep->addChild(translate); - sep->addChild(mat); - sep->addChild(font); - sep->addChild(degreetext); - - sw->addChild(sep); - - edit->infoGroup->addChild(sw); - sep->unref(); - mat->unref(); - } - else { - SoSwitch *sw = static_cast(edit->infoGroup->getChild(currentInfoNode)); - - if(visibleInformationChanged) - sw->whichChild = hGrpsk->GetBool("BSplineDegreeVisible", true)?SO_SWITCH_ALL:SO_SWITCH_NONE; - - SoSeparator *sep = static_cast(sw->getChild(0)); - - static_cast(sep->getChild(GEOINFO_BSPLINE_DEGREE_POS))->translation.setValue(midp.x,midp.y,zInfo); - - static_cast(sep->getChild(GEOINFO_BSPLINE_DEGREE_TEXT))->string = SbString(spline->getDegree()); - } - - currentInfoNode++; // switch to next node - - // control polygon -------------------------------------------------------- - if(rebuildinformationlayer) { - SoSwitch *sw = new SoSwitch(); - - sw->whichChild = hGrpsk->GetBool("BSplineControlPolygonVisible", true)?SO_SWITCH_ALL:SO_SWITCH_NONE; - - SoSeparator *sep = new SoSeparator(); - sep->ref(); - // no caching for fluctuand data structures - sep->renderCaching = SoSeparator::OFF; - - // every information visual node gets its own material for to-be-implemented preselection and selection - SoMaterial *mat = new SoMaterial; - mat->ref(); - mat->diffuseColor = InformationColor; - - SoLineSet *lineset = new SoLineSet; - - SoCoordinate3 *coords = new SoCoordinate3; - - if(spline->isPeriodic()) { - coords->point.setNum(poles.size()+1); - } - else { - coords->point.setNum(poles.size()); - } - - SbVec3f *vts = coords->point.startEditing(); - - int i=0; - for (std::vector::iterator it = poles.begin(); it != poles.end(); ++it, i++) { - vts[i].setValue((*it).x,(*it).y,zInfo); - } - - if(spline->isPeriodic()) { - vts[poles.size()].setValue(poles[0].x,poles[0].y,zInfo); - } - - coords->point.finishEditing(); - - sep->addChild(mat); - sep->addChild(coords); - sep->addChild(lineset); - - sw->addChild(sep); - - edit->infoGroup->addChild(sw); - sep->unref(); - mat->unref(); - } - else { - SoSwitch *sw = static_cast(edit->infoGroup->getChild(currentInfoNode)); - - if(visibleInformationChanged) - sw->whichChild = hGrpsk->GetBool("BSplineControlPolygonVisible", true)?SO_SWITCH_ALL:SO_SWITCH_NONE; - - SoSeparator *sep = static_cast(sw->getChild(0)); - - SoCoordinate3 *coords = static_cast(sep->getChild(GEOINFO_BSPLINE_POLYGON)); - - if(spline->isPeriodic()) { - coords->point.setNum(poles.size()+1); - } - else { - coords->point.setNum(poles.size()); - } - - SbVec3f *vts = coords->point.startEditing(); - - int i=0; - for (std::vector::iterator it = poles.begin(); it != poles.end(); ++it, i++) { - vts[i].setValue((*it).x,(*it).y,zInfo); - } - - if(spline->isPeriodic()) { - vts[poles.size()].setValue(poles[0].x,poles[0].y,zInfo); - } - - coords->point.finishEditing(); - - } - currentInfoNode++; // switch to next node - // curvature graph -------------------------------------------------------- - - // reimplementation of python source: - // https://github.com/tomate44/CurvesWB/blob/master/ParametricComb.py - // by FreeCAD user Chris_G + midp /= poles.size(); double firstparam = spline->getFirstParameter(); double lastparam = spline->getLastParameter(); const int ndiv = poles.size()>4?poles.size()*16:64; double step = (lastparam - firstparam ) / (ndiv -1); - + std::vector paramlist(ndiv); std::vector pointatcurvelist(ndiv); std::vector curvaturelist(ndiv); std::vector normallist(ndiv); + double maxcurv = 0; - double maxdisttocenterofmass = 0; - //double length = spline->length(firstparam,lastparam); - for(int i = 0; i < ndiv; i++) { paramlist[i] = firstparam + i * step; pointatcurvelist[i] = spline->pointAtParameter(paramlist[i]); @@ -3619,13 +3480,6 @@ void ViewProviderSketch::draw(bool temp /*=false*/, bool rebuildinformationlayer if(curvaturelist[i] > maxcurv) maxcurv = curvaturelist[i]; - try { - spline->normalAt(paramlist[i],normallist[i]); - } - catch(Base::Exception) { - normallist[i] = Base::Vector3d(0,0,0); - } - double temp = ( pointatcurvelist[i] - midp ).Length(); if( temp > maxdisttocenterofmass ) @@ -3633,174 +3487,11 @@ void ViewProviderSketch::draw(bool temp /*=false*/, bool rebuildinformationlayer } - double repscale; - repscale = ( 0.5 * maxdisttocenterofmass ) / maxcurv; // just a factor to make it reasonably visible - //repscale = ( 0.5 * length ) / maxcurv; // this is Chris_G's original - - std::vector pointatcomblist(ndiv); - - for(int i = 0; i < ndiv; i++) { - pointatcomblist[i] = pointatcurvelist[i] - repscale * curvaturelist[i] * normallist[i]; - } - - if(rebuildinformationlayer) { - SoSwitch *sw = new SoSwitch(); - - sw->whichChild = hGrpsk->GetBool("BSplineCombVisible", true)?SO_SWITCH_ALL:SO_SWITCH_NONE; - - SoSeparator *sep = new SoSeparator(); - sep->ref(); - // no caching for fluctuand data structures - sep->renderCaching = SoSeparator::OFF; - - // every information visual node gets its own material for to-be-implemented preselection and selection - SoMaterial *mat = new SoMaterial; - mat->ref(); - mat->diffuseColor = InformationColor; - - SoLineSet *lineset = new SoLineSet; - - SoCoordinate3 *coords = new SoCoordinate3; - - coords->point.setNum(3*ndiv); // 2*ndiv +1 points of ndiv separate segments + ndiv points for last segment - lineset->numVertices.setNum(ndiv+1); // ndiv separate segments of radials + 1 segment connecting at comb end - - int32_t *index = lineset->numVertices.startEditing(); - SbVec3f *vts = coords->point.startEditing(); - - for(int i = 0; i < ndiv; i++) { - vts[2*i].setValue(pointatcurvelist[i].x, pointatcurvelist[i].y, zInfo); // radials - vts[2*i+1].setValue(pointatcomblist[i].x, pointatcomblist[i].y, zInfo); - index[i] = 2; - - vts[2*ndiv+i].setValue(pointatcomblist[i].x, pointatcomblist[i].y, zInfo); // comb endpoint closing segment - } - - index[ndiv] = ndiv; // comb endpoint closing segment - - coords->point.finishEditing(); - lineset->numVertices.finishEditing(); - - sep->addChild(mat); - sep->addChild(coords); - sep->addChild(lineset); - - sw->addChild(sep); - - edit->infoGroup->addChild(sw); - sep->unref(); - mat->unref(); - } - else { - SoSwitch *sw = static_cast(edit->infoGroup->getChild(currentInfoNode)); - - if(visibleInformationChanged) - sw->whichChild = hGrpsk->GetBool("BSplineCombVisible", true)?SO_SWITCH_ALL:SO_SWITCH_NONE; - - SoSeparator *sep = static_cast(sw->getChild(0)); - - SoCoordinate3 *coords = static_cast(sep->getChild(GEOINFO_BSPLINE_POLYGON)); - - SoLineSet *lineset = static_cast(sep->getChild(GEOINFO_BSPLINE_POLYGON+1)); - - coords->point.setNum(3*ndiv); // 2*ndiv +1 points of ndiv separate segments + ndiv points for last segment - lineset->numVertices.setNum(ndiv+1); // ndiv separate segments of radials + 1 segment connecting at comb end - - int32_t *index = lineset->numVertices.startEditing(); - SbVec3f *vts = coords->point.startEditing(); - - for(int i = 0; i < ndiv; i++) { - vts[2*i].setValue(pointatcurvelist[i].x, pointatcurvelist[i].y, zInfo); // radials - vts[2*i+1].setValue(pointatcomblist[i].x, pointatcomblist[i].y, zInfo); - index[i] = 2; - - vts[2*ndiv+i].setValue(pointatcomblist[i].x, pointatcomblist[i].y, zInfo); // comb endpoint closing segment - } - - index[ndiv] = ndiv; // comb endpoint closing segment - - coords->point.finishEditing(); - lineset->numVertices.finishEditing(); - - } - - currentInfoNode++; // switch to next node - - // knot multiplicity -------------------------------------------------------- - std::vector knots = spline->getKnots(); - std::vector mult = spline->getMultiplicities(); - - std::vector::const_iterator itk; - std::vector::const_iterator itm; - - - if(rebuildinformationlayer) { - - for( itk = knots.begin(), itm = mult.begin(); itk != knots.end() && itm != mult.end(); ++itk, ++itm) { - - SoSwitch *sw = new SoSwitch(); - - sw->whichChild = hGrpsk->GetBool("BSplineKnotMultiplicityVisible", true)?SO_SWITCH_ALL:SO_SWITCH_NONE; - - SoSeparator *sep = new SoSeparator(); - sep->ref(); - // no caching for fluctuand data structures - sep->renderCaching = SoSeparator::OFF; - - // every information visual node gets its own material for to-be-implemented preselection and selection - SoMaterial *mat = new SoMaterial; - mat->ref(); - mat->diffuseColor = InformationColor; - - SoTranslation *translate = new SoTranslation; - - Base::Vector3d knotposition = spline->pointAtParameter(*itk); - - translate->translation.setValue(knotposition.x,knotposition.y,zInfo); - - SoFont *font = new SoFont; - font->name.setValue("Helvetica"); - font->size.setValue(fontSize); - - SoText2 *degreetext = new SoText2; - degreetext->string = SbString("(")+SbString(*itm)+SbString(")"); - - sep->addChild(translate); - sep->addChild(mat); - sep->addChild(font); - sep->addChild(degreetext); - - sw->addChild(sep); - - edit->infoGroup->addChild(sw); - sep->unref(); - mat->unref(); - - currentInfoNode++; // switch to next node - } - } - else { - for( itk = knots.begin(), itm = mult.begin(); itk != knots.end() && itm != mult.end(); ++itk, ++itm) { - SoSwitch *sw = static_cast(edit->infoGroup->getChild(currentInfoNode)); - - if(visibleInformationChanged) - sw->whichChild = hGrpsk->GetBool("BSplineKnotMultiplicityVisible", true)?SO_SWITCH_ALL:SO_SWITCH_NONE; - - SoSeparator *sep = static_cast(sw->getChild(0)); - - Base::Vector3d knotposition = spline->pointAtParameter(*itk); - - static_cast(sep->getChild(GEOINFO_BSPLINE_DEGREE_POS))->translation.setValue(knotposition.x,knotposition.y,zInfo); - - static_cast(sep->getChild(GEOINFO_BSPLINE_DEGREE_TEXT))->string = SbString("(")+SbString(*itm)+SbString(")"); - - currentInfoNode++; // switch to next node - } - } - - // End of knot multiplicity + double temprepscale = ( 0.5 * maxdisttocenterofmass ) / maxcurv; // just a factor to make a comb reasonably visible + if( temprepscale > combrepscale ) + combrepscale = temprepscale; } @@ -3808,6 +3499,359 @@ void ViewProviderSketch::draw(bool temp /*=false*/, bool rebuildinformationlayer } } + // geometry information layer for bsplines, as they need a second round now that max curvature is known + for (std::vector::const_iterator it = bsplineGeoIds.begin(); it != bsplineGeoIds.end(); ++it) { + + const Part::Geometry *geo = GeoById(*geomlist, *it); + + const Part::GeomBSplineCurve *spline = static_cast(geo); + + //---------------------------------------------------------- + // geometry information layer + + // polynom degree -------------------------------------------------------- + std::vector poles = spline->getPoles(); + + Base::Vector3d midp = Base::Vector3d(0,0,0); + + for (std::vector::iterator it = poles.begin(); it != poles.end(); ++it) { + midp += (*it); + } + + midp /= poles.size(); + + if(rebuildinformationlayer) { + SoSwitch *sw = new SoSwitch(); + + sw->whichChild = hGrpsk->GetBool("BSplineDegreeVisible", true)?SO_SWITCH_ALL:SO_SWITCH_NONE; + + SoSeparator *sep = new SoSeparator(); + sep->ref(); + // no caching for fluctuand data structures + sep->renderCaching = SoSeparator::OFF; + + // every information visual node gets its own material for to-be-implemented preselection and selection + SoMaterial *mat = new SoMaterial; + mat->ref(); + mat->diffuseColor = InformationColor; + + SoTranslation *translate = new SoTranslation; + + translate->translation.setValue(midp.x,midp.y,zInfo); + + SoFont *font = new SoFont; + font->name.setValue("Helvetica"); + font->size.setValue(fontSize); + + SoText2 *degreetext = new SoText2; + degreetext->string = SbString(spline->getDegree()); + + sep->addChild(translate); + sep->addChild(mat); + sep->addChild(font); + sep->addChild(degreetext); + + sw->addChild(sep); + + edit->infoGroup->addChild(sw); + sep->unref(); + mat->unref(); + } + else { + SoSwitch *sw = static_cast(edit->infoGroup->getChild(currentInfoNode)); + + if(visibleInformationChanged) + sw->whichChild = hGrpsk->GetBool("BSplineDegreeVisible", true)?SO_SWITCH_ALL:SO_SWITCH_NONE; + + SoSeparator *sep = static_cast(sw->getChild(0)); + + static_cast(sep->getChild(GEOINFO_BSPLINE_DEGREE_POS))->translation.setValue(midp.x,midp.y,zInfo); + + static_cast(sep->getChild(GEOINFO_BSPLINE_DEGREE_TEXT))->string = SbString(spline->getDegree()); + } + + currentInfoNode++; // switch to next node + + // control polygon -------------------------------------------------------- + if(rebuildinformationlayer) { + SoSwitch *sw = new SoSwitch(); + + sw->whichChild = hGrpsk->GetBool("BSplineControlPolygonVisible", true)?SO_SWITCH_ALL:SO_SWITCH_NONE; + + SoSeparator *sep = new SoSeparator(); + sep->ref(); + // no caching for fluctuand data structures + sep->renderCaching = SoSeparator::OFF; + + // every information visual node gets its own material for to-be-implemented preselection and selection + SoMaterial *mat = new SoMaterial; + mat->ref(); + mat->diffuseColor = InformationColor; + + SoLineSet *lineset = new SoLineSet; + + SoCoordinate3 *coords = new SoCoordinate3; + + if(spline->isPeriodic()) { + coords->point.setNum(poles.size()+1); + } + else { + coords->point.setNum(poles.size()); + } + + SbVec3f *vts = coords->point.startEditing(); + + int i=0; + for (std::vector::iterator it = poles.begin(); it != poles.end(); ++it, i++) { + vts[i].setValue((*it).x,(*it).y,zInfo); + } + + if(spline->isPeriodic()) { + vts[poles.size()].setValue(poles[0].x,poles[0].y,zInfo); + } + + coords->point.finishEditing(); + + sep->addChild(mat); + sep->addChild(coords); + sep->addChild(lineset); + + sw->addChild(sep); + + edit->infoGroup->addChild(sw); + sep->unref(); + mat->unref(); + } + else { + SoSwitch *sw = static_cast(edit->infoGroup->getChild(currentInfoNode)); + + if(visibleInformationChanged) + sw->whichChild = hGrpsk->GetBool("BSplineControlPolygonVisible", true)?SO_SWITCH_ALL:SO_SWITCH_NONE; + + SoSeparator *sep = static_cast(sw->getChild(0)); + + SoCoordinate3 *coords = static_cast(sep->getChild(GEOINFO_BSPLINE_POLYGON)); + + if(spline->isPeriodic()) { + coords->point.setNum(poles.size()+1); + } + else { + coords->point.setNum(poles.size()); + } + + SbVec3f *vts = coords->point.startEditing(); + + int i=0; + for (std::vector::iterator it = poles.begin(); it != poles.end(); ++it, i++) { + vts[i].setValue((*it).x,(*it).y,zInfo); + } + + if(spline->isPeriodic()) { + vts[poles.size()].setValue(poles[0].x,poles[0].y,zInfo); + } + + coords->point.finishEditing(); + + } + currentInfoNode++; // switch to next node + + // curvature graph -------------------------------------------------------- + + // reimplementation of python source: + // https://github.com/tomate44/CurvesWB/blob/master/ParametricComb.py + // by FreeCAD user Chris_G + + double firstparam = spline->getFirstParameter(); + double lastparam = spline->getLastParameter(); + + const int ndiv = poles.size()>4?poles.size()*16:64; + double step = (lastparam - firstparam ) / (ndiv -1); + + std::vector paramlist(ndiv); + std::vector pointatcurvelist(ndiv); + std::vector curvaturelist(ndiv); + std::vector normallist(ndiv); + + for(int i = 0; i < ndiv; i++) { + paramlist[i] = firstparam + i * step; + pointatcurvelist[i] = spline->pointAtParameter(paramlist[i]); + curvaturelist[i] = spline->curvatureAt(paramlist[i]); + + try { + spline->normalAt(paramlist[i],normallist[i]); + } + catch(Base::Exception) { + normallist[i] = Base::Vector3d(0,0,0); + } + + } + + std::vector pointatcomblist(ndiv); + + for(int i = 0; i < ndiv; i++) { + pointatcomblist[i] = pointatcurvelist[i] - combrepscale * curvaturelist[i] * normallist[i]; + } + + if(rebuildinformationlayer) { + SoSwitch *sw = new SoSwitch(); + + sw->whichChild = hGrpsk->GetBool("BSplineCombVisible", true)?SO_SWITCH_ALL:SO_SWITCH_NONE; + + SoSeparator *sep = new SoSeparator(); + sep->ref(); + // no caching for fluctuand data structures + sep->renderCaching = SoSeparator::OFF; + + // every information visual node gets its own material for to-be-implemented preselection and selection + SoMaterial *mat = new SoMaterial; + mat->ref(); + mat->diffuseColor = InformationColor; + + SoLineSet *lineset = new SoLineSet; + + SoCoordinate3 *coords = new SoCoordinate3; + + coords->point.setNum(3*ndiv); // 2*ndiv +1 points of ndiv separate segments + ndiv points for last segment + lineset->numVertices.setNum(ndiv+1); // ndiv separate segments of radials + 1 segment connecting at comb end + + int32_t *index = lineset->numVertices.startEditing(); + SbVec3f *vts = coords->point.startEditing(); + + for(int i = 0; i < ndiv; i++) { + vts[2*i].setValue(pointatcurvelist[i].x, pointatcurvelist[i].y, zInfo); // radials + vts[2*i+1].setValue(pointatcomblist[i].x, pointatcomblist[i].y, zInfo); + index[i] = 2; + + vts[2*ndiv+i].setValue(pointatcomblist[i].x, pointatcomblist[i].y, zInfo); // comb endpoint closing segment + } + + index[ndiv] = ndiv; // comb endpoint closing segment + + coords->point.finishEditing(); + lineset->numVertices.finishEditing(); + + sep->addChild(mat); + sep->addChild(coords); + sep->addChild(lineset); + + sw->addChild(sep); + + edit->infoGroup->addChild(sw); + sep->unref(); + mat->unref(); + } + else { + SoSwitch *sw = static_cast(edit->infoGroup->getChild(currentInfoNode)); + + if(visibleInformationChanged) + sw->whichChild = hGrpsk->GetBool("BSplineCombVisible", true)?SO_SWITCH_ALL:SO_SWITCH_NONE; + + SoSeparator *sep = static_cast(sw->getChild(0)); + + SoCoordinate3 *coords = static_cast(sep->getChild(GEOINFO_BSPLINE_POLYGON)); + + SoLineSet *lineset = static_cast(sep->getChild(GEOINFO_BSPLINE_POLYGON+1)); + + coords->point.setNum(3*ndiv); // 2*ndiv +1 points of ndiv separate segments + ndiv points for last segment + lineset->numVertices.setNum(ndiv+1); // ndiv separate segments of radials + 1 segment connecting at comb end + + int32_t *index = lineset->numVertices.startEditing(); + SbVec3f *vts = coords->point.startEditing(); + + for(int i = 0; i < ndiv; i++) { + vts[2*i].setValue(pointatcurvelist[i].x, pointatcurvelist[i].y, zInfo); // radials + vts[2*i+1].setValue(pointatcomblist[i].x, pointatcomblist[i].y, zInfo); + index[i] = 2; + + vts[2*ndiv+i].setValue(pointatcomblist[i].x, pointatcomblist[i].y, zInfo); // comb endpoint closing segment + } + + index[ndiv] = ndiv; // comb endpoint closing segment + + coords->point.finishEditing(); + lineset->numVertices.finishEditing(); + + } + + currentInfoNode++; // switch to next node + + // knot multiplicity -------------------------------------------------------- + std::vector knots = spline->getKnots(); + std::vector mult = spline->getMultiplicities(); + + std::vector::const_iterator itk; + std::vector::const_iterator itm; + + + if(rebuildinformationlayer) { + + for( itk = knots.begin(), itm = mult.begin(); itk != knots.end() && itm != mult.end(); ++itk, ++itm) { + + SoSwitch *sw = new SoSwitch(); + + sw->whichChild = hGrpsk->GetBool("BSplineKnotMultiplicityVisible", true)?SO_SWITCH_ALL:SO_SWITCH_NONE; + + SoSeparator *sep = new SoSeparator(); + sep->ref(); + // no caching for fluctuand data structures + sep->renderCaching = SoSeparator::OFF; + + // every information visual node gets its own material for to-be-implemented preselection and selection + SoMaterial *mat = new SoMaterial; + mat->ref(); + mat->diffuseColor = InformationColor; + + SoTranslation *translate = new SoTranslation; + + Base::Vector3d knotposition = spline->pointAtParameter(*itk); + + translate->translation.setValue(knotposition.x,knotposition.y,zInfo); + + SoFont *font = new SoFont; + font->name.setValue("Helvetica"); + font->size.setValue(fontSize); + + SoText2 *degreetext = new SoText2; + degreetext->string = SbString("(")+SbString(*itm)+SbString(")"); + + sep->addChild(translate); + sep->addChild(mat); + sep->addChild(font); + sep->addChild(degreetext); + + sw->addChild(sep); + + edit->infoGroup->addChild(sw); + sep->unref(); + mat->unref(); + + currentInfoNode++; // switch to next node + } + } + else { + for( itk = knots.begin(), itm = mult.begin(); itk != knots.end() && itm != mult.end(); ++itk, ++itm) { + SoSwitch *sw = static_cast(edit->infoGroup->getChild(currentInfoNode)); + + if(visibleInformationChanged) + sw->whichChild = hGrpsk->GetBool("BSplineKnotMultiplicityVisible", true)?SO_SWITCH_ALL:SO_SWITCH_NONE; + + SoSeparator *sep = static_cast(sw->getChild(0)); + + Base::Vector3d knotposition = spline->pointAtParameter(*itk); + + static_cast(sep->getChild(GEOINFO_BSPLINE_DEGREE_POS))->translation.setValue(knotposition.x,knotposition.y,zInfo); + + static_cast(sep->getChild(GEOINFO_BSPLINE_DEGREE_TEXT))->string = SbString("(")+SbString(*itm)+SbString(")"); + + currentInfoNode++; // switch to next node + } + } + + // End of knot multiplicity + } + + + visibleInformationChanged=false; // whatever that changed in Information layer is already updated edit->CurvesCoordinate->point.setNum(Coords.size());