/* * NodeSuperEllipsoid.cpp * * Copyright (C) 1999 Stephen F. White, 2004 J. "MUFTI" Scheurich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (see the file "COPYING" for details); if * not, write to the Free Software Foundation, Inc., 675 Mass Ave, * Cambridge, MA 02139, USA. */ #include #include #include "stdafx.h" #ifdef WIN32 # define M_PI_2 (M_PI/2.0) #endif #include "DuneApp.h" #include "NodeSuperEllipsoid.h" #include "Proto.h" #include "FieldValue.h" #include "Scene.h" #include "Mesh.h" #include "SFFloat.h" #include "SFInt32.h" #include "SFBool.h" #include "NodeIndexedFaceSet.h" #include "NodeCoordinate.h" #include "NodeNormal.h" #include "NodeTextureCoordinate.h" #include "NodeNurbsSurface.h" ProtoSuperEllipsoid::ProtoSuperEllipsoid(Scene *scene) : Proto(scene, "SuperEllipsoid") { n1.set( addExposedField(SFFLOAT, "n1", new SFFloat(1.0f), new SFFloat(0.0f))); n2.set( addExposedField(SFFLOAT, "n2", new SFFloat(1.0f), new SFFloat(0.0f))); border.set( addExposedField(SFFLOAT, "border", new SFFloat(M_PI / 2.0), new SFFloat(-M_PI / 2.0), new SFFloat(M_PI / 2.0))); creaseAngle.set( addField(SFFLOAT, "creaseAngle", new SFFloat(0.7854f), new SFFloat(0.0f))); texCoord.set( addExposedField(SFNODE, "texCoord", new SFNode(NULL), TEXTURE_COORDINATE_NODE)); uTessellation.set( addExposedField(SFINT32, "uTessellation", new SFInt32(0))); vTessellation.set( addExposedField(SFINT32, "vTessellation", new SFInt32(0))); } Node * ProtoSuperEllipsoid::create(Scene *scene) { return new NodeSuperEllipsoid(scene, this); } NodeSuperEllipsoid::NodeSuperEllipsoid(Scene *scene, Proto *def) : MeshBasedNode(scene, def) { } NodeSuperEllipsoid::~NodeSuperEllipsoid() { } static float cossign(float f) { // range -PI to PI if ((f < M_PI_2 + EPSILON) && (f > M_PI_2 - EPSILON)) return 0; if (f > M_PI_2) return -1; if ((f < -M_PI_2 + EPSILON) && (f > -M_PI_2 - EPSILON)) return 0; if (f > -M_PI_2) return 1; // -PI < x < -PI/2 return -1; } static float sinsign(float f) { // range -PI to PI if ((f < M_PI + EPSILON) && (f > M_PI - EPSILON)) return 0; if (f > M_PI) return -1; if ((f < 0 + EPSILON) && (f > 0 - EPSILON)) return 0; if (f > 0) return 1; if ((f < -M_PI + EPSILON) && (f > -M_PI - EPSILON)) return 0; if (f < -M_PI) return 1; // -PI < x < 0 return -1; } float NodeSuperEllipsoid::superellipse1xy(float angle1) { return cossign(angle1) * pow(fabs(cos(angle1)), n2()->getValue()); } float NodeSuperEllipsoid::superellipse1z(float angle1) { return sinsign(angle1)* pow(fabs(sin(angle1)), n2()->getValue()); } float NodeSuperEllipsoid::superellipse2x(float angle2) { float n = n1()->getValue(); if (fabs(n) < 1e-5) n = 1e-5; return cossign(angle2)* pow(fabs(cos(angle2)), n); } float NodeSuperEllipsoid::superellipse2y(float angle2) { float n = n1()->getValue(); if (fabs(n) < 1e-5) n = 1e-5; return sinsign(angle2)* pow(fabs(sin(angle2)), n); } void NodeSuperEllipsoid::createMesh() { if (_mesh) delete _mesh; _mesh = NULL; int uTess = uTessellation()->getValue(); int vTess = vTessellation()->getValue(); if (uTess <= 0) uTess = 32; if (vTess <= 0) vTess = 32; uTess++; vTess++; if (uTess < 3) return; if (vTess < 3) return; int size = uTess * vTess; Vec3f *vert = new Vec3f[size]; int* ci = new int[(uTess + 1) * (vTess + 1) * 5]; float low = -M_PI / 2.0; float high = border()->getValue(); float inc1 = (high - low) / (uTess-1); float inc2 = M_PI / (vTess-1) * 2.0; int a1; int a2; Array s1xy(uTess); Array s1z(uTess); for (a1 = 0; a1 < uTess; a1++) { float angle1 = low + a1 * inc1; s1xy[a1] = superellipse1xy(angle1); s1z[a1] = superellipse1z(angle1); } Array s2x(vTess); Array s2y(vTess); for (a2 = 0; a2 < vTess; a2++) { float angle2 = -M_PI + a2 * inc2; s2x[a2] = superellipse2x(angle2); s2y[a2] = superellipse2y(angle2); } int index=0; int cindex=0; for (a2 = 0; a2 < vTess; a2++) for (a1 = 0; a1 < uTess; a1++) { vert[index].z = s1xy[a1] * s2x[a2]; vert[index].x = s1xy[a1] * s2y[a2]; vert[index].y = s1z[a1]; index++; int c1 = a1 + 1; if (a1 == uTess - 1) continue; int c2 = a2 + 1; if (a2 == vTess - 1) c2 = 0; // continue; ci[cindex++] = a1 + a2 * uTess; ci[cindex++] = a1 + c2 * uTess; ci[cindex++] = c1 + c2 * uTess; ci[cindex++] = c1 + a2 * uTess; ci[cindex++] = -1; } cindex = cleanDoubleVertices(ci, vert, NULL, cindex); MFVec3f *vertices = new MFVec3f((float *) vert, size * 3); MFInt32 *coordIndex = new MFInt32(ci, cindex); MFVec2f *texCoords = NULL; if (texCoord()->getValue()) { if (texCoord()->getValue()->getType() == NODE_TEXTURE_COORDINATE) texCoords = ((NodeTextureCoordinate *)(texCoord()->getValue())) ->point(); } else texCoords = generateTextureCoordinates(vertices, coordIndex); bool solid = false; if (high == M_PI / 2.0) solid = true; int meshFlags = MESH_CCW; if (solid) meshFlags |= MESH_SOLID; _mesh = new Mesh(vertices, coordIndex, NULL, NULL, NULL, NULL, texCoords, NULL, creaseAngle()->getValue(), meshFlags); } bool NodeSuperEllipsoid::writeEXTERNPROTO(int f) { RET_ONERROR( mywritestr(f ,"EXTERNPROTO SuperEllipsoid[\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," exposedField SFFloat n1\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," exposedField SFFloat n2\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," exposedField SFFloat border\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," field SFFloat creaseAngle\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," field SFNode texCoord\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," exposedField SFInt32 uTessellation\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," exposedField SFInt32 vTessellation\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," ]\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ,"[\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ,"# \"") ) RET_ONERROR( mywritestr(f ,"SuperEllipsoidPROTO.wrl") ) RET_ONERROR( mywritestr(f ,"\"\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ,"\"") ) char *dunedocs = getenv("DUNEDOCS"); if (dunedocs != NULL) { RET_ONERROR( mywritestr(f ,dunedocs) ) RET_ONERROR( mywritestr(f ,"/scriptedNodes") ) } #ifdef HAVE_SCRIPTED_NODES_PROTO_URL else RET_ONERROR( mywritestr(f ,HAVE_SCRIPTED_NODES_PROTO_URL) ) #endif RET_ONERROR( mywritestr(f ,"/") ) RET_ONERROR( mywritestr(f ,"SuperEllipsoidPROTO.wrl") ) RET_ONERROR( mywritestr(f ,"\"\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ," \"http://www.csv.ica.uni-stuttgart.de/vrml/dune/docs/scriptedNodes/SuperEllipsoidPROTO.wrl\"\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( mywritestr(f ,"]\n") ) TheApp->incSelectionLinenumber(); return true; } int NodeSuperEllipsoid::write(int filedes, int indent) { if (_scene->isPureVRML97()) { Node *node = toIndexedFaceSet(); if (node == NULL) return 1; RET_ONERROR( node->write(filedes, indent) ) node->unref(); } else RET_ONERROR( NodeData::write(filedes, indent) ) return 0; } void NodeSuperEllipsoid::setField(int index, FieldValue *value) { _meshDirty = true; Node::setField(index, value); } Node* NodeSuperEllipsoid::toNurbs(int uTess, int vTess, int uDegree, int vDegree) { if (_meshDirty) { createMesh(); _meshDirty = false; } NodeNurbsSurface *node = (NodeNurbsSurface *) _scene->createNode( "NurbsSurface"); int vOrder = vDegree + 1; int uOrder = uDegree + 1; int oldUTess = uTessellation()->getValue(); int oldVTess = vTessellation()->getValue(); bool storeOldTesselation = false; if ((oldUTess != uTess) || (oldVTess != vTess)) { storeOldTesselation = true; uTessellation(new SFInt32(uTess)); vTessellation(new SFInt32(vTess)); createMesh(); _meshDirty = true; } uTess++; vTess++; int size = _mesh->getVertices()->getSize(); int uDimension = uTess; int vDimension = vTess; float *controlPoints = new float[size]; float *weights = new float[size]; float *uKnots = new float[uDimension + uOrder]; float *vKnots = new float[vDimension + vOrder]; int i; for (i = 0; i < size; i++){ controlPoints[i] = _mesh->getVertices()->getValues()[i]; } for(i = 0; i < size; i++){ weights[i] = 1; } //set u-knotvektor for(i = 0; i < uOrder; i++){ uKnots[i] = 0.0f; uKnots[i + uDimension] = (float) (uDimension - uOrder + 1); } for(i = 0; i < (uDimension - uOrder); i++){ uKnots[i + uOrder] = (float) (i + 1); } //set v-knotvektor for(i = 0; i < vOrder; i++){ vKnots[i] = 0.0f; vKnots[i + vDimension] = (float) (vDimension - vOrder + 1); } for(i = 0; i < (vDimension - vOrder); i++){ vKnots[i + vOrder] = (float) (i + 1); } node->setField(node->uDimension_Index(), new SFInt32(uDimension)); node->setField(node->vDimension_Index(), new SFInt32(vDimension)); node->uKnot(new MFFloat(uKnots, uDimension + uOrder)); node->vKnot(new MFFloat(vKnots, vDimension + vOrder)); node->setField(node->uOrder_Index(), new SFInt32(uOrder)); node->setField(node->vOrder_Index(), new SFInt32(vOrder)); node->controlPoint(new MFVec3f(controlPoints, uDimension * vDimension * 3)); node->weight(new MFFloat(weights, uDimension * vDimension)); node->ccw(new SFBool(_mesh->ccw())); node->solid(new SFBool(_mesh->solid())); node->setField(node->uTessellation_Index(), new SFInt32(uTess-1)); node->setField(node->vTessellation_Index(), new SFInt32(vTess-1)); for (int iteration = 0; iteration < 2; iteration++) { node->reInit(); node->createMesh(); if (node->getVertices() != NULL) { assert(size == node->getVertices()->getSize()); float *vert = new float[size]; MFVec3f *nurbsControlPoints = node->controlPoint(); for (i = 0; i < size; i++) { vert[i] = node->getVertices()->getValues()[i]; float meshValue =_mesh->getVertices()->getValues()[i]; float nurbsValue = nurbsControlPoints->getValues()[i]; if (fabs(vert[i]) > EPSILON) { vert[i] = nurbsValue + nurbsValue * meshValue / vert[i]; vert[i] = vert[i] / 2.0; } } for (i = 0; i < size; i++) { nurbsControlPoints->setValue(i, vert[i]); } } } node->setField(node->uTessellation_Index(), new SFInt32(0)); node->setField(node->vTessellation_Index(), new SFInt32(0)); if (storeOldTesselation) { uTessellation(new SFInt32(oldUTess)); vTessellation(new SFInt32(oldVTess)); } return node; }