Logo Search packages:      
Sourcecode: whitedune version File versions  Download package

NodeCylinder.cpp

/*
 * 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 <stdio.h>
#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<narea; i++){
      generatrix[i].x = i * stepradius;
      generatrix[i].y = y; 
      generatrix[i].z = 0; 
    }
    if(iside==1){
      for(i=narea; i<(narea+vDegree-2); i++){
      generatrix[i].x = (narea-1) * stepradius;
      generatrix[i].y = y; 
      generatrix[i].z = 0; 
      }
    }
  }
  //shell
  float stepdown;
  if (iside==1){
    if (nshell > 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; i<vDimension; i++){
    tmpWeights[i] = 1;
  }
  //v-knotvector
  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);  
  } 

  //rotate generatrix. 
  float arc = 360;
  Vec3f P1, P2;
  P1.x = P2.x = 0;
  P1.z = P2.z = 0;
  P1.y = 0;
  P2.y = -1;

  NurbsMakeRevolvedSurface nurbsSphere(generatrix, tmpWeights, vDimension, narcs, arc, uDegree, P1, P2);   
  if (!nurbsSphere.isValid())
      return NULL;

  float *controlPoints = new float[nurbsSphere.getPointSize()];
  float *weights = new float[nurbsSphere.getWeightSize()];
  int uDimension = nurbsSphere.getWeightSize() / vDimension;
  float *uKnots = new float[uDimension + uOrder]; 

  //get results of rotation
  //get control points
  max_i = nurbsSphere.getPointSize();
  for(i=0; i<max_i; i++){
    controlPoints[i] = nurbsSphere.getControlPoints(i);
  }
  //weights
  max_i = nurbsSphere.getWeightSize();
  for(i=0; i<max_i; i++){
    weights[i] = nurbsSphere.getWeights(i);
  }

  if (uDegree == 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);  
    } 
  }  
  else {
    //u-knotenvector
    max_i = nurbsSphere.getKnotSize();
    for(i=0; i<max_i; i++){
      uKnots[i] = nurbsSphere.getKnots(i);
    }
  }

  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));

  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;
}



Generated by  Doxygen 1.6.0   Back to index