/* * NodeCone.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 "NodeCone.h" #include "Proto.h" #include "FieldValue.h" #include "Scene.h" #include "SFFloat.h" #include "SFBool.h" #include "MFNode.h" #include "SFNode.h" #include "SFInt32.h" #include "MFFloat.h" #include "MFVec3f.h" #include "NurbsMakeRevolvedSurface.h" #include "NodeNurbsSurface.h" #include "RenderState.h" #include "SFVec3f.h" #include "Util.h" #include "MFNode.h" ProtoCone::ProtoCone(Scene *scene) : Proto(scene, "Cone") { bottomRadius.set( addField(SFFLOAT, "bottomRadius", new SFFloat(1.0f), new SFFloat(0.0f))); height.set( addField(SFFLOAT, "height", new SFFloat(2.0f), new SFFloat(0.0f))); side.set( addField(SFBOOL, "side", new SFBool(true))); bottom.set( addField(SFBOOL, "bottom", new SFBool(true))); } Node *ProtoCone::create(Scene *scene) { return new NodeCone(scene, this); } NodeCone::NodeCone(Scene *scene, Proto *def) : Node(scene, def) { } void NodeCone::draw() { float fbottomRadius = bottomRadius()->getValue(); float fheight = height()->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, fbottomRadius, 0.0f, fheight, 16, 2); } if (bottom()->getValue()) { glPushMatrix(); glRotatef(180.0f, 1.0f, 0.0f, 0.0f); gluDisk(obj, 0.0f, fbottomRadius, 20, 1); glPopMatrix(); } glPopMatrix(); gluDeleteQuadric(obj); } void NodeCone::drawHandles() { RenderState state; float fheight = height()->getValue(); float fbottomRadius = bottomRadius()->getValue(); glPushMatrix(); glScalef(fbottomRadius * 1.0f,fheight * 0.5f, fbottomRadius * 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 < 5; i++) { glLoadName(i); state.drawHandle(ConeCorners[i]); } state.endDrawHandles(); glPopName(); glPopAttrib(); glPopMatrix(); } Vec3f NodeCone::getHandle(int handle,int* constrait, int* field) { float fheight = height()->getValue(); float fbottomRadius = bottomRadius()->getValue(); switch (handle) { case COBLB: *field=1; return Vec3f(1.0f*fbottomRadius,1.0f*fheight,1.0f*fbottomRadius) * Vec3f(ConeCorners[handle]) * 0.5f; case COBRB: case COTRB: *field=0; return Vec3f(1.0f*fbottomRadius,0.0f,1.0f*fbottomRadius) * Vec3f(ConeCorners[handle]) * 1.0f; case COTLB: case COBLF: *field=0; return Vec3f(1.0f*fbottomRadius,0.0f,1.0f*fbottomRadius) * Vec3f(ConeCorners[handle]) * 1.0f; default: assert(0); return Vec3f(1.0f, 1.0f, 1.0f); } } void NodeCone::setHandle(int handle,const Vec3f &v) { switch (handle) { case COBLB: _scene->setField(this,height_Index(),new SFFloat(v.y*2.0f*Vec3f(ConeCorners[handle]).y)); break; case COBRB: case COTRB: _scene->setField(this,bottomRadius_Index(),new SFFloat(v.x*1.0f*Vec3f(ConeCorners[handle]).x)); break; case COTLB: case COBLF: _scene->setField(this,bottomRadius_Index(),new SFFloat(v.z*1.0f*Vec3f(ConeCorners[handle]).z)); break; } } Node* NodeCone::toNurbs(int nshell, int narea, int narcs, int uDegree, int vDegree) { NodeNurbsSurface *node = (NodeNurbsSurface *) _scene->createNode("NurbsSurface"); float fbottomRadius = bottomRadius()->getValue(); float fheight = height()->getValue(); int iside = side()->getValue(); int ibottom = bottom()->getValue(); /*At the edge (shell to bottom area) there are p circles at the same position to achieve sharp edge 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 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)) + nshell; } else{ vDimension = (ibottom * 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 //shell float stepdown; float stepradius; if (iside==1){ y = fheight / 2; //start at apex stepdown = fheight / (nshell - 1); stepradius = fbottomRadius / (nshell - 1); for(i=0; i<(iside*nshell); i++){ generatrix[i].x = i * stepradius; generatrix[i].y = y; generatrix[i].z = 0; y = y - stepdown; } } //bottom area if (ibottom==1){ y = - fheight / 2; stepradius = fbottomRadius / (narea - 1); if(iside==1){ for(i=(iside*nshell), j=1; i<((iside*nshell)+vDegree-2); i++, j++){ generatrix[i].x = (narea - 1) * stepradius; generatrix[i].y = y; generatrix[i].z = 0; } for(i=(nshell+vDegree-2), j=1; i<(nshell+narea+vDegree-2); i++, j++){ generatrix[i].x = (narea - j) * stepradius; generatrix[i].y = y; generatrix[i].z = 0; } } else{ for(i=0, j=1; 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 NodeCone::getMinBoundingBox(void) { float fheight = height()->getValue() * 0.5; Vec3f ret(-bottomRadius()->getValue(), -fheight, -bottomRadius()->getValue()); if (!(side()->getValue())) if (!(bottom()->getValue())) { ret.x = 0; ret.y = 0; ret.z = 0; } return ret; } Vec3f NodeCone::getMaxBoundingBox(void) { float fheight = height()->getValue() * 0.5; Vec3f ret(bottomRadius()->getValue(), fheight, bottomRadius()->getValue()); if (!(side()->getValue())) if (bottom()->getValue()) ret.y = -fheight; else { ret.x = 0; ret.y = 0; ret.z = 0; } return ret; } void NodeCone::flip(int index) { if (index == 1) { // cone can not handle a y-flip, convert to NurbsSurface Node *nurbs =_scene->convertConeToNurbs(this); if (nurbs != NULL) nurbs->flip(index); } }