/* * NodeCylinder.cpp * * Copyright (C) 1999 Stephen F. White * 2003 Th. Rothermel * 2004 Wu Qingwei * * 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 "stdafx.h" #include "NodeCylinder.h" #include "Proto.h" #include "FieldValue.h" #include "Node.h" #include "Scene.h" #include "SFBool.h" #include "SFFloat.h" #include "MFNode.h" #include "SFNode.h" #include "SFInt32.h" #include "MFFloat.h" #include "MFVec3f.h" #include "NurbsArc.h" #include "NurbsMakeRevolvedSurface.h" #include "NodeNurbsSurface.h" #include "RenderState.h" #include "SFVec3f.h" #include "Util.h" #include "MFNode.h" ProtoCylinder::ProtoCylinder(Scene *scene) : Proto(scene, "Cylinder") { bottom.set( addField(SFBOOL, "bottom", new SFBool(true))); height.set( addField(SFFLOAT, "height", new SFFloat(2.0f), new SFFloat(0.0f))); radius.set( addField(SFFLOAT, "radius", new SFFloat(1.0f), new SFFloat(0.0f))); side.set( addField(SFBOOL, "side", new SFBool(true))); top.set( addField(SFBOOL, "top", new SFBool(true))); } Node * ProtoCylinder::create(Scene *scene) { return new NodeCylinder(scene, this); } NodeCylinder::NodeCylinder(Scene *scene, Proto *def) : Node(scene, def) { } void NodeCylinder::draw() { float fheight = height()->getValue(); float fradius = radius()->getValue(); GLUquadricObj *obj = gluNewQuadric(); if (glIsEnabled(GL_TEXTURE_2D)) gluQuadricTexture(obj, GL_TRUE); glPushMatrix(); glRotatef(-90.0f, 1.0f, 0.0f, 0.0f); glTranslatef(0.0f, 0.0f, -fheight * 0.5f); if (side()->getValue()) { gluCylinder(obj, fradius, fradius, fheight, 20, 1); } if (bottom()->getValue()) { glPushMatrix(); glRotatef(180.0f, 1.0f, 0.0f, 0.0f); gluDisk(obj, 0.0f, fradius, 20, 1); glPopMatrix(); } if (top()->getValue()) { glPushMatrix(); glTranslatef(0.0f, 0.0f, fheight); gluDisk(obj, 0.0f, fradius, 20, 1); glPopMatrix(); } glPopMatrix(); gluDeleteQuadric(obj); } void NodeCylinder::drawHandles() { RenderState state; float fheight = height()->getValue(); float fradius = radius()->getValue(); glPushMatrix(); glScalef(fradius * 1.0f,fheight * 0.5f,fradius * 1.0f); glPushAttrib(GL_LIGHTING); glDisable(GL_LIGHTING); glPushName(0); Util::myGlColor3f(1.0f, 1.0f, 1.0f); state.startDrawHandles(); for (int i = 0; i < 6; i++) { glLoadName(i); state.drawHandle(CylinderCorners[i]); } state.endDrawHandles(); glPopName(); glPopAttrib(); glPopMatrix(); } Vec3f NodeCylinder::getHandle(int handle,int* constrait, int* field) { float fheight = height()->getValue(); float fradius = radius()->getValue(); switch (handle) { case CBRB: case CBLB: *field=1; return Vec3f(0.0f,1.0f*fheight,0.0f) * Vec3f(CylinderCorners[handle]) * 0.5f; case CTRB: case CBLF: *field=2; return Vec3f(1.0f*fradius,0.0f,0.0f) * Vec3f(CylinderCorners[handle]) * 1.0f; case CTLF:case CTLB: *field=2; return Vec3f(0.0f,0.0f,1.0f*fradius) * Vec3f(CylinderCorners[handle]) * 1.0f; default: assert(0); return Vec3f(1.0f, 1.0f, 1.0f); } } void NodeCylinder::setHandle(int handle, const Vec3f &v) { switch (handle) { case CBRB: _scene->setField(this,height_Index(),new SFFloat(v.y*2.0f*Vec3f(CylinderCorners[handle]).y)); break; case CBLB: _scene->setField(this,height_Index(),new SFFloat(v.y*2.0f*Vec3f(CylinderCorners[handle]).y)); break; case CTRB: case CBLF: _scene->setField(this,radius_Index(),new SFFloat(v.x*1.0f*Vec3f(CylinderCorners[handle]).x)); break; case CTLF:case CTLB: _scene->setField(this,radius_Index(),new SFFloat(v.z*1.0f*Vec3f(CylinderCorners[handle]).z)); break; } } Node* NodeCylinder::toNurbs(int nshell, int narea, int narcs, int uDegree, int vDegree) { NodeNurbsSurface *node = (NodeNurbsSurface *) _scene->createNode("NurbsSurface"); int ibottom = bottom()->getValue(); float fheight = height()->getValue(); float fradius = radius()->getValue(); int iside = side()->getValue(); int itop = top()->getValue(); /*At the edge (shell to bottom area) there are p circles at the same position to achieve sharp edge top and bottom turned on and shell turned off will result in volume looking like a barrel, and NOT in two independent surfaces meaning of the main variables: int narcs ->number of circular arc segments, cone consists of int nshell -> number of controlpoints on shell in direction of axis int narea -> number of controlpoints on top/bottom area in direction of radius int vDegree -> degree in direction v int uDegree -> degree in direction u, currently limited to 2 */ int vOrder = vDegree +1; int uOrder = uDegree +1; int vDimension; if(iside==1){ vDimension = (ibottom * (narea + vDegree - 2)) + (itop * (narea + vDegree - 2)) + nshell; } else{ vDimension = (ibottom * narea) + (itop * narea); } float *vKnots = new float[vDimension + vOrder]; Vec3f *generatrix = new Vec3f[vDimension]; float *tmpWeights = new float[vDimension]; int i,j; int max_i; float y; //load generatrix //top area float stepradius; if (narea>1){ stepradius = fradius / (narea-1); } else{ stepradius = fradius; } if (itop==1){ y = fheight / 2; for(i=0; i 1){ stepdown = fheight / (nshell - 1); y = fheight / 2; } else{ if ((nshell==1) && (itop==1) && (ibottom==1)){ y = 0; } if ((nshell==1) && (itop==1) && (ibottom==0)){ y = - fheight / 2; } if ((nshell==1) && (itop==0) && (ibottom==1)){ y = fheight / 2; } } for(i=(itop*(narea+vDegree-2)); i<((itop*(narea+vDegree-2))+(iside*nshell)); i++){ generatrix[i].x = fradius; generatrix[i].y = y; generatrix[i].z = 0; y = y - stepdown; } } //bottom area if (ibottom==1){ y = - fheight/2; if(iside==1){ for(i=((itop*(narea+vDegree-2))+(iside*nshell)); i<((itop*(narea+vDegree-2))+(iside*nshell)+(ibottom*(vDegree-2))); i++){ generatrix[i].x = (narea-1) * stepradius; generatrix[i].y = y; generatrix[i].z = 0; } for(i=((itop*(narea+vDegree-2))+(iside*nshell)+(ibottom*vDegree-2)), j=1; i<((itop*(narea+vDegree-2))+(iside*nshell)+(ibottom*(narea+vDegree-2))); i++, j++){ generatrix[i].x = (narea - j) * stepradius; generatrix[i].y = y; generatrix[i].z = 0; } } else{ for(i=((itop*narea)+(iside*nshell)), j=1; i<((itop*narea)+(iside*nshell)+(ibottom*narea)); i++, j++){ generatrix[i].x = (narea - j) * stepradius; generatrix[i].y = y; generatrix[i].z = 0; } } } //weights for(i=0; isetField(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)); return node; } Vec3f NodeCylinder::getMinBoundingBox(void) { float fheight = height()->getValue() * 0.5; Vec3f ret(- radius()->getValue(), - fheight, - radius()->getValue()); if (!(side()->getValue())) if (!(bottom()->getValue())) if (top()->getValue()) ret.y = fheight; else { ret.x = 0; ret.y = 0; ret.z = 0; } return ret; } Vec3f NodeCylinder::getMaxBoundingBox(void) { float fheight = height()->getValue() * 0.5; Vec3f ret(radius()->getValue(), fheight, radius()->getValue()); if (!(side()->getValue())) if (!(top()->getValue())) if (bottom()->getValue()) ret.y = - fheight; else { ret.x = 0; ret.y = 0; ret.z = 0; } return ret; }