Files
create/src/Mod/Mesh/Gui/ViewProviderCurvature.cpp

642 lines
24 KiB
C++

/***************************************************************************
* Copyright (c) 2004 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <Inventor/SoPickedPoint.h>
# include <Inventor/details/SoFaceDetail.h>
# include <Inventor/details/SoPointDetail.h>
# include <Inventor/events/SoMouseButtonEvent.h>
# include <Inventor/events/SoKeyboardEvent.h>
# include <Inventor/events/SoLocation2Event.h>
# include <Inventor/nodes/SoDrawStyle.h>
# include <Inventor/nodes/SoIndexedFaceSet.h>
# include <Inventor/nodes/SoMaterial.h>
# include <Inventor/nodes/SoMaterialBinding.h>
# include <Inventor/nodes/SoShapeHints.h>
# include <Inventor/sensors/SoIdleSensor.h>
# include <algorithm>
# include <sstream>
# include <QEvent>
# include <QMenu>
# include <QMessageBox>
# include <QCursor>
# include <QToolTip>
# include <QWhatsThis>
#endif
# include <iomanip>
# include <ios>
// Here the FreeCAD includes sorted by Base,App,Gui......
#include <Base/Console.h>
#include <Base/Parameter.h>
#include <Base/Exception.h>
#include <Base/Sequencer.h>
#include <App/Annotation.h>
#include <App/Application.h>
#include <App/Document.h>
#include <App/DocumentObjectGroup.h>
#include <Gui/Application.h>
#include <Gui/BitmapFactory.h>
#include <Gui/Document.h>
#include <Gui/MainWindow.h>
#include <Gui/Selection.h>
#include <Gui/SoFCSelection.h>
#include <Gui/SoFCColorBar.h>
#include <Gui/View3DInventorViewer.h>
#include <Gui/ViewProviderGeometryObject.h>
#include <Gui/Widgets.h>
#include <Mod/Mesh/App/MeshProperties.h>
#include <Mod/Mesh/App/MeshFeature.h>
#include <Mod/Mesh/App/FeatureMeshCurvature.h>
#include <Mod/Mesh/App/MeshProperties.h>
#include "ViewProvider.h"
#include "ViewProviderCurvature.h"
using namespace Mesh;
using namespace MeshGui;
using namespace std;
bool ViewProviderMeshCurvature::addflag = false;
PROPERTY_SOURCE(MeshGui::ViewProviderMeshCurvature, Gui::ViewProviderDocumentObject)
ViewProviderMeshCurvature::ViewProviderMeshCurvature()
{
pcColorRoot = new SoSeparator();
pcColorRoot->ref();
pcColorMat = new SoMaterial;
pcColorMat->ref();
pcColorStyle = new SoDrawStyle();
pcColorRoot->addChild(pcColorStyle);
// simple color bar
pcColorBar = new Gui::SoFCColorBar;
pcColorBar->Attach(this);
pcColorBar->ref();
pcColorBar->setRange(-0.5f, 0.5f, 3);
pcLinkRoot = new SoGroup;
pcLinkRoot->ref();
App::Material mat;
const SbColor* cols;
if (pcColorMat->ambientColor.getNum() == 1) {
cols = pcColorMat->ambientColor.getValues(0);
mat.ambientColor.setPackedValue(cols[0].getPackedValue());
}
if (pcColorMat->diffuseColor.getNum() == 1) {
cols = pcColorMat->diffuseColor.getValues(0);
mat.diffuseColor.setPackedValue(cols[0].getPackedValue());
}
if (pcColorMat->emissiveColor.getNum() == 1) {
cols = pcColorMat->emissiveColor.getValues(0);
mat.emissiveColor.setPackedValue(cols[0].getPackedValue());
}
if (pcColorMat->specularColor.getNum() == 1) {
cols = pcColorMat->specularColor.getValues(0);
mat.specularColor.setPackedValue(cols[0].getPackedValue());
}
if (pcColorMat->shininess.getNum() == 1) {
const float* shiny = pcColorMat->shininess.getValues(0);
mat.shininess = shiny[0];
}
if (pcColorMat->transparency.getNum() == 1) {
const float* trans = pcColorMat->transparency.getValues(0);
mat.transparency = trans[0];
}
ADD_PROPERTY(TextureMaterial,(mat));
}
ViewProviderMeshCurvature::~ViewProviderMeshCurvature()
{
pcColorRoot->unref();
pcColorMat->unref();
pcColorBar->Detach(this);
pcColorBar->unref();
pcLinkRoot->unref();
}
void ViewProviderMeshCurvature::onChanged(const App::Property* prop)
{
if (prop == &TextureMaterial) {
const App::Material& Mat = TextureMaterial.getValue();
pcColorMat->ambientColor.setValue(Mat.ambientColor.r,Mat.ambientColor.g,Mat.ambientColor.b);
pcColorMat->specularColor.setValue(Mat.specularColor.r,Mat.specularColor.g,Mat.specularColor.b);
pcColorMat->emissiveColor.setValue(Mat.emissiveColor.r,Mat.emissiveColor.g,Mat.emissiveColor.b);
pcColorMat->shininess.setValue(Mat.shininess);
pcColorMat->transparency.setValue(Mat.transparency);
}
ViewProviderDocumentObject::onChanged(prop);
}
void ViewProviderMeshCurvature::hide(void)
{
inherited::hide();
pcColorStyle->style = SoDrawStyle::INVISIBLE;
}
void ViewProviderMeshCurvature::show(void)
{
inherited::show();
pcColorStyle->style = SoDrawStyle::FILLED;
}
void ViewProviderMeshCurvature::init(const Mesh::PropertyCurvatureList* pCurvInfo)
{
std::vector<float> aMinValues, aMaxValues;
const std::vector<Mesh::CurvatureInfo>& fCurvInfo = pCurvInfo->getValues();
aMinValues.reserve(fCurvInfo.size());
aMaxValues.reserve(fCurvInfo.size());
for ( std::vector<Mesh::CurvatureInfo>::const_iterator jt=fCurvInfo.begin();jt!=fCurvInfo.end(); ++jt ) {
aMinValues.push_back( jt->fMinCurvature );
aMaxValues.push_back( jt->fMaxCurvature );
}
if ( aMinValues.empty() || aMaxValues.empty() )
return; // no values inside
float fMin = *std::min_element( aMinValues.begin(), aMinValues.end() );
float fMax = *std::max_element( aMinValues.begin(), aMinValues.end() );
// histogram over all values
std::map<int, int> aHistogram;
for ( std::vector<float>::const_iterator kt = aMinValues.begin(); kt != aMinValues.end(); ++kt ) {
int grp = (int)(10.0f*( *kt - fMin )/( fMax - fMin ));
aHistogram[grp]++;
}
float fRMin=-1.0f;
for ( std::map<int, int>::iterator mIt = aHistogram.begin(); mIt != aHistogram.end(); ++mIt ) {
if ( (float)mIt->second / (float)aMinValues.size() > 0.15f ) {
fRMin = mIt->first * ( fMax - fMin )/10.0f + fMin;
break;
}
}
fMin = *std::min_element( aMaxValues.begin(), aMaxValues.end() );
fMax = *std::max_element( aMaxValues.begin(), aMaxValues.end() );
// histogram over all values
aHistogram.clear();
for ( std::vector<float>::const_iterator it2 = aMaxValues.begin(); it2 != aMaxValues.end(); ++it2 ) {
int grp = (int)(10.0f*( *it2 - fMin )/( fMax - fMin ));
aHistogram[grp]++;
}
float fRMax=1.0f;
for ( std::map<int, int>::reverse_iterator rIt2 = aHistogram.rbegin(); rIt2 != aHistogram.rend(); ++rIt2 ) {
if ( (float)rIt2->second / (float)aMaxValues.size() > 0.15f ) {
fRMax = rIt2->first * ( fMax - fMin )/10.0f + fMin;
break;
}
}
float fAbs = std::max<float>(fabs(fRMin), fabs(fRMax));
fRMin = -fAbs;
fRMax = fAbs;
fMin = fRMin; fMax = fRMax;
pcColorBar->setRange( fMin, fMax, 3 );
}
void ViewProviderMeshCurvature::slotCreatedObject(const App::DocumentObject& Obj)
{
}
void ViewProviderMeshCurvature::slotDeletedObject(const App::DocumentObject& Obj)
{
}
void ViewProviderMeshCurvature::slotChangedObject(const App::DocumentObject& Obj, const App::Property& Prop)
{
// we get this for any object for that a property has changed. Thus, we must regard that object
// which is linked by our link property
App::DocumentObject* object = static_cast<Mesh::Curvature*>(pcObject)->Source.getValue();
if (object == &Obj) {
const Mesh::PropertyMeshKernel& mesh = static_cast<Mesh::Feature*>(object)->Mesh;
if ((&mesh) == (&Prop)) {
const Mesh::MeshObject& kernel = mesh.getValue();
pcColorMat->diffuseColor.setNum((int)kernel.countPoints());
pcColorMat->transparency.setNum((int)kernel.countPoints());
static_cast<Mesh::Curvature*>(pcObject)->Source.touch(); // make sure to recompute the feature
}
}
}
void ViewProviderMeshCurvature::slotCreatedDocument(const App::Document& Doc)
{
}
void ViewProviderMeshCurvature::slotDeletedDocument(const App::Document& Doc)
{
}
void ViewProviderMeshCurvature::attach(App::DocumentObject *pcFeat)
{
// creats the standard viewing modes
inherited::attach(pcFeat);
attachDocument(pcFeat->getDocument());
SoShapeHints * flathints = new SoShapeHints;
flathints->vertexOrdering = SoShapeHints::COUNTERCLOCKWISE ;
flathints->shapeType = SoShapeHints::UNKNOWN_SHAPE_TYPE;
SoGroup* pcColorShadedRoot = new SoGroup();
pcColorShadedRoot->addChild(flathints);
// color shaded
SoDrawStyle *pcFlatStyle = new SoDrawStyle();
pcFlatStyle->style = SoDrawStyle::FILLED;
pcColorShadedRoot->addChild(pcFlatStyle);
SoMaterialBinding* pcMatBinding = new SoMaterialBinding;
pcMatBinding->value = SoMaterialBinding::PER_VERTEX_INDEXED;
pcColorShadedRoot->addChild(pcColorMat);
pcColorShadedRoot->addChild(pcMatBinding);
pcColorShadedRoot->addChild(pcLinkRoot);
addDisplayMaskMode(pcColorShadedRoot, "ColorShaded");
// Check for an already existing color bar
Gui::SoFCColorBar* pcBar = ((Gui::SoFCColorBar*)findFrontRootOfType( Gui::SoFCColorBar::getClassTypeId() ));
if ( pcBar ) {
float fMin = pcColorBar->getMinValue();
float fMax = pcColorBar->getMaxValue();
// Attach to the foreign color bar and delete our own bar
pcBar->Attach(this);
pcBar->ref();
pcBar->setRange(fMin, fMax, 3);
pcBar->Notify(0);
pcColorBar->Detach(this);
pcColorBar->unref();
pcColorBar = pcBar;
}
pcColorRoot->addChild(pcColorBar);
}
void ViewProviderMeshCurvature::updateData(const App::Property* prop)
{
// set to the expected size
if (prop->getTypeId() == App::PropertyLink::getClassTypeId()) {
Mesh::Feature* object = static_cast<const App::PropertyLink*>(prop)->getValue<Mesh::Feature*>();
this->pcLinkRoot->removeAllChildren();
if (object) {
const Mesh::MeshObject& kernel = object->Mesh.getValue();
pcColorMat->diffuseColor.setNum((int)kernel.countPoints());
pcColorMat->transparency.setNum((int)kernel.countPoints());
// get the view provider of the associated mesh feature
App::Document* rDoc = pcObject->getDocument();
Gui::Document* pDoc = Gui::Application::Instance->getDocument(rDoc);
ViewProviderMesh* view = static_cast<ViewProviderMesh*>(pDoc->getViewProvider(object));
this->pcLinkRoot->addChild(view->getHighlightNode());
}
}
else if (prop->getTypeId() == Mesh::PropertyCurvatureList::getClassTypeId()) {
const Mesh::PropertyCurvatureList* curv = static_cast<const Mesh::PropertyCurvatureList*>(prop);
if (curv->getSize() < 3) return; // invalid array
#if 0 // FIXME: Do not always change the range
init(curv); // init color bar
#endif
setActiveMode();
}
}
SoSeparator* ViewProviderMeshCurvature::getFrontRoot(void) const
{
return pcColorRoot;
}
void ViewProviderMeshCurvature::setVertexCurvatureMode(int mode)
{
Mesh::PropertyCurvatureList* pCurvInfo=0;
std::map<std::string,App::Property*> Map;
pcObject->getPropertyMap(Map);
for( std::map<std::string,App::Property*>::iterator it = Map.begin(); it != Map.end(); ++it ) {
Base::Type t = it->second->getTypeId();
if ( t==Mesh::PropertyCurvatureList::getClassTypeId() ) {
pCurvInfo = (Mesh::PropertyCurvatureList*)it->second;
break;
}
}
if ( !pCurvInfo )
return; // cannot display this feature type due to missing curvature property
// curvature values
std::vector<float> fValues = pCurvInfo->getCurvature( mode );
unsigned long j=0;
for ( std::vector<float>::const_iterator jt = fValues.begin(); jt != fValues.end(); ++jt, j++ ) {
App::Color col = pcColorBar->getColor( *jt );
pcColorMat->diffuseColor.set1Value(j, SbColor(col.r, col.g, col.b));
if ( pcColorBar->isVisible( *jt ) ) {
pcColorMat->transparency.set1Value(j, 0.0f);
} else {
pcColorMat->transparency.set1Value(j, 0.8f);
}
}
}
QIcon ViewProviderMeshCurvature::getIcon() const
{
static QPixmap px = Gui::BitmapFactory().pixmap(":/icons/Mesh_Tree_Curvature_Plot.svg");
return px;
}
void ViewProviderMeshCurvature::setDisplayMode(const char* ModeName)
{
if ( strcmp("Mean curvature",ModeName)==0 ) {
setVertexCurvatureMode(Mesh::PropertyCurvatureList::MeanCurvature);
setDisplayMaskMode("ColorShaded");
}
else if ( strcmp("Gaussian curvature",ModeName)==0 ) {
setVertexCurvatureMode(Mesh::PropertyCurvatureList::GaussCurvature);
setDisplayMaskMode("ColorShaded");
}
else if ( strcmp("Maximum curvature",ModeName)==0 ) {
setVertexCurvatureMode(Mesh::PropertyCurvatureList::MaxCurvature);
setDisplayMaskMode("ColorShaded");
}
else if ( strcmp("Minimum curvature",ModeName)==0 ) {
setVertexCurvatureMode(Mesh::PropertyCurvatureList::MinCurvature);
setDisplayMaskMode("ColorShaded");
}
else if ( strcmp("Absolute curvature",ModeName)==0 ) {
setVertexCurvatureMode(Mesh::PropertyCurvatureList::AbsCurvature);
setDisplayMaskMode("ColorShaded");
}
inherited::setDisplayMode(ModeName);
}
const char* ViewProviderMeshCurvature::getDefaultDisplayMode() const
{
return "Absolute curvature";
}
std::vector<std::string> ViewProviderMeshCurvature::getDisplayModes(void) const
{
std::vector<std::string> StrList = inherited::getDisplayModes();
// add modes
StrList.push_back("Absolute curvature");
StrList.push_back("Mean curvature");
StrList.push_back("Gaussian curvature");
StrList.push_back("Maximum curvature");
StrList.push_back("Minimum curvature");
return StrList;
}
void ViewProviderMeshCurvature::OnChange(Base::Subject<int> &rCaller,int rcReason)
{
setActiveMode();
}
namespace MeshGui {
class Annotation
{
public:
Annotation(Gui::ViewProviderDocumentObject* vp,
const QString& s,const SbVec3f& p, const SbVec3f& n)
: vp(vp), s(s), p(p), n(n)
{
}
~Annotation()
{
}
static void run(void * data, SoSensor * sensor)
{
Annotation* self = reinterpret_cast<Annotation*>(data);
self->show();
delete self;
delete sensor;
}
void show()
{
App::Document* doc = vp->getObject()->getDocument();
std::vector<App::DocumentObject*> groups = doc->getObjectsOfType
(App::DocumentObjectGroup::getClassTypeId());
App::DocumentObjectGroup* group = 0;
std::string internalname = "CurvatureGroup";
for (std::vector<App::DocumentObject*>::iterator it = groups.begin(); it != groups.end(); ++it) {
if (internalname == (*it)->getNameInDocument()) {
group = static_cast<App::DocumentObjectGroup*>(*it);
break;
}
}
if (!group) {
group = static_cast<App::DocumentObjectGroup*>(doc->addObject
("App::DocumentObjectGroup",internalname.c_str()));
}
App::AnnotationLabel* anno = static_cast<App::AnnotationLabel*>
(group->addObject("App::AnnotationLabel", internalname.c_str()));
QStringList lines = s.split(QLatin1String("\n"));
std::vector<std::string> text;
for (QStringList::Iterator it = lines.begin(); it != lines.end(); ++it)
text.push_back((const char*)it->toAscii());
anno->LabelText.setValues(text);
std::stringstream str;
str << "Curvature info (" << group->Group.getSize() << ")";
anno->Label.setValue(str.str());
anno->BasePosition.setValue(p[0],p[1],p[2]);
anno->TextPosition.setValue(n[0],n[1],n[2]);
}
private:
Gui::ViewProviderDocumentObject* vp;
QString s;
SbVec3f p;
SbVec3f n;
};
}
void ViewProviderMeshCurvature::curvatureInfoCallback(void * ud, SoEventCallback * n)
{
Gui::View3DInventorViewer* view = reinterpret_cast<Gui::View3DInventorViewer*>(n->getUserData());
const SoEvent* ev = n->getEvent();
if (ev->getTypeId() == SoMouseButtonEvent::getClassTypeId()) {
const SoMouseButtonEvent * mbe = static_cast<const SoMouseButtonEvent *>(ev);
// Mark all incoming mouse button events as handled, especially, to deactivate the selection node
n->getAction()->setHandled();
if (mbe->getButton() == SoMouseButtonEvent::BUTTON2 && mbe->getState() == SoButtonEvent::UP) {
n->setHandled();
// context-menu
QMenu menu;
QAction* fl = menu.addAction(QObject::tr("Annotation"));
fl->setCheckable(true);
fl->setChecked(addflag);
QAction* cl = menu.addAction(QObject::tr("Leave info mode"));
QAction* id = menu.exec(QCursor::pos());
if (fl == id) {
addflag = fl->isChecked();
}
else if (cl == id) {
view->setEditing(false);
view->getWidget()->setCursor(QCursor(Qt::ArrowCursor));
view->setRedirectToSceneGraph(false);
view->removeEventCallback(SoEvent::getClassTypeId(), curvatureInfoCallback);
}
}
else if (mbe->getButton() == SoMouseButtonEvent::BUTTON1 && mbe->getState() == SoButtonEvent::UP) {
const SoPickedPoint * point = n->getPickedPoint();
if (point == NULL) {
Base::Console().Message("No facet picked.\n");
return;
}
n->setHandled();
// By specifying the indexed mesh node 'pcFaceSet' we make sure that the picked point is
// really from the mesh we render and not from any other geometry
Gui::ViewProvider* vp = static_cast<Gui::ViewProvider*>(view->getViewProviderByPath(point->getPath()));
if (!vp || !vp->getTypeId().isDerivedFrom(ViewProviderMeshCurvature::getClassTypeId()))
return;
ViewProviderMeshCurvature* self = static_cast<ViewProviderMeshCurvature*>(vp);
const SoDetail* detail = point->getDetail(point->getPath()->getTail());
if (detail && detail->getTypeId() == SoFaceDetail::getClassTypeId()) {
// safe downward cast, know the type
SoFaceDetail * facedetail = (SoFaceDetail *)detail;
// get the curvature info of the three points of the picked facet
int index1 = facedetail->getPoint(0)->getCoordinateIndex();
int index2 = facedetail->getPoint(1)->getCoordinateIndex();
int index3 = facedetail->getPoint(2)->getCoordinateIndex();
std::string info = self->curvatureInfo(true, index1, index2, index3);
QString text = QString::fromAscii(info.c_str());
if (addflag) {
SbVec3f pt = point->getPoint();
SbVec3f nl = point->getNormal();
Annotation* anno = new Annotation(self, text, pt, nl);
SoIdleSensor* sensor = new SoIdleSensor(Annotation::run, anno);
sensor->schedule();
}
else {
Gui::ToolTip::showText(QCursor::pos(), text);
}
}
}
}
else if (ev->getTypeId().isDerivedFrom(SoLocation2Event::getClassTypeId())) {
const SoPickedPoint * point = n->getPickedPoint();
if (point == NULL)
return;
n->setHandled();
// By specifying the indexed mesh node 'pcFaceSet' we make sure that the picked point is
// really from the mesh we render and not from any other geometry
Gui::ViewProvider* vp = static_cast<Gui::ViewProvider*>(view->getViewProviderByPath(point->getPath()));
if (!vp || !vp->getTypeId().isDerivedFrom(ViewProviderMeshCurvature::getClassTypeId()))
return;
ViewProviderMeshCurvature* that = static_cast<ViewProviderMeshCurvature*>(vp);
const SoDetail* detail = point->getDetail(point->getPath()->getTail());
if (detail && detail->getTypeId() == SoFaceDetail::getClassTypeId()) {
// safe downward cast, know the type
SoFaceDetail * facedetail = (SoFaceDetail *)detail;
// get the curvature info of the three points of the picked facet
int index1 = facedetail->getPoint(0)->getCoordinateIndex();
int index2 = facedetail->getPoint(1)->getCoordinateIndex();
int index3 = facedetail->getPoint(2)->getCoordinateIndex();
std::string info = that->curvatureInfo(false, index1, index2, index3);
Gui::getMainWindow()->setPaneText(1,QString::fromAscii(info.c_str()));
}
}
}
std::string ViewProviderMeshCurvature::curvatureInfo(bool detail, int index1, int index2, int index3) const
{
// get the curvature info of the three points of the picked facet
App::Property* prop = pcObject->getPropertyByName("CurvInfo");
std::stringstream str;
if (prop && prop->getTypeId() == Mesh::PropertyCurvatureList::getClassTypeId()) {
Mesh::PropertyCurvatureList* curv = (Mesh::PropertyCurvatureList*)prop;
const Mesh::CurvatureInfo& cVal1 = (*curv)[index1];
const Mesh::CurvatureInfo& cVal2 = (*curv)[index2];
const Mesh::CurvatureInfo& cVal3 = (*curv)[index3];
float fVal1 = 0.0f; float fVal2 = 0.0f; float fVal3 = 0.0f;
bool print=true;
std::string mode = getActiveDisplayMode();
if (mode == "Minimum curvature") {
fVal1 = cVal1.fMinCurvature;
fVal2 = cVal1.fMinCurvature;
fVal3 = cVal1.fMinCurvature;
}
else if (mode == "Maximum curvature") {
fVal1 = cVal1.fMaxCurvature;
fVal2 = cVal1.fMaxCurvature;
fVal3 = cVal1.fMaxCurvature;
}
else if (mode == "Gaussian curvature") {
fVal1 = cVal1.fMaxCurvature*cVal1.fMinCurvature;
fVal2 = cVal1.fMaxCurvature*cVal2.fMinCurvature;
fVal3 = cVal1.fMaxCurvature*cVal3.fMinCurvature;
}
else if (mode == "Mean curvature") {
fVal1 = 0.5f*(cVal1.fMaxCurvature+cVal1.fMinCurvature);
fVal2 = 0.5f*(cVal1.fMaxCurvature+cVal2.fMinCurvature);
fVal3 = 0.5f*(cVal1.fMaxCurvature+cVal3.fMinCurvature);
}
else if (mode == "Absolute curvature") {
fVal1 = fabs(cVal1.fMaxCurvature) > fabs(cVal1.fMinCurvature) ? cVal1.fMaxCurvature : cVal1.fMinCurvature;
fVal2 = fabs(cVal2.fMaxCurvature) > fabs(cVal2.fMinCurvature) ? cVal2.fMaxCurvature : cVal2.fMinCurvature;
fVal3 = fabs(cVal3.fMaxCurvature) > fabs(cVal3.fMinCurvature) ? cVal3.fMaxCurvature : cVal3.fMinCurvature;
}
else {
print = false;
}
if (print) {
if (!detail) {
str << mode << ": <" << fVal1 << ", " << fVal2 << ", " << fVal3 << ">";
}
else {
str.setf(std::ios::fixed | std::ios::showpoint);
str.precision(5);
str << mode << std::endl
<< "v1: " << std::setw(5) << fVal1 << std::endl
<< "v2: " << std::setw(5) << fVal2 << std::endl
<< "v3: " << std::setw(5) << fVal3;
}
}
else if (!detail) {
str << "No curvature mode set";
}
}
return str.str();
}