SuperEllipsoid         Using super ellipsoid for creating simple 3d primitives

Code for creating a super ellipsoid. Using a super ellipsoid makes it easy to create simple 3d primitives such as cube, cylinder, sphere etc. To use this class use the approach lined out in http://www.ogre3d.org/wiki/index.php/ManualSphereMeshes to make a genuine Mesh, or subclass SimpleRenderable and make use of writeData method.

# SuperEllipsoid.h

#ifndef _SUPERELLIPSOID_H_
#define _SUPERELLIPSOID_H_

#include <Ogre.h>

class SuperEllipsoid
{
public:
typedef enum Shape {CUBE, ROUNDED_CUBE, CYLINDER, SPHERE};

SuperEllipsoid();
SuperEllipsoid(int samples, float n1, float n2, float scale = 1.0);
SuperEllipsoid(Shape shape, int samples = 60, float scale = 1.0);
~SuperEllipsoid();

void createSuperEllipsoid(int samples, float n1, float n2, float scale = 1.0);
void createSuperEllipsoid(Shape shape, int samples = 60, float scale = 1.0);
int getNumVertices();
float *getPointerToVertexData() const;
Ogre::Vector3 getMaxPoint();
Ogre::Vector3 getMinPoint();

private:
float *vertexData;
size_t vertexDataSize;
Ogre::Vector3 maxPoint, minPoint;

std::vector<Ogre::Vector3> vertices;
std::vector<Ogre::Vector3> normals;
Ogre::Vector3 sampleSuperEllipsoid(float phi, float beta, float n1, float n2,
float scaleX=1.0, float scaleY=1.0, float scaleZ=1.0);
Ogre::Vector3 calculateNormal(float phi, float beta, float n1, float n2,
float scaleX, float scaleY, float scaleZ);
Ogre::Vector3 calculateNormal(Ogre::Vector3 p1, Ogre::Vector3 p2, Ogre::Vector3 p3);
void copyVertexDataToArray();
};

#endif

# SuperEllipsoid.cpp

#include "Superellipsoid.h"
#include <cmath>

#define SIGN(r) Ogre::Math::Sign(r)

SuperEllipsoid::SuperEllipsoid()
{
vertexData = NULL;
vertexDataSize = 0;
}

SuperEllipsoid::SuperEllipsoid(int samples, float n1, float n2, float scale)
{
vertexData = NULL;
vertexDataSize = 0;
createSuperEllipsoid(samples, n1, n2, scale);
}

SuperEllipsoid::SuperEllipsoid(Shape shape, int samples, float scale)
{
vertexData = NULL;
vertexDataSize = 0;
createSuperEllipsoid(shape, samples, scale);
}

SuperEllipsoid::~SuperEllipsoid()
{
delete [] vertexData;
}

void SuperEllipsoid::createSuperEllipsoid(int samples, float n1, float n2, float scale)
{
float phi = 0.0, phi2 = 0.0, beta = 0.0;
Ogre::Vector3 p1, p2, p3;

float dB = Ogre::Math::TWO_PI/samples;
float dP = Ogre::Math::TWO_PI/samples;

phi = -Ogre::Math::HALF_PI;

for(int j=0; j<=samples/2; j++)
{
beta = -Ogre::Math::PI;

for(int i=0; i<=samples; i++)
{
//Triangle #1
vertices.push_back(sampleSuperEllipsoid(phi, beta, n1, n2, scale, scale, scale));
normals.push_back(calculateNormal(phi, beta, n1, n2, scale, scale, scale));
vertices.push_back(sampleSuperEllipsoid(phi+dP, beta, n1, n2, scale, scale, scale));
normals.push_back(calculateNormal(phi+dP, beta, n1, n2, scale, scale, scale));
vertices.push_back(sampleSuperEllipsoid(phi+dP, beta+dB, n1, n2, scale, scale, scale));
normals.push_back(calculateNormal(phi+dP, beta+dB, n1, n2, scale, scale, scale));

//Triangle #2
vertices.push_back(sampleSuperEllipsoid(phi, beta, n1, n2, scale, scale, scale));
normals.push_back(calculateNormal(phi, beta, n1, n2, scale, scale, scale));
vertices.push_back(sampleSuperEllipsoid(phi+dP, beta+dB, n1, n2, scale, scale, scale));
normals.push_back(calculateNormal(phi+dP, beta+dB, n1, n2, scale, scale, scale));
vertices.push_back(sampleSuperEllipsoid(phi, beta+dB, n1, n2, scale, scale, scale));
normals.push_back(calculateNormal(phi, beta+dB, n1, n2, scale, scale, scale));

beta += dB;
}

phi += dP;
}

copyVertexDataToArray();
}

void SuperEllipsoid::createSuperEllipsoid(Shape shape, int samples, float scale)
{
float n1, n2;

switch(shape)
{
case CUBE:
n1 = n2 = 0.0;
break;
case ROUNDED_CUBE:
n1 = n2 = 0.2;
break;
case CYLINDER:
n1 = 0.2;
n2 = 1.0;
break;
case SPHERE:
n1 = n2 = 1.0;
break;
}

createSuperEllipsoid(samples, n1, n2, scale);
}

int SuperEllipsoid::getNumVertices()
{
return (int)vertices.size();
}

float *SuperEllipsoid::getPointerToVertexData() const
{
return vertexData;
}

Ogre::Vector3 SuperEllipsoid::getMaxPoint()
{
return maxPoint;
}

Ogre::Vector3 SuperEllipsoid::getMinPoint()
{
return minPoint;
}

Ogre::Vector3 SuperEllipsoid::sampleSuperEllipsoid(float phi, float beta, float n1, float n2,
float scaleX, float scaleY, float scaleZ)
{
Ogre::Vector3 vertex;

float cosPhi = cos(phi); float cosBeta = cos(beta);
float sinPhi = sin(phi); float sinBeta = sin(beta);

vertex.x = scaleX * SIGN(cosPhi) * pow(fabs(cosPhi), n1) * SIGN(cosBeta) * pow(fabs(cosBeta), n2);
vertex.z = scaleY * SIGN(cosPhi) * pow(fabs(cosPhi), n1) * SIGN(sinBeta) * pow(fabs(sinBeta), n2);
vertex.y = scaleZ * SIGN(sinPhi) * pow(fabs(sinPhi), n1);

return vertex;
}

Ogre::Vector3 SuperEllipsoid::calculateNormal(float phi, float beta, float n1, float n2,
float scaleX, float scaleY, float scaleZ)
{
Ogre::Vector3 normal;

float cosPhi = cos(phi); float cosBeta = cos(beta);
float sinPhi = sin(phi); float sinBeta = sin(beta);

normal.x = SIGN(cosPhi) * pow(fabs(cosPhi), 2-n1) * SIGN(cosBeta) * pow(fabs(cosBeta), 2-n2) / scaleX;
normal.z = SIGN(cosPhi) * pow(fabs(cosPhi), 2-n1) * SIGN(sinBeta) * pow(fabs(sinBeta), 2-n2) / scaleY;
normal.y = SIGN(sinPhi) * pow(fabs(sinPhi), 2-n1) / scaleZ;

normal.normalise();

return normal;
}

void SuperEllipsoid::copyVertexDataToArray()
{
size_t size = vertices.size() * 2 * 3; // vertices + normals

if(vertexData == NULL)
vertexData = new float[size];
else if(vertexDataSize != size)
{
delete [] vertexData;
vertexData = new float[size];
}

vertexDataSize = size;

size_t numVertices = vertices.size();

for(int i=0; i<numVertices; i++)
{
vertexData[i*6]   = vertices[i].x;
vertexData[i*6+1] = vertices[i].y;
vertexData[i*6+2] = vertices[i].z;

vertexData[i*6+3] = normals[i].x;
vertexData[i*6+4] = normals[i].y;
vertexData[i*6+5] = normals[i].z;

if(vertices[i].x < minPoint.x)
minPoint.x = vertices[i].x;
if(vertices[i].y < minPoint.y)
minPoint.y = vertices[i].y;
if(vertices[i].z < minPoint.z)
minPoint.z = vertices[i].z;

if(vertices[i].x > maxPoint.x)
maxPoint.x = vertices[i].x;
if(vertices[i].y > maxPoint.y)
maxPoint.y = vertices[i].y;
if(vertices[i].z > maxPoint.z)
maxPoint.z = vertices[i].z;
}
}

This code hasnt been fully tested so errors may occur. If you see some errors or enhancements that can be done please let me know!

30 online users