diff --git a/CHECK_OPENGL_ERROR.h b/CHECK_OPENGL_ERROR.h new file mode 100755 index 0000000..d9324ef --- /dev/null +++ b/CHECK_OPENGL_ERROR.h @@ -0,0 +1,15 @@ +#ifndef RTS_OPENGL_ERROR +#define RTS_OPENGL_ERROR + +#include +#include +#include + +#define CHECK_OPENGL_ERROR \ +{ GLenum error; \ + while ( (error = glGetError()) != GL_NO_ERROR) { \ + printf( "OpenGL ERROR: %s\nCHECK POINT: %s (line %d)\n", gluErrorString(error), __FILE__, __LINE__ ); \ + } \ +} + +#endif \ No newline at end of file diff --git a/PerformanceDataTemplate.h b/PerformanceDataTemplate.h new file mode 100755 index 0000000..9b5684e --- /dev/null +++ b/PerformanceDataTemplate.h @@ -0,0 +1,138 @@ +// add the following to a cpp file: +// PerformanceData PD; + + +#pragma once +#include +using namespace std; + +enum PerformanceDataType +{ + PD_DISPLAY=0, + PD_SPS, + PD_UNUSED0, + + //my stuff + SIMULATE_SPECTRUM, + SIMULATE_GPU, + KRAMERS_KRONIG, + + + + //end my stuff + PERFORMANCE_DATA_TYPE_COUNT +}; + +static char PDTypeNames[][255] = { + "Display ", + "Simulation Total ", + " ----------------- ", + //my stuff + "Simulate Spectrum ", + " GPU Portion ", + "Kramers-Kronig ", + + //end my stuff + +}; +#ifdef WIN32 +#include +#include +#include + +#include +#include + +//------------------------------------------------------------------------------- + +class PerformanceData +{ +public: + PerformanceData() { ClearAll(); QueryPerformanceFrequency(&cps); } + ~PerformanceData(){} + + void ClearAll() + { + for ( int i=0; i maxTime[type] ) maxTime[type] = t; + totalTime[type] -= times[type][ pos[type] ]; + times[type][ pos[type] ] = t; + totalTime[type] += t; + pos[type]++; + if ( pos[type] == 0 ) dataReady[type] = true; + } + + void PrintResult( ostream &os,int i=PERFORMANCE_DATA_TYPE_COUNT) + { + os.setf(ios::fixed); + if ((i=0)){ + double a = GetAvrgTime(i); + if ( a ) + os<< PDTypeNames[i]<<" : avrg="< +#include "cuda_runtime.h" +#include "device_launch_parameters.h" + +#ifndef CUDA_HANDLE_ERROR_H +#define CUDA_HANDLE_ERROR_H + +//handle error macro +static void HandleError( cudaError_t err, const char *file, int line ) { + if (err != cudaSuccess) { + FILE* outfile = fopen("cudaErrorLog.txt", "w"); + fprintf(outfile, "%s in %s at line %d\n", cudaGetErrorString( err ), file, line ); + fclose(outfile); + exit( EXIT_FAILURE ); + printf("%s in %s at line %d\n", cudaGetErrorString( err ), file, line ); + } +} +#define HANDLE_ERROR( err ) (HandleError( err, __FILE__, __LINE__ )) + +static cudaEvent_t tStartEvent; +static cudaEvent_t tStopEvent; +static void gpuStartTimer() +{ + //set up timing events + cudaEventCreate(&tStartEvent); + cudaEventCreate(&tStopEvent); + cudaEventRecord(tStartEvent, 0); +} + +static float gpuStopTimer() +{ + cudaEventRecord(tStopEvent, 0); + cudaEventSynchronize(tStopEvent); + float elapsedTime; + cudaEventElapsedTime(&elapsedTime, tStartEvent, tStopEvent); + cudaEventDestroy(tStartEvent); + cudaEventDestroy(tStopEvent); + return elapsedTime; +} + +#endif diff --git a/cuda_callable.h b/cuda_callable.h new file mode 100644 index 0000000..eefc437 --- /dev/null +++ b/cuda_callable.h @@ -0,0 +1,10 @@ +#ifndef CUDA_CALLABLE + +//define the CUDA_CALLABLE macro (will prefix all members) +#ifdef __CUDACC__ +#define CUDA_CALLABLE __host__ __device__ +#else +#define CUDA_CALLABLE +#endif + +#endif diff --git a/objJedi.cpp b/objJedi.cpp new file mode 100755 index 0000000..8b87934 --- /dev/null +++ b/objJedi.cpp @@ -0,0 +1,1531 @@ +/*BUG NOTES +The standard function calls for inserting vertices don't work anymore. I've fixed points +but everything beyond that has to be updated. +*/ + +#include "objJedi.h" +#include "rtsvector3D.h" +#include "rtspoint3D.h" +#include +//variable for use in global functions +rtsOBJ g_OBJ; + +/********UTILITY METHODS*******************************/ +void rtsOBJ::Scale(float scale_x, float scale_y, float scale_z) +{ + vector::iterator i; + for(i = v_list.begin(); i!= v_list.end(); i++) + { + (*i).x *= scale_x; + (*i).y *= scale_y; + (*i).z *= scale_z; + } +} + +void rtsOBJ::Translate(float trans_x, float trans_y, float trans_z) +{ + vector::iterator i; + for(i = v_list.begin(); i!= v_list.end(); i++) + { + (*i).x += trans_x; + (*i).y += trans_y; + (*i).z += trans_z; + } + +} + +float rtsOBJ::GetDistance(float x, float y, float z) +{ + //gets the distance between the specified point and the nearest surface of the OBJ + //currently only works for lines + + //cout<<"Primitives: "< p0, p1, p2; + double min_dist = 255; + double dist, numerator, denominator; + int p, l; + vector3D v, w; + double c1, c2, b; + point3D Pb; + + //for each line + for(l=0; l OBJ_POLYGON) + return OBJ_ERROR; + + //otherwise, go ahead and set the mode + g_CurrentMode = mode; + //set the number of vertices to zero + g_NumVertices = 0; + + //reset the current state primitive state + current_primitive_mask = 0x0; + + return OBJ_OK; +} + +OBJint rtsOBJ::objEnd() +{ + OBJint error = OBJ_OK; + //check to make sure the number of rendered vertices is valid for the current mode + switch(g_CurrentMode) + { + case OBJ_NONE: + //can't quit if we haven't started + error = OBJ_ERROR; + break; + case OBJ_LINES: + //if less than two vertices or an odd number of vertices + if(g_NumVertices < 2 || g_NumVertices%2 != 0) + { + //if there wasn't a vertex at all + if(g_NumVertices == 0) + error = OBJ_ERROR; + //if there was at least one vertex + else + { + //pop the last line off the list + primitives.pop_back(); + lines.pop_back(); + error = OBJ_ERROR; + } + } + break; + case OBJ_LINE_STRIP: + //if less than two vertices + if(g_NumVertices < 2) + { + //if there wasn't a vertex at all + if(g_NumVertices == 0) + error = OBJ_ERROR; + //if there was at least one vertex + else + { + //pop the last line off the list + primitives.pop_back(); + lines.pop_back(); + error = OBJ_ERROR; + } + } + break; + case OBJ_LINE_LOOP: + //if less than three vertices + if(g_NumVertices < 3) + { + //pop the last line off the list + primitives.pop_back(); + lines.pop_back(); + error = OBJ_ERROR; + } + //connect the first and last points + else + { + error = f_TerminateLineLoop(); + } + break; + case OBJ_TRIANGLES: + //if less than three vertices or not a power of three + if(g_NumVertices < 3 || g_NumVertices%3 !=0) + { + primitives.pop_back(); + faces.pop_back(); + error = OBJ_ERROR; + } + break; + case OBJ_TRIANGLE_STRIP: + //if less than three vertices + if(g_NumVertices < 3) + { + primitives.pop_back(); + faces.pop_back(); + error = OBJ_ERROR; + } + break; + case OBJ_TRIANGLE_FAN: + //if less than three vertices + if(g_NumVertices < 3) + { + primitives.pop_back(); + faces.pop_back(); + error = OBJ_ERROR; + } + break; + case OBJ_QUADS: + if(g_NumVertices < 4 || g_NumVertices%4 != 0) + { + primitives.pop_back(); + faces.pop_back(); + error = OBJ_ERROR; + } + break; + case OBJ_QUAD_STRIP: + //has to be at least 4 vertices and an even number + if(g_NumVertices < 4 || g_NumVertices%2 != 0) + { + primitives.pop_back(); + faces.pop_back(); + error = OBJ_ERROR; + } + break; + case OBJ_POLYGON: + //has to be at least three vertices + if(g_NumVertices < 3) + { + primitives.pop_back(); + faces.pop_back(); + error = OBJ_ERROR; + } + break; + } + + //reset the attribute mask + g_AttributeMask = 0x0; + //just for closure, reset the attribute reset mask + g_AttributeResetMask = 0x0; + //stop rendering + g_CurrentMode = OBJ_NONE; + return error; +} + +OBJint rtsOBJ::f_InsertVertexf(float x, float y, float z, float w, unsigned char mask) +{ + //make sure we're rendering + if(g_CurrentMode == OBJ_NONE) + return OBJ_ERROR; + + //insert the vertex into the vertex vector + vertex_position v; + v.x = x; v.y = y; v.z=z; v.w=w; v.mask = mask; + v_list.push_back(v); + f_AdjustExtents(v); //set the bounding box + //insert texture coordinate and normal if specified for this primitive + if((current_primitive_mask & OBJ_VT) && (vt_changed)) + vt_list.push_back(current_vt); + if((current_primitive_mask & OBJ_VN) && (vn_changed)) + vn_list.push_back(current_vn); + + + //increment the number of vertices inserted + g_NumVertices++; + + //handle each case of the vertex creation individually + OBJint error = OBJ_OK; + switch(g_CurrentMode) + { + case OBJ_POINTS: + error = f_InsertPointVertex(); + break; + case OBJ_LINES: + error = f_InsertLineVertex(); + break; + case OBJ_LINE_LOOP: + error = f_InsertLineLoopVertex(); + break; + case OBJ_LINE_STRIP: + error = f_InsertLineStripVertex(); + break; + case OBJ_TRIANGLES: + error = f_InsertTriangleVertex(); + break; + case OBJ_TRIANGLE_STRIP: + error = f_InsertTriangleStripVertex(); + break; + case OBJ_TRIANGLE_FAN: + error = f_InsertTriangleFanVertex(); + break; + case OBJ_QUADS: + error = f_InsertQuadVertex(); + break; + case OBJ_QUAD_STRIP: + error = f_InsertQuadStripVertex(); + break; + case OBJ_POLYGON: + error = f_InsertPolygonVertex(); + break; + } + //set the reset mask to zero + g_AttributeResetMask = 0x0; + + //set the attribute mask to include vertex position + g_AttributeMask = g_AttributeMask | OBJ_V; + + //return the result of the insertion + return error; +} + +OBJint rtsOBJ::objVertex1f(float x) +{ + return f_InsertVertexf(x, 0.0, 0.0, 0.0, OBJ_V_X); +} + +OBJint rtsOBJ::objVertex2f(float x, float y) +{ + return f_InsertVertexf(x, y, 0.0, 0.0, OBJ_V_X | OBJ_V_Y); +} + +OBJint rtsOBJ::objVertex3f(float x, float y, float z) +{ + return f_InsertVertexf(x, y, z, 0.0, OBJ_V_X | OBJ_V_Y | OBJ_V_Z); + +} + +OBJint rtsOBJ::objVertex4f(float x, float y, float z, float w) +{ + return f_InsertVertexf(x, y, z, w, OBJ_V_X | OBJ_V_Y | OBJ_V_Z | OBJ_V_W); +} + +OBJint rtsOBJ::objNormal3f(float i, float j, float k) +{ + return f_InsertNormalf(i, j, k, OBJ_VN_I | OBJ_VN_J | OBJ_VN_K); +} +OBJint rtsOBJ::objNormal2f(float i, float j) +{ + return f_InsertNormalf(i, j, 0.0, OBJ_VN_I | OBJ_VN_J); +} + +OBJint rtsOBJ::objNormal1f(float i) +{ + return f_InsertNormalf(i, 0.0, 0.0, OBJ_VN_I); +} + +OBJint rtsOBJ::f_InsertNormalf(float i, float j, float k, unsigned char mask) +{ + /*DEPRECATED + //if the mode is not rendering faces, there is an error + if(g_CurrentMode < OBJ_TRIANGLES) + return OBJ_ERROR; + //if the normal attribute flag is not set, set it (as long as a vertex hasn't been written) + if(!(g_AttributeMask & OBJ_VN)) + { + //if a vertex has been rendered, then we can't change the attribute, so exit + if(g_NumVertices > 0) + return OBJ_ERROR; + else + //otherwise, just set the attribute flag + g_AttributeMask = g_AttributeMask | OBJ_VN; + } + + + //insert the new normal into the normal list for the file + vertex_normal new_vn; + new_vn.i = i; new_vn.j = j; new_vn.k = k; + new_vn.mask = mask; + vn_list.push_back(new_vn); + */ + current_vn.i = i; //set the current texture state to the given coordinates + current_vn.j = j; + current_vn.k = k; + current_vn.mask = mask; //set the mask as appropriate + vn_changed = true; //the texture coordinate state has changed + current_primitive_mask = current_primitive_mask | OBJ_VN; //the current primitive now uses texture coordinates (if it didn't previously) + + return OBJ_OK; +} + +OBJint rtsOBJ::objTexCoord3f(float u, float v, float w) +{ + return f_InsertTexCoordf(u, v, w, OBJ_VT_U | OBJ_VT_V | OBJ_VT_W); +} + +OBJint rtsOBJ::objTexCoord2f(float u, float v) +{ + return f_InsertTexCoordf(u, v, 0.0, OBJ_VT_U | OBJ_VT_V); +} + +OBJint rtsOBJ::objTexCoord1f(float u) +{ + return f_InsertTexCoordf(u, 0.0, 0.0, OBJ_VT_U); +} + +OBJint rtsOBJ::f_InsertTexCoordf(float u, float v, float w, unsigned char mask) +{ + /* + DEPRECATED + //if the normal attribute flag is not set, set it (as long as a vertex hasn't been written) + if(!(g_AttributeMask & OBJ_VT)) + { + //if a vertex has been rendered, then we can't change the attribute, so exit + if(g_NumVertices > 0) + return OBJ_ERROR; + else + //otherwise, just set the attribute flag + g_AttributeMask = g_AttributeMask | OBJ_VT; + } + + //insert the new texture coordinate into the list for the file + vertex_texture new_vt; + new_vt.u = u; new_vt.v = v; new_vt.w = w; + new_vt.mask = mask; + vt_list.push_back(new_vt); + */ + current_vt.u = u; //set the current texture state to the given coordinates + current_vt.v = v; + current_vt.w = w; + current_vt.mask = mask; //set the mask as appropriate + vt_changed = true; //the texture coordinate state has changed + current_primitive_mask = current_primitive_mask | OBJ_VT; //the current primitive now uses texture coordinates (if it didn't previously) + + return OBJ_OK; +} + + +void rtsOBJ::insertVertexPosition(float x, float y, float z, unsigned char mask) +{ + vertex_position v; + v.x = x; + v.y = y; + v.z = z; + v.mask = mask; + + v_list.push_back(v); +} + +void rtsOBJ::insertLine(unsigned int num_points, unsigned int* pointlist, unsigned int* normallist, unsigned int* texturelist) +{ + //create the new primitive + primitive line; + line.type = OBJ_LINES; + line.mask = 0; + + //set the mask based on the passed data + if(pointlist != NULL) + line.mask = line.mask | OBJ_V; + if(normallist != NULL) + line.mask = line.mask | OBJ_VN; + if(texturelist != NULL) + line.mask = line.mask | OBJ_VT; + + //insert the line + int v; + vertex new_vert; + for(v=0; v 1) + points.push_back(p_index); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertLineVertex() +{ + //if this is an odd vertex, create a new line + if(g_NumVertices%2 == 1) + { + f_CreateNewLine(); + } + + f_InsertNewLineVertex(); + + return OBJ_OK; +} +OBJint rtsOBJ::f_InsertLineLoopVertex() +{ + //technically, this is the same as inserting a line strip vertex + f_InsertLineStripVertex(); + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertLineStripVertex() +{ + if(g_NumVertices == 1) + { + f_CreateNewLine(); + } + + f_InsertNewLineVertex(); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertTriangleVertex() +{ + //if this is the first vertex in a triangle, create a new triangle + if(g_NumVertices%3 == 1) + { + f_CreateNewFace(); + } + + + f_InsertNewFaceVertex(); + + return OBJ_OK; +} +OBJint rtsOBJ::f_InsertTriangleStripVertex() +{ + //in the special case of the first three vertices, just create a triangle + if(g_NumVertices <4) + f_InsertTriangleVertex(); + else + { + + //create a new face for the new triangle + f_CreateNewFace(); + + //insert the last two vertices from the previous triangle + f_InsertPreviousFaceVertex(1); + f_InsertPreviousFaceVertex(2); + //insert the new vertex + f_InsertNewFaceVertex(); + } + + return OBJ_OK; +} +OBJint rtsOBJ::f_InsertTriangleFanVertex() +{ + //in the special case of the first three vertices, just create a triangle + if(g_NumVertices <4) + f_InsertTriangleVertex(); + else + { + //create a new face for the new triangle + f_CreateNewFace(); + //add the previous vertices to the face + f_InsertFirstFaceVertex(0); + f_InsertPreviousFaceVertex(2); + //insert the current vertex + f_InsertNewFaceVertex(); + } + + return OBJ_OK; +} +OBJint rtsOBJ::f_InsertQuadVertex() +{ + //if this is the first vertex in a quad, create a new quad + if(g_NumVertices%4 == 1) + { + f_CreateNewFace(); + } + + f_InsertNewFaceVertex(); + + return OBJ_OK; +} +OBJint rtsOBJ::f_InsertQuadStripVertex() +{ + //in the case of one of the first four vertices, just create a quad + if(g_NumVertices < 5) + f_InsertQuadVertex(); + //if the vertex is odd (it will be the third vertex of a quad) + else if(g_NumVertices%2 == 1) + { + //create a new face for the new quad + f_CreateNewFace(); + //add the previous two vertices + f_InsertPreviousFaceVertex(2); + f_InsertPreviousFaceVertex(3); + //add the current vertex + f_InsertNewFaceVertex(); + } + else + { + //if this is the last vertex of the quad, just add it + f_InsertNewFaceVertex(); + + } + return OBJ_OK; +} +OBJint rtsOBJ::f_InsertPolygonVertex() +{ + //if this is the first vertex, create the quad + if(g_NumVertices == 1) + { + f_CreateNewFace(); + } + f_InsertNewFaceVertex(); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertPreviousFaceVertex(unsigned int v_index) +{ + /*Finds the vertex used in the previous face with the given index and + inserts it into the current face. This limits the redundancy in the file + for re-used vertices (in strips and fans). This also transfers texture + and normal information.*/ + + //find the index of the previous face + unsigned int prev_f_index = primitives.size() - 2; + //find the index of the current face + unsigned int f_index = prev_f_index +1; + //add the vertex information from the previous face to this face + primitives[f_index].p.push_back(primitives[prev_f_index].p[v_index]); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertFirstFaceVertex(unsigned int v_index) +{ + /*Finds the vertex used in the first face (since the last objBegin()) + with the given index and inserts it at the end of the current face. + This includes texture and normal information.*/ + + //The result depends on the type of face being rendered + //So far, this function only applies to triangle fans + if(g_CurrentMode != OBJ_TRIANGLE_FAN) + return OBJ_ERROR; + + //calculate the number of faces that have been rendered + unsigned int num_faces = g_NumVertices - 2; + //find the index of the first face + unsigned int first_f_index = primitives.size() - num_faces; + //find the index of the current face + unsigned int f_index = primitives.size() - 1; + //transfer the vertex information from the first face to this one + primitives[f_index].p.push_back(primitives[first_f_index].p[v_index]); + + + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertNewFaceVertex() +{ + /*This inserts information about the current vertex into the current face*/ + //find the new vertex index + vertex p; + p.v = v_list.size() -1; + p.vt = vt_list.size() - 1; + p.vn = vn_list.size() -1; + //find the face index + unsigned int f_index = primitives.size() -1; + //INSERT VERTEX AND ATTRIBUTE DATA + //just add the vertex to the face + primitives[f_index].p.push_back(p); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertNewLineVertex() +{ + /*This inserts information about the current vertex into the current line*/ + //find the new vertex index + vertex p; + p.v = v_list.size() -1; + p.vt = vt_list.size() - 1; + //find the line index + unsigned int l_index = primitives.size() -1; + + //ADD VERTEX AND ATTRIBUTE INFORMATION + //add the vertex to the line + primitives[l_index].p.push_back(p); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_CreateNewFace() +{ + primitive new_f; + new_f.type = OBJ_FACE; + new_f.mask = g_AttributeMask; + faces.push_back(primitives.size()); + primitives.push_back(new_f); + + + return OBJ_OK; +} + +OBJint rtsOBJ::f_CreateNewLine() +{ + primitive new_l; + new_l.type = OBJ_LINES; + new_l.mask = g_AttributeMask; + lines.push_back(primitives.size()); + primitives.push_back(new_l); + + return OBJ_OK; +} + + +OBJint rtsOBJ::f_TerminateLineLoop() +{ + /*This function just terminates the line loop by setting the last vertex + to the first vertex.*/ + if(g_CurrentMode != OBJ_LINE_LOOP) + return OBJ_ERROR; + //find the index for the current line + unsigned int l_index = lines.size() -1; + //insert the first vertex as the last vertex + primitives[l_index].p.push_back(primitives[l_index].p[0]); + + return OBJ_OK; +} + +void rtsOBJ::f_OutputVertices() +{ + //get the number of vertices in the object + unsigned int v_num = v_list.size(); + for(unsigned int i=0; i>new_vertex.x; + new_vertex.mask = OBJ_V_X; + + if(infile.peek() == ' ') + { + infile>>new_vertex.y; + new_vertex.mask = new_vertex.mask | OBJ_V_Y; + } + if(infile.peek() == ' ') + { + infile>>new_vertex.z; + new_vertex.mask = new_vertex.mask | OBJ_V_Z; + } + if(infile.peek() == ' ') + { + infile>>new_vertex.w; + new_vertex.mask = new_vertex.mask | OBJ_V_W; + } + int c = infile.peek(); + //ignore the rest of the line + infile.ignore(1000, '\n'); + c = infile.peek(); + + //cout<<"vertex read: "<>new_normal.i; + new_normal.mask = OBJ_VN_I; + //get every other component + if(infile.peek() == ' ') + { + infile>>new_normal.j; + new_normal.mask = new_normal.mask | OBJ_VN_J; + } + if(infile.peek() == ' ') + { + infile>>new_normal.k; + new_normal.mask = new_normal.mask | OBJ_VN_K; + } + //ignore the rest of the line + infile.ignore(1000, '\n'); + //insert the normal + vn_list.push_back(new_normal); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_ReadTexCoord(ifstream &infile) +{ + vertex_texture new_texcoord; + infile>>new_texcoord.u; + new_texcoord.mask = OBJ_VT_U; + //get every other component + if(infile.peek() == ' ') + { + infile>>new_texcoord.v; + new_texcoord.mask = new_texcoord.mask | OBJ_VT_V; + } + if(infile.peek() == ' ') + { + infile>>new_texcoord.w; + new_texcoord.mask = new_texcoord.mask | OBJ_VT_W; + } + + //ignore the rest of the line + infile.ignore(1000, '\n'); + //insert the texture coordinate + vt_list.push_back(new_texcoord); + + return OBJ_OK; + +} + +OBJint rtsOBJ::f_ReadVertex(ifstream &infile, vertex &new_point, unsigned char &mask) +{ + //store the line vertex + infile>>new_point.v; + new_point.v--; + mask = OBJ_V; + //new_face.v.push_back(new_v - 1); + if(infile.peek() == '/') + { + infile.get(); + //if there actually is a texcoord + if(infile.peek() != '/') + { + infile>>new_point.vt; //get the index + new_point.vt--; + mask = mask | OBJ_VT; //update the mask + //new_face.vt.push_back(new_vt - 1); + } + } + //check for a normal + if(infile.peek() == '/') + { + infile.get(); + infile>>new_point.vn; //get the index + new_point.vn--; + mask = mask | OBJ_VN; //update the mask + } + + return OBJ_OK; +} + +OBJint rtsOBJ::f_ReadPrimitive(ifstream &infile, primitive_type type) +{ + //create a new point list + primitive new_primitive; + new_primitive.type = type; + //until the end of the line + while(infile.peek() != '\n') + { + //read each point + if(infile.peek() == ' ') + infile.get(); + else + { + vertex new_point; + f_ReadVertex(infile, new_point, new_primitive.mask); + new_primitive.p.push_back(new_point); + } + } + //ignore the rest of the line + infile.ignore(1000, '\n'); + + //push the id of the primitive into the new list + //:DEBUG: + if(type == OBJ_POINTS) + points.push_back(primitives.size()); + else if(type == OBJ_LINES) + lines.push_back(primitives.size()); + else if(type == OBJ_FACE) + faces.push_back(primitives.size()); + + primitives.push_back(new_primitive); //push the new primitive + + return OBJ_OK; +} + + +OBJint rtsOBJ::f_AdjustExtents(vertex_position v) +{ + if(v.x < m_bounds.min.x) + m_bounds.min.x = v.x; + if(v.y < m_bounds.min.y) + m_bounds.min.y = v.y; + if(v.z < m_bounds.min.z) + m_bounds.min.z = v.z; + + if(v.x > m_bounds.max.x) m_bounds.max.x = v.x; + if(v.y > m_bounds.max.y) m_bounds.max.y = v.y; + if(v.z > m_bounds.max.z) m_bounds.max.z = v.z; + + return OBJ_OK; +} + +OBJint rtsOBJ::f_LoadOBJ(const char* filename) +{ + f_ClearAll(); + //open the file as a stream + ifstream infile; + infile.open(filename); + if(!infile.is_open()) + return OBJ_ERROR; + + unsigned int vertices = 0; + + string token; + infile>>token; + while(!infile.eof()) + { + //if the token is some vertex property + if(token == "v") + f_ReadPosition(infile); + else if(token == "vn") + f_ReadNormal(infile); + else if(token == "vt") + f_ReadTexCoord(infile); + else if(token == "p") + f_ReadPrimitive(infile, OBJ_POINTS); + else if(token == "l") + f_ReadPrimitive(infile, OBJ_LINES); + else if(token == "f") + f_ReadPrimitive(infile, OBJ_FACE); + else + infile.ignore(9999, '\n'); + //vertices++; + + infile>>token; + } + +} + +OBJint rtsOBJ::f_LoadSWC(const char* filename) +{ + f_ClearAll(); + //open the file as a stream + ifstream infile; + infile.open(filename); + if(!infile.is_open()) + return OBJ_ERROR; + + vector swcVertices; + float token; + objBegin(OBJ_LINES); + while(!infile.eof()) + { + vertex_position v; + infile>>token; //get the id + infile>>token; //get the fiber type + infile>>v.x; //get the node position + infile>>v.y; + infile>>v.z; + infile>>token; //get the radius + infile>>token; //get the parent + + //insert the node into the swc vector + swcVertices.push_back(v); + //now draw the line from the parent to the current node + if(token != -1) + { + objVertex3f(swcVertices[token-1].x, swcVertices[token-1].y, swcVertices[token-1].z); + objVertex3f(v.x, v.y, v.z); + } + } + objEnd(); + + + return OBJ_OK; + +} +OBJint rtsOBJ::LoadFile(const char* filename) +{ + string strFilename = filename; + int length = strFilename.length(); + string extension = strFilename.substr(strFilename.length() - 3, 3); + if(!extension.compare(string("obj"))) + return f_LoadOBJ(filename); + else if(!extension.compare(string("swc"))) + return f_LoadSWC(filename); + else return f_LoadOBJ(filename); + +} + +OBJint rtsOBJ::SaveFile(const char* filename) +{ + //open the file as a stream + ofstream outfile; + outfile.open(filename); + if(!outfile.is_open()) + return OBJ_ERROR; + + //output vertex positions + vector::iterator v; + for(v=v_list.begin(); v!= v_list.end(); v++) + { + outfile<<"v"; + if((*v).mask & OBJ_V_X) + { + outfile<<' '<<(*v).x; + if((*v).mask & OBJ_V_Y) + { + outfile<<' '<<(*v).y; + if((*v).mask & OBJ_V_Z) + { + outfile<<' '<<(*v).z; + if((*v).mask & OBJ_V_W) + outfile<<' '<<(*v).w; + } + } + } + outfile<<'\n'; + } + + //output vertex texture coordinates + vector::iterator vt; + for(vt=vt_list.begin(); vt!= vt_list.end(); vt++) + { + outfile<<"vt"; + if((*vt).mask & OBJ_VT_U) + { + outfile<<' '<<(*vt).u; + if((*vt).mask & OBJ_VT_V) + { + outfile<<' '<<(*vt).v; + if((*vt).mask & OBJ_VT_W) + outfile<<' '<<(*vt).w; + } + } + outfile<<'\n'; + } + + //output vertex normal coordinates + vector::iterator vn; + for(vn=vn_list.begin(); vn!= vn_list.end(); vn++) + { + outfile<<"vn"; + if((*vn).mask & OBJ_VN_I) + { + outfile<<' '<<(*vn).i; + if((*vn).mask & OBJ_VN_J) + { + outfile<<' '<<(*vn).j; + if((*vn).mask & OBJ_VN_K) + outfile<<' '<<(*vn).k; + } + } + outfile<<'\n'; + } + + //output each primitive + vector::iterator p; + vector::iterator vert; + for(p=primitives.begin(); p!= primitives.end(); p++) + { + switch((*p).type) + { + case OBJ_POINTS: + outfile<<"p"; //output the points token + break; + case OBJ_LINES: + outfile<<"l"; //output the lines token + break; + case OBJ_FACE: + outfile<<"f"; //output the face token + break; + } + + //for each vertex in the list for the primitive + for(vert = (*p).p.begin(); vert != (*p).p.end(); vert++) + { + outfile<<' '<<(*vert).v + 1; + if((*p).mask & OBJ_VT) + outfile<<'/'<<(*vert).vt + 1; + if((*p).mask & OBJ_VN) + { + if(!((*p).mask & OBJ_VT)) + outfile<<'/'; + outfile<<'/'<<(*vert).vn + 1; + } + } + outfile<<'\n'; + + } + + + +} + +//get methods +unsigned int rtsOBJ::getNumVertices(){return v_list.size();} +unsigned int rtsOBJ::getNumLines(){return lines.size();} +unsigned int rtsOBJ::getNumFaces(){return faces.size();} +unsigned int rtsOBJ::getNumPointLists(){return points.size();} +unsigned int rtsOBJ::getNumTexCoords(){return vt_list.size();} +unsigned int rtsOBJ::getNumNormals(){return vn_list.size();} + +//these functions return the coordinate index as well as the value +unsigned int rtsOBJ::getNumFaceVertices(unsigned int face){return primitives[face].p.size();} +unsigned int rtsOBJ::getFaceVertex(unsigned int face, unsigned int vertex){return primitives[face].p[vertex].v;} +unsigned int rtsOBJ::getFaceNormal(unsigned int face, unsigned int normal){return primitives[face].p[normal].vn;} +unsigned int rtsOBJ::getFaceTexCoord(unsigned int face, unsigned int texcoord){return primitives[face].p[texcoord].vt;} +unsigned int rtsOBJ::getNumLineVertices(unsigned int line){return primitives[line].p.size();} +unsigned int rtsOBJ::getLineVertex(unsigned int line, unsigned int vertex){return primitives[line].p[vertex].v;} +unsigned int rtsOBJ::getLineTexCoord(unsigned int line, unsigned int texcoord){return primitives[line].p[texcoord].vt;} +point3D rtsOBJ::getVertex3d(unsigned int index) +{ + return point3D(v_list[index].x, v_list[index].y, v_list[index].z); +} +point3D rtsOBJ::getTexCoord3d(unsigned int index) +{ + return point3D(vt_list[index].u, vt_list[index].v, vt_list[index].w); +} +point3D rtsOBJ::getNormal3d(unsigned int index) +{ + return point3D(vn_list[index].i, vn_list[index].j, vn_list[index].k); +} +vertex_position rtsOBJ::getVertex(unsigned int index){return v_list[index];} +vertex_texture rtsOBJ::getTexCoord(unsigned int index){return vt_list[index];} +vertex_normal rtsOBJ::getNormal(unsigned int index){return vn_list[index];} + + +unsigned int rtsOBJ::getPrimitiveType(unsigned int primitive) +{ + /* + switch(primitives[i].type) + { + case OBJ_POINTS: + return OBJ_POINTS; + break; + case OBJ_LINES: + return OBJ_LINES; + break; + case OBJ_FACE: + f_RenderFace(i); + break; + }*/ + return 0; +} +/****************************************************/ +/*******Iterator Methods*****************************/ +/****************************************************/ + +rtsOBJ::iterator rtsOBJ::begin() +{ + //create an iterator that will be returned and assign it to this OBJ + iterator result; + result.obj = this; + result.end_object = false; + result.end_primitive = false; + + //if there are no primitives, return the end iterator + if(primitives.size() == 0) + return end(); + + //start at the beginning of the primitive array + result.primitive_index = 0; + + return result; +} + +rtsOBJ::iterator rtsOBJ::end() +{ + //create an end iterator to return + iterator result; + result.obj = this; + result.end_primitive = true; + result.primitive_index = result.obj->primitives.size(); + + return result; +} + +void rtsOBJ::iterator::operator++() +{ + primitive_index++; + if(primitive_index >= obj->primitives.size()) + (*this) = obj->end(); + +} + +bool rtsOBJ::iterator::operator ==(rtsOBJ::iterator operand) +{ + if(operand.primitive_index == primitive_index) + return true; + else return false; +} + +bool rtsOBJ::iterator::operator !=(rtsOBJ::iterator operand) +{ + if(operand.primitive_index != primitive_index) + return true; + else return false; +} + +unsigned int rtsOBJ::iterator::operator*() +{ + return primitive_index; +} + +void rtsOBJ::iterator::print() +{ + cout<<"This is a test"< +#include +#include +#include +using namespace std; + +//masks for valid vertex components +#define OBJ_V_X 0x1 +#define OBJ_V_Y 0x2 +#define OBJ_V_Z 0x4 +#define OBJ_V_W 0x8 + +#define OBJ_VT_U 0x1 +#define OBJ_VT_V 0x2 +#define OBJ_VT_W 0x4 + +#define OBJ_VN_I 0x1 +#define OBJ_VN_J 0x2 +#define OBJ_VN_K 0x4 + +#define OBJ_V 0x1 +#define OBJ_VT 0x2 +#define OBJ_VN 0x4 + +//primitive types +typedef unsigned char primitive_type; + +#define OBJ_END 0x0 +#define OBJ_POINTS 0x1 +#define OBJ_LINES 0x2 +#define OBJ_FACE 0x3 + + +#define OBJ_INVALID ULONG_MAX +//define the point structures +struct vertex_position{float x,y,z,w; unsigned char mask;}; +struct vertex_texture{float u,v,w; unsigned char mask;}; +struct vertex_normal{float i,j,k; unsigned char mask;}; +//the point structure contains indices to the relative 3-vectors in the lists +struct vertex +{ + unsigned int v; + unsigned int vt; + unsigned int vn; +}; + +struct primitive +{ + vector p; //indices to the point + unsigned char mask; //mask describing which features (v, vt, vn) are used + primitive_type type; //the type of primitive (points, lines, face) +}; + +//axis-aligned bounding box +struct AABB +{ + vertex_position min; + vertex_position max; +}; + +//create variable types +typedef unsigned int OBJint; + +//define the OBJ data class +class rtsOBJ +{ +private: + + /*Current state variables. These variables are committed to the OBJ object + when a vertex is added. However, we are careful to only add them once (if they don't + change with every vertex. + */ + vertex_texture current_vt; + vertex_normal current_vn; + bool vt_changed; //true if a new vt or vn was inserted since the last vertex + bool vn_changed; + unsigned char current_primitive_mask; //defines what coordinates are being used by the current primitive + //global variable storing the current render mode + OBJint g_CurrentMode; + //output file stream + ofstream g_objFile; + //obj file object + //objData g_OBJ; + //number of vertices since the last BEGIN + unsigned int g_NumVertices; + /*Attribute mask. This indicates what attributes are stored for each vertex. + Only a single mask applies to each vertex between objBegin() and objEnd(). The + attribute mask is flipped the first time an attribute is set but it is fixed after + the first vertex is passed.*/ + unsigned char g_AttributeMask; + /*Attribute reset mask. This indicates whether or not an attribute has been + reset since the last vertex was rendered. This applies to OBJ_VT and OBJ_VN*/ + unsigned char g_AttributeResetMask; + //latest texture coordinate sent + unsigned int g_LatestVT; + //latest vertex normal sent + unsigned int g_LatestVN; + + //extents of the points in the OBJ file + AABB m_bounds; + + OBJint f_InsertPointVertex(); + OBJint f_InsertLineVertex(); + OBJint f_InsertLineLoopVertex(); + OBJint f_InsertLineStripVertex(); + OBJint f_InsertTriangleVertex(); + OBJint f_InsertTriangleStripVertex(); + OBJint f_InsertTriangleFanVertex(); + OBJint f_InsertQuadVertex(); + OBJint f_InsertQuadStripVertex(); + OBJint f_InsertPolygonVertex(); + OBJint f_InsertPreviousFaceVertex(unsigned int v_index); + OBJint f_InsertFirstFaceVertex(unsigned int v_index); + OBJint f_InsertNewFaceVertex(); + OBJint f_InsertNewLineVertex(); + OBJint f_CreateNewFace(); + OBJint f_CreateNewLine(); + OBJint f_TerminateLineLoop(); + OBJint f_LoadOBJ(const char* filename); + OBJint f_LoadSWC(const char* filename); + + //insert coordinate commands + //these are used to handle coordinates of different dimensions (and are called by the associated public function) + OBJint f_InsertVertexf(float x, float y, float z, float w, unsigned char mask); + OBJint f_InsertTexCoordf(float u, float v, float w, unsigned char mask); + OBJint f_InsertNormalf(float i, float j, float k, unsigned char mask); + //output functions + void f_OutputVertices(); + void f_OutputPoints(); + void f_OutputLines(); + void f_OutputFaces(); + void f_OutputVertexNormals(); + void f_OutputTextureCoordinates(); + void f_ClearAll(); + + //methods for reading from a file + OBJint f_ReadPosition(ifstream &infile); + OBJint f_ReadNormal(ifstream &infile); + OBJint f_ReadTexCoord(ifstream &infile); + OBJint f_ReadVertex(ifstream &infile, vertex &new_point, unsigned char &mask); + OBJint f_ReadPrimitive(ifstream &infile, primitive_type type); + OBJint f_AdjustExtents(vertex_position v); + +public: + /*These vectors store the vertex and primitive data from the obj file. + All vertices, texture coordinates, and normals are stored in m_v, m_vt, m_vn + respectively. The vectors for each primitive store an index into m_v, m_vt, + and m_vn identifying the associated coordinate. Basically, the data is stored + in a structure very similar to the OBJ file itself. + */ + vector v_list; + vector vt_list; + vector vn_list; + vector primitives; + + vector points; + vector lines; + vector faces; + +public: + + OBJint objOpen(const char* filename); + OBJint objBegin(OBJint obj_mode); + OBJint objEnd(); + OBJint objClose(); + OBJint objNormal3f(float i, float j, float k); + OBJint objNormal2f(float i, float j); + OBJint objNormal1f(float i); + OBJint objTexCoord3f(float u, float v, float w); + OBJint objTexCoord2f(float u, float v); + OBJint objTexCoord1f(float u); + OBJint objVertex1f(float x); + OBJint objVertex2f(float x, float y); + OBJint objVertex3f(float x, float y, float z); + OBJint objVertex4f(float x, float y, float z, float w); + OBJint LoadFile(const char* filename); + OBJint SaveFile(const char* filename); + + //direct insertion methods + void insertVertexPosition(float x, float y, float z, unsigned char mask = OBJ_V_X | OBJ_V_Y | OBJ_V_Z); + void insertLine(unsigned int num_points, unsigned int* pointlist, unsigned int* normallist, unsigned int* texturelist); + + //get methods + unsigned int getNumVertices(); + unsigned int getNumLines(); + unsigned int getNumFaces(); + unsigned int getNumPointLists(); + unsigned int getNumTexCoords(); + unsigned int getNumNormals(); + + //these functions return the coordinate index as well as the value + unsigned int getNumFaceVertices(unsigned int face); + unsigned int getFaceVertex(unsigned int face, unsigned int vertex); + unsigned int getFaceNormal(unsigned int face, unsigned int normal); + unsigned int getFaceTexCoord(unsigned int face, unsigned int texcoord); + unsigned int getNumLineVertices(unsigned int line); + unsigned int getLineVertex(unsigned int line, unsigned int vertex); + unsigned int getLineTexCoord(unsigned int line, unsigned int texcoord); + point3D getVertex3d(unsigned int index); + point3D getTexCoord3d(unsigned int index); + point3D getNormal3d(unsigned int index); + vertex_position getVertex(unsigned int index); + vertex_texture getTexCoord(unsigned int index); + vertex_normal getNormal(unsigned int index); + AABB getBoundingBox(){return m_bounds;} + void Scale(float scale_x, float scale_y, float scale_z); + void Translate(float trans_x, float trans_y, float trans_z); + + float GetDistance(float x, float y, float z); + + //return data about primitives + unsigned int getPrimitiveType(unsigned int primitive); + + //constructors + rtsOBJ(); + void CopyOBJ(const rtsOBJ& obj); + //assignment + rtsOBJ& operator=(const rtsOBJ& obj) + { + CopyOBJ(obj); + return *this; + } + //copy + rtsOBJ(const rtsOBJ& obj) + { + CopyOBJ(obj); + //return *this; + } + + + + //Iterator stuff + class iterator + { + friend class rtsOBJ; + private: + rtsOBJ* obj; + bool end_primitive; + bool end_object; + unsigned int primitive_index; + public: + unsigned int operator*(); + void operator++(); + bool operator==(rtsOBJ::iterator operand); + bool operator!=(rtsOBJ::iterator operand); + unsigned int size(){return obj->primitives[primitive_index].p.size();}; + void print(); + }; + + iterator begin(); + iterator end(); +}; + +//define error codes +#define OBJ_OK 0x0100 +#define OBJ_ERROR 0x0101 + +//define the different modes +#define OBJ_NONE 0x0 +#define OBJ_POINTS 0x1 +#define OBJ_LINES 0x2 +#define OBJ_LINE_STRIP 0x3 +#define OBJ_LINE_LOOP 0x4 +#define OBJ_TRIANGLES 0x5 +#define OBJ_TRIANGLE_STRIP 0x6 +#define OBJ_TRIANGLE_FAN 0x7 +#define OBJ_QUADS 0x8 +#define OBJ_QUAD_STRIP 0x9 +#define OBJ_POLYGON 0x10 + + + + + + +//initialize the OBJ file +OBJint objOpen(char* filename); +//close the obj file +OBJint objClose(); + +//start rendering in a certain mode +OBJint objBegin(OBJint mode); +//stop the current rendering sequence +OBJint objEnd(void); +//render a vertex to the file +OBJint objVertex1f(float x); +OBJint objVertex2f(float x, float y); +OBJint objVertex3f(float x, float y, float z); +OBJint objVertex4f(float x, float y, float z, float w); +//set a normal vector for a vertex +OBJint objNormal3f(float i, float j, float k); +OBJint objNormal2f(float i, float j); +OBJint objNormal1f(float i); +//set a texture coordinate for a vertex +OBJint objTexCoord3f(float u, float v, float w); +OBJint objTexCoord2f(float u, float v); +OBJint objTexCoord1f(float u); + +//global variable for global functions +extern rtsOBJ g_OBJ; + +/*BUG NOTES +The standard function calls for inserting vertices don't work anymore. I've fixed points +but everything beyond that has to be updated. +*/ + +#include "objJedi.h" +#include "rtsVector3d.h" +#include "rtsPoint3d.h" +#include +//variable for use in global functions +rtsOBJ g_OBJ; + +/********UTILITY METHODS*******************************/ +void rtsOBJ::Scale(float scale_x, float scale_y, float scale_z) +{ + vector::iterator i; + for(i = v_list.begin(); i!= v_list.end(); i++) + { + (*i).x *= scale_x; + (*i).y *= scale_y; + (*i).z *= scale_z; + } +} + +void rtsOBJ::Translate(float trans_x, float trans_y, float trans_z) +{ + vector::iterator i; + for(i = v_list.begin(); i!= v_list.end(); i++) + { + (*i).x += trans_x; + (*i).y += trans_y; + (*i).z += trans_z; + } + +} + +float rtsOBJ::GetDistance(float x, float y, float z) +{ + //gets the distance between the specified point and the nearest surface of the OBJ + //currently only works for lines + + //cout<<"Primitives: "< p0, p1, p2; + float min_dist = 255; + float dist; + unsigned int p, l; + vector3D v, w; + float c1, c2, b; + point3D Pb; + + //for each line + for(l=0; l OBJ_POLYGON) + return OBJ_ERROR; + + //otherwise, go ahead and set the mode + g_CurrentMode = mode; + //set the number of vertices to zero + g_NumVertices = 0; + + //reset the current state primitive state + current_primitive_mask = 0x0; + + return OBJ_OK; +} + +OBJint rtsOBJ::objEnd() +{ + OBJint error = OBJ_OK; + //check to make sure the number of rendered vertices is valid for the current mode + switch(g_CurrentMode) + { + case OBJ_NONE: + //can't quit if we haven't started + error = OBJ_ERROR; + break; + case OBJ_LINES: + //if less than two vertices or an odd number of vertices + if(g_NumVertices < 2 || g_NumVertices%2 != 0) + { + //if there wasn't a vertex at all + if(g_NumVertices == 0) + error = OBJ_ERROR; + //if there was at least one vertex + else + { + //pop the last line off the list + primitives.pop_back(); + lines.pop_back(); + error = OBJ_ERROR; + } + } + break; + case OBJ_LINE_STRIP: + //if less than two vertices + if(g_NumVertices < 2) + { + //if there wasn't a vertex at all + if(g_NumVertices == 0) + error = OBJ_ERROR; + //if there was at least one vertex + else + { + //pop the last line off the list + primitives.pop_back(); + lines.pop_back(); + error = OBJ_ERROR; + } + } + break; + case OBJ_LINE_LOOP: + //if less than three vertices + if(g_NumVertices < 3) + { + //pop the last line off the list + primitives.pop_back(); + lines.pop_back(); + error = OBJ_ERROR; + } + //connect the first and last points + else + { + error = f_TerminateLineLoop(); + } + break; + case OBJ_TRIANGLES: + //if less than three vertices or not a power of three + if(g_NumVertices < 3 || g_NumVertices%3 !=0) + { + primitives.pop_back(); + faces.pop_back(); + error = OBJ_ERROR; + } + break; + case OBJ_TRIANGLE_STRIP: + //if less than three vertices + if(g_NumVertices < 3) + { + primitives.pop_back(); + faces.pop_back(); + error = OBJ_ERROR; + } + break; + case OBJ_TRIANGLE_FAN: + //if less than three vertices + if(g_NumVertices < 3) + { + primitives.pop_back(); + faces.pop_back(); + error = OBJ_ERROR; + } + break; + case OBJ_QUADS: + if(g_NumVertices < 4 || g_NumVertices%4 != 0) + { + primitives.pop_back(); + faces.pop_back(); + error = OBJ_ERROR; + } + break; + case OBJ_QUAD_STRIP: + //has to be at least 4 vertices and an even number + if(g_NumVertices < 4 || g_NumVertices%2 != 0) + { + primitives.pop_back(); + faces.pop_back(); + error = OBJ_ERROR; + } + break; + case OBJ_POLYGON: + //has to be at least three vertices + if(g_NumVertices < 3) + { + primitives.pop_back(); + faces.pop_back(); + error = OBJ_ERROR; + } + break; + } + + //reset the attribute mask + g_AttributeMask = 0x0; + //just for closure, reset the attribute reset mask + g_AttributeResetMask = 0x0; + //stop rendering + g_CurrentMode = OBJ_NONE; + return error; +} + +OBJint rtsOBJ::f_InsertVertexf(float x, float y, float z, float w, unsigned char mask) +{ + //make sure we're rendering + if(g_CurrentMode == OBJ_NONE) + return OBJ_ERROR; + + //insert the vertex into the vertex vector + vertex_position v; + v.x = x; v.y = y; v.z=z; v.w=w; v.mask = mask; + v_list.push_back(v); + f_AdjustExtents(v); //set the bounding box + //insert texture coordinate and normal if specified for this primitive + if((current_primitive_mask & OBJ_VT) && (vt_changed)) + vt_list.push_back(current_vt); + if((current_primitive_mask & OBJ_VN) && (vn_changed)) + vn_list.push_back(current_vn); + + + //increment the number of vertices inserted + g_NumVertices++; + + //handle each case of the vertex creation individually + OBJint error = OBJ_OK; + switch(g_CurrentMode) + { + case OBJ_POINTS: + error = f_InsertPointVertex(); + break; + case OBJ_LINES: + error = f_InsertLineVertex(); + break; + case OBJ_LINE_LOOP: + error = f_InsertLineLoopVertex(); + break; + case OBJ_LINE_STRIP: + error = f_InsertLineStripVertex(); + break; + case OBJ_TRIANGLES: + error = f_InsertTriangleVertex(); + break; + case OBJ_TRIANGLE_STRIP: + error = f_InsertTriangleStripVertex(); + break; + case OBJ_TRIANGLE_FAN: + error = f_InsertTriangleFanVertex(); + break; + case OBJ_QUADS: + error = f_InsertQuadVertex(); + break; + case OBJ_QUAD_STRIP: + error = f_InsertQuadStripVertex(); + break; + case OBJ_POLYGON: + error = f_InsertPolygonVertex(); + break; + } + //set the reset mask to zero + g_AttributeResetMask = 0x0; + + //set the attribute mask to include vertex position + g_AttributeMask = g_AttributeMask | OBJ_V; + + //return the result of the insertion + return error; +} + +OBJint rtsOBJ::objVertex1f(float x) +{ + return f_InsertVertexf(x, 0.0, 0.0, 0.0, OBJ_V_X); +} + +OBJint rtsOBJ::objVertex2f(float x, float y) +{ + return f_InsertVertexf(x, y, 0.0, 0.0, OBJ_V_X | OBJ_V_Y); +} + +OBJint rtsOBJ::objVertex3f(float x, float y, float z) +{ + return f_InsertVertexf(x, y, z, 0.0, OBJ_V_X | OBJ_V_Y | OBJ_V_Z); + +} + +OBJint rtsOBJ::objVertex4f(float x, float y, float z, float w) +{ + return f_InsertVertexf(x, y, z, w, OBJ_V_X | OBJ_V_Y | OBJ_V_Z | OBJ_V_W); +} + +OBJint rtsOBJ::objNormal3f(float i, float j, float k) +{ + return f_InsertNormalf(i, j, k, OBJ_VN_I | OBJ_VN_J | OBJ_VN_K); +} +OBJint rtsOBJ::objNormal2f(float i, float j) +{ + return f_InsertNormalf(i, j, 0.0, OBJ_VN_I | OBJ_VN_J); +} + +OBJint rtsOBJ::objNormal1f(float i) +{ + return f_InsertNormalf(i, 0.0, 0.0, OBJ_VN_I); +} + +OBJint rtsOBJ::f_InsertNormalf(float i, float j, float k, unsigned char mask) +{ + /*DEPRECATED + //if the mode is not rendering faces, there is an error + if(g_CurrentMode < OBJ_TRIANGLES) + return OBJ_ERROR; + //if the normal attribute flag is not set, set it (as long as a vertex hasn't been written) + if(!(g_AttributeMask & OBJ_VN)) + { + //if a vertex has been rendered, then we can't change the attribute, so exit + if(g_NumVertices > 0) + return OBJ_ERROR; + else + //otherwise, just set the attribute flag + g_AttributeMask = g_AttributeMask | OBJ_VN; + } + + + //insert the new normal into the normal list for the file + vertex_normal new_vn; + new_vn.i = i; new_vn.j = j; new_vn.k = k; + new_vn.mask = mask; + vn_list.push_back(new_vn); + */ + current_vn.i = i; //set the current texture state to the given coordinates + current_vn.j = j; + current_vn.k = k; + current_vn.mask = mask; //set the mask as appropriate + vn_changed = true; //the texture coordinate state has changed + current_primitive_mask = current_primitive_mask | OBJ_VN; //the current primitive now uses texture coordinates (if it didn't previously) + + return OBJ_OK; +} + +OBJint rtsOBJ::objTexCoord3f(float u, float v, float w) +{ + return f_InsertTexCoordf(u, v, w, OBJ_VT_U | OBJ_VT_V | OBJ_VT_W); +} + +OBJint rtsOBJ::objTexCoord2f(float u, float v) +{ + return f_InsertTexCoordf(u, v, 0.0, OBJ_VT_U | OBJ_VT_V); +} + +OBJint rtsOBJ::objTexCoord1f(float u) +{ + return f_InsertTexCoordf(u, 0.0, 0.0, OBJ_VT_U); +} + +OBJint rtsOBJ::f_InsertTexCoordf(float u, float v, float w, unsigned char mask) +{ + /* + DEPRECATED + //if the normal attribute flag is not set, set it (as long as a vertex hasn't been written) + if(!(g_AttributeMask & OBJ_VT)) + { + //if a vertex has been rendered, then we can't change the attribute, so exit + if(g_NumVertices > 0) + return OBJ_ERROR; + else + //otherwise, just set the attribute flag + g_AttributeMask = g_AttributeMask | OBJ_VT; + } + + //insert the new texture coordinate into the list for the file + vertex_texture new_vt; + new_vt.u = u; new_vt.v = v; new_vt.w = w; + new_vt.mask = mask; + vt_list.push_back(new_vt); + */ + current_vt.u = u; //set the current texture state to the given coordinates + current_vt.v = v; + current_vt.w = w; + current_vt.mask = mask; //set the mask as appropriate + vt_changed = true; //the texture coordinate state has changed + current_primitive_mask = current_primitive_mask | OBJ_VT; //the current primitive now uses texture coordinates (if it didn't previously) + + return OBJ_OK; +} + + +void rtsOBJ::insertVertexPosition(float x, float y, float z, unsigned char mask) +{ + vertex_position v; + v.x = x; + v.y = y; + v.z = z; + v.mask = mask; + + v_list.push_back(v); +} + +void rtsOBJ::insertLine(unsigned int num_points, unsigned int* pointlist, unsigned int* normallist, unsigned int* texturelist) +{ + //create the new primitive + primitive line; + line.type = OBJ_LINES; + line.mask = 0; + + //set the mask based on the passed data + if(pointlist != NULL) + line.mask = line.mask | OBJ_V; + if(normallist != NULL) + line.mask = line.mask | OBJ_VN; + if(texturelist != NULL) + line.mask = line.mask | OBJ_VT; + + //insert the line + unsigned int v; + vertex new_vert; + for(v=0; v 1) + points.push_back(p_index); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertLineVertex() +{ + //if this is an odd vertex, create a new line + if(g_NumVertices%2 == 1) + { + f_CreateNewLine(); + } + + f_InsertNewLineVertex(); + + return OBJ_OK; +} +OBJint rtsOBJ::f_InsertLineLoopVertex() +{ + //technically, this is the same as inserting a line strip vertex + f_InsertLineStripVertex(); + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertLineStripVertex() +{ + if(g_NumVertices == 1) + { + f_CreateNewLine(); + } + + f_InsertNewLineVertex(); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertTriangleVertex() +{ + //if this is the first vertex in a triangle, create a new triangle + if(g_NumVertices%3 == 1) + { + f_CreateNewFace(); + } + + + f_InsertNewFaceVertex(); + + return OBJ_OK; +} +OBJint rtsOBJ::f_InsertTriangleStripVertex() +{ + //in the special case of the first three vertices, just create a triangle + if(g_NumVertices < 4) + f_InsertTriangleVertex(); + else + { + + //create a new face for the new triangle + f_CreateNewFace(); + + //make sure to get the ordering right: + // Even vertices provide the previous two vertices "in order": (v2, v3, v4) + // Odd vertices provide the previous two vertices in reverse order: (v1, v3, v2) + if(g_NumVertices % 2 == 1) + { + f_InsertPreviousFaceVertex(2); + f_InsertPreviousFaceVertex(1); + f_InsertNewFaceVertex(); + } + else + { + f_InsertPreviousFaceVertex(1); + f_InsertNewFaceVertex(); + f_InsertPreviousFaceVertex(2); + } + } + + return OBJ_OK; +} +OBJint rtsOBJ::f_InsertTriangleFanVertex() +{ + //in the special case of the first three vertices, just create a triangle + if(g_NumVertices <4) + f_InsertTriangleVertex(); + else + { + //create a new face for the new triangle + f_CreateNewFace(); + //add the previous vertices to the face + f_InsertFirstFaceVertex(0); + f_InsertPreviousFaceVertex(2); + //insert the current vertex + f_InsertNewFaceVertex(); + } + + return OBJ_OK; +} +OBJint rtsOBJ::f_InsertQuadVertex() +{ + //if this is the first vertex in a quad, create a new quad + if(g_NumVertices%4 == 1) + { + f_CreateNewFace(); + } + + f_InsertNewFaceVertex(); + + return OBJ_OK; +} +OBJint rtsOBJ::f_InsertQuadStripVertex() +{ + //in the case of one of the first four vertices, just create a quad + if(g_NumVertices < 5) + f_InsertQuadVertex(); + //if the vertex is odd (it will be the third vertex of a quad) + else if(g_NumVertices%2 == 1) + { + //create a new face for the new quad + f_CreateNewFace(); + //add the previous two vertices + f_InsertPreviousFaceVertex(2); + f_InsertPreviousFaceVertex(3); + //add the current vertex + f_InsertNewFaceVertex(); + } + else + { + //if this is the last vertex of the quad, just add it + f_InsertNewFaceVertex(); + + } + return OBJ_OK; +} +OBJint rtsOBJ::f_InsertPolygonVertex() +{ + //if this is the first vertex, create the quad + if(g_NumVertices == 1) + { + f_CreateNewFace(); + } + f_InsertNewFaceVertex(); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertPreviousFaceVertex(unsigned int v_index) +{ + /*Finds the vertex used in the previous face with the given index and + inserts it into the current face. This limits the redundancy in the file + for re-used vertices (in strips and fans). This also transfers texture + and normal information.*/ + + //find the index of the previous face + unsigned int prev_f_index = primitives.size() - 2; + //find the index of the current face + unsigned int f_index = prev_f_index +1; + //add the vertex information from the previous face to this face + primitives[f_index].p.push_back(primitives[prev_f_index].p[v_index]); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertFirstFaceVertex(unsigned int v_index) +{ + /*Finds the vertex used in the first face (since the last objBegin()) + with the given index and inserts it at the end of the current face. + This includes texture and normal information.*/ + + //The result depends on the type of face being rendered + //So far, this function only applies to triangle fans + if(g_CurrentMode != OBJ_TRIANGLE_FAN) + return OBJ_ERROR; + + //calculate the number of faces that have been rendered + unsigned int num_faces = g_NumVertices - 2; + //find the index of the first face + unsigned int first_f_index = primitives.size() - num_faces; + //find the index of the current face + unsigned int f_index = primitives.size() - 1; + //transfer the vertex information from the first face to this one + primitives[f_index].p.push_back(primitives[first_f_index].p[v_index]); + + + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertNewFaceVertex() +{ + /*This inserts information about the current vertex into the current face*/ + //find the new vertex index + vertex p; + p.v = v_list.size() -1; + p.vt = vt_list.size() - 1; + p.vn = vn_list.size() -1; + //find the face index + unsigned int f_index = primitives.size() -1; + //INSERT VERTEX AND ATTRIBUTE DATA + //just add the vertex to the face + primitives[f_index].p.push_back(p); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_InsertNewLineVertex() +{ + /*This inserts information about the current vertex into the current line*/ + //find the new vertex index + vertex p; + p.v = v_list.size() -1; + p.vt = vt_list.size() - 1; + //find the line index + unsigned int l_index = primitives.size() -1; + + //ADD VERTEX AND ATTRIBUTE INFORMATION + //add the vertex to the line + primitives[l_index].p.push_back(p); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_CreateNewFace() +{ + primitive new_f; + new_f.type = OBJ_FACE; + new_f.mask = g_AttributeMask; + faces.push_back(primitives.size()); + primitives.push_back(new_f); + + + return OBJ_OK; +} + +OBJint rtsOBJ::f_CreateNewLine() +{ + primitive new_l; + new_l.type = OBJ_LINES; + new_l.mask = g_AttributeMask; + lines.push_back(primitives.size()); + primitives.push_back(new_l); + + return OBJ_OK; +} + + +OBJint rtsOBJ::f_TerminateLineLoop() +{ + /*This function just terminates the line loop by setting the last vertex + to the first vertex.*/ + if(g_CurrentMode != OBJ_LINE_LOOP) + return OBJ_ERROR; + //find the index for the current line + unsigned int l_index = lines.size() -1; + //insert the first vertex as the last vertex + primitives[l_index].p.push_back(primitives[l_index].p[0]); + + return OBJ_OK; +} + +void rtsOBJ::f_OutputVertices() +{ + //get the number of vertices in the object + unsigned int v_num = v_list.size(); + for(unsigned int i=0; i>new_vertex.x; + new_vertex.mask = OBJ_V_X; + + if(infile.peek() == ' ') + { + infile>>new_vertex.y; + new_vertex.mask = new_vertex.mask | OBJ_V_Y; + } + if(infile.peek() == ' ') + { + infile>>new_vertex.z; + new_vertex.mask = new_vertex.mask | OBJ_V_Z; + } + if(infile.peek() == ' ') + { + infile>>new_vertex.w; + new_vertex.mask = new_vertex.mask | OBJ_V_W; + } + int c = infile.peek(); + //ignore the rest of the line + infile.ignore(1000, '\n'); + c = infile.peek(); + + //cout<<"vertex read: "<>new_normal.i; + new_normal.mask = OBJ_VN_I; + //get every other component + if(infile.peek() == ' ') + { + infile>>new_normal.j; + new_normal.mask = new_normal.mask | OBJ_VN_J; + } + if(infile.peek() == ' ') + { + infile>>new_normal.k; + new_normal.mask = new_normal.mask | OBJ_VN_K; + } + //ignore the rest of the line + infile.ignore(1000, '\n'); + //insert the normal + vn_list.push_back(new_normal); + + return OBJ_OK; +} + +OBJint rtsOBJ::f_ReadTexCoord(ifstream &infile) +{ + vertex_texture new_texcoord; + infile>>new_texcoord.u; + new_texcoord.mask = OBJ_VT_U; + //get every other component + if(infile.peek() == ' ') + { + infile>>new_texcoord.v; + new_texcoord.mask = new_texcoord.mask | OBJ_VT_V; + } + if(infile.peek() == ' ') + { + infile>>new_texcoord.w; + new_texcoord.mask = new_texcoord.mask | OBJ_VT_W; + } + + //ignore the rest of the line + infile.ignore(1000, '\n'); + //insert the texture coordinate + vt_list.push_back(new_texcoord); + + return OBJ_OK; + +} + +OBJint rtsOBJ::f_ReadVertex(ifstream &infile, vertex &new_point, unsigned char &mask) +{ + //store the line vertex + infile>>new_point.v; + new_point.v--; + mask = OBJ_V; + //new_face.v.push_back(new_v - 1); + if(infile.peek() == '/') + { + infile.get(); + //if there actually is a texcoord + if(infile.peek() != '/') + { + infile>>new_point.vt; //get the index + new_point.vt--; + mask = mask | OBJ_VT; //update the mask + //new_face.vt.push_back(new_vt - 1); + } + } + //check for a normal + if(infile.peek() == '/') + { + infile.get(); + infile>>new_point.vn; //get the index + new_point.vn--; + mask = mask | OBJ_VN; //update the mask + } + + return OBJ_OK; +} + +OBJint rtsOBJ::f_ReadPrimitive(ifstream &infile, primitive_type type) +{ + //create a new point list + primitive new_primitive; + new_primitive.type = type; + //until the end of the line + while(infile.peek() != '\n') + { + //read each point + if(infile.peek() == ' ') + infile.get(); + else + { + vertex new_point; + f_ReadVertex(infile, new_point, new_primitive.mask); + new_primitive.p.push_back(new_point); + } + } + //ignore the rest of the line + infile.ignore(1000, '\n'); + + //push the id of the primitive into the new list + //:DEBUG: + if(type == OBJ_POINTS) + points.push_back(primitives.size()); + else if(type == OBJ_LINES) + lines.push_back(primitives.size()); + else if(type == OBJ_FACE) + faces.push_back(primitives.size()); + + primitives.push_back(new_primitive); //push the new primitive + + return OBJ_OK; +} + + +OBJint rtsOBJ::f_AdjustExtents(vertex_position v) +{ + if(v.x < m_bounds.min.x) + m_bounds.min.x = v.x; + if(v.y < m_bounds.min.y) + m_bounds.min.y = v.y; + if(v.z < m_bounds.min.z) + m_bounds.min.z = v.z; + + if(v.x > m_bounds.max.x) m_bounds.max.x = v.x; + if(v.y > m_bounds.max.y) m_bounds.max.y = v.y; + if(v.z > m_bounds.max.z) m_bounds.max.z = v.z; + + return OBJ_OK; +} + +OBJint rtsOBJ::f_LoadOBJ(const char* filename) +{ + f_ClearAll(); + //open the file as a stream + ifstream infile; + infile.open(filename); + if(!infile) + exit(1); + + unsigned int vertices = 0; + + string token; + infile>>token; + while(!infile.eof()) + { + //if the token is some vertex property + if(token == "v") + f_ReadPosition(infile); + else if(token == "vn") + f_ReadNormal(infile); + else if(token == "vt") + f_ReadTexCoord(infile); + else if(token == "p") + f_ReadPrimitive(infile, OBJ_POINTS); + else if(token == "l") + f_ReadPrimitive(infile, OBJ_LINES); + else if(token == "f") + f_ReadPrimitive(infile, OBJ_FACE); + else + infile.ignore(9999, '\n'); + //vertices++; + + infile>>token; + } + +} + +OBJint rtsOBJ::f_LoadSWC(const char* filename) +{ + f_ClearAll(); + //open the file as a stream + ifstream infile; + infile.open(filename); + if(!infile.is_open()) + return OBJ_ERROR; + + vector swcVertices; + float token; + objBegin(OBJ_LINES); + while(!infile.eof()) + { + vertex_position v; + infile>>token; //get the id + infile>>token; //get the fiber type + infile>>v.x; //get the node position + infile>>v.y; + infile>>v.z; + infile>>token; //get the radius + infile>>token; //get the parent + + //insert the node into the swc vector + swcVertices.push_back(v); + //now draw the line from the parent to the current node + if(token != -1) + { + unsigned int i = (unsigned int)token - 1; + objVertex3f(swcVertices[i].x, swcVertices[i].y, swcVertices[i].z); + objVertex3f(v.x, v.y, v.z); + } + } + objEnd(); + + + return OBJ_OK; + +} +OBJint rtsOBJ::LoadFile(const char* filename) +{ + string strFilename = filename; + int length = strFilename.length(); + string extension = strFilename.substr(strFilename.length() - 3, 3); + if(!extension.compare(string("obj"))) + return f_LoadOBJ(filename); + else if(!extension.compare(string("swc"))) + return f_LoadSWC(filename); + else return f_LoadOBJ(filename); + +} + +OBJint rtsOBJ::SaveFile(const char* filename) +{ + //open the file as a stream + ofstream outfile; + outfile.open(filename); + if(!outfile.is_open()) + return OBJ_ERROR; + + //output vertex positions + vector::iterator v; + for(v=v_list.begin(); v!= v_list.end(); v++) + { + outfile<<"v"; + if((*v).mask & OBJ_V_X) + { + outfile<<' '<<(*v).x; + if((*v).mask & OBJ_V_Y) + { + outfile<<' '<<(*v).y; + if((*v).mask & OBJ_V_Z) + { + outfile<<' '<<(*v).z; + if((*v).mask & OBJ_V_W) + outfile<<' '<<(*v).w; + } + } + } + outfile<<'\n'; + } + + //output vertex texture coordinates + vector::iterator vt; + for(vt=vt_list.begin(); vt!= vt_list.end(); vt++) + { + outfile<<"vt"; + if((*vt).mask & OBJ_VT_U) + { + outfile<<' '<<(*vt).u; + if((*vt).mask & OBJ_VT_V) + { + outfile<<' '<<(*vt).v; + if((*vt).mask & OBJ_VT_W) + outfile<<' '<<(*vt).w; + } + } + outfile<<'\n'; + } + + //output vertex normal coordinates + vector::iterator vn; + for(vn=vn_list.begin(); vn!= vn_list.end(); vn++) + { + outfile<<"vn"; + if((*vn).mask & OBJ_VN_I) + { + outfile<<' '<<(*vn).i; + if((*vn).mask & OBJ_VN_J) + { + outfile<<' '<<(*vn).j; + if((*vn).mask & OBJ_VN_K) + outfile<<' '<<(*vn).k; + } + } + outfile<<'\n'; + } + + //output each primitive + vector::iterator p; + vector::iterator vert; + for(p=primitives.begin(); p!= primitives.end(); p++) + { + switch((*p).type) + { + case OBJ_POINTS: + outfile<<"p"; //output the points token + break; + case OBJ_LINES: + outfile<<"l"; //output the lines token + break; + case OBJ_FACE: + outfile<<"f"; //output the face token + break; + } + + //for each vertex in the list for the primitive + for(vert = (*p).p.begin(); vert != (*p).p.end(); vert++) + { + outfile<<' '<<(*vert).v + 1; + if((*p).mask & OBJ_VT) + outfile<<'/'<<(*vert).vt + 1; + if((*p).mask & OBJ_VN) + { + if(!((*p).mask & OBJ_VT)) + outfile<<'/'; + outfile<<'/'<<(*vert).vn + 1; + } + } + outfile<<'\n'; + + } + + + +} + +//get methods +unsigned int rtsOBJ::getNumVertices(){return v_list.size();} +unsigned int rtsOBJ::getNumLines(){return lines.size();} +unsigned int rtsOBJ::getNumFaces(){return faces.size();} +unsigned int rtsOBJ::getNumPointLists(){return points.size();} +unsigned int rtsOBJ::getNumTexCoords(){return vt_list.size();} +unsigned int rtsOBJ::getNumNormals(){return vn_list.size();} + +//these functions return the coordinate index as well as the value +unsigned int rtsOBJ::getNumFaceVertices(unsigned int face){return primitives[face].p.size();} +unsigned int rtsOBJ::getFaceVertex(unsigned int face, unsigned int vertex){return primitives[face].p[vertex].v;} +unsigned int rtsOBJ::getFaceNormal(unsigned int face, unsigned int normal){return primitives[face].p[normal].vn;} +unsigned int rtsOBJ::getFaceTexCoord(unsigned int face, unsigned int texcoord){return primitives[face].p[texcoord].vt;} +unsigned int rtsOBJ::getNumLineVertices(unsigned int line){return primitives[line].p.size();} +unsigned int rtsOBJ::getLineVertex(unsigned int line, unsigned int vertex){return primitives[line].p[vertex].v;} +unsigned int rtsOBJ::getLineTexCoord(unsigned int line, unsigned int texcoord){return primitives[line].p[texcoord].vt;} +point3D rtsOBJ::getVertex3d(unsigned int index) +{ + return point3D(v_list[index].x, v_list[index].y, v_list[index].z); +} +point3D rtsOBJ::getTexCoord3d(unsigned int index) +{ + return point3D(vt_list[index].u, vt_list[index].v, vt_list[index].w); +} +point3D rtsOBJ::getNormal3d(unsigned int index) +{ + return point3D(vn_list[index].i, vn_list[index].j, vn_list[index].k); +} +vertex_position rtsOBJ::getVertex(unsigned int index){return v_list[index];} +vertex_texture rtsOBJ::getTexCoord(unsigned int index){return vt_list[index];} +vertex_normal rtsOBJ::getNormal(unsigned int index){return vn_list[index];} + + +unsigned int rtsOBJ::getPrimitiveType(unsigned int primitive) +{ + /* + switch(primitives[i].type) + { + case OBJ_POINTS: + return OBJ_POINTS; + break; + case OBJ_LINES: + return OBJ_LINES; + break; + case OBJ_FACE: + f_RenderFace(i); + break; + }*/ + return 0; +} +/****************************************************/ +/*******Iterator Methods*****************************/ +/****************************************************/ + +rtsOBJ::iterator rtsOBJ::begin() +{ + //create an iterator that will be returned and assign it to this OBJ + iterator result; + result.obj = this; + result.end_object = false; + result.end_primitive = false; + + //if there are no primitives, return the end iterator + if(primitives.size() == 0) + return end(); + + //start at the beginning of the primitive array + result.primitive_index = 0; + + return result; +} + +rtsOBJ::iterator rtsOBJ::end() +{ + //create an end iterator to return + iterator result; + result.obj = this; + result.end_primitive = true; + result.primitive_index = result.obj->primitives.size(); + + return result; +} + +void rtsOBJ::iterator::operator++() +{ + primitive_index++; + if(primitive_index >= obj->primitives.size()) + (*this) = obj->end(); + +} + +bool rtsOBJ::iterator::operator ==(rtsOBJ::iterator operand) +{ + if(operand.primitive_index == primitive_index) + return true; + else return false; +} + +bool rtsOBJ::iterator::operator !=(rtsOBJ::iterator operand) +{ + if(operand.primitive_index != primitive_index) + return true; + else return false; +} + +unsigned int rtsOBJ::iterator::operator*() +{ + return primitive_index; +} + +void rtsOBJ::iterator::print() +{ + cout<<"This is a test"< +#include "cuda_runtime.h" +#include "device_launch_parameters.h" + +#ifndef CUDA_HANDLE_ERROR_H +#define CUDA_HANDLE_ERROR_H + +//handle error macro +static void HandleError( cudaError_t err, const char *file, int line ) { + if (err != cudaSuccess) { + //FILE* outfile = fopen("cudaErrorLog.txt", "w"); + //fprintf(outfile, "%s in %s at line %d\n", cudaGetErrorString( err ), file, line ); + //fclose(outfile); + printf("%s in %s at line %d\n", cudaGetErrorString( err ), file, line ); + //exit( EXIT_FAILURE ); + + } +} +#define HANDLE_ERROR( err ) (HandleError( err, __FILE__, __LINE__ )) + + + +#endif diff --git a/rts/cuda_timer.h b/rts/cuda_timer.h new file mode 100644 index 0000000..fd2786d --- /dev/null +++ b/rts/cuda_timer.h @@ -0,0 +1,21 @@ +static cudaEvent_t tStartEvent; +static cudaEvent_t tStopEvent; + +static void gpuStartTimer() +{ + //set up timing events + cudaEventCreate(&tStartEvent); + cudaEventCreate(&tStopEvent); + cudaEventRecord(tStartEvent, 0); +} + +static float gpuStopTimer() +{ + cudaEventRecord(tStopEvent, 0); + cudaEventSynchronize(tStopEvent); + float elapsedTime; + cudaEventElapsedTime(&elapsedTime, tStartEvent, tStopEvent); + cudaEventDestroy(tStartEvent); + cudaEventDestroy(tStopEvent); + return elapsedTime; +} \ No newline at end of file diff --git a/rts/legendre.h b/rts/legendre.h new file mode 100644 index 0000000..fceca36 --- /dev/null +++ b/rts/legendre.h @@ -0,0 +1,45 @@ +#ifndef RTS_LEGENDRE_H +#define RTS_LEGENDRE_H + +#include "rts/cuda_callable.h" + +namespace rts{ + +template +CUDA_CALLABLE void init_legendre(T x, T& P0, T& P1) +{ + //compute the first two Legendre polynomials + P0 = 1; + P1 = x; +} + +template +CUDA_CALLABLE void shift_legendre(int n, T x, T& P0, T& P1) +{ + //compute the next (order n) Legendre polynomial + T Pnew = ( (2 * n - 1) * x * P1 - (n-1) * P0 ) / n; + + //shift and add the new value to the array + P0 = P1; + P1 = Pnew; +} + +template +CUDA_CALLABLE void legendre(int n, T x, T* P) +{ + P[0] = 1; + + if(n >= 1) + P[1] = x; + + for(int i=2; i<=n; i++) + { + P[i] = ( (2 * i - 1) * x * P[i-1] - (i-1) * P[i-2] ) / i; + } + +} + +} + + +#endif diff --git a/rts/material.h b/rts/material.h new file mode 100644 index 0000000..d7d763d --- /dev/null +++ b/rts/material.h @@ -0,0 +1,530 @@ +#ifndef MATERIALSTRUCT_H +#define MATERIALSTRUCT_H + +#include +#include +#include +#include +#include +#include +#include +#include "rts/rtcomplex.h" + +#define PI 3.14159 + +namespace rts{ + + enum field_type {field_microns, field_wavenumber, field_n, field_k, field_A, field_ignore}; + + //conversion functions + + //convert wavenumber to lambda + template + static T _wn(T inverse_cm) + { + return (T)10000.0/inverse_cm; + } + + template + static T _2wn(T lambda) + { + return (T)10000.0/lambda; + } + + //convert absorbance to k + template + static T _A(T absorbance, T lambda) + { + return (absorbance * lambda) / (4 * PI); + } + template + static T _2A(T k, T lambda) + { + return (4 * PI * k)/lambda; + } + + //define the dispersion as a single wavelength/refractive index pair + template + struct refIndex + { + //wavelength (in microns) + T lambda; + rtcomplex n; + }; + + template + struct entryType + { + //list of value types per entry + std::vector valueList; + + entryType(std::string format) + { + //location of the end of a parameter + size_t e; + + //string storing a token + std::string token; + + do + { + //find the end of the first parameter + e = format.find_first_of(','); + + //get the substring up to the comma + token = format.substr(0, e); + + //turn the token into a val_type + if(token == "microns") + valueList.push_back(field_microns); + else if(token == "wavenumber") + valueList.push_back(field_wavenumber); + else if(token == "n") + valueList.push_back(field_n); + else if(token == "k") + valueList.push_back(field_k); + else if(token == "A") + valueList.push_back(field_A); + else + valueList.push_back(field_ignore); + + //remove the first token from the format string + format = format.substr(e+1, format.length()-1); + }while(e != std::string::npos); + + + + } + + void addValue(field_type value) + { + valueList.push_back(value); + } + + refIndex inputEntry(std::string line, T scaleA = 1.0) + { + T val; + std::stringstream ss(line); + + //create a new refractive index + refIndex newRI; + + + //read the entry from an input string + for(int i=0; i>val; + + //store the value in the appropriate location + switch(valueList[i]) + { + case field_microns: + newRI.lambda = val; + break; + case field_wavenumber: + newRI.lambda = _wn(val); + break; + case field_n: + newRI.n.real(val); + break; + case field_k: + newRI.n.imag(val); + break; + case field_A: + newRI.n.imag(_A(val * scaleA, newRI.lambda)); + break; + } + } + + //return the refractive index associated with the entry + return newRI; + + } + + std::string outputEntry(refIndex material) + { + //std::string result; + std::stringstream ss; + + //for each field in the entry + for(int i=0; i 0) + ss<<"\t"; + //store the value in the appropriate location + switch(valueList[i]) + { + case field_microns: + ss< + class material + { + //dispersion (refractive index as a function of wavelength) + std::vector< refIndex > dispersion; + + //average refractive index (approximately 1.4) + T n0; + + void add(refIndex ri) + { + //refIndex converted = convert(ri, measurement); + dispersion.push_back(ri); + } + + //comparison function for sorting + static bool compare(refIndex a, refIndex b) + { + return (a.lambda < b.lambda); + } + + //comparison function for searching lambda + static bool findCeiling(refIndex a, refIndex b) + { + return (a.lambda > b.lambda); + } + + public: + + unsigned int nSamples() + { + return dispersion.size(); + } + material computeN(T _n0, unsigned int n_samples = 0, T pf = 2) + { + /* This function computes the real part of the refractive index + from the imaginary part. The Hilbert transform is required. I + use an FFT in order to simplify this, so either the FFTW or CUFFT + packages are required. CUFFT is used if this file is passed through + a CUDA compiler. Otherwise, FFTW is used if available. + */ + + n0 = _n0; + + int N; + if(n_samples) + N = n_samples; + else + N = dispersion.size(); + + +#ifdef FFTW_AVAILABLE + //allocate memory for the FFT + rtcomplex* Chi2 = (rtcomplex*)fftw_malloc(sizeof(rtcomplex) * N * pf); + rtcomplex* Chi2FFT = (rtcomplex*)fftw_malloc(sizeof(rtcomplex) * N * pf); + rtcomplex* Chi1 = (rtcomplex*)fftw_malloc(sizeof(rtcomplex) * N * pf); + + //create an FFT plan for the forward and inverse transforms + fftw_plan planForward, planInverse; + planForward = fftw_plan_dft_1d(N*pf, (fftw_complex*)Chi2, (fftw_complex*)Chi2FFT, FFTW_FORWARD, FFTW_ESTIMATE); + planInverse = fftw_plan_dft_1d(N*pf, (fftw_complex*)Chi2FFT, (fftw_complex*)Chi1, FFTW_BACKWARD, FFTW_ESTIMATE); + + float k, alpha; + T chi_temp; + + //the spectrum will be re-sampled in uniform values of wavenumber + T nuMin = _2wn(dispersion.back().lambda); + T nuMax = _2wn(dispersion.front().lambda); + T dnu = (nuMax - nuMin)/(N-1); + T lambda, tlambda; + for(int i=0; i nMin = dispersion.back(); + //rtcomplex nMax = dispersion.front(); + T a; + for(int i=N; i j(0, 1); + for(int i=0; i N/2, multiply by -i + else + Chi2FFT[i] *= -j; + } + + //execute the inverse Fourier transform (completing the Hilbert transform) + fftw_execute(planInverse); + + //divide the Chi1 values by N + for(int i=0; i newM; + newM.dispersion.clear(); + refIndex ri; + for(int i=0; i(); + } + + material(T lambda = 1.0, T n = 1.4, T k = 0.0) + { + //create a default refractive index + refIndex def; + def.lambda = lambda; + def.n.real(n); + def.n.imag(k); + add(def); + + //set n0 + n0 = n; + } + + material(std::string filename, std::string format, T scaleA = 1.0) + { + fromFile(filename, format); + } + + void fromFile(std::string filename, std::string format, T scaleA = 1.0) + { + //clear any previous values + dispersion.clear(); + + //load the file into a string + std::ifstream ifs(filename.c_str()); + + std::string line; + + if(!ifs.is_open()) + { + std::cout<<"Error: material file not found"<(ifs)), std::istreambuf_iterator()); + fromStr(instr, format, scaleA); + + } + + void fromStr(std::string str, std::string format, T scaleA = 1.0) + { + //create a string stream to process the input data + std::stringstream ss(str); + + //this string will be read line-by-line (where each line is an entry) + std::string line; + + //create an entry structure (for now just a basic one) + entryType entry(format); + + T lambda, n, k; + while(!ss.eof()) + { + //read a line from the string + getline(ss, line); + + //if the line is not a comment, process it + if(line[0] != '#') + { + //load the entry and add it to the dispersion list + add(entry.inputEntry(line, scaleA)); + } + //generally have to peek to trigger the eof flag + ss.peek(); + } + + //sort the vector by lambda + sort(dispersion.begin(), dispersion.end(), &material::compare); + } + + //convert the material to a string + std::string toStr(std::string format = "microns,n,k") + { + std::stringstream ss; + entryType entry(format); + for(unsigned int l=0; l 0) ss<& operator[](unsigned int i) + { + return dispersion[i]; + + } + + rtcomplex getN(T l) + { + //declare an iterator + typename std::vector< refIndex >::iterator it; + + refIndex r; + r.lambda = l; + + it = search(dispersion.begin(), dispersion.end(), &r, &r + 1, &material::findCeiling); + + //if the wavelength is past the end of the list, return the back + if(it == dispersion.end()) + return dispersion.back().n; + //if the wavelength is before the beginning of the list, return the front + else if(it == dispersion.begin()) + return dispersion.front().n; + //otherwise interpolate + else + { + T lMax = (*it).lambda; + T lMin = (*(it - 1)).lambda; + //std::cout< riMin = (*(it - 1)).n; + rtcomplex riMax = (*it).n; + rtcomplex interp; + interp = rtcomplex(a, 0.0) * riMin + rtcomplex(1.0 - a, 0.0) * riMax; + return interp; + } + + } + //interpolate the given lambda value and return the index of refraction + rtcomplex operator()(T l) + { + return getN(l); + } + + + }; +} //end namespace rts + +template +std::ostream& operator<<(std::ostream& os, rts::material m) +{ + os< + +namespace rts +{ + +template +struct point +{ + T p[N]; + + CUDA_CALLABLE point() + { + + } + + //efficiency constructor, makes construction easier for 1D-4D vectors + CUDA_CALLABLE point(T x, T y = (T)0.0, T z = (T)0.0, T w = (T)0.0) + { + if(N >= 1) + p[0] = x; + if(N >= 2) + p[1] = y; + if(N >= 3) + p[2] = z; + if(N >= 4) + p[3] = w; + } + + //arithmetic operators + CUDA_CALLABLE rts::point operator+(rts::vector v) + { + rts::point r; + + //calculate the position of the resulting point + for(int i=0; i operator-(rts::vector v) + { + rts::point r; + + //calculate the position of the resulting point + for(int i=0; i operator-(rts::point rhs) + { + rts::vector r; + + //calculate the position of the resulting point + for(int i=0; i operator*(T rhs) + { + rts::point r; + + //calculate the position of the resulting point + for(int i=0; i +std::ostream& operator<<(std::ostream& os, rts::point p) +{ + os< +CUDA_CALLABLE rts::point operator*(T lhs, rts::point rhs) +{ + rts::point r; + + return rhs * lhs; +} + + + +#endif diff --git a/rts/rect.h b/rts/rect.h new file mode 100644 index 0000000..53e07f3 --- /dev/null +++ b/rts/rect.h @@ -0,0 +1,141 @@ +#ifndef RTS_RECT_H +#define RTS_RECT_H + +//enable CUDA_CALLABLE macro +#include "rts/cuda_callable.h" +#include "rts/vector.h" +#include "rts/point.h" +#include + +namespace rts{ + +//template for a rectangle class in ND space +template +struct rect +{ + /* + C------------------>O + ^ ^ + | | + Y | + | | + | | + A---------X-------->B + */ + + /*T A[N]; + T B[N]; + T C[N];*/ + + rts::point A; + rts::vector X; + rts::vector Y; + + + CUDA_CALLABLE rect() + { + + } + + CUDA_CALLABLE rect(point a, point b, point c) + { + + A = a; + X = b - a; + Y = c - a; + + } + + CUDA_CALLABLE rect(rts::point pMin, rts::point pMax, rts::vector normal) + { + + //assign the corner point + A = pMin; + + //compute the vector from pMin to pMax + rts::vector v0; + v0 = pMax - pMin; + + //compute the cross product of A and the plane normal + rts::vector v1; + v1 = v0.cross(normal); + + + //calculate point B + rts::point B; + B = A + v0 * 0.5 + v1 * 0.5; + + //calculate point C + rts::point C; + C = A + v0 * 0.5 - v1 * 0.5; + + //calculate X and Y + X = B - A; + Y = C - A; + + + + + } + + /*CUDA_CALLABLE rect(rts::point p, rts::vector x, rts::vector y, T sx, T sy) + { + //This constructor creates a rect given a position, orientation, and size + // p = center position of the rect + // x = x-axis for the rectangle + // y = y-axis for the rectangle + // sx = size of the rect along the A-B axis + // sy = size of the rect along the A-C axis + + //normalize x and y + rts::vector nx = x.norm(); + rts::vector ny = y.norm(); + + //compute X and Y + X = sx * x; + Y = sy * y; + + //compute A + A = p - 0.5 * X - 0.5 * Y; + + }*/ + + CUDA_CALLABLE rts::point p(T a, T b) + { + rts::point result; + //given the two parameters a, b = [0 1], returns the position in world space + result = A + X * a + Y * b; + + return result; + } + + CUDA_CALLABLE rts::point operator()(T a, T b) + { + return p(a, b); + } + + std::string toStr() + { + std::stringstream ss; + + ss<<"A = "< +#include +#include +#include + +namespace rts +{ + +template +struct rtcomplex +{ + T r, i; + + //default constructor + CUDA_CALLABLE rtcomplex() + { + r = 0.0; + i = 0.0; + } + + //access methods + T real() + { + return r; + } + + T real(T r_val) + { + r = r_val; + return r_val; + } + + T imag() + { + return i; + } + T imag(T i_val) + { + i = i_val; + return i_val; + } + + + + + + //constructor when given real and imaginary values + CUDA_CALLABLE rtcomplex(T r, T i) + { + this->r = r; + this->i = i; + } + + //return the current value multiplied by i + CUDA_CALLABLE rtcomplex imul() + { + rtcomplex result; + result.r = -i; + result.i = r; + + return result; + } + + //ARITHMETIC OPERATORS-------------------- + + //binary + operator (returns the result of adding two complex values) + CUDA_CALLABLE rtcomplex operator+ (const rtcomplex rhs) + { + rtcomplex result; + result.r = r + rhs.r; + result.i = i + rhs.i; + return result; + } + + CUDA_CALLABLE rtcomplex operator+ (const T rhs) + { + rtcomplex result; + result.r = r + rhs; + result.i = i; + return result; + } + + //binary - operator (returns the result of adding two complex values) + CUDA_CALLABLE rtcomplex operator- (const rtcomplex rhs) + { + rtcomplex result; + result.r = r - rhs.r; + result.i = i - rhs.i; + return result; + } + + //binary - operator (returns the result of adding two complex values) + CUDA_CALLABLE rtcomplex operator- (const T rhs) + { + rtcomplex result; + result.r = r - rhs; + result.i = i; + return result; + } + + //binary MULTIPLICATION operators (returns the result of multiplying complex values) + CUDA_CALLABLE rtcomplex operator* (const rtcomplex rhs) + { + rtcomplex result; + result.r = r * rhs.r - i * rhs.i; + result.i = r * rhs.i + i * rhs.r; + return result; + } + CUDA_CALLABLE rtcomplex operator* (const T rhs) + { + return rtcomplex(r * rhs, i * rhs); + } + + //binary DIVISION operators (returns the result of dividing complex values) + CUDA_CALLABLE rtcomplex operator/ (const rtcomplex rhs) + { + rtcomplex result; + T denom = rhs.r * rhs.r + rhs.i * rhs.i; + result.r = (r * rhs.r + i * rhs.i) / denom; + result.i = (- r * rhs.i + i * rhs.r) / denom; + + return result; + } + CUDA_CALLABLE rtcomplex operator/ (const T rhs) + { + return rtcomplex(r / rhs, i / rhs); + } + + //ASSIGNMENT operators----------------------------------- + CUDA_CALLABLE rtcomplex & operator=(const rtcomplex &rhs) + { + //check for self-assignment + if(this != &rhs) + { + this->r = rhs.r; + this->i = rhs.i; + } + return *this; + } + CUDA_CALLABLE rtcomplex & operator=(const T &rhs) + { + this->r = rhs; + this->i = 0; + + return *this; + } + + //arithmetic assignment operators + CUDA_CALLABLE rtcomplex operator+=(const rtcomplex &rhs) + { + *this = *this + rhs; + return *this; + } + CUDA_CALLABLE rtcomplex operator+=(const T &rhs) + { + *this = *this + rhs; + return *this; + } + + CUDA_CALLABLE rtcomplex operator*=(const rtcomplex &rhs) + { + *this = *this * rhs; + return *this; + } + CUDA_CALLABLE rtcomplex operator*=(const T &rhs) + { + *this = *this * rhs; + return *this; + } + //divide and assign + CUDA_CALLABLE rtcomplex operator/=(const rtcomplex &rhs) + { + *this = *this / rhs; + return *this; + } + CUDA_CALLABLE rtcomplex operator/=(const T &rhs) + { + *this = *this / rhs; + return *this; + } + + //absolute value operator (returns the absolute value of the complex number) + CUDA_CALLABLE T abs() + { + return std::sqrt(r * r + i * i); + } + + CUDA_CALLABLE rtcomplex log() + { + rtcomplex result; + result.r = std::log(std::sqrt(r * r + i * i)); + result.i = std::atan2(i, r); + + + return result; + } + + CUDA_CALLABLE rtcomplex exp() + { + rtcomplex result; + + T e_r = std::exp(r); + result.r = e_r * std::cos(i); + result.i = e_r * std::sin(i); + + return result; + } + + /*CUDA_CALLABLE complex pow(int y) + { + + return pow((double)y); + }*/ + + CUDA_CALLABLE rtcomplex pow(T y) + { + rtcomplex result; + + result = log() * y; + + return result.exp(); + } + + CUDA_CALLABLE rtcomplex sqrt() + { + rtcomplex result; + + //convert to polar coordinates + T a = std::sqrt(r*r + i*i); + T theta = std::atan2(i, r); + + //find the square root + T a_p = std::sqrt(a); + T theta_p = theta/2.0; + + //convert back to cartesian coordinates + result.r = a_p * std::cos(theta_p); + result.i = a_p * std::sin(theta_p); + + return result; + } + + std::string toStr() + { + std::stringstream ss; + ss<<"("< rhs) + { + if(r == rhs.r && i == rhs.i) + return true; + return false; + } + + CUDA_CALLABLE bool operator==(T rhs) + { + if(r == rhs && i == (T)0.0) + return true; + return false; + } + + /*//FRIEND functions + //unary minus operator (for negating the complex number) + template CUDA_CALLABLE friend complex operator-(const complex &rhs); + + //multiplication by T values when the complex number isn't on the left hand side + template CUDA_CALLABLE friend complex operator*(const A a, const complex b); + + //division by T values when the complex number isn't on the left hand side + template CUDA_CALLABLE friend complex operator/(const A a, const complex b); + + //POW function + //template CUDA_CALLABLE friend complex pow(const complex x, T y); + template CUDA_CALLABLE friend complex pow(const complex x, int y); + + //log function + template CUDA_CALLABLE friend complex log(complex x); + + //exp function + template CUDA_CALLABLE friend complex exp(complex x); + + //sqrt function + template CUDA_CALLABLE friend complex sqrt(complex x); + + //trigonometric functions + template CUDA_CALLABLE friend complex sin(complex x); + + template CUDA_CALLABLE friend complex cos(complex x);*/ + +}; + +//addition +template +CUDA_CALLABLE static rtcomplex operator+(const double a, const rtcomplex b) +{ + return rtcomplex(a + b.r, b.i); +} + +//subtraction with a real value +template +CUDA_CALLABLE static rtcomplex operator-(const double a, const rtcomplex b) +{ + return rtcomplex(a - b.r, -b.i); +} + +//minus sign +template +CUDA_CALLABLE static rtcomplex operator-(const rtcomplex &rhs) +{ + return rtcomplex(-rhs.r, -rhs.i); +} + +//multiply a T value by a complex value +template +CUDA_CALLABLE static rtcomplex operator*(const double a, const rtcomplex b) +{ + return rtcomplex(a * b.r, a * b.i); +} + +//divide a T value by a complex value +template +CUDA_CALLABLE static rtcomplex operator/(const double a, const rtcomplex b) +{ + //return complex(a * b.r, a * b.i); + rtcomplex result; + + T denom = b.r * b.r + b.i * b.i; + + result.r = (a * b.r) / denom; + result.i = -(a * b.i) / denom; + + return result; +} + +//POW function +/*template +CUDA_CALLABLE static complex pow(complex x, int y) +{ + return x.pow(y); +}*/ + +template +CUDA_CALLABLE static rtcomplex pow(rtcomplex x, T y) +{ + return x.pow(y); +} + +//log function +template +CUDA_CALLABLE static rtcomplex log(rtcomplex x) +{ + return x.log(); +} + +//exp function +template +CUDA_CALLABLE static rtcomplex exp(rtcomplex x) +{ + return x.exp(); +} + +//sqrt function +template +CUDA_CALLABLE static rtcomplex sqrt(rtcomplex x) +{ + return x.sqrt(); +} + + +template +CUDA_CALLABLE static T abs(rtcomplex a) +{ + return a.abs(); +} + +template +CUDA_CALLABLE static T real(rtcomplex a) +{ + return a.r; +} + +template +CUDA_CALLABLE static T imag(rtcomplex a) +{ + return a.i; +} + +//trigonometric functions +template +CUDA_CALLABLE rtcomplex sin(const rtcomplex x) +{ + rtcomplex result; + result.r = std::sin(x.r) * std::cosh(x.i); + result.i = std::cos(x.r) * std::sinh(x.i); + + return result; +} + +template +CUDA_CALLABLE rtcomplex cos(const rtcomplex x) +{ + rtcomplex result; + result.r = std::cos(x.r) * std::cosh(x.i); + result.i = -(std::sin(x.r) * std::sinh(x.i)); + + return result; +} + + + +} //end RTS namespace + +template +std::ostream& operator<<(std::ostream& os, rts::rtcomplex x) +{ + os< + + +namespace rts{ + +#define RTS_BESSEL_CONVERGENCE_FLOAT 0.00045 + +template +CUDA_CALLABLE void sbesselj(int n, rtcomplex x, rtcomplex* j) +{ + //compute the first bessel function + if(n >= 0) + j[0] = sin(x) / x; + + //compute the second bessel function + if(n >= 1) + j[1] = j[0] / x - cos(x) / x; + + //use the recurrence relation to compute the rest + for(int i = 2; i <= n; i++) + { + j[i] = ( (2 * i - 1) / x ) * j[i-1] - j[i-2]; + } + + //if x = 0, deal with the degenerate case + /*if( isnan(j[0].r) ) + { + j[0] = (T)1.0; + for(int i = 1; i<=n; i++) + j[i] = (T)0.0; + }*/ +} + +template +CUDA_CALLABLE void sbessely(int n, rtcomplex x, rtcomplex* y) +{ + //compute the first bessel function + if(n >= 0) + y[0] = -cos(x) / x; + + //compute the second bessel function + if(n >= 1) + y[1] = y[0] / x - sin(x) / x; + + //use the recurrence relation to compute the rest + for(int i = 2; i <= n; i++) + { + y[i] = ( (2 * i - 1) / x ) * y[i-1] - y[i-2]; + } + +} + +//spherical Hankel functions of the first kind +template +CUDA_CALLABLE void sbesselh1(int n, rtcomplex x, rtcomplex* h) +{ + //compute j_0 and j_1 + rtcomplex j[2]; + sbesselj(1, x, j); + + //compute y_0 and y_1 + rtcomplex y[2]; + sbessely(1, x, y); + + //compute the first-order Hhankel function + if(n >= 0) + h[0] = j[0] + y[0].imul(); + + //compute the second bessel function + if(n >= 1) + h[1] = j[1] + y[1].imul(); + + //use the recurrence relation to compute the rest + for(int i = 2; i <= n; i++) + { + h[i] = ( (2 * i - 1) / x ) * h[i-1] - h[i-2]; + } +} + +template +CUDA_CALLABLE void init_sbesselj(T x, T* j) +{ + /*if(x < EPSILON_FLOAT) + { + j[0] = (T)1; + j[1] = (T)0; + return; + }*/ + + //compute the first 2 bessel functions + j[0] = std::sin(x) / x; + + j[1] = j[0] / x - std::cos(x) / x; + + //deal with the degenerate case of x = 0 + /*if(isnan(j[0])) + { + j[0] = (T)1; + j[1] = (T)0; + }*/ + +} + +template +CUDA_CALLABLE void shift_sbesselj(int n, T x, T* j)//, T stability = 1.4) +{ + + /*if(x < EPSILON_FLOAT) + { + j[0] = j[1]; + j[1] = (T)0; + return; + }*/ + + T jnew; + + //compute the next (order n) Bessel function + jnew = ((2 * n - 1) * j[1])/x - j[0]; + + //if(n > stability*x) + if(n > x) + if(jnew < RTS_BESSEL_CONVERGENCE_FLOAT) + jnew = (T)0; + + //deal with the degenerate case of x = 0 + //if(isnan(jnew)) + // jnew = (T)0; + + //shift and add the new value to the array + j[0] = j[1]; + j[1] = jnew; +} + + + +} //end namespace rts + + + +#endif diff --git a/rts/vector.h b/rts/vector.h new file mode 100644 index 0000000..776d9d6 --- /dev/null +++ b/rts/vector.h @@ -0,0 +1,211 @@ +#ifndef RTS_VECTOR_H +#define RTS_VECTOR_H + +#include +//#include "rts/point.h" + +namespace rts +{ + + + +template +struct vector +{ + T v[N]; + + CUDA_CALLABLE vector() + { + //memset(v, 0, sizeof(T) * N); + } + + //efficiency constructor, makes construction easier for 1D-4D vectors + CUDA_CALLABLE vector(T x, T y = (T)0.0, T z = (T)0.0, T w = (T)0.0) + { + if(N >= 1) + v[0] = x; + if(N >= 2) + v[1] = y; + if(N >= 3) + v[2] = z; + if(N >= 4) + v[3] = w; + } + + CUDA_CALLABLE vector(const T(&data)[N]) + { + memcpy(v, data, sizeof(T) * N); + } + + CUDA_CALLABLE T len() + { + //compute and return the vector length + T sum_sq = (T)0; + for(int i=0; i cart2sph() + { + //convert the vector from cartesian to spherical coordinates + //x, y, z -> r, theta, phi + + vector sph; + sph[0] = std::sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); + sph[1] = std::atan2(v[1], v[0]); + sph[2] = std::acos(v[2] / sph[0]); + + return sph; + } + + CUDA_CALLABLE vector sph2cart() + { + //convert the vector from cartesian to spherical coordinates + //r, theta, phi -> x, y, z + + vector cart; + cart[0] = v[0] * std::cos(v[1]) * std::sin(v[2]); + cart[1] = v[0] * std::sin(v[1]) * std::sin(v[2]); + cart[2] = v[0] * std::cos(v[2]); + + return cart; + } + + CUDA_CALLABLE vector norm() + { + //compute and return the vector norm + vector result; + + //compute the vector length + T l = len(); + + //normalize + for(int i=0; i cross(vector rhs) + { + vector result; + + //compute the cross product (only valid for 3D vectors) + result[0] = v[1] * rhs[2] - v[2] * rhs[1]; + result[1] = v[2] * rhs[0] - v[0] * rhs[2]; + result[2] = v[0] * rhs[1] - v[1] * rhs[0]; + + return result; + } + + CUDA_CALLABLE T dot(vector rhs) + { + T result = (T)0; + + for(int i=0; i operator+(vector rhs) + { + vector result; + + for(int i=0; i operator-(vector rhs) + { + vector result; + + for(int i=0; i operator*(T rhs) + { + vector result; + + for(int i=0; i operator/(T rhs) + { + vector result; + + for(int i=0; i +std::ostream& operator<<(std::ostream& os, rts::vector v) +{ + os< +CUDA_CALLABLE rts::vector operator-(rts::vector v) +{ + rts::vector r; + + //negate the vector + for(int i=0; i +CUDA_CALLABLE rts::vector operator*(T lhs, rts::vector rhs) +{ + rts::vector r; + + return rhs * lhs; +} + +#endif diff --git a/rtsCamera.h b/rtsCamera.h new file mode 100755 index 0000000..0b2e4b5 --- /dev/null +++ b/rtsCamera.h @@ -0,0 +1,191 @@ +#include "rtsVector3d.h" +#include "rtsPoint3d.h" +#include "rtsQuaternion.h" + +#ifndef RTS_CAMERA_H +#define RTS_CAMERA_H + +class rtsCamera +{ + vector3D d; //direction that the camera is pointing + point3D p; //position of the camera + vector3D up; //"up" direction + float focus; //focal length of the camera + float fov; + + //private function makes sure that the up vector is orthogonal to the direction vector and both are normalized + void stabalize() + { + vector3D side = up.X(d); + up = d.X(side); + up.Normalize(); + d.Normalize(); + } + +public: + void setPosition(point3D pos) + { + p = pos; + } + void setPosition(float x, float y, float z){setPosition(point3D(x, y, z));} + + void setFocalDistance(float distance){focus = distance;} + void setFOV(float field_of_view){fov = field_of_view;} + + void LookAt(point3D pos) + { + //find the new direction + d = pos - p; + + //find the distance from the look-at point to the current position + focus = d.Length(); + + //stabalize the camera + stabalize(); + } + void LookAt(float px, float py, float pz){LookAt(point3D(px, py, pz));} + void LookAt(point3D pos, vector3D new_up){up = new_up; LookAt(pos);} + void LookAt(float px, float py, float pz, float ux, float uy, float uz){LookAt(point3D(px, py, pz), vector3D(ux, uy, uz));} + void LookAtDolly(float lx, float ly, float lz) + { + //find the current focus point + point3D f = p + focus*d; + vector3D T = point3D(lx, ly, lz) - f; + p = p + T; + } + + void Dolly(vector3D direction) + { + p = p+direction; + } + void Dolly(float x, float y, float z){Dolly(vector3D(x, y, z));} + void Push(float delta) + { + if(delta > focus) + delta = focus; + + focus -= delta; + + Dolly(d*delta); + } + + void Pan(float theta_x, float theta_y, float theta_z) + { + //x rotation is around the up axis + rtsQuaternion qx; + qx.CreateRotation(theta_x, up.x, up.y, up.z); + + //y rotation is around the side axis + vector3D side = up.X(d); + rtsQuaternion qy; + qy.CreateRotation(theta_y, side.x, side.y, side.z); + + //z rotation is around the direction vector + rtsQuaternion qz; + qz.CreateRotation(theta_z, d.x, d.y, d.z); + + //combine the rotations in x, y, z order + rtsQuaternion final = qz*qy*qx; + + //get the rotation matrix + matrix4x4 rot_matrix = final.toMatrix(); + + //apply the rotation + d = rot_matrix*d; + up = rot_matrix*up; + + //stabalize the camera + stabalize(); + + } + void Pan(float theta_x){Pan(theta_x, 0, 0);} + void Tilt(float theta_y){Pan(0, theta_y, 0);} + void Twist(float theta_z){Pan(0, 0, theta_z);} + + void Zoom(float delta) + { + fov -= delta; + if(fov < 0.5) + fov = 0.5; + if(fov > 180) + fov = 180; + } + + void OrbitFocus(float theta_x, float theta_y) + { + //find the focal point + point3D focal_point = p + focus*d; + + //center the coordinate system on the focal point + point3D centered = p - (focal_point - point3D(0, 0, 0)); + + //create the x rotation (around the up vector) + rtsQuaternion qx; + qx.CreateRotation(theta_x, up.x, up.y, up.z); + centered = qx.toMatrix()*centered; + + //get a side vector for theta_y rotation + vector3D side = up.X((point3D(0, 0, 0) - centered).Normalize()); + + rtsQuaternion qy; + qy.CreateRotation(theta_y, side.x, side.y, side.z); + centered = qy.toMatrix()*centered; + + //perform the rotation on the centered camera position + //centered = final.toMatrix()*centered; + + //re-position the camera + p = centered + (focal_point - point3D(0, 0, 0)); + + //make sure we are looking at the focal point + LookAt(focal_point); + + //stabalize the camera + stabalize(); + + } + + void Slide(float u, float v) + { + vector3D V = up.Normalize(); + vector3D U = up.X(d).Normalize(); + + p = p + (V * v) + (U * u); + } + + //accessor methods + point3D getPosition(){return p;} + vector3D getUp(){return up;} + vector3D getDirection(){return d;} + point3D getLookAt(){return p + focus*d;} + float getFOV(){return fov;} + + //output the camera settings + const void print(ostream& output) + { + output<<"Position: "<(0, 0, 0); + d = vector3D(0, 0, 1); + up = vector3D(0, 1, 0); + focus = 1; + + } +}; + + + +#endif \ No newline at end of file diff --git a/rtsCameraController.cpp b/rtsCameraController.cpp new file mode 100755 index 0000000..d53af24 --- /dev/null +++ b/rtsCameraController.cpp @@ -0,0 +1,407 @@ +#include "rtsCameraController.h" +#include +rtsCamera::rtsCamera() +{ + m_camera_state.position = point3D(10, 10, 10); + m_camera_state.lookat = point3D(0, 0, 0); + m_camera_state.up = vector3D(0, 1, 0); + m_camera_state.pers_view_angle = 60; + m_camera_state.near_plane = 1; + m_camera_state.far_plane = 100; +} + +rtsCamera::~rtsCamera() +{ + +} + +rtsCamera::rtsCamera(rtsCameraState initial_state) +{ + m_camera_state = initial_state; + + //make sure that the view and lookat vectors are orthogonal + vector3D lookat = m_camera_state.lookat - m_camera_state.position; + vector3D up = m_camera_state.up; + vector3D side = lookat.X(up); + up = side.X(lookat); + up.Normalize(); + m_camera_state.up = up; +} + +rtsCameraState rtsCamera::getState() +{ + return m_camera_state; +} + +vector3D rtsCamera::getViewVector() +{ + vector3D result = m_camera_state.lookat - m_camera_state.position; + result.Normalize(); + return result; +} + +vector3D rtsCamera::getUpVector() +{ + return m_camera_state.up; +} + +point3D rtsCamera::getPosition() +{ + return m_camera_state.position; +} + +void rtsCamera::setState(rtsCameraState camera_state) +{ + m_camera_state = camera_state; + + //re-orthogonalize the vectors + vector3D view = m_camera_state.lookat - m_camera_state.position; + vector3D side = view.X(m_camera_state.up); + m_camera_state.up = side.X(view); + m_camera_state.up.Normalize(); +} + +void rtsCamera::LookAt(point3D point) +{ + //looks at a point + + //find the new view vector + vector3D view = point - m_camera_state.position; + + //normalize the view vector + view.Normalize(); + + //prepare a new side vector and up vector + vector3D side; + vector3D up; + + //get the up vector + //if the new viewvector is at 0 or 180 degrees to the up vector + float cos_angle = view*m_camera_state.up; + if(cos_angle == 1.0f || cos_angle == -1.0f) + { + //re-calculate the up vector + up = m_camera_state.up.X(m_camera_state.lookat - m_camera_state.position); + } + else + { + //otherwise, just get the current up vector + up = m_camera_state.up; + } + + + //correct the up vector based on the new view vector + side = up.X(view); + up = view.X(side); + up.Normalize(); + + //change the camera state + m_camera_state.up = up; + m_camera_state.lookat = point; +} + +void rtsCamera::Position(point3D p) +{ + m_camera_state.position = p; +} + +void rtsCamera::Up(vector3D up) +{ + m_camera_state.up = up; +} + +void rtsCamera::DollyPosition(point3D p) +{ + vector3D adjustment = p-m_camera_state.position; + m_camera_state.position = p; + m_camera_state.lookat = m_camera_state.lookat + adjustment; +} + +point3D rtsCamera::getLookAtPoint() +{ + return m_camera_state.lookat; +} + + + +void rtsCamera::Pan(double x, double y) +{ + //first calculate the lookat and side vectors + vector3D lookatvector=m_camera_state.lookat - m_camera_state.position; + vector3D sidevector = lookatvector.X(m_camera_state.up); + sidevector.Normalize(); + + m_camera_state.position=m_camera_state.position+sidevector*x; + m_camera_state.lookat=m_camera_state.lookat+sidevector*x; + + vector3D upvector = lookatvector.X(sidevector); + upvector.Normalize(); + m_camera_state.position=m_camera_state.position+upvector*y; + m_camera_state.lookat=m_camera_state.lookat+upvector*y; +} + +void rtsCamera::RotateUpDown(double degrees) +{ + //first calculate the lookat and side vectors + vector3D lookatvector=m_camera_state.lookat-m_camera_state.position; + vector3D sidevector = lookatvector.X(m_camera_state.up); + m_camera_state.up=sidevector.X(lookatvector); + m_camera_state.up.Normalize(); + sidevector.Normalize(); + + //translate the look-at point to the origin (and the camera with it) + point3D origin = point3D(0.0, 0.0, 0.0); + vector3D translateCamera = origin-m_camera_state.lookat; + + point3D translatedCamera=m_camera_state.position+translateCamera; + + //the next step is to rotate the side vector so that it lines up with the z axis + double a=sidevector.x; + double b=sidevector.y; + double c=sidevector.z; + + double d=sqrt(b*b + c*c); + + //error correction for when we are already looking down the z-axis + if(d==0) + return; + + vector3D XZplane = vector3D(translatedCamera.x, + (translatedCamera.y*c/d - translatedCamera.z*b/d), + (translatedCamera.y*b/d + translatedCamera.z*c/d)); + + vector3D Zaxis = vector3D(XZplane.x*d - XZplane.z*a, + XZplane.y, + XZplane.x*a + XZplane.z*d); + + vector3D rotated = vector3D(Zaxis.x*cos(TORADIANS(degrees)) - Zaxis.y*sin(TORADIANS(degrees)), + Zaxis.x*sin(TORADIANS(degrees)) + Zaxis.y*cos(TORADIANS(degrees)), + Zaxis.z); + + vector3D XZout = vector3D( rotated.x*(d/(a*a + d*d)) + rotated.z*(a/(a*a + d*d)), + rotated.y, + rotated.x*(-a/(a*a+d*d)) + rotated.z*(d/(a*a + d*d))); + + vector3D result = vector3D( XZout.x, + XZout.y*(c*d/(b*b + c*c)) + XZout.z*(b*d/(b*b + c*c)), + XZout.y*(-b*d/(b*b + c*c)) + XZout.z*(c*d/(b*b + c*c))); + + result=result-translateCamera; + + m_camera_state.position.x=result.x; + m_camera_state.position.y=result.y; + m_camera_state.position.z=result.z; + +} + +void rtsCamera::Yaw(double degrees) +{ + //basically, we have to rotate the look-at point around the up vector + //first, translate the look-at point so that the camera is at the origin + point3D origin(0.0, 0.0, 0.0); + point3D temp_lookat = m_camera_state.lookat - (m_camera_state.position - origin); + + //create a rotation matrix to rotate the lookat point around the up vector + float x=m_camera_state.up.x; + float y=m_camera_state.up.y; + float z=m_camera_state.up.z; + float c=cos(TORADIANS(-degrees)); + float s=sin(TORADIANS(-degrees)); + float t=1.0 - cos(TORADIANS(-degrees)); + float m00 = t*x*x + c; + float m01 = t*x*y + s*z; + float m02 = t*x*z - s*y; + float m03 = 0; + float m10 = t*x*y - s*z; + float m11 = t*y*y + c; + float m12 = t*y*z + s*x; + float m13 = 0; + float m20 = t*x*z + s*y; + float m21 = t*y*z - s*x; + float m22 = t*z*z + c; + float m23 = 0; + float m30 = 0; + float m31 = 0; + float m32 = 0; + float m33 = 1; + matrix4x4 rotation(m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, + m30, m31, m32, m33); + point3D result = rotation*temp_lookat + (m_camera_state.position - origin); + m_camera_state.lookat = result; +} + +void rtsCamera::Pitch(double degrees) +{ + //basically, we have to rotate the look-at point and up vector around the side vector + //first, translate the look-at point so that the camera is at the origin + point3D origin(0.0, 0.0, 0.0); + + //find all three necessary vectors + vector3D temp_lookat = m_camera_state.lookat - m_camera_state.position; + double lookat_length = temp_lookat.Length(); + vector3D temp_up = m_camera_state.up; + vector3D temp_side = temp_lookat.X(temp_up); + temp_lookat.Normalize(); + temp_up.Normalize(); + temp_side.Normalize(); + + + //create a rotation matrix to rotate around the side vector + float x=temp_side.x; + float y=temp_side.y; + float z=temp_side.z; + float c=cos(TORADIANS(degrees)); + float s=sin(TORADIANS(degrees)); + float t=1.0 - cos(TORADIANS(degrees)); + float m00 = t*x*x + c; + float m01 = t*x*y + s*z; + float m02 = t*x*z - s*y; + float m03 = 0; + float m10 = t*x*y - s*z; + float m11 = t*y*y + c; + float m12 = t*y*z + s*x; + float m13 = 0; + float m20 = t*x*z + s*y; + float m21 = t*y*z - s*x; + float m22 = t*z*z + c; + float m23 = 0; + float m30 = 0; + float m31 = 0; + float m32 = 0; + float m33 = 1; + matrix4x4 rotation(m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, + m30, m31, m32, m33); + + //rotate the up and look-at vectors around the side vector + vector3D result_lookat = rotation*temp_lookat; + vector3D result_up = rotation*temp_up; + result_lookat.Normalize(); + result_up.Normalize(); + + m_camera_state.lookat = m_camera_state.position + result_lookat * lookat_length; + m_camera_state.up = result_up; +} + + +void rtsCamera::RotateLeftRight(double degrees) +//this function rotates the camera around the up vector (which always points along hte positive +//Y world axis). +{ + //translate the look-at point to the origin (and the camera with it) + point3D origin = point3D(0.0, 0.0, 0.0); + vector3D translateCamera = origin-m_camera_state.lookat; + + point3D translatedCamera=m_camera_state.position+translateCamera; + + + //perform the rotation around the look-at point + //using the y-axis as the rotation axis + point3D newcamera; + newcamera.x=translatedCamera.x*cos(TORADIANS(degrees)) - translatedCamera.z*sin(TORADIANS(degrees)); + newcamera.z=translatedCamera.x*sin(TORADIANS(degrees)) + translatedCamera.z*cos(TORADIANS(degrees)); + newcamera.y=translatedCamera.y; + + vector3D newup; + newup.x=m_camera_state.up.x*cos(TORADIANS(degrees)) - m_camera_state.up.z*sin(TORADIANS(degrees)); + newup.z=m_camera_state.up.x*sin(TORADIANS(degrees)) + m_camera_state.up.z*cos(TORADIANS(degrees)); + newup.y=m_camera_state.up.y; + + //translate the lookat point back to it's original position (along with the camera) + newcamera=newcamera-translateCamera; + + m_camera_state.position.x=newcamera.x; + m_camera_state.position.y=newcamera.y; + m_camera_state.position.z=newcamera.z; + + m_camera_state.up.x=newup.x; + m_camera_state.up.y=newup.y; + m_camera_state.up.z=newup.z; + m_camera_state.up.Normalize(); + +} + +void rtsCamera::Forward(double distance) +{ + //calculate the lookat vector (direction of travel) + vector3D old_lookat=m_camera_state.lookat-m_camera_state.position; + old_lookat.Normalize(); + + //calculate the new position of the camera + point3D new_position = m_camera_state.position+old_lookat*distance; + //now calculate the new lookat vector + vector3D new_lookat=m_camera_state.lookat-new_position; + //find the length of the new lookat vector + /*double newlength=lookatvector.length(); + //if the length is 0 or the camera flipped + if((newlength <= 0.0)) + { + //recalculate the lookat vector using the old position + lookatvector=m_camera_state.lookat-m_camera_state.position; + lookatvector.Normalize(); + //adjust the lookat point appropriately + m_camera_state.lookat = new_position + lookatvector; + }*/ + //move the camera to the new position + m_camera_state.position = new_position; +} + +void rtsCamera::ScaleForward(double factor, double min, double max) +{ + /*This function moves the camera forward, scaling the magnitude + of the motion by the length of the view vector. Basically, the closer + the camera is to the lookat point, the slower the camera moves.*/ + + //calculate the lookat vector (direction of travel) + vector3D lookatvector=m_camera_state.lookat-m_camera_state.position; + //find the length of the view vector + double length = lookatvector.Length(); + //normalize + lookatvector.Normalize(); + + //prevent motion if the bounds would be passed + double new_distance = length - (factor*length); + if(new_distance < min || new_distance > max) + factor = 0; + //move the camera + m_camera_state.position=m_camera_state.position+lookatvector*factor*length; + lookatvector=m_camera_state.lookat-m_camera_state.position; + /*double newlength=lookatvector.length(); + if((newlength < 2)) + { + lookatvector.Normalize(); + m_camera_state.lookat = m_camera_state.position + lookatvector*2; + }*/ + + +} + +void rtsCamera::DollyLeftRight(double distance) +{ + //calculate the side vector vector (direction of travel) + vector3D lookatvector=m_camera_state.lookat-m_camera_state.position; + vector3D side = lookatvector.X(m_camera_state.up); + side.Normalize(); + + m_camera_state.position=m_camera_state.position+side*distance; + m_camera_state.lookat = m_camera_state.lookat + side*distance; + //lookatvector=m_camera_state.lookat-m_camera_state.position; +} + +void rtsCamera::DollyUpDown(double distance) +{ + //move along the up vector + m_camera_state.up.Normalize(); + + m_camera_state.position=m_camera_state.position+m_camera_state.up*distance; + m_camera_state.lookat = m_camera_state.lookat + m_camera_state.up*distance; + //lookatvector=m_camera_state.lookat-m_camera_state.position; +} + +void rtsCamera::Zoom(double angle) +{ + m_camera_state.pers_view_angle += angle; +} \ No newline at end of file diff --git a/rtsCameraController.h b/rtsCameraController.h new file mode 100755 index 0000000..d17c2b0 --- /dev/null +++ b/rtsCameraController.h @@ -0,0 +1,77 @@ +#include "rtsLinearAlgebra.h" + +#ifndef _RTSMATH_H +#define _RTSMATH_H + +#define CAMERA_UP -1 +#define CAMERA_DOWN 1 +#define CAMERA_LEFT -1 +#define CAMERA_RIGHT 1 + +struct rtsCameraState +{ + point3D position; + point3D lookat; + vector3D up; + float pers_view_angle; + float ortho_width; + float ortho_height; + float near_plane; + float far_plane; +}; + +class rtsCamera +{ + //members + rtsCameraState m_camera_state; + +public: + + //methods + void RotateUpDown(double degrees); + void RotateLeftRight(double degrees); + void Pan(double x, double y); + void Yaw(double degrees); + void Pitch(double degrees); + void Forward(double distance); + void ScaleForward(double factor, double min = 0, double max = 999999); + void DollyLeftRight(double distance); + void DollyUpDown(double distance); + void Zoom(double angle); + void LookAt(point3D point); + void Position(point3D point); + void Up(vector3D up); + void DollyPosition(point3D point); //moves the camera but keeps the current orientation + + //get methods + rtsCameraState getState(); + vector3D getViewVector(); + vector3D getUpVector(); + point3D getPosition(); + point3D getLookAtPoint(); + double getViewAngle(){return m_camera_state.pers_view_angle;} + double getNearPlane(){return m_camera_state.near_plane;} + double getFarPlane(){return m_camera_state.far_plane;} + double getOrthoWidth(){return m_camera_state.ortho_width;} + double getOrthoHeight(){return m_camera_state.ortho_height;} + + //set methods + void setState(rtsCameraState camera_state); + + //initialization methods + //int SetPosition(double x, double y, double z); + //int OrthogonalCamera(double width, double height, double near, double far); + //int LookAt(double x, double y, double z); //looks at a point in space + //int SetUpVector(double x, double y, double z); + /*int InitializePerspectiveCamera(double position_x, double position_y, double position_z, + double lookat_x, double lookat_y, double lookat_z, + double up_x, double up_y, double up_z, + double angle, double near_dist, double far_dist);*/ + //int InitializeCamera(); //initializes a camera to defaults + + rtsCamera(); + rtsCamera(rtsCameraState initial_state); + ~rtsCamera(); +}; + +#endif \ No newline at end of file diff --git a/rtsConstants.h b/rtsConstants.h new file mode 100755 index 0000000..70e683f --- /dev/null +++ b/rtsConstants.h @@ -0,0 +1,15 @@ +#define RTS_OK 0 +#define RTS_ERROR 99 + + +#define RTS_EMPTY 1 //an element can't be deleted if it contains no data +#define RTS_INVALID_ID 2 //an object with this identifier does not exist +#define RTS_INVALID_CONSTANT 3 //an invalid constant passed as a parameter + +//objects +#define RTS_END_OBJECT 4 //reached the end of an object's elements + +//utility constants +#define RTS_NULL 0 + +#define RTS_NO_INTERSECTION 1 //there is no intersection in intersection calculations \ No newline at end of file diff --git a/rtsCubeSampler.cpp b/rtsCubeSampler.cpp new file mode 100755 index 0000000..eab89b1 --- /dev/null +++ b/rtsCubeSampler.cpp @@ -0,0 +1,56 @@ +#include "rtsCubeSampler.h" + +vector rtsCubeSampler::Evaluate() +{ + /*This function evaluates the cube with the given parameters and returns + a vector of sample normalized sample vectors.*/ + + //find a valid up vector + vector3D u(0.0, 1.0, 0.0); + //calculate the side vector + vector3D s = u.cross(m_main_vector); + //orthogonalize the up vector + u = m_main_vector.cross(s); + //normalize all three vectors + m_main_vector.normalize(); + u.normalize(); + s.normalize(); + + //create a vector representing each side of the cube + vector3D sides[6]; + sides[0] = m_main_vector; + sides[1] = (m_main_vector)*(-1); + sides[2] = u; + sides[3] = u*(-1); + sides[4] = s; + sides[5] = s*(-1); + + //calculate the step size along the basis vectors for a side + double step = 1.0/((double)m_squared_samples_per_side); + + //evaluate the cube, storing the result in an STL vector + vector result; + for(int k=0; k<6; k++) + for(int i=0; i= cos(TORADIANS(max_angle))) + result.push_back(final_vector); + } + + //return the vector of results + return result; +} \ No newline at end of file diff --git a/rtsCubeSampler.h b/rtsCubeSampler.h new file mode 100755 index 0000000..9d92b3c --- /dev/null +++ b/rtsCubeSampler.h @@ -0,0 +1,32 @@ +/*This class returns a series of normalized vectors that sample the surface of a cube*/ +/*TODO: +-)Implement random sampling +-)Allow the user to provide a total number of samples + +*/ +#ifndef RTSCUBESAMPLER_H +#define RTSCUBESAMPLER_H + +#include +#include "rtsMath.h" + +using namespace std; + +//definitions for sample types +#define RTS_RANDOM_UNIFORM 0x00001001 +#define RTS_RANDOM_GAUSSIAN 0x00001002 +#define RTS_REGULAR 0x00001003 + +class rtsCubeSampler +{ +public: + + unsigned int m_sample_type; + unsigned int m_squared_samples_per_side; + double max_angle; + vector3D m_main_vector; + + vector Evaluate(); +}; + +#endif \ No newline at end of file diff --git a/rtsDTGrid1D.h b/rtsDTGrid1D.h new file mode 100755 index 0000000..8ec59b8 --- /dev/null +++ b/rtsDTGrid1D.h @@ -0,0 +1,624 @@ +#ifndef _RTS_DTGRID1D_H +#define _RTS_DTGRID1D_H + +#include +#include +using namespace std; + +struct ConnectedComponent +{ + int toValue; + int coordMin; + int coordMax; +}; + + + + +template +class rtsDTGrid1D +{ + +private: + //main arrays + vector value; + vector conn; + + //variables to keep track of insertion + int max_coord; + bool insertion_started; + bool randomIndex(int &v, int &c, int x1); + + +public: + T background; + rtsDTGrid1D() + { + insertion_started = false; + max_coord = 0; + } + int getMaxX1(){return max_coord;} + + T random(int x1); + T& back(); + bool push(int x1, T value); + void insert(rtsDTGrid1D toInsert); + void getBounds(int &min_x1, int &max_x1); + void dilate(int H); + template rtsDTGrid1D

getStorage() + { + //create the resulting grid + rtsDTGrid1D

result; + //create an iterator to run over the existing grid + P* new_value = (P*)calloc(1, sizeof(P)); + for(iterator i = begin(); i!=end(); i.increment()) + { + result.push(i.X1(), *new_value); + } + return result; + + } + void operator=(T rhs); + void print(); + + //iterator + class iterator; + friend class iterator; + class stencil_iterator; + iterator randomIterator(int x1); + iterator begin(); + iterator end(); + iterator before(); + iterator after(); + +}; + +/***************ITERATOR*************************/ +template +class rtsDTGrid1D::iterator +{ + friend class rtsDTGrid1D; + + +protected: + rtsDTGrid1D* parent; + int iv; + int ic; + int x1; + +public: + T Value(){return parent->value[iv];} + int X1(){return x1;} + void SetValue(T val){parent->value[iv] = val;} + + iterator(){parent = NULL;} + + void p() + { + //increment the current coordinate and value + x1++; + iv++; + //if we are outside of the current connected component + if(x1 > parent->conn[ic].coordMax) + { + //if this is the last connected component, set the iterator to END and return + if(ic == parent->conn.size() - 1) + { + (*this) = parent->after(); + return; + } + //otherwise move to the next connected component and update the coordinate + ic++; + x1 = parent->conn[ic].coordMin; + } + } + void n() + { + //increment the current coordinate and value + x1--; + iv--; + //if we are outside of the current connected component + if(x1 < parent->conn[ic].coordMin) + { + //if this is the last connected component, set the iterator to END and return + if(ic <= 0) + { + (*this) = parent->before(); + return; + } + //otherwise move to the next connected component and update the coordinate + ic--; + x1 = parent->conn[ic].coordMax; + } + + + } + //boolean operators for comparing iterators + bool operator==(iterator &rhs) + { + if(parent == rhs.parent && iv == rhs.iv) + return true; + //if(x1 == rhs.x1) + // return true; + return false; + } + bool operator!=(iterator &rhs){return !((*this) == rhs);} + bool operator<(iterator &rhs) + { + if(parent == rhs.parent && iv == rhs.iv) + return true; + //if the parents are the same, test value indices + //if(parent == rhs.parent && iv < rhs.iv) + // return true; + //otherwise test coordinates + //if(parent != rhs.parent && x1 < rhs.x1) + // return true; + return false; + } + bool operator<=(iterator &rhs) + { + if(parent == rhs.parent && iv <= rhs.iv) + return true; + //if(x1 <= rhs.x1) + // return true; + return false; + } + void operator++(){p();} + void operator--(){n();} + + void increment_until(int pos) + { + while(x1 < pos && (*this) != parent->after()) + { + p(); + } + } +}; + + +/************STENCIL ITERATOR********************/ +template +class rtsDTGrid1D::stencil_iterator : public iterator +{ +private: + //list of iterators that make up the template + vector iterator_list; + //iterator positions (relative to the position of the stencil iterator) + vector position_list; + //list containing the values for each position in the stencil + vector value_list; + + void refresh_iterators(); + void set_values(); + void increment_all(); + +public: + typename rtsDTGrid1D::stencil_iterator operator=(const iterator rhs); + void addPosition(int p); + void operator++(){p();} + void p(); + T getValue(int id){return value_list[id];} + bool exists(int id); + +}; + +template +void rtsDTGrid1D::stencil_iterator::increment_all() +{ + //run through each iterator and increment to the correct position + int i; + int dest; + for(i=0; i +void rtsDTGrid1D::stencil_iterator::p() +{ + //increment the current position + rtsDTGrid1D::iterator::p(); + + increment_all(); +} + +template +void rtsDTGrid1D::stencil_iterator::refresh_iterators() +{ + //make sure that the iterator position has been set + if(parent == NULL) + { + cout<<"Iterator location not set."<begin(); + } + increment_all(); + //set the values for all of the iterators + set_values(); +} + +template +void rtsDTGrid1D::stencil_iterator::set_values() +{ + int i; + int dest; + for(i=0; ibackground; + } + + +} + +template +typename rtsDTGrid1D::stencil_iterator rtsDTGrid1D::stencil_iterator::operator=(const iterator rhs) +{ + parent = rhs.parent; + iv = rhs.iv; + ic = rhs.ic; + x1 = rhs.x1; + + refresh_iterators(); + + return (*this); +} + +template +void rtsDTGrid1D::stencil_iterator::addPosition(int p) +{ + position_list.push_back(p); + rtsDTGrid1D::iterator new_iter; + /*If the parent variable is valid (the current iterator is assigned to + a grid), assign the position just added to the same grid. + If the parent isn't set, all iterators are assigned to the appropriate grid + later on when the operator= is used to assign the grid to the stencil. + */ + if(parent != NULL) + { + new_iter = parent->begin(); + refresh_iterators(); + } + + iterator_list.push_back(new_iter); + value_list.resize(value_list.size() + 1); +} + +template +bool rtsDTGrid1D::stencil_iterator::exists(int id) +{ + //returns true if the iterator defined by id points to an actual grid node + + //determine the appropriate position for the iterator + int dest = x1 + position_list[id]; + + if(iterator_list[id].X1() == dest) + return true; + else + return false; + +} + + +/**************ITERATOR METHODS IN DT GRID*******************/ +template +typename rtsDTGrid1D::iterator rtsDTGrid1D::begin() +{ + //if the grid is empty, return after() + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.ic = 0; + result.iv = 0; + result.x1 = conn[0].coordMin; + return result; +} +template +typename rtsDTGrid1D::iterator rtsDTGrid1D::before() +{ + //if the grid is empty, return after() + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.ic = 0; + result.iv = -1; + //result.x1 = conn[0].coordMin; + return result; +} + +template +typename rtsDTGrid1D::iterator rtsDTGrid1D::end() +{ + //if the grid is empty, return after() + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.ic = conn.size() - 1; + result.iv = value.size() - 1; + result.x1 = conn[result.ic].coordMax; + return result; +} +template +typename rtsDTGrid1D::iterator rtsDTGrid1D::after() +{ + iterator result; + result.parent = this; + result.ic = conn.size() - 1; + result.iv = value.size(); + //result.x1 = conn[result.ic].coordMax; + return result; +} + + + + +template +typename rtsDTGrid1D::iterator rtsDTGrid1D::randomIterator(int x1) +{ + //if the grid is empty return a "after" iterator + if(value.size() == 0) + return after(); + + rtsDTGrid1D::iterator result; + result.parent = this; + int v_i, c_i; + + //if the value exists in the grid, create the iterator and return + if(randomIndex(v_i, c_i, x1)) + { + result.iv = v_i; + result.ic = c_i; + int offset = v_i - conn[c_i].toValue; + result.x1 = conn[c_i].coordMin + offset; + } + //if the value doesn't exist + else + { + //if the value lies before the current column + if(x1 < conn[c_i].coordMin) + { + result.ic = c_i; + + } + else + { + //if this is the last connected component + if(c_i >= conn.size() - 1) + return after(); + else + { + c_i++; + result.ic = c_i; + } + } + result.iv = conn[c_i].toValue; + result.x1 = conn[c_i].coordMin; + } + return result; + +} +template +void rtsDTGrid1D::print() +{ + rtsDTGrid1D::iterator i; + i = begin(); + while(i != after()) + { + cout< +bool rtsDTGrid1D::push(int x1, T v) +{ + //test to make sure the insertion is happening in the right order + if(insertion_started && x1 <= max_coord) + { + cout<<"Out-of-order insertion in D = 1: X1 = "< (max_coord + 1)) + { + //start a new connected component + ConnectedComponent new_conn; + new_conn.toValue = value.size(); + new_conn.coordMin = x1; + new_conn.coordMax = x1; + conn.push_back(new_conn); + insertion_started = true; + } + + //insert the value into the grid: + //(a) Insert the value at the end of the coord array + //(b) Increment the coordMax value of the current connected component + //(c) Change the maximum inserted coordinate to the new value + value.push_back(v); + conn[conn.size() - 1].coordMax = x1; + //change max_coord to the new coordinate + max_coord = x1; + return true; +} + +template +void rtsDTGrid1D::insert(rtsDTGrid1D toInsert) +{ + //create source and destination iterators + rtsDTGrid1D::iterator source = toInsert.begin(); + rtsDTGrid1D::iterator dest = begin(); + + while(source != toInsert.after()) + { + //move the destination iterator to the current source position + dest.increment_until(source.X1()); + //if the position exists in dest + if(dest.X1() == source.X1()) + dest.SetValue(source.Value()); + source++; + } + +} + +template +void rtsDTGrid1D::getBounds(int &min_x1, int &max_x1) +{ + //return an empty bounding volume if the grid is empty + if(value.size() == 0) + { + min_x1 = 0; + max_x1 = 0; + return; + } + + //get the minimum and maximum coordinates + min_x1 = conn[0].coordMin; + max_x1 = conn.back().coordMax; +} +template +void rtsDTGrid1D::dilate(int H) +{ + //this function creates a new DT grid dilated by H and copies + //the original grid into the new grid + + //create a new grid + rtsDTGrid1D new_grid; + + //determine the dilated values for the first connected component + int numValues = 0; + int start = conn[0].coordMin - H; + int end = conn[0].coordMax + H; + + //run through each remaining connected component + for(int i=1; i +bool rtsDTGrid1D::randomIndex(int &v, int &c, int x1) +{ + //if the grid is empty return false + if(value.size() == 0) + return false; + + int low = 0; + int high = conn.size()-1; + int mid; + do + { + mid = low + (high - low)/2; + if(x1 > conn[mid].coordMax) + low = mid + 1; + //else if(x1 < conn[mid].coordMin) + else if(x1 < conn[mid].coordMin) + high = mid - 1; + else break; + } + while(low <= high); + + //at this point, mid is either at the appropriate connected component, + //or x1 is not in the grid + int offset = x1 - conn[mid].coordMin; + v = conn[mid].toValue + offset; + c = mid; + if(x1 >= conn[mid].coordMin && x1 <= conn[mid].coordMax) + { + return true; + } + else + { + return false; + } +} + +template +void rtsDTGrid1D::operator=(T rhs) +{ + for(int i=0; i +T& rtsDTGrid1D::back() +{ + return value[value.size()-1]; +} + +template +T rtsDTGrid1D::random(int x1) +{ + int v_i, c_i; + + if(randomIndex(v_i, c_i, x1)) + return value[v_i]; + else + return background; +} + + +#endif diff --git a/rtsDTGrid1D_v1.h b/rtsDTGrid1D_v1.h new file mode 100755 index 0000000..ab5b9bb --- /dev/null +++ b/rtsDTGrid1D_v1.h @@ -0,0 +1,594 @@ + +#include +#include +using namespace std; + +#ifndef _RTS_DTGRID1D_H +#define _RTS_DTGRID1D_H + +struct ConnectedComponent +{ + int toValue; + int coordMin; + int coordMax; +}; + + + + +template +class rtsDTGrid1D +{ + +private: + //main arrays + vector value; + vector conn; + + //variables to keep track of insertion + int max_coord; + bool insertion_started; + bool randomIndex(int &v, int &c, int x1); + + +public: + T background; + rtsDTGrid1D() + { + insertion_started = false; + max_coord = 0; + } + int getMaxX1(){return max_coord;} + + T random(int x1); + T& back(); + bool push(int x1, T value); + void insert(rtsDTGrid1D toInsert); + void getBounds(int &min_x1, int &max_x1); + void dilate(int H); + template rtsDTGrid1D

getStorage() + { + //create the resulting grid + rtsDTGrid1D

result; + //create an iterator to run over the existing grid + P* new_value = (P*)calloc(1, sizeof(P)); + for(iterator i = begin(); i!=end(); i.increment()) + { + result.push(i.X1(), *new_value); + } + return result; + + } + void operator=(T rhs); + void print(); + + //iterator + class iterator; + friend class iterator; + class stencil_iterator; + iterator randomIterator(int x1); + iterator begin(); + iterator end(); + iterator before(); + iterator after(); + +}; + +/***************ITERATOR*************************/ +template +class rtsDTGrid1D::iterator +{ + friend class rtsDTGrid1D; + + +protected: + rtsDTGrid1D* parent; + int iv; + int ic; + int x1; + +public: + T Value(){return parent->value[iv];} + int X1(){return x1;} + void SetValue(T val){parent->value[iv] = val;} + + iterator(){parent = NULL;} + + void increment() + { + //increment the current coordinate and value + x1++; + iv++; + //if we are outside of the current connected component + if(x1 > parent->conn[ic].coordMax) + { + //if this is the last connected component, set the iterator to END and return + if(ic == parent->conn.size() - 1) + { + (*this) = parent->after(); + return; + } + //otherwise move to the next connected component and update the coordinate + ic++; + x1 = parent->conn[ic].coordMin; + } + } + + //boolean operators for comparing iterators + bool operator==(iterator rhs) + { + if(parent == rhs.parent && iv == rhs.iv) + return true; + return false; + } + bool operator!=(iterator rhs){return !((*this) == rhs);} + friend bool operator<(iterator &left, iterator &right) + { + if(left.iv < right.iv) + return true; + return false; + } + friend bool operator<=(iterator &left, iterator &right) + { + if(left.iv <= right.iv) + return true; + return false; + } + void operator++(){increment();} + + void increment_until(int pos) + { + while(x1 < pos && (*this) != parent->after()) + { + p(); + } + } +}; + + +/************STENCIL ITERATOR********************/ +template +class rtsDTGrid1D::stencil_iterator : public iterator +{ +private: + //list of iterators that make up the template + vector iterator_list; + //iterator positions (relative to the position of the stencil iterator) + vector position_list; + //list containing the values for each position in the stencil + vector value_list; + + void refresh_iterators(); + void set_values(); + void increment_all(); + +public: + typename rtsDTGrid1D::stencil_iterator operator=(const iterator rhs); + void addPosition(int p); + void operator++(){p();} + void p(); + T getValue(int id){return value_list[id];} + bool exists(int id); + +}; + +template +void rtsDTGrid1D::stencil_iterator::increment_all() +{ + //run through each iterator and increment to the correct position + int i; + int dest; + for(i=0; i +void rtsDTGrid1D::stencil_iterator::increment() +{ + //increment the current position + rtsDTGrid1D::iterator::increment(); + + increment_all(); +} + +template +void rtsDTGrid1D::stencil_iterator::refresh_iterators() +{ + //make sure that the iterator position has been set + if(parent == NULL) + { + cout<<"Iterator location not set."<begin(); + } + increment_all(); + //set the values for all of the iterators + set_values(); +} + +template +void rtsDTGrid1D::stencil_iterator::set_values() +{ + int i; + int dest; + for(i=0; ibackground; + } + + +} + +template +typename rtsDTGrid1D::stencil_iterator rtsDTGrid1D::stencil_iterator::operator=(const iterator rhs) +{ + parent = rhs.parent; + iv = rhs.iv; + ic = rhs.ic; + x1 = rhs.x1; + + refresh_iterators(); + + return (*this); +} + +template +void rtsDTGrid1D::stencil_iterator::addPosition(int p) +{ + position_list.push_back(p); + rtsDTGrid1D::iterator new_iter; + /*If the parent variable is valid (the current iterator is assigned to + a grid), assign the position just added to the same grid. + If the parent isn't set, all iterators are assigned to the appropriate grid + later on when the operator= is used to assign the grid to the stencil. + */ + if(parent != NULL) + { + new_iter = parent->begin(); + refresh_iterators(); + } + + iterator_list.push_back(new_iter); + value_list.resize(value_list.size() + 1); +} + +template +bool rtsDTGrid1D::stencil_iterator::exists(int id) +{ + //returns true if the iterator defined by id points to an actual grid node + + //determine the appropriate position for the iterator + int dest = x1 + position_list[id]; + + if(iterator_list[id].X1() == dest) + return true; + else + return false; + +} + + +/**************ITERATOR METHODS IN DT GRID*******************/ +template +typename rtsDTGrid1D::iterator rtsDTGrid1D::begin() +{ + //if the grid is empty, return after() + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.ic = 0; + result.iv = 0; + result.x1 = conn[0].coordMin; + return result; +} +template +typename rtsDTGrid1D::iterator rtsDTGrid1D::before() +{ + //if the grid is empty, return after() + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.ic = 0; + result.iv = -1; + //result.x1 = conn[0].coordMin; + return result; +} + +template +typename rtsDTGrid1D::iterator rtsDTGrid1D::end() +{ + //if the grid is empty, return after() + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.ic = conn.size() - 1; + result.iv = value.size() - 1; + result.x1 = conn[result.ic].coordMax; + return result; +} +template +typename rtsDTGrid1D::iterator rtsDTGrid1D::after() +{ + iterator result; + result.parent = this; + result.ic = conn.size() - 1; + result.iv = value.size(); + //result.x1 = conn[result.ic].coordMax; + return result; +} + + + + +template +typename rtsDTGrid1D::iterator rtsDTGrid1D::randomIterator(int x1) +{ + //if the grid is empty return a "after" iterator + if(value.size() == 0) + return after(); + + rtsDTGrid1D::iterator result; + result.parent = this; + int v_i, c_i; + + //if the value exists in the grid, create the iterator and return + if(randomIndex(v_i, c_i, x1)) + { + result.iv = v_i; + result.ic = c_i; + int offset = v_i - conn[c_i].toValue; + result.x1 = conn[c_i].coordMin + offset; + } + //if the value doesn't exist + else + { + //if the value lies before the current column + if(x1 < conn[c_i].coordMin) + { + result.ic = c_i; + + } + else + { + //if this is the last connected component + if(c_i >= conn.size() - 1) + return after(); + else + { + c_i++; + result.ic = c_i; + } + } + result.iv = conn[c_i].toValue; + result.x1 = conn[c_i].coordMin; + } + return result; + +} +template +void rtsDTGrid1D::print() +{ + rtsDTGrid1D::iterator i; + i = begin(); + while(i != after()) + { + cout< +bool rtsDTGrid1D::push(int x1, T v) +{ + //test to make sure the insertion is happening in the right order + if(insertion_started && x1 <= max_coord) + { + cout<<"Out-of-order insertion in D = 1: X1 = "< (max_coord + 1)) + { + //start a new connected component + ConnectedComponent new_conn; + new_conn.toValue = value.size(); + new_conn.coordMin = x1; + new_conn.coordMax = x1; + conn.push_back(new_conn); + insertion_started = true; + } + + //insert the value into the grid: + //(a) Insert the value at the end of the coord array + //(b) Increment the coordMax value of the current connected component + //(c) Change the maximum inserted coordinate to the new value + value.push_back(v); + conn[conn.size() - 1].coordMax = x1; + //change max_coord to the new coordinate + max_coord = x1; + return true; +} + +template +void rtsDTGrid1D::insert(rtsDTGrid1D toInsert) +{ + //create source and destination iterators + rtsDTGrid1D::iterator source = toInsert.begin(); + rtsDTGrid1D::iterator dest = begin(); + + while(source != toInsert.after()) + { + //move the destination iterator to the current source position + dest.increment_until(source.X1()); + //if the position exists in dest + if(dest.X1() == source.X1()) + dest.SetValue(source.Value()); + source++; + } + +} + +template +void rtsDTGrid1D::getBounds(int &min_x1, int &max_x1) +{ + //return an empty bounding volume if the grid is empty + if(value.size() == 0) + { + min_x1 = 0; + max_x1 = 0; + return; + } + + //get the minimum and maximum coordinates + min_x1 = conn[0].coordMin; + max_x1 = conn.back().coordMax; +} +template +void rtsDTGrid1D::dilate(int H) +{ + //this function creates a new DT grid dilated by H and copies + //the original grid into the new grid + + //create a new grid + rtsDTGrid1D new_grid; + + //determine the dilated values for the first connected component + int numValues = 0; + int start = conn[0].coordMin - H; + int end = conn[0].coordMax + H; + + //run through each remaining connected component + for(int i=1; i +bool rtsDTGrid1D::randomIndex(int &v, int &c, int x1) +{ + //if the grid is empty return false + if(value.size() == 0) + return false; + + int low = 0; + int high = conn.size()-1; + int mid; + do + { + mid = low + (high - low)/2; + if(x1 > conn[mid].coordMax) + low = mid + 1; + //else if(x1 < conn[mid].coordMin) + else if(x1 < conn[mid].coordMin) + high = mid - 1; + else break; + } + while(low <= high); + + //at this point, mid is either at the appropriate connected component, + //or x1 is not in the grid + int offset = x1 - conn[mid].coordMin; + v = conn[mid].toValue + offset; + c = mid; + if(x1 >= conn[mid].coordMin && x1 <= conn[mid].coordMax) + { + return true; + } + else + { + return false; + } +} + +template +void rtsDTGrid1D::operator=(T rhs) +{ + for(int i=0; i +T& rtsDTGrid1D::back() +{ + return value[value.size()-1]; +} + +template +T rtsDTGrid1D::random(int x1) +{ + int v_i, c_i; + + if(randomIndex(v_i, c_i, x1)) + return value[v_i]; + else + return background; +} + + +#endif diff --git a/rtsDTGrid2D.h b/rtsDTGrid2D.h new file mode 100755 index 0000000..568f6fc --- /dev/null +++ b/rtsDTGrid2D.h @@ -0,0 +1,1072 @@ + +#ifndef _RTS_DTGRID2D_H +#define _RTS_DTGRID2D_H + +#include +#include +using namespace std; + +#include "rtsDTGrid1D.h" + + + +struct IndexPair +{ + //int toValue; + int toConn; + int numConn; +}; + + +struct Coord2D +{ + int x1; + int x2; +}; + +#include +using namespace std; + +class ColumnUnion +{ +private: + list Q; + vector* toConn; + +public: + void InsertColumn(IndexPair col) + { + Q.push_back(col); + } + void RemoveColumn() + { + Q.pop_front(); + } + vector MergeColumns(vector *Pc, + vector *n, + int H) + { + int i_Pc = 0; + int i_n = 0; + int smallest_column; + ConnectedComponent smallest_cc; + vector result; + + //iterate while there are remaining connected components in each column + while(i_Pc < Pc->size() || i_n < n->size()) + { + //find the smallest coordMin value at the two index locations + + //if the index is at the end of the primary array + if(i_Pc == Pc->size()) + { + smallest_cc = n->at(i_n); + smallest_cc.coordMin -= H; + smallest_cc.coordMax += H; + i_n++; + } + //if n is at the end of the array + else if(i_n == n->size()) + { + smallest_cc = Pc->at(i_Pc); + i_Pc++; + } + else if(n->at(i_n).coordMin - H < Pc->at(i_Pc).coordMin) + { + smallest_cc = n->at(i_n); + smallest_cc.coordMin -= H; + smallest_cc.coordMax += H; + i_n++; + } + else + { + smallest_cc = Pc->at(i_Pc); + i_Pc++; + } + + //merge the connected component into result + //if the result array is empty or the last connected component doesn't overlap with smallest_cc + if(result.size() == 0 || result.back().coordMax + 1 < smallest_cc.coordMin) + result.push_back(smallest_cc); + else if(result.back().coordMax < smallest_cc.coordMax) + result.back().coordMax = smallest_cc.coordMax; + } + return result; + + } + + vector ComputeUnion(int H) + { + //create a vector to store the result + vector result; + + //for each column in the list, merge it with the result vector + list::iterator i; + vector::iterator start; + vector::iterator end; + for(i = Q.begin(); i != Q.end(); i++) + { + start = toConn->begin() + (*i).toConn; + end = start + (*i).numConn; + vector column(start, end); + result = MergeColumns(&result, &column, H); + } + + //output result + //for(int i=0; i *cc_list) + { + toConn = cc_list; + } +}; + + +/*vector ColumnUnion::MergeColumns(vector *Pc, vector *n, int H) +{ + int i_Pc = 0; + int i_n = 0; + int smallest_column; + ConnectedComponent smallest_cc; + vector result; + + //iterate while there are remaining connected components in each column + while(i_Pc < Pc->size() || i_n < n->size()) + { + //find the smallest coordMin value at the two index locations + + //if the index is at the end of the primary array + if(i_Pc == Pc->size()) + { + smallest_cc = n->at(i_n); + smallest_cc.coordMin -= H; + smallest_cc.coordMax += H; + i_n++; + } + //if n is at the end of the array + else if(i_n == n->size()) + { + smallest_cc = Pc->at(i_Pc); + i_Pc++; + } + else if(n->at(i_n).coordMin - H < Pc->at(i_Pc).coordMin) + { + smallest_cc = n->at(i_n); + smallest_cc.coordMin -= H; + smallest_cc.coordMax += H; + i_n++; + } + else + { + smallest_cc = Pc->at(i_Pc); + i_Pc++; + } + + //merge the connected component into result + //if the result array is empty or the last connected component doesn't overlap with smallest_cc + if(result.size() == 0 || result.back().coordMax + 1 < smallest_cc.coordMin) + result.push_back(smallest_cc); + else if(result.back().coordMax < smallest_cc.coordMax) + result.back().coordMax = smallest_cc.coordMax; + } + return result; +}*/ + +/*vector ColumnUnion::ComputeUnion(int H) +{ + + //create a vector to store the result + vector result; + + //for each column in the list, merge it with the result vector + list::iterator i; + vector::iterator start; + vector::iterator end; + for(i = Q.begin(); i != Q.end(); i++) + { + start = toConn->begin() + (*i).toConn; + end = start + (*i).numConn; + vector column(start, end); + result = MergeColumns(&result, &column, H); + } + + //output result + //for(int i=0; i +class rtsDTGrid2D +{ +private: + //main arrays + vector value; + vector conn; + rtsDTGrid1D proj1D; + bool randomIndex(rtsDTGrid1D::iterator &iter1D, int &v_i, int &c_i, int x1, int x2); + + + + //variables to keep track of insertion + int max_coord; + bool grid_insertion_started; + bool column_insertion_started; + + +public: + rtsDTGrid2D() + { + grid_insertion_started = false; + column_insertion_started = false; + proj1D.background.toConn = -1; + max_coord = 0; + } + + bool push(int x1, int x2, T v); + T random(int x1, int x2); + T& back(); + T background; + void print(); + + friend class ColumnUnion; + void dilate(int H); + void insert(rtsDTGrid2D toInsert); + void operator=(T rhs); + void getBounds(int &min_x1, int &min_x2, int &max_x1, int &max_x2); + + void dumpValue(); + void dumpConn(); + + //iterator + class iterator; + friend class iterator; + class stencil_iterator; + iterator randomIterator(int x1, int x2); + iterator begin(); + iterator before(); + iterator end(); + iterator after(); + + //other types of iteration + iterator begin_pn(); + iterator end_pn(); + iterator begin_np(); + iterator end_np(); +}; + +/**********ITERATOR***********************/ +template +class rtsDTGrid2D::iterator +{ + friend class rtsDTGrid2D; + rtsDTGrid2D* parent; + rtsDTGrid1D::iterator loc1D; + int iv; + int ic; + int x2; + +public: + + + T Value(){return parent->value[iv];} + int X1(){return loc1D.X1();} + int X2(){return x2;} + iterator(){parent = NULL;} + void SetValue(T value){parent->value[iv] = value;} + + + void pp() + { + //increment the value + iv++; + //if this exceeds the length of the value array, we are at the end of the grid + if(iv == parent->value.size()) + { + (*this) = parent->after(); + return; + } + + //increment the current coordinate + x2++; + //if we are outside of the current connected component + if(x2 > parent->conn[ic].coordMax) + { + //move to the next connected component + ic++; + //if this is the last connected component in the column + if(ic == loc1D.Value().toConn + loc1D.Value().numConn) + loc1D++; + //if there are no more connected components + if(ic == parent->conn.size()) + { + //we're at the end, return end + (*this) = parent->end(); + return; + } + x2 = parent->conn[ic].coordMin; + } + } + + void nn() + { + //decrement the value + iv--; + //if this is less than 0, we are at the beginning of the grid + if(iv < 0) + { + (*this) = parent->before(); + return; + } + + //decrement the current coordinate + x2--; + //if we are outside of the current connected component + if(x2 < parent->conn[ic].coordMin) + { + //move to the previous connected component + ic--; + //if this is the first connected component in the column + if(ic < loc1D.Value().toConn) + loc1D--; + //if there are no more connected components + if(ic < 0) + { + //we're at the beginning, return begin + (*this) = parent->before(); + return; + } + x2 = parent->conn[ic].coordMax; + } + + } + + void pn() + { + //for the most part we will be going backwards through the array + //so first decrement iv + iv--; + x2--; + //if iv is less than the current connected component + if(iv < parent->conn[ic].toValue) + { + //go to the previous connected component + ic--; + //if we are before the first connected component in the column + if(ic < loc1D.Value().toConn) + { + //increment the 1D iterator + loc1D++; + //reset ic to the last component of the new column + ic = loc1D.Value().toConn + loc1D.Value().numConn - 1; + //find the new value identifier + iv = parent->conn[ic].toValue + (parent->conn[ic].coordMax - parent->conn[ic].coordMin); + } + //compute the currect coordinate + x2 = parent->conn[ic].coordMax; + } + } + + void np() + { + //for the most part we will be going forward through the grid + //increment iv + iv++; + x2++; + + //if we are outside of the current connected component + if(x2 > parent->conn[ic].coordMax) + { + //move to the next connected component + ic++; + //if this is the last connected component in the column + if(ic == loc1D.Value().toConn + loc1D.Value().numConn) + { + loc1D--; + ic = loc1D.Value().toConn; + iv = parent->conn[ic].toValue; + } + + x2 = parent->conn[ic].coordMin; + } + + } + + //boolean operators for comparing iterators + bool operator==(iterator &rhs) + { + if(parent == rhs.parent && iv == rhs.iv) + return true; + //if(loc1D == rhs.loc1D && x2 == rhs.x2) + // return true; + return false; + } + bool operator!=(iterator &rhs){return !((*this) == rhs);} + + bool operator<(iterator &rhs) + { + if(parent == rhs.parent && iv < rhs.iv) + return true; + //if(loc1D < rhs.loc1D) + // return true; + //else if(loc1D == rhs.loc1D && x2 < rhs.x2) + // return true; + return false; + } + bool operator<=(iterator &rhs) + { + if(parent == rhs.parent && iv <= rhs.iv) + return true; + //if(loc1D <= rhs.loc1D) + // return true; + //else if(loc1D == rhs.loc1D && x2 <= rhs.x2) + // return true; + return false; + } + void operator++(){pp();} + void operator--(){nn();} + void increment_until(int p1, int p2) + { + while((*this) != parent->end()) + { + if(X1() > p1) + return; + else if(X1() == p1 && X2() >= p2) + return; + + pp(); + } + } +}; + +/********STENCIL ITERATOR*****************/ +template +class rtsDTGrid2D::stencil_iterator : public iterator +{ +private: + //list of iterators that make up the template + vector iterator_list; + //iterator positions (relative to the position of the stencil iterator) + vector position_list; + //list containing the values for each position in the stencil + vector value_list; + + void refresh_iterators(); + void set_values(); + void increment_all(); + +public: + typename rtsDTGrid2D::stencil_iterator operator=(const iterator rhs); + void addPosition(int p1, int p2); + void increment(); + void operator++() + { + increment(); + } + T getValue(int id){return value_list[id];} + bool exists(int id); + +}; + +template +void rtsDTGrid2D::stencil_iterator::increment_all() +{ + //run through each iterator and increment to the correct position + int i; + Coord2D dest; + for(i=0; i +void rtsDTGrid2D::stencil_iterator::increment() +{ + //increment the current position + rtsDTGrid2D::iterator::pp(); + + increment_all(); +} + +template +void rtsDTGrid2D::stencil_iterator::refresh_iterators() +{ + //make sure that the iterator position has been set + if(parent == NULL) + { + cout<<"Iterator location not set."<begin(); + iterator_list[i] = parent->randomIterator(X1() + position_list[i].x1, + X2() + position_list[i].x2); + } + //increment_all(); + //set the values for all of the iterators + set_values(); +} + +template +void rtsDTGrid2D::stencil_iterator::set_values() +{ + int i; + Coord2D dest; + for(i=0; ibackground; + } + + +} + +template +typename rtsDTGrid2D::stencil_iterator rtsDTGrid2D::stencil_iterator::operator=(const iterator rhs) +{ + parent = rhs.parent; + loc1D = rhs.loc1D; + iv = rhs.iv; + ic = rhs.ic; + x2 = rhs.x2; + + refresh_iterators(); + + return (*this); +} + +template +void rtsDTGrid2D::stencil_iterator::addPosition(int p1, int p2) +{ + //add a position to the position list and add a new iterator to the iterator list + Coord2D p; + p.x1 = p1; + p.x2 = p2; + position_list.push_back(p); + rtsDTGrid2D::iterator new_iter; + + + iterator_list.push_back(new_iter); + T empty; + value_list.push_back(empty); +} + +template +bool rtsDTGrid2D::stencil_iterator::exists(int id) +{ + int i; + Coord2D dest; + + //determine the appropriate position for the iterator + dest.x1 = X1() + position_list[id].x1; + dest.x2 = X2() + position_list[id].x2; + //now add the value to the value list + if(iterator_list[id].X1() == dest.x1 && iterator_list[id].X2() == dest.x2) + return true; + else + return false; + +} + +/**************ITERATOR METHODS IN DT GRID*******************/ +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::begin() +{ + //if the grid is empty, return an iterator to "after" + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.ic = 0; + result.iv = 0; + result.x2 = conn[0].coordMin; + result.loc1D = proj1D.begin(); + + return result; +} +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::before() +{ + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.ic = 0; + result.iv = -1; + //result.x2 = conn[0].coordMin; + result.loc1D = proj1D.before(); + + return result; +} + +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::end() +{ + //if the grid is empty, return after() + if(value.size() == 0) + return after(); + iterator result; + result.parent = this; + result.ic = conn.size() - 1; + result.iv = value.size() - 1; + result.x2 = conn[result.ic].coordMax; + result.loc1D = proj1D.end(); + return result; +} + +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::randomIterator(int x1, int x2) +{ + rtsDTGrid2D::iterator result; + result.parent = this; + + //perform the random search + int v_i, c_i; + rtsDTGrid1D::iterator iter1D; + + //if the value exists in the grid, create the iterator and return + if(randomIndex(iter1D, v_i, c_i, x1, x2)) + { + result.loc1D = iter1D; + result.iv = v_i; + result.ic = c_i; + int offset = v_i - conn[c_i].toValue; + result.x2 = conn[c_i].coordMin + offset; + } + //if the value doesn't exist + else + { + //if the 1D iterator is at the end of the grid, return after() + if(iter1D == proj1D.after()) + return after(); + + //if the value lies before the current column + if(x1 < iter1D.X1() || (x1 == iter1D.X1() && x2 < conn[c_i].coordMin) ) + { + result.ic = c_i; + } + //else if the value lies after the current column + else + { + //increment the 1D iterator + iter1D++; + //if this is the last connected component + if(c_i >= conn.size() - 1) + return after(); + else + { + c_i++; + result.ic = c_i; + } + } + + + result.loc1D = iter1D; + result.iv = conn[c_i].toValue; + result.x2 = conn[c_i].coordMin; + } + return result; + + +} +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::after() +{ + iterator result; + result.parent = this; + result.ic = conn.size() - 1; + result.iv = value.size(); + //result.x2 = conn[result.ic].coordMax; + result.loc1D = proj1D.after(); + return result; +} +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::begin_pn() +{ + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.loc1D = proj1D.begin(); + result.ic = result.loc1D.Value().toConn + result.loc1D.Value().numConn - 1; + result.iv = conn[result.ic].toValue + (conn[result.ic].coordMax - conn[result.ic].coordMin); + result.x2 = conn[result.ic].coordMax; + + return result; +} +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::begin_np() +{ + //this is the opposite corner of pn + return end_pn(); +} +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::end_pn() +{ + if(value.size() == 0) + return after(); + iterator result; + result.parent = this; + result.loc1D = proj1D.end(); + result.ic = result.loc1D.Value().toConn; + result.iv = conn[result.ic].toValue; + result.x2 = conn[result.ic].coordMin; + + return result; +} +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::end_np() +{ + //this is the opposite corner of pn + return begin_pn(); +} + +template +void rtsDTGrid2D::print() +{ + rtsDTGrid2D::iterator i; + i = begin(); + while(i!=end()) + { + cout< +bool rtsDTGrid2D::push(int x1, int x2, T v) +{ + //run this code if we have to start a new column in X1. This happens when: + //(a) we have just inserted the first value into the grid + //(b) the value of x1 is greater than the last value of x1 + if(grid_insertion_started == false || x1 != proj1D.getMaxX1()) + { + //assume that a new column is being created + //create the column in proj1D + IndexPair newPair; + newPair.toConn = conn.size(); + //newPair.toValue = value.size(); + newPair.numConn = 0; + + //if this insertion throws an error, the value was inserted incorrectly + //the error will get thrown by DTGrid1D, so just return + if(!proj1D.push(x1, newPair)) + { + cout<<"Out-of-order insertion in D = 2: X1 = "< result = CUqueue.ComputeUnion(H); + + //compute the new IndexPair representing the column + new_pair.toConn = new_grid.conn.size(); + new_pair.numConn = result.size(); + //store the index pair + iteratorNew.SetValue(new_pair); + + //insert each of the connected components + for(ccIterator = result.begin(); ccIterator!=result.end(); ccIterator++) + { + new_grid.conn.push_back(*ccIterator); + new_grid.conn.back().toValue = numValues; + numValues += (*ccIterator).coordMax - (*ccIterator).coordMin + 1; + } + + //if a column is leaving the stencil + if(iteratorDilate.getValue(0).numConn) + CUqueue.RemoveColumn(); + } + + //allocate space for the new value array + new_grid.value.resize(numValues, background); + + //copy the data from this grid into the new grid + new_grid.insert(*this); + + //replace this grid with the new grid + conn = new_grid.conn; + value = new_grid.value; + proj1D = new_grid.proj1D; + + +} + +template +void rtsDTGrid2D::insert(rtsDTGrid2D toInsert) +{ + //create source and destination iterators + rtsDTGrid2D::iterator source = toInsert.begin(); + rtsDTGrid2D::iterator dest = begin(); + + for(source = toInsert.begin(); source != toInsert.after(); source++) + { + //move the destination iterator to the current source position + dest.increment_until(source.X1(), source.X2()); + //cout<<"source: "< +void rtsDTGrid2D::getBounds(int &min_x1, int &min_x2, int &max_x1, int &max_x2) +{ + //if the grid is empty, return an empty bounding volume + if(value.size() == 0) + { + min_x1 = min_x2 = max_x1 = max_x2 = 0; + return; + } + + //get the min and max values for the 1D grid (x1 coordinate) + proj1D.getBounds(min_x1, max_x1); + + //initialize the min and max values + min_x2 = conn[0].coordMin; + max_x2 = conn.back().coordMax; + + //iterate through all columns finding the smallest and largest coordinate values + rtsDTGrid1D::iterator i; + IndexPair col; + for(i=proj1D.begin(); i!=proj1D.after(); i++) + { + col = i.Value(); + if(conn[col.toConn].coordMin < min_x2) + min_x2 = conn[col.toConn].coordMin; + if(conn[col.toConn + col.numConn - 1].coordMax > max_x2) + max_x2 = conn[col.toConn + col.numConn - 1].coordMax; + } + + +} +template +void rtsDTGrid2D::operator =(T rhs) +{ + for(int i=0; i +void rtsDTGrid2D::dumpValue() +{ + for(int i=0; i +void rtsDTGrid2D::dumpConn() +{ + for(int i=0; i +#include +using namespace std; + +#include "rtsDTGrid1D.h" + +#ifndef _RTS_DTGRID2D_H +#define _RTS_DTGRID2D_H + +struct IndexPair +{ + //int toValue; + int toConn; + int numConn; +}; + +#include "ColumnUnion.h" + +struct Coord2D +{ + int x1; + int x2; +}; + + + +template +class rtsDTGrid2D +{ +private: + //main arrays + vector value; + vector conn; + rtsDTGrid1D proj1D; + bool randomIndex(rtsDTGrid1D::iterator &iter1D, int &v_i, int &c_i, int x1, int x2); + + + + //variables to keep track of insertion + int max_coord; + bool grid_insertion_started; + bool column_insertion_started; + + +public: + rtsDTGrid2D() + { + grid_insertion_started = false; + column_insertion_started = false; + proj1D.background.toConn = -1; + max_coord = 0; + } + + bool push(int x1, int x2, T v); + T random(int x1, int x2); + T& back(); + T background; + void print(); + + friend class ColumnUnion; + void dilate(int H); + void insert(rtsDTGrid2D toInsert); + void operator=(T rhs); + void getBounds(int &min_x1, int &min_x2, int &max_x1, int &max_x2); + + void dumpValue(); + void dumpConn(); + + //iterator + class iterator; + friend class iterator; + class stencil_iterator; + iterator randomIterator(int x1, int x2); + iterator begin(); + iterator before(); + iterator end(); + iterator after(); +}; + +/**********ITERATOR***********************/ +template +class rtsDTGrid2D::iterator +{ + friend class rtsDTGrid2D; + rtsDTGrid2D* parent; + rtsDTGrid1D::iterator loc1D; + int iv; + int ic; + int x2; + +public: + + + T Value(){return parent->value[iv];} + int X1(){return loc1D.X1();} + int X2(){return x2;} + iterator(){parent = NULL;} + void SetValue(T value){parent->value[iv] = value;} + + + void increment() + { + //increment the value + iv++; + //if this exceeds the length of the value array, we are at the end of the grid + if(iv == parent->value.size()) + { + (*this) = parent->after(); + return; + } + + //increment the current coordinate + x2++; + //if we are outside of the current connected component + if(x2 > parent->conn[ic].coordMax) + { + //move to the next connected component + ic++; + //if this is the last connected component in the column + if(ic == loc1D.Value().toConn + loc1D.Value().numConn) + loc1D++; + //if there are no more connected components + if(ic == parent->conn.size()) + { + //we're at the end, return end + (*this) = parent->end(); + return; + } + x2 = parent->conn[ic].coordMin; + } + } + + + //boolean operators for comparing iterators + bool operator==(iterator rhs) + { + if(parent == rhs.parent && iv == rhs.iv) + return true; + return false; + } + bool operator!=(iterator rhs){return !((*this) == rhs);} + + friend bool operator<(iterator &left, iterator &right) + { + if(left.iv < right.iv) + return true; + return false; + } + friend bool operator<=(iterator &left, iterator &right) + { + if(left.iv <= right.iv) + return true; + return false; + } + void operator++(){increment();} + void increment_until(int p1, int p2) + { + while((*this) != parent->end()) + { + if(X1() > p1) + return; + else if(X1() == p1 && X2() >= p2) + return; + + increment(); + } + } +}; + +/********STENCIL ITERATOR*****************/ +template +class rtsDTGrid2D::stencil_iterator : public iterator +{ +private: + //list of iterators that make up the template + vector iterator_list; + //iterator positions (relative to the position of the stencil iterator) + vector position_list; + //list containing the values for each position in the stencil + vector value_list; + + void refresh_iterators(); + void set_values(); + void increment_all(); + +public: + typename rtsDTGrid2D::stencil_iterator operator=(const iterator rhs); + void addPosition(int p1, int p2); + void increment(); + void operator++() + { + increment(); + } + T getValue(int id){return value_list[id];} + bool exists(int id); + +}; + +template +void rtsDTGrid2D::stencil_iterator::increment_all() +{ + //run through each iterator and increment to the correct position + int i; + Coord2D dest; + for(i=0; i +void rtsDTGrid2D::stencil_iterator::increment() +{ + //increment the current position + rtsDTGrid2D::iterator::increment(); + + increment_all(); +} + +template +void rtsDTGrid2D::stencil_iterator::refresh_iterators() +{ + //make sure that the iterator position has been set + if(parent == NULL) + { + cout<<"Iterator location not set."<begin(); + iterator_list[i] = parent->randomIterator(X1() + position_list[i].x1, + X2() + position_list[i].x2); + } + //increment_all(); + //set the values for all of the iterators + set_values(); +} + +template +void rtsDTGrid2D::stencil_iterator::set_values() +{ + int i; + Coord2D dest; + for(i=0; ibackground; + } + + +} + +template +typename rtsDTGrid2D::stencil_iterator rtsDTGrid2D::stencil_iterator::operator=(const iterator rhs) +{ + parent = rhs.parent; + loc1D = rhs.loc1D; + iv = rhs.iv; + ic = rhs.ic; + x2 = rhs.x2; + + refresh_iterators(); + + return (*this); +} + +template +void rtsDTGrid2D::stencil_iterator::addPosition(int p1, int p2) +{ + //add a position to the position list and add a new iterator to the iterator list + Coord2D p; + p.x1 = p1; + p.x2 = p2; + position_list.push_back(p); + rtsDTGrid2D::iterator new_iter; + + + iterator_list.push_back(new_iter); + T empty; + value_list.push_back(empty); +} + +template +bool rtsDTGrid2D::stencil_iterator::exists(int id) +{ + int i; + Coord2D dest; + + //determine the appropriate position for the iterator + dest.x1 = X1() + position_list[id].x1; + dest.x2 = X2() + position_list[id].x2; + //now add the value to the value list + if(iterator_list[id].X1() == dest.x1 && iterator_list[id].X2() == dest.x2) + return true; + else + return false; + +} + +/**************ITERATOR METHODS IN DT GRID*******************/ +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::begin() +{ + //if the grid is empty, return an iterator to "after" + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.ic = 0; + result.iv = 0; + result.x2 = conn[0].coordMin; + result.loc1D = proj1D.begin(); + + return result; +} +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::before() +{ + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.ic = 0; + result.iv = -1; + //result.x2 = conn[0].coordMin; + result.loc1D = proj1D.before(); + + return result; +} + +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::end() +{ + //if the grid is empty, return after() + if(value.size() == 0) + return after(); + iterator result; + result.parent = this; + result.ic = conn.size() - 1; + result.iv = value.size() - 1; + result.x2 = conn[result.ic].coordMax; + result.loc1D = proj1D.end(); + return result; +} + +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::randomIterator(int x1, int x2) +{ + rtsDTGrid2D::iterator result; + result.parent = this; + + //perform the random search + int v_i, c_i; + rtsDTGrid1D::iterator iter1D; + + //if the value exists in the grid, create the iterator and return + if(randomIndex(iter1D, v_i, c_i, x1, x2)) + { + result.loc1D = iter1D; + result.iv = v_i; + result.ic = c_i; + int offset = v_i - conn[c_i].toValue; + result.x2 = conn[c_i].coordMin + offset; + } + //if the value doesn't exist + else + { + //if the 1D iterator is at the end of the grid, return after() + if(iter1D == proj1D.after()) + return after(); + + //if the value lies before the current column + if(x1 < iter1D.X1() || (x1 == iter1D.X1() && x2 < conn[c_i].coordMin) ) + { + result.ic = c_i; + } + //else if the value lies after the current column + else + { + //increment the 1D iterator + iter1D++; + //if this is the last connected component + if(c_i >= conn.size() - 1) + return after(); + else + { + c_i++; + result.ic = c_i; + } + } + + + result.loc1D = iter1D; + result.iv = conn[c_i].toValue; + result.x2 = conn[c_i].coordMin; + } + return result; + + +} +template +typename rtsDTGrid2D::iterator rtsDTGrid2D::after() +{ + iterator result; + result.parent = this; + result.ic = conn.size() - 1; + result.iv = value.size(); + //result.x2 = conn[result.ic].coordMax; + result.loc1D = proj1D.after(); + return result; +} + +/**************DT GRID**************************/ +template +bool rtsDTGrid2D::push(int x1, int x2, T v) +{ + //run this code if we have to start a new column in X1. This happens when: + //(a) we have just inserted the first value into the grid + //(b) the value of x1 is greater than the last value of x1 + if(grid_insertion_started == false || x1 != proj1D.getMaxX1()) + { + //assume that a new column is being created + //create the column in proj1D + IndexPair newPair; + newPair.toConn = conn.size(); + //newPair.toValue = value.size(); + newPair.numConn = 0; + + //if this insertion throws an error, the value was inserted incorrectly + //the error will get thrown by DTGrid1D, so just return + if(!proj1D.push(x1, newPair)) + { + cout<<"Out-of-order insertion in D = 2: X1 = "< result = CUqueue.ComputeUnion(H); + + //compute the new IndexPair representing the column + new_pair.toConn = new_grid.conn.size(); + new_pair.numConn = result.size(); + //store the index pair + iteratorNew.SetValue(new_pair); + + //insert each of the connected components + for(ccIterator = result.begin(); ccIterator!=result.end(); ccIterator++) + { + new_grid.conn.push_back(*ccIterator); + new_grid.conn.back().toValue = numValues; + numValues += (*ccIterator).coordMax - (*ccIterator).coordMin + 1; + } + + //if a column is leaving the stencil + if(iteratorDilate.getValue(0).numConn) + CUqueue.RemoveColumn(); + } + + //allocate space for the new value array + new_grid.value.resize(numValues, background); + + //copy the data from this grid into the new grid + new_grid.insert(*this); + + //replace this grid with the new grid + conn = new_grid.conn; + value = new_grid.value; + proj1D = new_grid.proj1D; + + +} + +template +void rtsDTGrid2D::insert(rtsDTGrid2D toInsert) +{ + //create source and destination iterators + rtsDTGrid2D::iterator source = toInsert.begin(); + rtsDTGrid2D::iterator dest = begin(); + + for(source = toInsert.begin(); source != toInsert.after(); source++) + { + //move the destination iterator to the current source position + dest.increment_until(source.X1(), source.X2()); + //cout<<"source: "< +void rtsDTGrid2D::getBounds(int &min_x1, int &min_x2, int &max_x1, int &max_x2) +{ + //if the grid is empty, return an empty bounding volume + if(value.size() == 0) + { + min_x1 = min_x2 = max_x1 = max_x2 = 0; + return; + } + + //get the min and max values for the 1D grid (x1 coordinate) + proj1D.getBounds(min_x1, max_x1); + + //initialize the min and max values + min_x2 = conn[0].coordMin; + max_x2 = conn.back().coordMax; + + //iterate through all columns finding the smallest and largest coordinate values + rtsDTGrid1D::iterator i; + IndexPair col; + for(i=proj1D.begin(); i!=proj1D.after(); i++) + { + col = i.Value(); + if(conn[col.toConn].coordMin < min_x2) + min_x2 = conn[col.toConn].coordMin; + if(conn[col.toConn + col.numConn - 1].coordMax > max_x2) + max_x2 = conn[col.toConn + col.numConn - 1].coordMax; + } + + +} +template +void rtsDTGrid2D::operator =(T rhs) +{ + for(int i=0; i +void rtsDTGrid2D::dumpValue() +{ + for(int i=0; i +void rtsDTGrid2D::dumpConn() +{ + for(int i=0; i +#include +using namespace std; + +#include "rtsDTGrid2D.h" + +struct Coord3D +{ + int x1; + int x2; + int x3; + + bool operator==(Coord3D &rhs) + { + if( (x1 == rhs.x1) && (x2 == rhs.x2) && (x3 == rhs.x3) ) + return true; + return false; + } + + bool operator<(Coord3D &rhs) + { + if(x1 < rhs.x1) + return true; + else if( (x1 == rhs.x1) && (x2 < rhs.x2) ) + return true; + else if( (x1 == rhs.x1) && (x2 == rhs.x2) && (x3 < rhs.x3) ) + return true; + return false; + + } + +}; + + + + +/**************DT GRID**************************/ +template +class rtsDTGrid3D +{ +private: + //main arrays + vector value; + vector conn; + rtsDTGrid2D proj2D; + Coord2D current_column; + bool randomIndex(rtsDTGrid2D::iterator &iter2D, int &v_i, int &c_i, int x1, int x2, int x3); + + + + //variables to keep track of insertion + int max_coord; + bool grid_insertion_started; + bool column_insertion_started; + + +public: + rtsDTGrid3D() + { + grid_insertion_started = false; + column_insertion_started = false; + proj2D.background.toConn = -1; + max_coord = 0; + } + + bool push(int x1, int x2, int x3, T v); + T random(int x1, int x2, int x3); + T background; + + + T& back(); + + void print(); + void operator=(T rhs); + void getBounds(int &min_x1, int &min_x2, int &min_x3, int &max_x1, int &max_x2, int &max_x3); + int getNumNodes(){return value.size();} + void insert(rtsDTGrid3D toInsert); + + //arithmetic + rtsDTGrid3D operator+(rtsDTGrid3D &rhs); + rtsDTGrid3D operator-(rtsDTGrid3D &rhs); + + + //dilation + friend class ColumnUnion; + void dilate(int H); + + /* + + + + + + //other types of iteration + iterator begin_pn(); + iterator end_pn(); + iterator begin_np(); + iterator end_np(); + */ + + //iterator + class iterator; + friend class iterator; + class stencil_iterator; + //iterator randomIterator(int x1, int x2); + iterator begin(); + iterator before(); + iterator end(); + iterator after(); + + //other types of iteration + iterator begin_ppn(); + iterator begin_nnp(); + iterator begin_pnp(); + iterator begin_npn(); + iterator begin_pnn(); + iterator begin_npp(); + + + iterator end_ppn(){return begin_nnp();} + iterator end_nnp(){return begin_ppn();} + iterator end_pnp(){return begin_npn();} + iterator end_npn(){return begin_pnp();} + iterator end_pnn(){return begin_npp();} + iterator end_npp(){return begin_pnn();} +}; + + +/**********ITERATOR***********************/ +template +class rtsDTGrid3D::iterator +{ + friend class rtsDTGrid3D; + rtsDTGrid3D* parent; + rtsDTGrid2D::iterator loc2D; + int iv; + int ic; + int x3; + +public: + + + T Value(){return parent->value[iv];} + int X1(){return loc2D.X1();} + int X2(){return loc2D.X2();} + int X3(){return x3;} + Coord3D Coord() + { + Coord3D result; + result.x1 = X1(); + result.x2 = X2(); + result.x3 = X3(); + return result; + } + iterator(){parent = NULL;} + void SetValue(T value){parent->value[iv] = value;} + + + void ppp() + { + //increment the value + iv++; + //if this exceeds the length of the value array, we are at the end of the grid + if(iv == parent->value.size()) + { + (*this) = parent->after(); + return; + } + + //increment the current coordinate + x3++; + //if we are outside of the current connected component + if(x3 > parent->conn[ic].coordMax) + { + //move to the next connected component + ic++; + //if this is the last connected component in the column + if(ic == loc2D.Value().toConn + loc2D.Value().numConn) + loc2D++; + //if there are no more connected components + if(ic == parent->conn.size()) + { + //we're at the end, return end + (*this) = parent->end(); + return; + } + x3 = parent->conn[ic].coordMin; + } + } + void ppn() + { + //decrement the value + iv--; + + //decrement the current coordinate + x3--; + //if we are outside of the current connected component + if(x3 < parent->conn[ic].coordMin) + { + //move to the previous connected component + ic--; + //if this is before the first connected component in the column + if(ic < loc2D.Value().toConn) + { + //increment to the next column + loc2D++; + //set the connected component to the last one in the column + ic = loc2D.Value().toConn + loc2D.Value().numConn - 1; + int num_values = parent->conn[ic].coordMax - parent->conn[ic].coordMin + 1; + iv = parent->conn[ic].toValue + num_values - 1; + } + + x3 = parent->conn[ic].coordMax; + } + + + } + + void nnp() + { + //increment the value + iv++; + + //increment the current coordinate + x3++; + //if we are outside of the current connected component + if(x3 > parent->conn[ic].coordMax) + { + //move to the next connected component + ic++; + //if this is after the last connected component in the column + if(ic == loc2D.Value().toConn + loc2D.Value().numConn) + { + //decrement to the previous column + loc2D--; + //set the connected component to the first one in the column + ic = loc2D.Value().toConn; + iv = parent->conn[ic].toValue; + } + + x3 = parent->conn[ic].coordMin; + } + + + } + + + void nnn() + { + //decrement the value + iv--; + //if this is less than 0, we are at the beginning of the grid + if(iv < 0) + { + (*this) = parent->before(); + return; + } + + //decrement the current coordinate + x3--; + //if we are outside of the current connected component + if(x3 < parent->conn[ic].coordMin) + { + //move to the previous connected component + ic--; + //if this is the first connected component in the column + if(ic < loc2D.Value().toConn) + loc2D--; + //if there are no more connected components + if(ic < 0) + { + //we're at the beginning, return begin + (*this) = parent->before(); + return; + } + x3 = parent->conn[ic].coordMax; + } + + } + + void pnp() + { + //increment the value + iv++; + + //increment the current coordinate + x3++; + //if we are outside of the current connected component + if(x3 > parent->conn[ic].coordMax) + { + //move to the next connected component + ic++; + //if this is after the last connected component in the column + if(ic == loc2D.Value().toConn + loc2D.Value().numConn) + { + //decrement to the previous column + loc2D.pn(); + //set the connected component to the first one in the column + ic = loc2D.Value().toConn; + iv = parent->conn[ic].toValue; + } + + x3 = parent->conn[ic].coordMin; + } + + + } + void npn() + { + //decrement the value + iv--; + + //decrement the current coordinate + x3--; + //if we are outside of the current connected component + if(x3 < parent->conn[ic].coordMin) + { + //move to the previous connected component + ic--; + //if this is before the first connected component in the column + if(ic < loc2D.Value().toConn) + { + //increment to the next column + loc2D.np(); + //set the connected component to the last one in the column + ic = loc2D.Value().toConn + loc2D.Value().numConn - 1; + int num_values = parent->conn[ic].coordMax - parent->conn[ic].coordMin + 1; + iv = parent->conn[ic].toValue + num_values - 1; + } + + x3 = parent->conn[ic].coordMax; + } + + + } + void pnn() + { + //decrement the value + iv--; + + //decrement the current coordinate + x3--; + //if we are outside of the current connected component + if(x3 < parent->conn[ic].coordMin) + { + //move to the previous connected component + ic--; + //if this is before the first connected component in the column + if(ic < loc2D.Value().toConn) + { + //increment to the next column + loc2D.pn(); + //set the connected component to the last one in the column + ic = loc2D.Value().toConn + loc2D.Value().numConn - 1; + int num_values = parent->conn[ic].coordMax - parent->conn[ic].coordMin + 1; + iv = parent->conn[ic].toValue + num_values - 1; + } + + x3 = parent->conn[ic].coordMax; + } + + + } + void npp() + { + //increment the value + iv++; + + //increment the current coordinate + x3++; + //if we are outside of the current connected component + if(x3 > parent->conn[ic].coordMax) + { + //move to the next connected component + ic++; + //if this is after the last connected component in the column + if(ic == loc2D.Value().toConn + loc2D.Value().numConn) + { + //decrement to the previous column + loc2D.np(); + //set the connected component to the first one in the column + ic = loc2D.Value().toConn; + iv = parent->conn[ic].toValue; + } + + x3 = parent->conn[ic].coordMin; + } + + + } + + /* + void pn() + { + //for the most part we will be going backwards through the array + //so first decrement iv + iv--; + x2--; + //if iv is less than the current connected component + if(iv < parent->conn[ic].toValue) + { + //go to the previous connected component + ic--; + //if we are before the first connected component in the column + if(ic < loc1D.Value().toConn) + { + //increment the 1D iterator + loc1D++; + //reset ic to the last component of the new column + ic = loc1D.Value().toConn + loc1D.Value().numConn - 1; + //find the new value identifier + iv = parent->conn[ic].toValue + (parent->conn[ic].coordMax - parent->conn[ic].coordMin); + } + //compute the currect coordinate + x2 = parent->conn[ic].coordMax; + } + } + + void np() + { + //for the most part we will be going forward through the grid + //increment iv + iv++; + x2++; + + //if we are outside of the current connected component + if(x2 > parent->conn[ic].coordMax) + { + //move to the next connected component + ic++; + //if this is the last connected component in the column + if(ic == loc1D.Value().toConn + loc1D.Value().numConn) + { + loc1D--; + ic = loc1D.Value().toConn; + iv = parent->conn[ic].toValue; + } + + x2 = parent->conn[ic].coordMin; + } + + } + + + + + friend bool operator<(iterator &left, iterator &right) + { + if(left.iv < right.iv) + return true; + return false; + } + friend bool operator<=(iterator &left, iterator &right) + { + if(left.iv <= right.iv) + return true; + return false; + } + + */ + + void increment_until(int p1, int p2, int p3) + { + while((*this) != parent->end()) + { + if(X1() > p1) + return; + if(X1() == p1 && X2() > p2) + return; + else if(X1() == p1 && X2() == p2 && X3() >= p3) + return; + + ppp(); + } + } + void operator++(){ppp();} + void operator--(){nnn();} + + //boolean operators for comparing iterators + bool operator==(iterator &rhs) + { + if(parent == rhs.parent && iv == rhs.iv) + return true; + + //if(loc2D == rhs.loc2D && x3 == rhs.x3) + // return true; + return false; + } + bool operator!=(iterator &rhs){return !((*this) == rhs);} + bool operator<(iterator rhs) + { + if(parent == rhs.parent && iv < rhs.iv) + return true; + //if(loc2D < rhs.loc2D && x3 < rhs.x3) + // return true; + return false; + + } +}; + +/**************ITERATOR METHODS IN DT GRID*******************/ +template +typename rtsDTGrid3D::iterator rtsDTGrid3D::begin() +{ + //if the grid is empty, return an iterator to "after" + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.ic = 0; + result.iv = 0; + result.x3 = conn[0].coordMin; + result.loc2D = proj2D.begin(); + + return result; +} +template +typename rtsDTGrid3D::iterator rtsDTGrid3D::end() +{ + //if the grid is empty, return after() + if(value.size() == 0) + return after(); + iterator result; + result.parent = this; + result.ic = conn.size() - 1; + result.iv = value.size() - 1; + result.x3 = conn[result.ic].coordMax; + result.loc2D = proj2D.end(); + return result; +} +template +typename rtsDTGrid3D::iterator rtsDTGrid3D::after() +{ + iterator result; + result.parent = this; + result.ic = conn.size() - 1; + result.iv = value.size(); + //result.x2 = conn[result.ic].coordMax; + result.loc2D = proj2D.after(); + return result; +} + + +template +typename rtsDTGrid3D::iterator rtsDTGrid3D::before() +{ + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.ic = 0; + result.iv = -1; + //result.x2 = conn[0].coordMin; + result.loc2D = proj2D.before(); + + return result; +} + +template +typename rtsDTGrid3D::iterator rtsDTGrid3D::begin_ppn() +{ + //if the grid is empty, return an iterator to "after" + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.loc2D = proj2D.begin(); + //find the index of the last connected component in the first column + int last_conn = result.loc2D.Value().toConn + result.loc2D.Value().numConn - 1; + result.ic = last_conn; + result.iv = conn[last_conn].toValue + conn[last_conn].coordMax - conn[last_conn].coordMin; + result.x3 = conn[last_conn].coordMax; + + + return result; +} + +template +typename rtsDTGrid3D::iterator rtsDTGrid3D::begin_nnp() +{ + //if the grid is empty, return an iterator to "after" + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.loc2D = proj2D.end(); + //find the index of the first connected component in the last column + int first_conn = result.loc2D.Value().toConn; + result.ic = first_conn; + result.iv = conn[first_conn].toValue; + result.x3 = conn[first_conn].coordMin; + + + return result; +} +template +typename rtsDTGrid3D::iterator rtsDTGrid3D::begin_pnp() +{ + //if the grid is empty, return an iterator to "after" + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.loc2D = proj2D.begin_pn(); + //find the index of the first connected component in the column + int first_conn = result.loc2D.Value().toConn; + result.ic = first_conn; + result.iv = conn[first_conn].toValue; + result.x3 = conn[first_conn].coordMin; + + + return result; +} +template +typename rtsDTGrid3D::iterator rtsDTGrid3D::begin_npn() +{ + //if the grid is empty, return an iterator to "after" + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.loc2D = proj2D.begin_np(); + //find the index of the last connected component in the column + int last_conn = result.loc2D.Value().toConn + result.loc2D.Value().numConn - 1; + result.ic = last_conn; + result.iv = conn[last_conn].toValue + conn[last_conn].coordMax - conn[last_conn].coordMin; + result.x3 = conn[last_conn].coordMax; + + + return result; +} +template +typename rtsDTGrid3D::iterator rtsDTGrid3D::begin_pnn() +{ + //if the grid is empty, return an iterator to "after" + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.loc2D = proj2D.begin_pn(); + //find the index of the last connected component in the column + int last_conn = result.loc2D.Value().toConn + result.loc2D.Value().numConn - 1; + result.ic = last_conn; + result.iv = conn[last_conn].toValue + conn[last_conn].coordMax - conn[last_conn].coordMin; + result.x3 = conn[last_conn].coordMax; + + + return result; +} +template +typename rtsDTGrid3D::iterator rtsDTGrid3D::begin_npp() +{ + //if the grid is empty, return an iterator to "after" + if(value.size() == 0) + return after(); + + iterator result; + result.parent = this; + result.loc2D = proj2D.begin_np(); + //find the index of the first connected component in the column + int first_conn = result.loc2D.Value().toConn; + result.ic = first_conn; + result.iv = conn[first_conn].toValue; + result.x3 = conn[first_conn].coordMin; + + + return result; +} +/**************DT GRID METHODS**************************/ +template +bool rtsDTGrid3D::push(int x1, int x2, int x3, T v) +{ + //run this code if we have to start a new column. This happens when: + //(a) we have just inserted the first value into the grid + //(b) the insertion takes place in a different column + if(grid_insertion_started == false || x1 != current_column.x1 || x2 != current_column.x2) + { + //assume that a new column is being created + //create the column in proj1D + IndexPair newPair; + newPair.toConn = conn.size(); + //newPair.toValue = value.size(); + newPair.numConn = 0; + + //if this insertion throws an error, the value was inserted incorrectly + //the error will get thrown by DTGrid2D, so just return + if(!proj2D.push(x1, x2, newPair)) + { + cout<<"Out-of-order insertion in D = 3: X1 = "< +void rtsDTGrid3D::operator =(T rhs) +{ + for(int i=0; i +void rtsDTGrid3D::getBounds(int &min_x1, int &min_x2, int &min_x3, int &max_x1, int &max_x2, int &max_x3) +{ + //if the grid is empty, return an empty bounding volume + if(value.size() == 0) + { + min_x1 = min_x2 = min_x3 = max_x1 = max_x2 = max_x3 = 0; + return; + } + + //get the min and max values for the 1D grid (x1 coordinate) + proj2D.getBounds(min_x1, min_x2, max_x1, max_x2); + + //initialize the min and max values + min_x3 = conn[0].coordMin; + max_x3 = conn.back().coordMax; + + //iterate through all columns finding the smallest and largest coordinate values + rtsDTGrid2D::iterator i; + IndexPair col; + for(i=proj2D.begin(); i!=proj2D.after(); i++) + { + col = i.Value(); + if(conn[col.toConn].coordMin < min_x3) + min_x3 = conn[col.toConn].coordMin; + if(conn[col.toConn + col.numConn - 1].coordMax > max_x3) + max_x3 = conn[col.toConn + col.numConn - 1].coordMax; + } + + +} +template +void rtsDTGrid3D::insert(rtsDTGrid3D toInsert) +{ + //create source and destination iterators + rtsDTGrid3D::iterator source = toInsert.begin(); + rtsDTGrid3D::iterator dest = begin(); + + for(source = toInsert.begin(); source != toInsert.after(); source++) + { + //move the destination iterator to the current source position + dest.increment_until(source.X1(), source.X2(), source.X3()); + //cout<<"source: "< +void rtsDTGrid3D::dilate(int H) +{ + //if the grid is empty, return unchanged + if(value.size() == 0) + return; + + ColumnUnion CUqueue; + CUqueue.ConnectToGrid(&conn); + + + //dilate the N-1 DT-Grid constituent + rtsDTGrid2D dilated_proj2D = proj2D; + + //an empty pair has a number of connected components equal to zero + //this should not happen in reality and can therefore be used to check for new columns + IndexPair empty_pair; + empty_pair.numConn = 0; + + //set the background node to the empty node and dilate the 2D projection + dilated_proj2D.background = empty_pair; + dilated_proj2D.dilate(H); + + //create a new DT Grid that will replace this one + rtsDTGrid3D new_grid; + new_grid.proj2D = dilated_proj2D; + new_grid.proj2D.background.toConn = -1; + + //create iteratorDilate that iterates along the dilated N-1 grid + rtsDTGrid2D::stencil_iterator iteratorDilate; + + //create the template entrance nodes + int n; + for(n=-H; n<=H; n++) + iteratorDilate.addPosition(n, H); + //create the template exit nodes + for(n=-H; n<=H; n++) + iteratorDilate.addPosition(n, -H); + + //create an iterator to set the new proj2D values + rtsDTGrid2D::iterator iteratorNew; + + + //variables for each iteration + IndexPair new_pair; + vector::iterator ccIterator; + unsigned int numValues = 0; + for(iteratorNew = new_grid.proj2D.begin(), + iteratorDilate = dilated_proj2D.begin(); + iteratorDilate != dilated_proj2D.after(); + iteratorNew++, + iteratorDilate++) + { + //if a column is entering the stencil + for(n=0; n<=(2*H); n++) + if(iteratorDilate.getValue(n).numConn) + CUqueue.InsertColumn(iteratorDilate.getValue(n)); + + //compute the union of all columns in the queue + vector result = CUqueue.ComputeUnion(H); + + //compute the new IndexPair representing the column + new_pair.toConn = new_grid.conn.size(); + new_pair.numConn = result.size(); + //store the index pair + iteratorNew.SetValue(new_pair); + + //insert each of the connected components + for(ccIterator = result.begin(); ccIterator!=result.end(); ccIterator++) + { + new_grid.conn.push_back(*ccIterator); + new_grid.conn.back().toValue = numValues; + numValues += (*ccIterator).coordMax - (*ccIterator).coordMin + 1; + } + + //if a column is leaving the stencil + for(n=(2*H + 1); n<=(4*H + 1); n++) + if(iteratorDilate.getValue(n).numConn) + CUqueue.RemoveColumn(); + } + + //allocate space for the new value array + new_grid.value.resize(numValues, background); + + //copy the data from this grid into the new grid + new_grid.insert(*this); + + //replace this grid with the new grid + conn = new_grid.conn; + value = new_grid.value; + proj2D = new_grid.proj2D; + + +} + + + +/***************ARITHMETIC********************************/ +template +rtsDTGrid3D rtsDTGrid3D::operator+(rtsDTGrid3D &rhs) +{ + rtsDTGrid3D result; + + //create an iterator for each DT Grid + rtsDTGrid3D::iterator left = begin(); + rtsDTGrid3D::iterator right = rhs.begin(); + + //iterate both until one iterator has hit after() + while(left != after() && right != rhs.after()) + { + //if the iterators are at the same coordinate + if(left.Coord() == right.Coord()) + { + //insert their sum into the new grid + result.push(left.X1(), left.X2(), left.X3(), left.Value() + right.Value()); + //increment both + left++; right++; + } + //add the lowest (lexicographically) value to the background, insert the result, and increment + else if( (left.Coord() < right.Coord()) ) + { + result.push(left.X1(), left.X2(), left.X3(), left.Value() + rhs.background); + left++; + } + else if( (right.Coord() < left.Coord()) ) + { + result.push(right.X1(), right.X2(), right.X3(), right.Value() + background); + right++; + } + } + + //if the left iterator hasn't finished, iterate to finish it off + while(left != after()) + { + result.push(left.X1(), left.X2(), left.X3(), left.Value() + rhs.background); + left++; + } + + while(right != rhs.after()) + { + result.push(right.X1(), right.X2(), right.X3(), right.Value() + rhs.background); + right++; + } + + + return result; + + +} + +template +rtsDTGrid3D rtsDTGrid3D::operator-(rtsDTGrid3D &rhs) +{ + rtsDTGrid3D result; + + //create an iterator for each DT Grid + rtsDTGrid3D::iterator left = begin(); + rtsDTGrid3D::iterator right = rhs.begin(); + + //iterate both until one iterator has hit after() + while(left != after() && right != rhs.after()) + { + //if the iterators are at the same coordinate + if(left.Coord() == right.Coord()) + { + //insert their sum into the new grid + result.push(left.X1(), left.X2(), left.X3(), left.Value() - right.Value()); + //increment both + left++; right++; + } + //add the lowest (lexicographically) value to the background, insert the result, and increment + else if( (left.Coord() < right.Coord()) ) + { + result.push(left.X1(), left.X2(), left.X3(), left.Value() - rhs.background); + left++; + } + else if( (right.Coord() < left.Coord()) ) + { + result.push(right.X1(), right.X2(), right.X3(), background - right.Value()); + right++; + } + } + + //if the left iterator hasn't finished, iterate to finish it off + while(left != after()) + { + result.push(left.X1(), left.X2(), left.X3(), left.Value() - rhs.background); + left++; + } + + while(right != rhs.after()) + { + result.push(right.X1(), right.X2(), right.X3(), background - right.Value()); + right++; + } + + + return result; + + +} +#endif diff --git a/rtsFilamentNetwork.cpp b/rtsFilamentNetwork.cpp new file mode 100755 index 0000000..0806f8e --- /dev/null +++ b/rtsFilamentNetwork.cpp @@ -0,0 +1,92 @@ +#include "rtsFilamentNetwork.h" + +int rtsFilamentNetwork::LoadFIB(const char* filename) +{ + return fib_load(filename); +} + +int rtsFilamentNetwork::fib_load(const char* filename) +{ + //open the input file + ifstream infile; + infile.open(filename); + if(!infile) return 0; + + //temporary vector storing points + vector> vertices; + vector radii; + point3D input; + point3D max(0.0, 0.0, 0.0); //maximum extents of the points in the file + + float r; + + int i,j; + //get all of the nodes from the file + int num_nodes; + infile>>num_nodes; + int id; + for(i=0; i>id; + infile>>input.x; infile>>input.y; infile>>input.z; infile>>r; + + //update the maximum + if(input.x > max.x) max.x = input.x; + if(input.y > max.y) max.y = input.y; + if(input.z > max.z) max.z = input.z; + + vertices.push_back(input); + radii.push_back(r); + } + + /*Scale the node values based on the maximum value. I do this so that + every node is between 0 - 1 rather than the original scale. In the long run, + it should make rendering easier. + */ + for(i=0; i>num_filaments; + + for(i=0; iobjBegin(OBJ_LINE_STRIP); //begin the filament + infile>>num_edges; + for(j = 1; j>id; id--; + network->objVertex3f(vertices[id].x, vertices[id].y, vertices[id].z); + //this final read is required because of redundancy in the input file + infile>>id; + } + infile>>id; //this final read is also required due to redundancy in the input file + id--; + network->objVertex3f(vertices[id].x, vertices[id].y, vertices[id].z); + infile>>id; + id--; + network->objVertex3f(vertices[id].x, vertices[id].y, vertices[id].z); + network->objEnd(); + } + return 1; +} + +void rtsFilamentNetwork::PrintProperties() +{ + + cout<<"Number of Filaments: "<getNumLines(); +} + +void rtsFilamentNetwork::PrintNetwork() +{ + +} \ No newline at end of file diff --git a/rtsFilamentNetwork.h b/rtsFilamentNetwork.h new file mode 100755 index 0000000..f9a3144 --- /dev/null +++ b/rtsFilamentNetwork.h @@ -0,0 +1,35 @@ +#ifndef RTSFILAMENTNETWORK_H +#define RTSFILAMENTNETWORK_H + +#include "rtsLinearAlgebra.h" +#include "objJedi.h" +#include +#include + +using namespace std; + + +class rtsFilamentNetwork +{ +protected: + rtsOBJ* network; + int fib_load(const char* filename); + +public: + rtsFilamentNetwork(){network = new rtsOBJ();} + + virtual int LoadFIB(const char* filename); + void PrintProperties(); + void PrintNetwork(); + +}; + + + +#endif + + + + + + \ No newline at end of file diff --git a/rtsFilename.h b/rtsFilename.h new file mode 100755 index 0000000..414bbca --- /dev/null +++ b/rtsFilename.h @@ -0,0 +1,67 @@ +#include + +using namespace std; + +#ifndef RTS_FILENAME_H +#define RTS_FILENAME_H + +class rtsFilename +{ +private: + string filename; + +public: + string getFilename() + { + int pos = filename.find_last_of("/\\"); + string name = filename.substr(pos+1, filename.size()); + return name; + } + + rtsFilename& operator=(const string str) + { + filename = str; + return *this; + } + rtsFilename(const string str){filename = str;} + rtsFilename(){filename = "";} + + string getExtension() + { + int pos = filename.find_last_of("."); + string ext = filename.substr(pos+1, filename.size() - pos); + return ext; + } + + string getDirectory() + { + int pos = filename.find_last_of("/\\"); + string directory; + if(pos != -1) + directory = filename.substr(0, pos); + else + directory = ""; + return directory; + } + + string getPrefix() + { + int slash = filename.find_last_of("/\\"); + int dot = filename.find_last_of("."); + + string prefix; + prefix = filename.substr(slash+1, dot - slash - 1); + return prefix; + + } + + string getString() + { + return filename; + } + + + +}; + +#endif \ No newline at end of file diff --git a/rtsFunction3D.h b/rtsFunction3D.h new file mode 100755 index 0000000..3711979 --- /dev/null +++ b/rtsFunction3D.h @@ -0,0 +1,913 @@ +#ifndef RTSFUNCTION3D_H +#define RTSFUNCTION3D_H + +#define DIST_MAX 255 + +#include "rtsLinearAlgebra.h" +//#include "rtsDTGrid3D.h" +#include +//#include +//#include +//#include +//#include +using namespace std; + +typedef int indextype; + +///This class represents a 3D implicit function as a grid. It provides methods for accessing values, interpolation, and several utilities. + +template class rtsFunction3D +{ +private: + //pointer to store the data + T* m_data; + //resolution of the data (x, y, z) dimensional extents + vector3D m_resolution; + T m_boundary; //boundary condition + point3D m_domain_min; //min and max range values (used for parametric access) + point3D m_domain_max; + vector3D m_voxel_size; + + //bit-blit function copies 3D data quickly from source to dest + void blit3D(const T* source, + indextype s_px, indextype s_py, indextype s_pz, + indextype s_sx, indextype s_sy, indextype s_sz, + T* dest, + indextype d_px, indextype d_py, indextype d_pz, + indextype d_sx, indextype d_sy, indextype d_sz, + indextype blit_size_x, indextype blit_size_y, indextype blit_size_z); + + void shallow_copy(const rtsFunction3D source, rtsFunction3D &dest); + inline point3D getParameter(indextype i); + void initialize_empty(indextype res_x, indextype res_y, indextype res_z); + +public: + //construct an implicit function with a size of 1 + rtsFunction3D(); /// resolution, T boundary, point3D min_domain, point3D max_domain); + //full copy constructor, defines all variables + rtsFunction3D(T* data, vector3D resolution, T boundary, point3D min_domain, point3D max_domain); + rtsFunction3D(const rtsFunction3D &original); //copy constructor + ~rtsFunction3D(); //destructor + void Init(indextype res_x, indextype res_y, indextype res_z); + + //overloaded operators + rtsFunction3D& operator=(const rtsFunction3D& original); ///& operator=(const T constant); ///& operator*=(const T constant); ///& operator+=(const T constant); ///& operator-=(const T constant); ///& operator/=(const T constant); /// operator+(const T constant); /// operator-(const T constant); /// operator*(const T constant); /// operator/(const T constant); /// friend class rtsFunction3D; + template operator rtsFunction3D(); /// operator*(const T lhs, rtsFunction3D rhs){return rhs*lhs;} /// operator+(const T lhs, rtsFunction3D rhs){return rhs+lhs;} /// operator-(const T lhs, rtsFunction3D rhs) /// result; + rhs.shallow_copy(rhs, result); //make a copy of all of the shallow variables and allocate memory + indextype size = rhs.m_resolution.x * rhs.m_resolution.y * rhs.m_resolution.z; + //iterate and subtract + for(indextype i=0; i operator/(const T lhs, rtsFunction3D rhs); + + //loading/saving data to disk + void LoadRAW(indextype header_size, indextype data_x, indextype data_y, indextype data_z, const char* filename); /// Project2D(); // getParameter(indextype x, indextype y, indextype z); + inline point3D getNearestIndex(double i, double j, double k); + inline point3D getFractionalIndex(double i, double j, double k); + inline point3D getNearestIndex(indextype i); + point3D getMinDomain(){return m_domain_min;} + point3D getMaxDomain(){return m_domain_max;} + + //data input methods + void Insert(rtsFunction3D* source, indextype x, indextype y, indextype z); + + //data massaging + + void Scale(T min, T max); + void Crop(indextype x, indextype y, indextype z, indextype size_x, indextype size_y, indextype size_z); + void Binary(T threshold, T true_value); ///* Resample(indextype newres_x, indextype newres_y, indextype newres_z); + + //output functions + void toConsole(); + +}; + +template +void rtsFunction3D::blit3D(const T* source, + indextype s_px, indextype s_py, indextype s_pz, + indextype s_sx, indextype s_sy, indextype s_sz, + T* dest, + indextype d_px, indextype d_py, indextype d_pz, + indextype d_sx, indextype d_sy, indextype d_sz, + indextype blit_size_x, indextype blit_size_y, indextype blit_size_z) +{ + indextype ps, pd; //stores the mapping for the source point to the dest point + //find the maximum points that can be blit to (in case source overlaps the edges of dest) + blit_size_x = min(blit_size_x, min(s_sx - s_px, d_sx - d_px)); + blit_size_y = min(blit_size_y, min(s_sy - s_py, d_sy - d_py)); + blit_size_z = min(blit_size_z, min(s_sz - s_pz, d_sz - d_pz)); + + indextype source_z_offset = s_sx * s_sy; + indextype dest_z_offset = d_sx * d_sy; + + indextype z,y; + for(z=0; z +void rtsFunction3D::shallow_copy(const rtsFunction3D source, rtsFunction3D &dest) +{ + dest = rtsFunction3D(source.m_resolution.x, source.m_resolution.y, source.m_resolution.z); + dest.m_boundary = source.m_boundary; + dest.m_domain_max = source.m_domain_max; + dest.m_domain_min = source.m_domain_max; + dest.m_voxel_size = source.m_voxel_size; +} + +template +rtsFunction3D::rtsFunction3D(vector3D resolution, T boundary, point3D domain_min, point3D domain_max) +{ + //This function creates an implicit function based on all of the shallow variables + m_resolution = resolution; + m_boundary = boundary; + m_domain_min = domain_min; + m_domain_max = domain_max; + m_voxel_size = domain_max - domain_min; + m_voxel_size.x /= m_resolution.x; + m_voxel_size.y /= m_resolution.y; + m_voxel_size.z /= m_resolution.z; + + //allocate the data + m_data = new T[m_resolution.x * m_resolution.y * m_resolution.z]; +} + +template +rtsFunction3D::rtsFunction3D(T* data, vector3D resolution, T boundary, point3D domain_min, point3D domain_max) +{ + //This function creates an implicit function based on ALL of the variables + m_resolution = resolution; + m_boundary = boundary; + m_domain_min = domain_min; + m_domain_max = domain_max; + m_voxel_size = domain_max - domain_min; + m_voxel_size.x /= m_resolution.x; + m_voxel_size.y /= m_resolution.y; + m_voxel_size.z /= m_resolution.z; + + //allocate the data + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + m_data = new T[size]; + memcpy(m_data, data, sizeof(T)*size); + //for(int i=0; i +rtsFunction3D::rtsFunction3D() +{ + m_resolution.x = 1; + m_resolution.y = 1; + m_resolution.z = 1; + m_data = new T[1]; + memset(&m_boundary, 0, sizeof(T)); //initialize boundary condition + m_domain_min = point3D(0.0, 0.0, 0.0); //set range parameters + m_domain_max = point3D(1.0, 1.0, 1.0); + m_voxel_size = vector3D(1.0, 1.0, 1.0); +} + +template +void rtsFunction3D::initialize_empty(indextype res_x, indextype res_y, indextype res_z) +{ + m_resolution.x = res_x; //set resolution vector + m_resolution.y = res_y; + m_resolution.z = res_z; + m_data = (T*)calloc(res_x*res_y*res_z, sizeof(T)); //allocate data +} + +template +rtsFunction3D::rtsFunction3D(indextype res_x, indextype res_y, indextype res_z) +{ + initialize_empty(res_x, res_y, res_z); + memset(&m_boundary, 0, sizeof(T)); //initialize boundary condition + m_domain_min = point3D(0.0, 0.0, 0.0); //set range parameters + m_domain_max = point3D(1.0, 1.0, 1.0); + + m_voxel_size = m_domain_max - m_domain_min; + m_voxel_size.x /= m_resolution.x; + m_voxel_size.y /= m_resolution.y; + m_voxel_size.z /= m_resolution.z; +} + +template +void rtsFunction3D::Init(indextype res_x, indextype res_y, indextype res_z) +{ + initialize_empty(res_x, res_y, res_z); + m_domain_min = point3D(0.0, 0.0, 0.0); //set range parameters + m_domain_max = point3D(1.0, 1.0, 1.0); + memset(&m_boundary, 0, sizeof(T)); //initialize boundary condition + + m_voxel_size = m_domain_max - m_domain_min; + m_voxel_size.x /= m_resolution.x; + m_voxel_size.y /= m_resolution.y; + m_voxel_size.z /= m_resolution.z; +} + +template +rtsFunction3D::rtsFunction3D(T* data, indextype res_x, indextype res_y, indextype res_z) +{ + m_resolution.x = res_x; //set resolution vector + m_resolution.y = res_y; + m_resolution.z = res_z; + m_data = new T[res_x*res_y*res_z]; //allocate data + //copy the sample data into the data array + indextype size = res_x*res_y*res_z; + for(indextype i=0; i(0.0, 0.0, 0.0); //set range parameters + m_domain_max = point3D(1.0, 1.0, 1.0); + + m_voxel_size = domain_max - domain_min; + m_voxel_size.x /= m_resolution.x; + m_voxel_size.y /= m_resolution.y; + m_voxel_size.z /= m_resolution.z; +} + +template +rtsFunction3D::rtsFunction3D(const rtsFunction3D& original) +{ + //copy the shallow variables + m_resolution = original.m_resolution; + m_boundary = original.m_boundary; + m_domain_min = original.m_domain_min; + m_domain_max = original.m_domain_max; + m_voxel_size = original.m_voxel_size; + + //allocate space for the data + m_data = new T[m_resolution.x * m_resolution.y * m_resolution.z]; + //copy the data + blit3D(original.m_data, + 0, 0, 0, + m_resolution.x, m_resolution.y, m_resolution.z, + m_data, + 0, 0, 0, + m_resolution.x, m_resolution.y, m_resolution.z, + m_resolution.x, m_resolution.y, m_resolution.z); +} + +template +rtsFunction3D::~rtsFunction3D() +{ + delete m_data; +} + +template +typename rtsFunction3D& rtsFunction3D::operator=(const T rhs) +{ + indextype size = m_resolution.x*m_resolution.y*m_resolution.z; + for(int i=0; i +typename rtsFunction3D& rtsFunction3D::operator=(const rtsFunction3D& rhs) +{ + //check for self-assignment + if(this == &rhs) + return *this; + + //deallocate memory + if(m_data != NULL) + delete m_data; + + //copy the shallow variables + m_resolution = rhs.m_resolution; + m_boundary = rhs.m_boundary; + m_domain_min = rhs.m_domain_min; + m_domain_max = rhs.m_domain_max; + m_voxel_size = rhs.m_voxel_size; + + //allocate and copy memory + m_data = new T[m_resolution.x * m_resolution.y * m_resolution.z]; + //copy the data + blit3D(rhs.m_data, + 0,0,0, + m_resolution.x, m_resolution.y, m_resolution.z, + m_data, + 0, 0, 0, + m_resolution.x, m_resolution.y, m_resolution.z, + m_resolution.x, m_resolution.y, m_resolution.z); + + //return the left hand side + return *this; +} + +template +inline T& rtsFunction3D::operator ()(indextype x, indextype y, indextype z) +{ + return xyz(x, y, z); +} + +template +inline T rtsFunction3D::operator()(double i, double j, double k) +{ + return ijk(i, j, k); +} + +template +rtsFunction3D& rtsFunction3D::operator *=(const T constant) +{ + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + for(indextype i = 0; i +rtsFunction3D& rtsFunction3D::operator +=(const T constant) +{ + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + for(indextype i = 0; i +rtsFunction3D& rtsFunction3D::operator -=(const T constant) +{ + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + for(indextype i = 0; i +rtsFunction3D& rtsFunction3D::operator /=(const T constant) +{ + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + for(indextype i = 0; i +const rtsFunction3D rtsFunction3D::operator *(const T constant) +{ + rtsFunction3D result = (*this); + result *= constant; + + return result; +} + +template +const rtsFunction3D rtsFunction3D::operator +(const T constant) +{ + rtsFunction3D result = (*this); + result += constant; + + return result; +} + +template +const rtsFunction3D rtsFunction3D::operator -(const T constant) +{ + rtsFunction3D result = (*this); + result -= constant; + + return result; +} + +template +const rtsFunction3D rtsFunction3D::operator /(const T constant) +{ + rtsFunction3D result = (*this); + result /= constant; + + return result; +} + +template +template +rtsFunction3D::operator rtsFunction3D() +{ + //cast one type to another + //create the data pointer from the current function + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + U* new_data = new U[size]; + for(int i=0; i cast_result(new_data, m_resolution, m_boundary, m_domain_min, m_domain_max); + + return cast_result; +} + +template +inline T& rtsFunction3D::xyz(indextype x, indextype y, indextype z) +{ + if(x<0 || y<0 || z<0 || x>=m_resolution.x || y>=m_resolution.y || z>=m_resolution.z) + return m_boundary; + //return m_data[(z * m_resolution.x * m_resolution.y) + (y * m_resolution.x) + x]; + return m_data[x + m_resolution.x * (y + z * m_resolution.y)]; + +} + +template +inline point3D rtsFunction3D::getNearestIndex(indextype i) +{ + point3D result; + result.z = i/(m_resolution.x*m_resolution.y); + indextype mod = i%(m_resolution.x*m_resolution.y); + result.y = mod/m_resolution.x; + result.x = mod%m_resolution.x; + + return result; + +} + +template +void rtsFunction3D::LoadRAW(indextype header_size, indextype size_x, + indextype size_y, indextype size_z, const char *filename) +{ + //set the data size + m_resolution = vector3D(size_x, size_y, size_z); + //delete any previous data + if(m_data != NULL) + { + delete m_data; + m_data = NULL; + } + + ifstream infile(filename, ios::in | ios::binary); + + //load the header + unsigned char* header = new unsigned char[header_size]; + infile.read((char*)header, header_size); + + //load the actual data + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + //m_data = (T*)malloc(size*sizeof(T)); + initialize_empty(m_resolution.x, m_resolution.y, m_resolution.z); + infile.read((char*)m_data, size*sizeof(T)); + + //calculate min and maxes + infile.close(); +} + +template +void rtsFunction3D::LoadVOL(const char *filename) +{ + ifstream infile(filename, ios::in | ios::binary); //create the files stream + if(!infile) + return; + + indextype size_x, size_y, size_z; //create variables to store the size of the data set + //load the dimensions of the data set + infile.read((char*)&size_x, sizeof(int)); //load the file header + infile.read((char*)&size_y, sizeof(int)); + infile.read((char*)&size_z, sizeof(int)); + + //close the file + infile.close(); + //load the raw data + LoadRAW(12, size_x, size_y, size_z, filename); +} + +template +void rtsFunction3D::SaveVOL(const char *filename) +{ + ofstream outfile(filename, ios::out | ios::binary); //create the binary file stream + + //write the volume size to the file + vector3D vol_size = m_resolution; + outfile.write((char*)&vol_size.x, sizeof(int)); + outfile.write((char*)&vol_size.y, sizeof(int)); + outfile.write((char*)&vol_size.z, sizeof(int)); + + outfile.write((char*)m_data, sizeof(T)*vol_size.x*vol_size.y*vol_size.z); +} + +template +void rtsFunction3D::SaveRAW(const char *filename) +{ + ofstream outfile(filename, ios::out | ios::binary); //create the binary file stream + + //write the volume data + outfile.write((char*)m_data, sizeof(T)*m_resolution.x*m_resolution.y*m_resolution.z); +} + +template +inline T rtsFunction3D::ijk(double i, double j, double k) +{ + /*This function determines the value at the specified parametric points + defined by the m_domain_min and m_domain_max parameter values.*/ + + //if the parameter is outside the range, return the boundary value + if(im_domain_max.x || j>m_domain_max.y || k>m_domain_max.z) + return m_boundary; + + point3D index = getFractionalIndex(i, j, k); + + //cout< +void rtsFunction3D::Parameterize(double x_min, double x_max, double y_min, double y_max, double z_min, double z_max) +{ + m_domain_min = point3D(x_min, y_min, z_min); + m_domain_max = point3D(x_max, y_max, z_max); + m_voxel_size = m_domain_max - m_domain_min; + m_voxel_size.x /= m_resolution.x; + m_voxel_size.y /= m_resolution.y; + m_voxel_size.z /= m_resolution.z; +} + +template +inline point3D rtsFunction3D::getParameter(indextype x, indextype y, indextype z) +{ + //get the value between 0 and 1 + point3D normalized((double)x / (double)(m_resolution.x) + (1.0/(m_resolution.x*2.0)), + (double)y / (double)(m_resolution.y) + (1.0/(m_resolution.y*2.0)), + (double)z/(double)(m_resolution.z) + (1.0/(m_resolution.z*2.0))); + + point3D result(normalized.x * (m_domain_max.x - m_domain_min.x) + m_domain_min.x, + normalized.y * (m_domain_max.y - m_domain_min.y) + m_domain_min.y, + normalized.z * (m_domain_max.z - m_domain_min.z) + m_domain_min.z); + + return result; +} + +template +inline point3D rtsFunction3D::getNearestIndex(double i, double j, double k) +{ + //this function returns the index of the voxel containing the specified parameter point + point3D normalized((i - m_domain_min.x)/(m_domain_max.x-m_domain_min.x), + (j - m_domain_min.y)/(m_domain_max.y-m_domain_min.y), + (k - m_domain_min.z)/(m_domain_max.z-m_domain_min.z)); + + point3D result((normalized.x - (1.0/(m_resolution.x*2.0)))*(double)m_resolution.x+0.5, + (normalized.y - (1.0/(m_resolution.y*2.0)))*(double)m_resolution.y+0.5, + (normalized.z - (1.0/(m_resolution.z*2.0)))*(double)m_resolution.z+0.5); + + return result; +} + +template +inline point3D rtsFunction3D::getFractionalIndex(double i, double j, double k) +{ + //this function returns the index of the voxel containing the specified parameter point + point3D normalized((i - m_domain_min.x)/(m_domain_max.x-m_domain_min.x), + (j - m_domain_min.y)/(m_domain_max.y-m_domain_min.y), + (k - m_domain_min.z)/(m_domain_max.z-m_domain_min.z)); + + point3D result((normalized.x - (1.0/(m_resolution.x*2.0)))*(double)m_resolution.x, + (normalized.y - (1.0/(m_resolution.y*2.0)))*(double)m_resolution.y, + (normalized.z - (1.0/(m_resolution.z*2.0)))*(double)m_resolution.z); + return result; +} + + +template +T* rtsFunction3D::GetBits() +{ + /*Returns bit data in lexocographical order (possibly for 3D texture mapping)*/ + return m_data; +} + +template +rtsFunction3D* rtsFunction3D::Resample(indextype newres_x, indextype newres_y, indextype newres_z) +{ + /*This function resamples the current function at the specified resolution. + No convolution is done for reducing he resolution. + */ + + rtsFunction3D* result = new rtsFunction3D(vector3D(newres_x, newres_y, newres_z), + m_boundary, m_domain_min, m_domain_max); + + //run through the entire resolution of the new function, sampling the current function + int x, y, z; + point3D parametric; + for(x = 0; xgetParameter(x, y, z); + (*result)(x, y, z) = ijk(parametric.x, parametric.y, parametric.z); + } + + return result; +} + +template +void rtsFunction3D::Scale(T new_min, T new_max) +{ + /*This function scales all values of the implicit function to within a specified range + */ + + //find the minimum and maximum values in this function + indextype data_size = m_resolution.x * m_resolution.y * m_resolution.z; + T min = m_data[0]; + T max = m_data[0]; + for(indextype i=0; i max) + max = m_data[i]; + } + + //scale all values to the specified range + T current_range = max - min; + T new_range = new_max - new_min; + for(indextype i=0; i +void rtsFunction3D::Crop(indextype x, indextype y, indextype z, + indextype size_x, indextype size_y, indextype size_z) +{ + /*This function crops the implicit function at the specified nodes + */ + //create a pointer for the new data + T* new_data = new T[size_x*size_y*size_z]; + + //blit from the old data to the new data + blit3D(m_data, + x, y, z, + m_resolution.x, m_resolution.y, m_resolution.z, + new_data, + 0, 0, 0, + size_x, size_y, size_z, + size_x, size_y, size_z); + + //change the shallow variables + vector3D new_resolution = vector3D(size_x, size_y, size_z); + vector3D voxel_size = getParameter(0,0,0) - getParameter(1,1,1); + point3D new_domain_min = getParameter(x, y, z) - 0.5*voxel_size; + point3D new_domain_max = getParameter(size_x-1, size_y - 1, size_z-1) + 0.5*voxel_size; + //copy new shallow variables + m_resolution = new_resolution; + m_domain_min = new_domain_min; + m_domain_max = new_domain_max; + + //copy data + delete m_data; + m_data = new_data; + +} + +template +void rtsFunction3D::Threshold(T min, T value) +{ + /*This function sets all values between min and max to value. + */ + int x, y, z; + T test_value; + for(x=0; x= min) + xyz(x, y, z) = value; + } +} + +template +void rtsFunction3D::Threshold(T min, T max, T value) +{ + /*This function sets all values between min and max to value. + */ + int x, y, z; + T test_value; + for(x=0; x= min && test_value <= max) + xyz(x, y, z) = value; + } +} + +template +void rtsFunction3D::Threshold(T min, T max, T inside, T outside) +{ + /*This function sets all values between min and max to value. + */ + int x, y, z; + T test_value; + for(x=0; x= min && test_value <= max) + xyz(x, y, z) = inside; + else + xyz(x, y, z) = outside; + } +} + +template +void rtsFunction3D::Insert(rtsFunction3D* source, indextype x, indextype y, indextype z) +{ + blit3D(source->m_data, 0, 0, 0, source->m_resolution.x, source->m_resolution.y, source->m_resolution.z, + m_data, x, y, z, m_resolution.x, m_resolution.y, m_resolution.z, + source->m_resolution.x, source->m_resolution.y, source->m_resolution.z); +} + + + + +template +void rtsFunction3D::Binary(T threshold, T true_value) +{ + /** + This function converts an implicit function into a binary or characteristic function describing the solid represented by the level + set at isovalue "threshold". All values below threshold are set to zero while all values above threshold are set to the specified + "true_value". In order to use this function, the data type T must be able to be set to 0. + **/ + int max_index = m_resolution.x * m_resolution.y * m_resolution.z; //find the size of the data array + int i; + for(i=0; i= threshold) + m_data[i] = true_value; + else + m_data[i] = 0; +} + + + +template +void rtsFunction3D::ClampMax(T max) +{ + int i; + int elements = m_resolution.x * m_resolution.y * m_resolution.z; + for(i=0; i max) + m_data[i] = max; +} + +template +void rtsFunction3D::ClampMin(T min) +{ + int i; + int elements = m_resolution.x * m_resolution.y * m_resolution.z; + for(i=0; i +T rtsFunction3D::getMin() +{ + int i; + int elements = m_resolution.x * m_resolution.y * m_resolution.z; + T current = m_data[0]; + for(i=1; i +T rtsFunction3D::getMax() +{ + int i; + int elements = m_resolution.x * m_resolution.y * m_resolution.z; + T current = m_data[0]; + for(i=1; i current) + current = m_data[i]; + return current; +} + + +template +void rtsFunction3D::toConsole() +{ + cout< +rtsFunction3D rtsFunction3D::Project2D() +{ + /** + This function projects the entire 3D function onto a 2D function along the z-axis. + **/ + rtsFunction3D result(m_resolution.x, m_resolution.y, 1); + result = 0; + + indextype x, y, z; + for(x = 0; x +#include +#include +#include +#include +#include + +#ifndef _USE_OLD_IOSTREAMS + +using namespace std; +#endif + +// maximum mumber of lines the output console should have + +static const WORD MAX_CONSOLE_LINES = 500; +//#ifdef _DEBUG + +void RedirectIOToConsole(int Xpos = 0, int Ypos = 0, int Width = 700, int Height = 400) +{ + int hConHandle; + long lStdHandle; + CONSOLE_SCREEN_BUFFER_INFO coninfo; + FILE *fp; + // allocate a console for this app + AllocConsole(); + // set the screen buffer to be big enough to let us scroll text + GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo); + coninfo.dwSize.Y = MAX_CONSOLE_LINES; + SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), + coninfo.dwSize); + // redirect unbuffered STDOUT to the console + lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE); + hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + fp = _fdopen( hConHandle, "w" ); + *stdout = *fp; + setvbuf( stdout, NULL, _IONBF, 0 ); + // redirect unbuffered STDIN to the console + lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE); + hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + fp = _fdopen( hConHandle, "r" ); + *stdin = *fp; + setvbuf( stdin, NULL, _IONBF, 0 ); + + // redirect unbuffered STDERR to the console + lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE); + hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + fp = _fdopen( hConHandle, "w" ); + *stderr = *fp; + setvbuf( stderr, NULL, _IONBF, 0 ); + + // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog + // point to console as well + ios::sync_with_stdio(); + //position + MoveWindow(GetConsoleWindow(), Xpos, Ypos, Width, Height, true); +} + +#else +void RedirectIOToConsole(int Xpos = 0, int Ypos = 0, int Width = 700, int Height = 400) +{ +} +#endif + +#endif + +/* End of File */ \ No newline at end of file diff --git a/rtsGraph.h b/rtsGraph.h new file mode 100755 index 0000000..f18efea --- /dev/null +++ b/rtsGraph.h @@ -0,0 +1,142 @@ +#ifndef RTS_GRAPH_H +#define RTS_GRAPH_H + +#include +#include + +using namespace std; + +template +class rtsGraph +{ + unsigned int current_id; +public: + class rtsGraphNode; + typedef typename list::iterator rtsGraphNodePtr; + + class rtsGraphNode + { + public: + list ConnectionList; + unsigned int ID; + T Data; + }; + + list NodeList; + + rtsGraphNodePtr addNode(T data) + { + //Adds a node to the graph. This node is unconnected by default. + + //create the new node + rtsGraphNode new_node; + //set the data to the data provided + new_node.Data = data; + //set the id + new_node.ID = current_id++; + + //add the node to the node list + NodeList.push_back(new_node); + rtsGraphNodePtr result = NodeList.end(); + result--; + return result; + } + bool cmpPtr(const rtsGraphNodePtr a, const rtsGraphNodePtr b) + { + return (*a).ID < (*b).ID; + } + + void addConnection(rtsGraphNodePtr n0, rtsGraphNodePtr n1) + { + //adds a connection between two nodes + //connect n0 to n1 + (*n0).ConnectionList.push_back(n1); + (*n1).ConnectionList.push_back(n0); + + } + + void removeNode(rtsGraphNodePtr n) + { + + typename list::iterator i; + typename list::iterator j; + typename list::iterator temp; + rtsGraphNodePtr m; + rtsGraphNodePtr k; + /*Remove all of the connections TO n*/ + + //for each node m connected to n + for(i = (*n).ConnectionList.begin(); i != (*n).ConnectionList.end(); i++) + { + m = (*i); + //for each node k connected to m + j = (*m).ConnectionList.begin(); + while(j != (*m).ConnectionList.end()) + { + k = (*j); + //if k is the same as n, remove it + if(k == n) + { + temp = j; + j++; + (*m).ConnectionList.erase(temp); + } + else + j++; + + } + } + + /*Add all connections to neighboring nodes*/ + + //for each node m connected to n + for(i = (*n).ConnectionList.begin(); i != (*n).ConnectionList.end(); i++) + { + m = (*i); + //for each node k connected to n + for(j = (*n).ConnectionList.begin(); j != (*n).ConnectionList.end(); j++) + { + k = (*j); + if(k != m) + (*m).ConnectionList.push_back(k); + + } + //(*m).ConnectionList.sort(&rtsGraph::cmpPtr); + //sort((*m).ConnectionList.begin(), (*m).ConnectionList.end(), rtsGraph::cmpPtr); + (*m).ConnectionList.unique(); + } + + + + + + + + } + + + void PrintGraph() + { + rtsGraphNodePtr i; + typename list::iterator c; + for(i = NodeList.begin(); i != NodeList.end(); i++) + { + cout<<(*i).Data<<": "; + for(c = (*i).ConnectionList.begin(); c != (*i).ConnectionList.end(); c++) + { + if(c != (*i).ConnectionList.begin()) + cout<<"--"; + cout<<(*(*c)).Data; + } + cout< +#include +#include + +using namespace std; +using namespace cimg_library; + + +///This file contains a series of functions useful for loading images into other structures. These function use the CImg header file. + +void rts_cimgLoadImage(rtsFunction3D& result, const char* filename) /// image(filename), visu(500,400,1,3,0); + + result = rtsFunction3D(image.width, image.height, 1); + unsigned int x, y; + for(x=0; x& result, int z, const char* filename) +{ + CImg image(result.DimX(), result.DimY()); + unsigned int x, y; + for(x=0; x& result, const char* filename, unsigned int min, unsigned int max, unsigned int color = 0) +{ + /** + This function loads a sequence of images into a 3D implicit function. The filename is passed using the '?' wild + card. The wild cards are then replaced with the given min through max values in order to construct the names + for the image files to be loaded. The files are then loaded and placed in sequential order along the z-axis + of the implicit function. + **/ + string sequence_name = filename; //turn the filename into a string + unsigned int wild_card_begin = sequence_name.find_first_of('?'); //find the start and end indices of the wild card + unsigned int wild_card_end = sequence_name.find_last_of('?'); + + unsigned int max_number_length = wild_card_end - wild_card_begin + 1; //find the maximum number of characters in the image number + unsigned int max_number = (unsigned int)pow((double)10, (double)max_number_length) - 1; //find the maximum possible number + + //make sure that the data is given correctly + if(max < min) return; + if(max > max_number) max = max_number; + + //create an array of file names + int num_images = max - min + 1; //compute the number of images + bool implicit_created = false; + for(int i=0; i image(file_name.c_str()); //load the frame + if(implicit_created == false) //create the implicit function for the first frame + { + result = rtsFunction3D(image.width, image.height, num_images); + implicit_created = true; + } + + //place the frame in the implicit function + unsigned int x, y; + for(x=0; x& result, const char* filename) +{ + string sequence_name = filename; //turn the filename into a string + unsigned int wild_card_begin = sequence_name.find_first_of('?'); //find the start and end indices of the wild card + unsigned int wild_card_end = sequence_name.find_last_of('?'); + + unsigned int max_number_length = wild_card_end - wild_card_begin + 1; //find the maximum number of characters in the image number + unsigned int max_number = (unsigned int)pow((double)10, (double)max_number_length) - 1; //find the maximum possible number + + //make sure that the data is given correctly + unsigned int max = result.DimZ(); + if(max > max_number) max = max_number; + + //save each individual file + int num_images = max; //compute the number of images + CImg image(result.DimX(), result.DimY()); //create an image for saving + for(int i=0; i source, unsigned int z) +{ + CImg image(source.DimX(), source.DimY()); + + int x, y; + for(x=0; x +#include +#include +#include +#include +using namespace std; + +typedef int indextype; + +///This class represents a 3D implicit function as a grid. It provides methods for accessing values, interpolation, and several utilities. + +template class rtsImplicit3D +{ +private: + //pointer to store the data + T* m_data; + //resolution of the data (x, y, z) dimensional extents + vector3D m_resolution; + T m_boundary; //boundary condition + point3D m_domain_min; //min and max range values (used for parametric access) + point3D m_domain_max; + vector3D m_voxel_size; + + //bit-blit function copies 3D data quickly from source to dest + void blit3D(const T* source, + indextype s_px, indextype s_py, indextype s_pz, + indextype s_sx, indextype s_sy, indextype s_sz, + T* dest, + indextype d_px, indextype d_py, indextype d_pz, + indextype d_sx, indextype d_sy, indextype d_sz, + indextype blit_size_x, indextype blit_size_y, indextype blit_size_z); + + void shallow_copy(const rtsImplicit3D source, rtsImplicit3D &dest); + inline point3D getParameter(indextype i); + + inline float isosurface_distance(point3D p0, point3D p1, T isovalue); + inline float manhattan_distance(rtsImplicit3D* function, point3D p, bool sdf = false); + void compute_distance_function_boundary(T isovalue, rtsImplicit3D* &result, rtsImplicit3D* &mask, bool sdf = false); + + +public: + //construct an implicit function with a size of 1 + rtsImplicit3D(); /// resolution, T boundary, point3D min_domain, point3D max_domain); + //full copy constructor, defines all variables + rtsImplicit3D(T* data, vector3D resolution, T boundary, point3D min_domain, point3D max_domain); + rtsImplicit3D(const rtsImplicit3D &original); //copy constructor + ~rtsImplicit3D(); //destructor + + //overloaded operators + rtsImplicit3D& operator=(const rtsImplicit3D& original); ///& operator=(const T constant); ///& operator*=(const T constant); ///& operator+=(const T constant); ///& operator-=(const T constant); ///& operator/=(const T constant); /// operator+(const T constant); /// operator-(const T constant); /// operator*(const T constant); /// operator/(const T constant); /// friend class rtsImplicit3D; + template operator rtsImplicit3D(); /// operator*(const T lhs, rtsImplicit3D rhs){return rhs*lhs;} /// operator+(const T lhs, rtsImplicit3D rhs){return rhs+lhs;} /// operator-(const T lhs, rtsImplicit3D rhs) /// result; + rhs.shallow_copy(rhs, result); //make a copy of all of the shallow variables and allocate memory + indextype size = rhs.m_resolution.x * rhs.m_resolution.y * rhs.m_resolution.z; + //iterate and subtract + for(indextype i=0; i operator/(const T lhs, rtsImplicit3D rhs); + + //loading/saving data to disk + void LoadRAW(indextype header_size, indextype data_x, indextype data_y, indextype data_z, const char* filename); /// getParameter(indextype x, indextype y, indextype z); + inline point3D getNearestIndex(double i, double j, double k); + inline point3D getFractionalIndex(double i, double j, double k); + inline point3D getNearestIndex(indextype i); + point3D getMinDomain(){return m_domain_min;} + point3D getMaxDomain(){return m_domain_max;} + vector> getEdgeNodes(T isovalue, bool protrusions = true); /// Project2D(); //* dt_grid, double factor, indextype x, indextype y, indextype z); + void Insert(rtsImplicit3D* source, indextype x, indextype y, indextype z); + + //data massaging + + void Scale(T min, T max); + void Crop(indextype x, indextype y, indextype z, indextype size_x, indextype size_y, indextype size_z); + void Binary(T threshold, T true_value); ///* Resample(indextype newres_x, indextype newres_y, indextype newres_z); + rtsImplicit3D* Isodistance_Manhattan(T isovalue, bool sdf = false); + rtsImplicit3D>* Gradient(); + rtsImplicit3D* EstimateAmbient(T threshold); + rtsImplicit3D* EstimateAttenuatedAmbient(T surface, T transparent, float attenuation); + + //implicit shapes + //(these functions create some basic implicit shapes just for fun) + void Sphere(double center_i, double center_j, double center_k, double radius, T in_value); + + //output functions + void toConsole(); + +}; + +template +void rtsImplicit3D::blit3D(const T* source, + indextype s_px, indextype s_py, indextype s_pz, + indextype s_sx, indextype s_sy, indextype s_sz, + T* dest, + indextype d_px, indextype d_py, indextype d_pz, + indextype d_sx, indextype d_sy, indextype d_sz, + indextype blit_size_x, indextype blit_size_y, indextype blit_size_z) +{ + indextype ps, pd; //stores the mapping for the source point to the dest point + //find the maximum points that can be blit to (in case source overlaps the edges of dest) + blit_size_x = min(blit_size_x, min(s_sx - s_px, d_sx - d_px)); + blit_size_y = min(blit_size_y, min(s_sy - s_py, d_sy - d_py)); + blit_size_z = min(blit_size_z, min(s_sz - s_pz, d_sz - d_pz)); + + indextype source_z_offset = s_sx * s_sy; + indextype dest_z_offset = d_sx * d_sy; + + indextype z,y; + for(z=0; z +void rtsImplicit3D::shallow_copy(const rtsImplicit3D source, rtsImplicit3D &dest) +{ + dest = rtsImplicit3D(source.m_resolution.x, source.m_resolution.y, source.m_resolution.z); + dest.m_boundary = source.m_boundary; + dest.m_domain_max = source.m_domain_max; + dest.m_domain_min = source.m_domain_max; + dest.m_voxel_size = source.m_voxel_size; +} + +template +rtsImplicit3D::rtsImplicit3D(vector3D resolution, T boundary, point3D domain_min, point3D domain_max) +{ + //This function creates an implicit function based on all of the shallow variables + m_resolution = resolution; + m_boundary = boundary; + m_domain_min = domain_min; + m_domain_max = domain_max; + m_voxel_size = domain_max - domain_min; + m_voxel_size.x /= m_resolution.x; + m_voxel_size.y /= m_resolution.y; + m_voxel_size.z /= m_resolution.z; + + //allocate the data + m_data = new T[m_resolution.x * m_resolution.y * m_resolution.z]; +} + +template +rtsImplicit3D::rtsImplicit3D(T* data, vector3D resolution, T boundary, point3D domain_min, point3D domain_max) +{ + //This function creates an implicit function based on ALL of the variables + m_resolution = resolution; + m_boundary = boundary; + m_domain_min = domain_min; + m_domain_max = domain_max; + m_voxel_size = domain_max - domain_min; + m_voxel_size.x /= m_resolution.x; + m_voxel_size.y /= m_resolution.y; + m_voxel_size.z /= m_resolution.z; + + //allocate the data + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + m_data = new T[size]; + memcpy(m_data, data, sizeof(T)*size); + //for(int i=0; i +rtsImplicit3D::rtsImplicit3D() +{ + m_resolution.x = 1; + m_resolution.y = 1; + m_resolution.z = 1; + m_data = new T[1]; + //m_boundary = 0; //initialize boundary condition + m_domain_min = point3D(0.0, 0.0, 0.0); //set range parameters + m_domain_max = point3D(1.0, 1.0, 1.0); + m_voxel_size = vector3D(1.0, 1.0, 1.0); +} + +template +rtsImplicit3D::rtsImplicit3D(indextype res_x, indextype res_y, indextype res_z) +{ + m_resolution.x = res_x; //set resolution vector + m_resolution.y = res_y; + m_resolution.z = res_z; + m_data = new T[res_x*res_y*res_z]; //allocate data + memset(&m_boundary, 0, sizeof(T)); //initialize boundary condition + m_domain_min = point3D(0.0, 0.0, 0.0); //set range parameters + m_domain_max = point3D(1.0, 1.0, 1.0); + + m_voxel_size = m_domain_max - m_domain_min; + m_voxel_size.x /= m_resolution.x; + m_voxel_size.y /= m_resolution.y; + m_voxel_size.z /= m_resolution.z; +} + +template +rtsImplicit3D::rtsImplicit3D(T* data, indextype res_x, indextype res_y, indextype res_z) +{ + m_resolution.x = res_x; //set resolution vector + m_resolution.y = res_y; + m_resolution.z = res_z; + m_data = new T[res_x*res_y*res_z]; //allocate data + //copy the sample data into the data array + indextype size = res_x*res_y*res_z; + for(indextype i=0; i(0.0, 0.0, 0.0); //set range parameters + m_domain_max = point3D(1.0, 1.0, 1.0); + + m_voxel_size = domain_max - domain_min; + m_voxel_size.x /= m_resolution.x; + m_voxel_size.y /= m_resolution.y; + m_voxel_size.z /= m_resolution.z; +} + +template +rtsImplicit3D::rtsImplicit3D(const rtsImplicit3D& original) +{ + //copy the shallow variables + m_resolution = original.m_resolution; + m_boundary = original.m_boundary; + m_domain_min = original.m_domain_min; + m_domain_max = original.m_domain_max; + m_voxel_size = original.m_voxel_size; + + //allocate space for the data + m_data = new T[m_resolution.x * m_resolution.y * m_resolution.z]; + //copy the data + blit3D(original.m_data, + 0, 0, 0, + m_resolution.x, m_resolution.y, m_resolution.z, + m_data, + 0, 0, 0, + m_resolution.x, m_resolution.y, m_resolution.z, + m_resolution.x, m_resolution.y, m_resolution.z); +} + +template +rtsImplicit3D::~rtsImplicit3D() +{ + delete m_data; +} + +template +typename rtsImplicit3D& rtsImplicit3D::operator=(const T rhs) +{ + indextype size = m_resolution.x*m_resolution.y*m_resolution.z; + for(int i=0; i +typename rtsImplicit3D& rtsImplicit3D::operator=(const rtsImplicit3D& rhs) +{ + //check for self-assignment + if(this == &rhs) + return *this; + + //deallocate memory + if(m_data != NULL) + delete m_data; + + //copy the shallow variables + m_resolution = rhs.m_resolution; + m_boundary = rhs.m_boundary; + m_domain_min = rhs.m_domain_min; + m_domain_max = rhs.m_domain_max; + m_voxel_size = rhs.m_voxel_size; + + //allocate and copy memory + m_data = new T[m_resolution.x * m_resolution.y * m_resolution.z]; + //copy the data + blit3D(rhs.m_data, + 0,0,0, + m_resolution.x, m_resolution.y, m_resolution.z, + m_data, + 0, 0, 0, + m_resolution.x, m_resolution.y, m_resolution.z, + m_resolution.x, m_resolution.y, m_resolution.z); + + //return the left hand side + return *this; +} + +template +inline T& rtsImplicit3D::operator ()(indextype x, indextype y, indextype z) +{ + return xyz(x, y, z); +} + +template +inline T rtsImplicit3D::operator()(double i, double j, double k) +{ + return ijk(i, j, k); +} + +template +rtsImplicit3D& rtsImplicit3D::operator *=(const T constant) +{ + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + for(indextype i = 0; i +rtsImplicit3D& rtsImplicit3D::operator +=(const T constant) +{ + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + for(indextype i = 0; i +rtsImplicit3D& rtsImplicit3D::operator -=(const T constant) +{ + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + for(indextype i = 0; i +rtsImplicit3D& rtsImplicit3D::operator /=(const T constant) +{ + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + for(indextype i = 0; i +const rtsImplicit3D rtsImplicit3D::operator *(const T constant) +{ + rtsImplicit3D result = (*this); + result *= constant; + + return result; +} + +template +const rtsImplicit3D rtsImplicit3D::operator +(const T constant) +{ + rtsImplicit3D result = (*this); + result += constant; + + return result; +} + +template +const rtsImplicit3D rtsImplicit3D::operator -(const T constant) +{ + rtsImplicit3D result = (*this); + result -= constant; + + return result; +} + +template +const rtsImplicit3D rtsImplicit3D::operator /(const T constant) +{ + rtsImplicit3D result = (*this); + result /= constant; + + return result; +} + +template +template +rtsImplicit3D::operator rtsImplicit3D() +{ + //cast one type to another + //create the data pointer from the current function + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + U* new_data = new U[size]; + for(int i=0; i cast_result(new_data, m_resolution, m_boundary, m_domain_min, m_domain_max); + + return cast_result; +} + +template +inline T& rtsImplicit3D::xyz(indextype x, indextype y, indextype z) +{ + if(x<0 || y<0 || z<0 || x>=m_resolution.x || y>=m_resolution.y || z>=m_resolution.z) + return m_boundary; + //return m_data[(z * m_resolution.x * m_resolution.y) + (y * m_resolution.x) + x]; + return m_data[x + m_resolution.x * (y + z * m_resolution.y)]; + +} + +template +inline point3D rtsImplicit3D::getNearestIndex(indextype i) +{ + point3D result; + result.z = i/(m_resolution.x*m_resolution.y); + indextype mod = i%(m_resolution.x*m_resolution.y); + result.y = mod/m_resolution.x; + result.x = mod%m_resolution.x; + + return result; + +} + +template +void rtsImplicit3D::LoadRAW(indextype header_size, indextype size_x, + indextype size_y, indextype size_z, const char *filename) +{ + //set the data size + m_resolution = vector3D(size_x, size_y, size_z); + //delete any previous data + if(m_data != NULL) + delete m_data; + + ifstream infile(filename, ios::in | ios::binary); + + //load the header + unsigned char* header = new unsigned char[header_size]; + infile.read((char*)header, header_size); + + //load the actual data + indextype size = m_resolution.x * m_resolution.y * m_resolution.z; + m_data = new T[size]; + infile.read((char*)m_data, size*sizeof(T)); + + //calculate min and maxes + infile.close(); +} + +template +void rtsImplicit3D::LoadVOL(const char *filename) +{ + ifstream infile(filename, ios::in | ios::binary); //create the files stream + if(!infile) + return; + + indextype size_x, size_y, size_z; //create variables to store the size of the data set + //load the dimensions of the data set + infile.read((char*)&size_x, sizeof(int)); //load the file header + infile.read((char*)&size_y, sizeof(int)); + infile.read((char*)&size_z, sizeof(int)); + + //close the file + infile.close(); + //load the raw data + LoadRAW(12, size_x, size_y, size_z, filename); +} + +template +void rtsImplicit3D::SaveVOL(const char *filename) +{ + ofstream outfile(filename, ios::out | ios::binary); //create the binary file stream + + //write the volume size to the file + vector3D vol_size = m_resolution; + outfile.write((char*)&vol_size.x, sizeof(int)); + outfile.write((char*)&vol_size.y, sizeof(int)); + outfile.write((char*)&vol_size.z, sizeof(int)); + + outfile.write((char*)m_data, sizeof(char)*vol_size.x*vol_size.y*vol_size.z); +} + +template +void rtsImplicit3D::SaveRAW(const char *filename) +{ + ofstream outfile(filename, ios::out | ios::binary); //create the binary file stream + + //write the volume data + outfile.write((char*)m_data, sizeof(T)*m_resolution.x*m_resolution.y*m_resolution.z); +} + +template +inline T rtsImplicit3D::ijk(double i, double j, double k) +{ + /*This function determines the value at the specified parametric points + defined by the m_domain_min and m_domain_max parameter values.*/ + + //if the parameter is outside the range, return the boundary value + if(im_domain_max.x || j>m_domain_max.y || k>m_domain_max.z) + return m_boundary; + + point3D index = getFractionalIndex(i, j, k); + + //cout< +void rtsImplicit3D::Parameterize(double x_min, double x_max, double y_min, double y_max, double z_min, double z_max) +{ + m_domain_min = point3D(x_min, y_min, z_min); + m_domain_max = point3D(x_max, y_max, z_max); + m_voxel_size = m_domain_max - m_domain_min; + m_voxel_size.x /= m_resolution.x; + m_voxel_size.y /= m_resolution.y; + m_voxel_size.z /= m_resolution.z; +} + +template +inline point3D rtsImplicit3D::getParameter(indextype x, indextype y, indextype z) +{ + //get the value between 0 and 1 + point3D normalized((double)x / (double)(m_resolution.x) + (1.0/(m_resolution.x*2.0)), + (double)y / (double)(m_resolution.y) + (1.0/(m_resolution.y*2.0)), + (double)z/(double)(m_resolution.z) + (1.0/(m_resolution.z*2.0))); + + point3D result(normalized.x * (m_domain_max.x - m_domain_min.x) + m_domain_min.x, + normalized.y * (m_domain_max.y - m_domain_min.y) + m_domain_min.y, + normalized.z * (m_domain_max.z - m_domain_min.z) + m_domain_min.z); + + return result; +} + +template +inline point3D rtsImplicit3D::getNearestIndex(double i, double j, double k) +{ + //this function returns the index of the voxel containing the specified parameter point + point3D normalized((i - m_domain_min.x)/(m_domain_max.x-m_domain_min.x), + (j - m_domain_min.y)/(m_domain_max.y-m_domain_min.y), + (k - m_domain_min.z)/(m_domain_max.z-m_domain_min.z)); + + point3D result((normalized.x - (1.0/(m_resolution.x*2.0)))*(double)m_resolution.x+0.5, + (normalized.y - (1.0/(m_resolution.y*2.0)))*(double)m_resolution.y+0.5, + (normalized.z - (1.0/(m_resolution.z*2.0)))*(double)m_resolution.z+0.5); + + return result; +} + +template +inline point3D rtsImplicit3D::getFractionalIndex(double i, double j, double k) +{ + //this function returns the index of the voxel containing the specified parameter point + point3D normalized((i - m_domain_min.x)/(m_domain_max.x-m_domain_min.x), + (j - m_domain_min.y)/(m_domain_max.y-m_domain_min.y), + (k - m_domain_min.z)/(m_domain_max.z-m_domain_min.z)); + + point3D result((normalized.x - (1.0/(m_resolution.x*2.0)))*(double)m_resolution.x, + (normalized.y - (1.0/(m_resolution.y*2.0)))*(double)m_resolution.y, + (normalized.z - (1.0/(m_resolution.z*2.0)))*(double)m_resolution.z); + return result; +} + + +template +T* rtsImplicit3D::GetBits() +{ + /*Returns bit data in lexocographical order (possibly for 3D texture mapping)*/ + return m_data; +} + +template +rtsImplicit3D* rtsImplicit3D::Resample(indextype newres_x, indextype newres_y, indextype newres_z) +{ + /*This function resamples the current function at the specified resolution. + No convolution is done for reducing he resolution. + */ + + rtsImplicit3D* result = new rtsImplicit3D(vector3D(newres_x, newres_y, newres_z), + m_boundary, m_domain_min, m_domain_max); + + //run through the entire resolution of the new function, sampling the current function + int x, y, z; + point3D parametric; + for(x = 0; xgetParameter(x, y, z); + (*result)(x, y, z) = ijk(parametric.x, parametric.y, parametric.z); + } + + return result; +} + +template +void rtsImplicit3D::Scale(T new_min, T new_max) +{ + /*This function scales all values of the implicit function to within a specified range + */ + + //find the minimum and maximum values in this function + indextype data_size = m_resolution.x * m_resolution.y * m_resolution.z; + T min = m_data[0]; + T max = m_data[0]; + for(indextype i=0; i max) + max = m_data[i]; + } + + //scale all values to the specified range + T current_range = max - min; + T new_range = new_max - new_min; + for(indextype i=0; i +void rtsImplicit3D::Crop(indextype x, indextype y, indextype z, + indextype size_x, indextype size_y, indextype size_z) +{ + /*This function crops the implicit function at the specified nodes + */ + //create a pointer for the new data + T* new_data = new T[size_x*size_y*size_z]; + + //blit from the old data to the new data + blit3D(m_data, + x, y, z, + m_resolution.x, m_resolution.y, m_resolution.z, + new_data, + 0, 0, 0, + size_x, size_y, size_z, + size_x, size_y, size_z); + + //change the shallow variables + vector3D new_resolution = vector3D(size_x, size_y, size_z); + vector3D voxel_size = getParameter(0,0,0) - getParameter(1,1,1); + point3D new_domain_min = getParameter(x, y, z) - 0.5*voxel_size; + point3D new_domain_max = getParameter(size_x-1, size_y - 1, size_z-1) + 0.5*voxel_size; + //copy new shallow variables + m_resolution = new_resolution; + m_domain_min = new_domain_min; + m_domain_max = new_domain_max; + + //copy data + delete m_data; + m_data = new_data; + +} + +template +void rtsImplicit3D::Threshold(T min, T value) +{ + /*This function sets all values between min and max to value. + */ + int x, y, z; + T test_value; + for(x=0; x= min) + xyz(x, y, z) = value; + } +} + +template +void rtsImplicit3D::Threshold(T min, T max, T value) +{ + /*This function sets all values between min and max to value. + */ + int x, y, z; + T test_value; + for(x=0; x= min && test_value <= max) + xyz(x, y, z) = value; + } +} + +template +void rtsImplicit3D::Threshold(T min, T max, T inside, T outside) +{ + /*This function sets all values between min and max to value. + */ + int x, y, z; + T test_value; + for(x=0; x= min && test_value <= max) + xyz(x, y, z) = inside; + else + xyz(x, y, z) = outside; + } +} + +template +void rtsImplicit3D::Insert(rtsDTGrid3D* dt_grid, double factor, indextype pos_x, indextype pos_y, indextype pos_z) +{ +/* This function copies a 3D DT-Grid into the implicit function at the specified position. +*/ + rtsDTGrid3D::iterator i; + indextype x, y, z; + for(i=dt_grid->begin(); i != dt_grid->end(); i.increment()) //for each node in the grid + { + x = pos_x + i.getX(); + y = pos_y + i.getY(); + z = pos_z + i.getZ(); + if(x >= 0 || x < m_resolution.x || + y >= 0 || y < m_resolution.y || + y >= 0 || y < m_resolution.z) + xyz(x, y, z) = max(i.value* factor, (double)xyz(x, y, z)); + } +} + +template +void rtsImplicit3D::Insert(rtsImplicit3D* source, indextype x, indextype y, indextype z) +{ + blit3D(source->m_data, 0, 0, 0, source->m_resolution.x, source->m_resolution.y, source->m_resolution.z, + m_data, x, y, z, m_resolution.x, m_resolution.y, m_resolution.z, + source->m_resolution.x, source->m_resolution.y, source->m_resolution.z); +} + + +template +inline float rtsImplicit3D::manhattan_distance(rtsImplicit3D* function, point3D point, bool sdf) +{ + /*This function updates the manhattan distance from a surface using the manhattan + distance of its neighboring points. + */ + indextype x, y, z; + x=point.x; y=point.y, z=point.z; + int sign = 1; + float result = DIST_MAX; + float near_value; //the value of the neighbor being considered + float possible_value; + if(x!=0) + { + near_value = (*function)(x-1, y, z); + if(!sdf) + result = min(result, near_value + (float)m_voxel_size.x); + else + { + if(near_value<0) sign = -1; else sign = 1; //determine if the value is inside or outside + possible_value = sign*(fabs(near_value) + m_voxel_size.x); + if(fabs(possible_value) < fabs(result)) + result = possible_value; + } + + } + if(x!=function->DimX()-1) + { + near_value = (*function)(x+1, y, z); + if(!sdf) + result = min(result, near_value + (float)m_voxel_size.x); + else + { + if(near_value<0) sign = -1; else sign = 1; //determine if the value is inside or outside + possible_value = sign*(fabs(near_value) + m_voxel_size.x); + if(fabs(possible_value) < fabs(result)) + result = possible_value; + } + } + if(y!=0) + { + near_value = (*function)(x, y-1, z); + if(!sdf) + result = min(result, near_value + (float)m_voxel_size.y); + else + { + if(near_value<0) sign = -1; else sign = 1; //determine if the value is inside or outside + possible_value = sign*(fabs(near_value) + m_voxel_size.y); + if(fabs(possible_value) < fabs(result)) + result = possible_value; + } + } + if(y!=function->DimY()-1) + { + near_value = (*function)(x, y+1, z); + if(!sdf) + result = min(result, near_value + (float)m_voxel_size.y); + else + { + if(near_value<0) sign = -1; else sign = 1; //determine if the value is inside or outside + possible_value = sign*(fabs(near_value) + m_voxel_size.y); + if(fabs(possible_value) < fabs(result)) + result = possible_value; + } + } + if(z!=0) + { + near_value = (*function)(x, y, z-1); + if(!sdf) + result = min(result, near_value + (float)m_voxel_size.z); + else + { + if(near_value<0) sign = -1; else sign = 1; //determine if the value is inside or outside + possible_value = sign*(fabs(near_value) + m_voxel_size.z); + if(fabs(possible_value) < fabs(result)) + result = possible_value; + } + } + if(z!=function->DimZ()-1) + { + near_value = (*function)(x, y, z+1); + if(!sdf) + result = min(result, near_value + (float)m_voxel_size.z); + else + { + if(near_value<0) sign = -1; else sign = 1; //determine if the value is inside or outside + possible_value = sign*(fabs(near_value) + m_voxel_size.z); + if(fabs(possible_value) < fabs(result)) + result = possible_value; + } + } + return result; +} + +template +inline float rtsImplicit3D::isosurface_distance(point3D p0, point3D p1, T isovalue) +{ + /*This function computes the distance from p0 to the surface, given two points p0 and p1 + on either side of the surface. isovalue specifies + the value at the surface. Right now, this function returns a float. I'll have to think + of something better to do in the future. + */ + + //compute the normalized position of the surface between p0 and p1 + float val0 = ijk(p0.x, p0.y, p0.z); + float val1 = ijk(p1.x, p1.y, p1.z); + float isovalue_norm_pos = (isovalue - val0) / (val1 - val0); + //compute the actual position of the surface + point3D s_pos = p0 + isovalue_norm_pos * (p1 - p0); + //compute the distance from p0 to the surface + float result = (s_pos - p0).Length(); + //cout<<"distance: "< +void rtsImplicit3D::compute_distance_function_boundary(T isovalue, + rtsImplicit3D* &result, + rtsImplicit3D* &mask, bool sdf) +{ + /*This function creates an initial signed distance function from a threshold image. + All voxels adjacent to the surface specified by the threshold are initialized with a + distance value. Low values are inside, high values are outside. + */ + //current and neighboring voxel flags (false = inside, true = outside) + bool c, x_p, x_n, y_p, y_n, z_p, z_n; + float d_xp, d_xn, d_yp, d_yn, d_zp, d_zn; + float in_out = 1; + + //boundary condition function and the mask + result = new rtsImplicit3D(m_resolution.x, m_resolution.y, m_resolution.z); + //get the parameterization + result->Parameterize(m_domain_min.x, m_domain_max.x, m_domain_min.y, m_domain_max.y, m_domain_min.z, m_domain_max.z); + (*result) = DIST_MAX; + result->setBoundary(DIST_MAX); + //create a mask + mask = new rtsImplicit3D(m_resolution.x, m_resolution.y, m_resolution.z); + (*mask) = false; + + cout<<"done making boundary condition function"<= m_resolution.x) x_p = c; + else if(xyz(x+1, y, z) < isovalue) x_p = false; + if(y-1 < 0) y_n = c; //Y + else if(xyz(x, y-1, z) < isovalue) y_n = false; + if(y+1 >= m_resolution.y) y_p = c; + else if(xyz(x, y+1, z) < isovalue) y_p = false; + if(z-1 < 0) z_n = c; //Z + else if(xyz(x, y, z-1) < isovalue) z_n = false; + if(z+1 >= m_resolution.z) z_p = c; + else if(xyz(x, y, z+1) < isovalue) z_p = false; + + //set the distance from the isosurface + if(c == false && sdf) + in_out = -1.0; + if(x_n != c) + (*result)(x, y, z) = min((*result)(x,y,z), + isosurface_distance(getParameter(x, y, z), + getParameter(x-1, y, z), + isovalue) * in_out); + if(x_p != c) + (*result)(x, y, z) = min((*result)(x,y,z), + isosurface_distance(getParameter(x, y, z), + getParameter(x+1, y, z), + isovalue) * in_out); + if(y_n != c) + (*result)(x, y, z) = min((*result)(x,y,z), + isosurface_distance(getParameter(x, y, z), + getParameter(x, y-1, z), + isovalue) * in_out); + if(y_p != c) + (*result)(x, y, z) = min((*result)(x,y,z), + isosurface_distance(getParameter(x, y, z), + getParameter(x, y+1, z), + isovalue) * in_out); + if(z_n != c) + (*result)(x, y, z) = min((*result)(x,y,z), + isosurface_distance(getParameter(x, y, z-1), + getParameter(x, y, z), + isovalue) * in_out); + if(z_p != c) + (*result)(x, y, z) = min((*result)(x,y,z), + isosurface_distance(getParameter(x, y, z), + getParameter(x, y, z+1), + isovalue) * in_out); + + //set the mask to 1 if the voxel is on an edge node + if(x_n != c || x_p != c || y_n != c || y_p != c || z_n != c || z_p != c) + (*mask)(x, y, z) = true; + } + + + //if a line between the two voxels crosses the surface + //find the distance between the voxel center and the surface + + + cout<<"done computing boundary conditions"< +rtsImplicit3D* rtsImplicit3D::EstimateAmbient(T threshold) +{ + rtsImplicit3D* result = new rtsImplicit3D(m_resolution.x, m_resolution.y, m_resolution.z); //create a new implicit function + (*result) = 0.0f; + rtsImplicit3D* temp = new rtsImplicit3D(m_resolution.x, m_resolution.y, m_resolution.z); //temp buffer for current lighting iteration + (*temp) = 0.0f; + temp->setBoundary(1.0); + + cout<<"first iteration..."< 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; z--) + { + ambient = 0.0; + if(xyz(x-1, y, z) < threshold) + ambient += (*temp)(x-1, y, z); + if(xyz(x, y-1, z) < threshold) + ambient += (*temp)(x, y-1, z); + if(xyz(x, y, z+1) < threshold) + ambient += (*temp)(x, y, z+1); + + (*temp)(x, y, z) += ambient/3.0; + (*result)(x, y, z) += ambient/3.0; + if(ambient > 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; y--) + for(z=0; z 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; y--) + for(z=m_resolution.z-1; z>=0; z--) + { + ambient = 0.0; + if(xyz(x-1, y, z) < threshold) + ambient += (*temp)(x-1, y, z); + if(xyz(x, y+1, z) < threshold) + ambient += (*temp)(x, y+1, z); + if(xyz(x, y, z+1) < threshold) + ambient += (*temp)(x, y, z+1); + + (*temp)(x, y, z) += ambient/3.0; + (*result)(x, y, z) += ambient/3.0; + if(ambient > 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; x--) + for(y=0; y 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; x--) + for(y=0; y=0; z--) + { + ambient = 0.0; + if(xyz(x+1, y, z) < threshold) + ambient += (*temp)(x+1, y, z); + if(xyz(x, y-1, z) < threshold) + ambient += (*temp)(x, y-1, z); + if(xyz(x, y, z+1) < threshold) + ambient += (*temp)(x, y, z+1); + + (*temp)(x, y, z) += ambient/3.0; + (*result)(x, y, z) += ambient/3.0; + if(ambient > 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; x--) + for(y=m_resolution.y-1; y>=0; y--) + for(z=0; z 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; x--) + for(y=m_resolution.y-1; y>=0; y--) + for(z=m_resolution.z-1; z>=0; z--) + { + ambient = 0.0; + if(xyz(x+1, y, z) < threshold) + ambient += (*temp)(x+1, y, z); + if(xyz(x, y+1, z) < threshold) + ambient += (*temp)(x, y+1, z); + if(xyz(x, y, z+1) < threshold) + ambient += (*temp)(x, y, z+1); + + (*temp)(x, y, z) += ambient/3.0; + (*result)(x, y, z) += ambient/3.0; + if(ambient > 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."< +rtsImplicit3D* rtsImplicit3D::EstimateAttenuatedAmbient(T threshold, T transparent, float attenuation) +{ + rtsImplicit3D* result = new rtsImplicit3D(m_resolution.x, m_resolution.y, m_resolution.z); //create a new implicit function + (*result) = 0.0f; + rtsImplicit3D* temp = new rtsImplicit3D(m_resolution.x, m_resolution.y, m_resolution.z); //temp buffer for current lighting iteration + (*temp) = 0.0f; + temp->setBoundary(1.0); + + cout<<"first iteration..."< 3.0) + // cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; z--) + { + ambient = 0.0; + if(xyz(x-1, y, z) < threshold) + ambient += (*temp)(x-1, y, z)*(1.0 - (xyz(x-1, y, z)/255.0)*attenuation); + if(xyz(x, y-1, z) < threshold) + ambient += (*temp)(x, y-1, z)*(1.0 - (xyz(x, y-1, z)/255.0)*attenuation); + if(xyz(x, y, z+1) < threshold) + ambient += (*temp)(x, y, z+1)*(1.0 - (xyz(x, y, z+1)/255.0)*attenuation); + + (*temp)(x, y, z) += ambient/3.0; + (*result)(x, y, z) += ambient/3.0; + if(ambient > 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; y--) + for(z=0; z 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; y--) + for(z=m_resolution.z-1; z>=0; z--) + { + ambient = 0.0; + if(xyz(x-1, y, z) < threshold) + ambient += (*temp)(x-1, y, z)*(1.0 - (xyz(x-1, y, z)/255.0)*attenuation); + if(xyz(x, y+1, z) < threshold) + ambient += (*temp)(x, y+1, z)*(1.0 - (xyz(x, y+1, z)/255.0)*attenuation); + if(xyz(x, y, z+1) < threshold) + ambient += (*temp)(x, y, z+1)*(1.0 - (xyz(x, y, z+1)/255.0)*attenuation); + + (*temp)(x, y, z) += ambient/3.0; + (*result)(x, y, z) += ambient/3.0; + if(ambient > 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; x--) + for(y=0; y 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; x--) + for(y=0; y=0; z--) + { + ambient = 0.0; + if(xyz(x+1, y, z) < threshold) + ambient += (*temp)(x+1, y, z)*(1.0 - (xyz(x+1, y, z)/255.0)*attenuation); + if(xyz(x, y-1, z) < threshold) + ambient += (*temp)(x, y-1, z)*(1.0 - (xyz(x, y-1, z)/255.0)*attenuation); + if(xyz(x, y, z+1) < threshold) + ambient += (*temp)(x, y, z+1)*(1.0 - (xyz(x, y, z+1)/255.0)*attenuation); + + (*temp)(x, y, z) += ambient/3.0; + (*result)(x, y, z) += ambient/3.0; + if(ambient > 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; x--) + for(y=m_resolution.y-1; y>=0; y--) + for(z=0; z 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."<=0; x--) + for(y=m_resolution.y-1; y>=0; y--) + for(z=m_resolution.z-1; z>=0; z--) + { + ambient = 0.0; + if(xyz(x+1, y, z) < threshold) + ambient += (*temp)(x+1, y, z)*(1.0 - (xyz(x+1, y, z)/255.0)*attenuation); + if(xyz(x, y+1, z) < threshold) + ambient += (*temp)(x, y+1, z)*(1.0 - (xyz(x, y+1, z)/255.0)*attenuation); + if(xyz(x, y, z+1) < threshold) + ambient += (*temp)(x, y, z+1)*(1.0 - (xyz(x, y, z+1)/255.0)*attenuation); + + (*temp)(x, y, z) += ambient/3.0; + (*result)(x, y, z) += ambient/3.0; + if(ambient > 3.0) + cout<<"error"<setBoundary(1.0); + cout<<"done."< +rtsImplicit3D* rtsImplicit3D::Isodistance_Manhattan(T isovalue, bool sdf) +{ + rtsImplicit3D* function; + rtsImplicit3D* mask; + compute_distance_function_boundary(isovalue, function, mask, sdf); + + //compute the manhattan distance for the entire function + //use fast sweeping to compute the manhattan distance + //0:X 0:Y 0:Z + cout<<"first iteration..."<(x, y, z), sdf); + cout<<"done."<=0; z--) + //if the current point is not a boundary value + if(!(*mask)(x, y, z)) + (*function)(x,y,z) = manhattan_distance(function, point3D(x, y, z), sdf); + cout<<"done."<=0; y--) + for(z=0; z(x, y, z), sdf); + cout<<"done."<=0; y--) + for(z=m_resolution.z-1; z>=0; z--) + //if the current point is not a boundary value + if(!(*mask)(x, y, z)) + (*function)(x,y,z) = manhattan_distance(function, point3D(x, y, z), sdf); + cout<<"done."<=0; x--) + for(y=0; y(x, y, z), sdf); + cout<<"done."<=0; x--) + for(y=0; y=0; z--) + //if the current point is not a boundary value + if(!(*mask)(x, y, z)) + (*function)(x,y,z) = manhattan_distance(function, point3D(x, y, z), sdf); + cout<<"done."<=0; x--) + for(y=m_resolution.y-1; y>=0; y--) + for(z=0; z(x, y, z), sdf); + cout<<"done."<=0; x--) + for(y=m_resolution.y-1; y>=0; y--) + for(z=m_resolution.z-1; z>=0; z--) + //if the current point is not a boundary value + if(!(*mask)(x, y, z)) + (*function)(x,y,z) = manhattan_distance(function, point3D(x, y, z), sdf); + cout<<"done."< +rtsImplicit3D>* rtsImplicit3D::Gradient() +{ + int x, y, z; + rtsImplicit3D>* result = new rtsImplicit3D>(m_resolution.x, m_resolution.y, m_resolution.z); + for(x=0; xxyz(x, y, z).x = xyz(x-1, y, z) - xyz(x, y, z); + result->xyz(x, y, z).y = xyz(x, y-1, z) - xyz(x, y, z); + result->xyz(x, y, z).z = xyz(x, y, z-1) - xyz(x, y, z); + } + return result; +} + + +template +int rtsImplicit3D::Neighbors26(indextype x, indextype y, indextype z, T isovalue) +{ + int neighbors = 0; + int u,v,w; + + for(u=-1; u<=1; u++) + for(v=-1; v<=1; v++) + for(w=-1; w<=1; w++) + if(xyz(x+u, y+v, z+w) >= isovalue) + neighbors++; + if(xyz(x, y, z) > isovalue) + neighbors--; + + return neighbors; +} + +template +unsigned int rtsImplicit3D::Neighbors6(indextype x, indextype y, indextype z, T threshold) +{ + + unsigned int neighbors = 0; + if(xyz(x+1, y, z) >= threshold) + neighbors++; + if(xyz(x-1, y, z) >= threshold) + neighbors++; + if(xyz(x, y+1, z) >= threshold) + neighbors++; + if(xyz(x, y-1, z) >= threshold) + neighbors++; + if(xyz(x, y, z+1) >= threshold) + neighbors++; + if(xyz(x, y, z-1) >= threshold) + neighbors++; + + return neighbors; +} + +template +bool rtsImplicit3D::TestTopology(T isovalue, unsigned int x, unsigned int y, unsigned int z) +{ + if(xyz(x,y,z) < isovalue) + return false; + //This function returns true if a voxel is necessary, otherwise it returns false + unsigned int neighbors = Neighbors(x, y, z, isovalue); + + if(neighbors == 3) + return false; + if(neighbors == 0 || neighbors == 1 || neighbors == 4) + return true; + if(neighbors == 2) + { + if(xyz(x-1, y, z) >= isovalue && xyz(x+1, y, z) >= isovalue) + return true; + if(xyz(x, y-1, z) >= isovalue && xyz(x, y+1, z) >= isovalue) + return true; + return false; + } + +} + +template +void rtsImplicit3D::FloodFill6(indextype x, indextype y, indextype z, T target_value) +{ + T old_value = xyz(x, y, z); //find the old value (the value being flood-filled) + if(target_value == old_value) //if the target value is the same as the old value, nothing to do + return; + + queue> Q; //create a queue for neighboring points + point3D current(x, y, z); //start with the current point + xyz(current.x, current.y, current.z) = target_value; + point3D next; + Q.push(current); + indextype u, v, w; + + while(!Q.empty()) //continue until the queue is empty + { + current = Q.front(); //get the first element from the queue + Q.pop(); + + if(current.x != m_resolution.x - 1) + if(xyz(current.x + 1, current.y, current.z) == old_value) + { + xyz(current.x + 1, current.y, current.z) = target_value; + Q.push(point3D(current.x + 1, current.y, current.z)); + } + if(current.x != 0) + if(xyz(current.x - 1, current.y, current.z) == old_value) + { + xyz(current.x - 1, current.y, current.z) = target_value; + Q.push(point3D(current.x - 1, current.y, current.z)); + } + if(current.y != m_resolution.y - 1) + if(xyz(current.x, current.y +1, current.z) == old_value) + { + xyz(current.x, current.y+1, current.z) = target_value; + Q.push(point3D(current.x, current.y+1, current.z)); + } + if(current.y != 0) + if(xyz(current.x, current.y-1, current.z) == old_value) + { + xyz(current.x, current.y-1, current.z) = target_value; + Q.push(point3D(current.x, current.y-1, current.z)); + } + if(current.z != m_resolution.z - 1) + if(xyz(current.x, current.y, current.z+1) == old_value) + { + xyz(current.x, current.y, current.z+1) = target_value; + Q.push(point3D(current.x, current.y, current.z+1)); + } + if(current.z != 0) + if(xyz(current.x, current.y, current.z-1) == old_value) + { + xyz(current.x, current.y, current.z-1) = target_value; + Q.push(point3D(current.x, current.y, current.z-1)); + } + + } + +} + +template +void rtsImplicit3D::FloodFill26(int x, int y, int z, T target_value) +{ + T old_value = xyz(x, y, z); + if(target_value == old_value) + return; + + queue> Q; + point3D current(x, y, z); + point3D next; + Q.push(current); + indextype u, v, w; + while(!Q.empty()) + { + current = Q.front(); + if(xyz(current.x, current.y, current.z) == old_value) + xyz(current.x, current.y, current.z) = target_value; + Q.pop(); + for(u=-1; u<=1; u++) + for(v=-1; v<=1; v++) + for(w=-1; w<=1; w++) + { + next.x = current.x + u; + next.y = current.y + v; + next.z = current.z + w; + + if(next.x >= 0 && next.x < m_resolution.x && + next.y >= 0 && next.y < m_resolution.y && + next.z >= 0 && next.z < m_resolution.z && + xyz(next.x, next.y, next.z) == old_value) + { + xyz(next.x, next.y, next.z) = target_value; + Q.push(next); + } + } + } + + +} + +template +void rtsImplicit3D::Binary(T threshold, T true_value) +{ + /** + This function converts an implicit function into a binary or characteristic function describing the solid represented by the level + set at isovalue "threshold". All values below threshold are set to zero while all values above threshold are set to the specified + "true_value". In order to use this function, the data type T must be able to be set to 0. + **/ + int max_index = m_resolution.x * m_resolution.y * m_resolution.z; //find the size of the data array + int i; + for(i=0; i= threshold) + m_data[i] = true_value; + else + m_data[i] = 0; +} + +template +vector> rtsImplicit3D::getEdgeNodes(T isovalue, bool protrusions = true) +{ + vector> result; + indextype x, y, z; + int neighbors; + for(x=0; x= isovalue) + { + neighbors = Neighbors26(x, y, z, isovalue); + if(protrusions == false && neighbors < 1) + continue; + if(neighbors < 26) + result.push_back(point3D(x, y, z)); + } + } + + return result; + +} + +template +unsigned int rtsImplicit3D::BackgroundComponents6(indextype x, indextype y, indextype z, T threshold, int n = 18) +{ + /** + This function computes the number of 6-connected background components in the local region of (x, y, z). + This computation is performed by testing all 6 possible voxels that can connect to the specified node. If + a background node is found, the entire background component associated with that node is filled and the counter + is incremented by 1. The value n specifies the connectivity domain for the flood fill. + The definition of background components is that specified by He, Kischell, Rioult and Holmes. + **/ + + //see if there is at least one BG component + if(Neighbors6(x, y, z, threshold) == 6) + return 0; + + + //retrieve the local region of the function + rtsImplicit3D local(3, 3, 3); + point3D corner(x-1, y-1, z-1); + indextype u, v, w; + for(u=0; u<3; u++) + for(v=0; v<3; v++) + for(w=0; w<3; w++) + local(u, v, w) = xyz(corner.x + u, corner.y + v, corner.z + w); + + //threshold the background to find inside/outside points + local.Binary(threshold, 1); + //fill points that are not in the connectivity domain + if(n == 18) + { + local(0, 0, 0) = 1; + local(0, 0, 2) = 1; + local(0, 2, 0) = 1; + local(0, 2, 2) = 1; + local(2, 0, 0) = 1; + local(2, 0, 2) = 1; + local(2, 2, 0) = 1; + local(2, 2, 2) = 1; + } + //local.toConsole(); + + //search all 6 possible connected points. If a background node is found, fill the component + unsigned int components = 0; + if(local(0, 1, 1) == 0) + { + components++; + local.FloodFill6(0, 1, 1, 1); + } + if(local(2, 1, 1) == 0) + { + components++; + local.FloodFill6(2, 1, 1, 1); + } + if(local(1, 0, 1) == 0) + { + components++; + local.FloodFill6(1, 0, 1, 1); + } + if(local(1, 2, 1) == 0) + { + components++; + local.FloodFill6(1, 2, 1, 1); + } + if(local(1, 1, 0) == 0) + { + components++; + local.FloodFill6(1, 1, 0, 1); + } + if(local(1, 1, 2) == 0) + { + components++; + local.FloodFill6(1, 1, 2, 1); + } + + return components; +} + +template +rtsImplicit3D rtsImplicit3D::Project2D() +{ + /** + This function projects the entire 3D function onto a 2D function along the z-axis. + **/ + rtsImplicit3D result(m_resolution.x, m_resolution.y, 1); + result = 0; + + indextype x, y, z; + for(x = 0; x +void rtsImplicit3D::Erode(T isovalue, T fill_value) +{ + vector> border_nodes; //get the border nodes for the image + indextype x, y, z; + int condition; + for(x=0; x= isovalue && BackgroundComponents6(x, y, z, isovalue) == 1) + { + condition = 0; + //now find the border pairs. A border point must meet two of the following conditions to be a border pair. + //south border: s(p) is background + if(xyz(x, y-1, z) < isovalue) + condition++; + //north border: n(p) is background, s(p) and s(s(p)) are foreground + if(xyz(x, y+1, z) < isovalue && xyz(x, y-1, z) >= isovalue && xyz(x, y-2, z) >= isovalue) + condition++; + //west border: w(p) is background + if(xyz(x-1, y, z) < isovalue) + condition++; + //east border: e(p) is background, w(p) and w(w(p)) are foreground + if(xyz(x+1, y, z) < isovalue && xyz(x-1, y, z) >= isovalue && xyz(x-2, y, z) >= isovalue) + condition++; + //up border: u(p) is background + if(xyz(x, y, z-1) < isovalue) + condition++; + //down border: d(p) is background, u(p) and u(u(p)) are foreground + if(xyz(x, y, z+1) < isovalue && xyz(x, y, z-1) >= isovalue && xyz(x, y, z-2) >= isovalue) + condition++; + + if(condition > 1) + border_nodes.push_back(point3D(x, y, z)); + } + cout<<"Number of border nodes: "<>::iterator i; + for(i=border_nodes.begin(); i!= border_nodes.end(); i++) + xyz((*i).x, (*i).y, (*i).z) = fill_value; + + +} + +template +void rtsImplicit3D::ClampMax(T max) +{ + int i; + int elements = m_resolution.x * m_resolution.y * m_resolution.z; + for(i=0; i max) + m_data[i] = max; +} + +template +void rtsImplicit3D::ClampMin(T min) +{ + int i; + int elements = m_resolution.x * m_resolution.y * m_resolution.z; + for(i=0; i +void rtsImplicit3D::ClampMin(T min, T value) +{ + int i; + int elements = m_resolution.x * m_resolution.y * m_resolution.z; + for(i=0; i +void rtsImplicit3D::MedianFilter(int dist_x, int dist_y, int dist_z, double factor = 0.5) +{ + rtsImplicit3D result = (*this); + indextype x, y, z; + indextype min_x, min_y, min_z; + indextype max_x, max_y, max_z; + indextype u, v, w; + vector region; + for(x=0; x +unsigned int rtsImplicit3D::Thin(T isovalue) +{ + /** + This function computes the skeleton of an isosurface embedded in the implicit function and + described by the "isovalue" parameter. + **/ + + vector> border_nodes; //get the border nodes for the image + indextype x, y, z; + int condition; + for(x=0; x= isovalue && BackgroundComponents6(x, y, z, isovalue) == 1 && Neighbors26(x, y, z, isovalue) != 1) + { + condition = 0; + //now find the border pairs. A border point must meet two of the following conditions to be a border pair. + //south border: s(p) is background + if(xyz(x, y-1, z) < isovalue) + condition++; + //north border: n(p) is background, s(p) and s(s(p)) are foreground + if(xyz(x, y+1, z) < isovalue && xyz(x, y-1, z) >= isovalue && xyz(x, y-2, z) >= isovalue) + condition++; + //west border: w(p) is background + if(xyz(x-1, y, z) < isovalue) + condition++; + //east border: e(p) is background, w(p) and w(w(p)) are foreground + if(xyz(x+1, y, z) < isovalue && xyz(x-1, y, z) >= isovalue && xyz(x-2, y, z) >= isovalue) + condition++; + //up border: u(p) is background + if(xyz(x, y, z-1) < isovalue) + condition++; + //down border: d(p) is background, u(p) and u(u(p)) are foreground + if(xyz(x, y, z+1) < isovalue && xyz(x, y, z-1) >= isovalue && xyz(x, y, z-2) >= isovalue) + condition++; + + if(condition > 1) + border_nodes.push_back(point3D(x, y, z)); + } + cout<<"Number of border nodes: "< local(3, 3, 3); //store the region local to the current voxel + int nodes_before, nodes_after; //number of neighboring nodes before and after the filling operation + point3D fill_start; + vector>::iterator i; + + /* + Here we determine if a point can be removed by looking at the number of foreground connected + components in the local region. If there is more than one connected component + */ + unsigned int removed = 0; + for(i=border_nodes.begin(); i= isovalue && local(1, 0, 0) >= isovalue && local(1, 2, 0) >= isovalue && local(2, 1, 0) >= isovalue) + // continue; + local(1, 1, 1) = 0; //remove the center voxel + local.Binary(isovalue, 1); + nodes_before = local.Neighbors26(1, 1, 1, 1); + //if(nodes_before == 1) //prevent reducing ends + // continue; + + //find an interior voxel to fill + for(x=0; x<3; x++) + for(y=0; y<3; y++) + for(z=0; z<3; z++) + if(local(x, y, z) > 0) + fill_start = point3D(x, y, z); + + //fill the local region + local.FloodFill26(fill_start.x, fill_start.y, fill_start.z, 2); + //get the number of filled neighbors + nodes_after = local.Neighbors26(1, 1, 1, 2); + if(nodes_after == nodes_before) + { + xyz((*i).x, (*i).y, (*i).z) = 0; + removed++; + //cout<<"removed"<>c;*/ + //} + } + return removed; +} + +/*Shape functions*/ +/*These functions create implicit shapes in the function. +Generally, the shape is based on the parameterization.*/ +template +void rtsImplicit3D::Sphere(double center_i, double center_j, double center_k, double radius, T in_value) +{ + point3D center(center_i, center_j, center_k); + //for each point in the function + indextype x, y, z; + double radius_squared = radius*radius; + vector3D point_to_point; + point3D result; + double distance_squared; + + for(x=0; x +void rtsImplicit3D::toConsole() +{ + cout< +#include "rtsVector3d.h" +#include "rtsPoint3d.h" +#include "rtsMatrix4x4.h" \ No newline at end of file diff --git a/rtsMath.cpp b/rtsMath.cpp new file mode 100755 index 0000000..a8d14e9 --- /dev/null +++ b/rtsMath.cpp @@ -0,0 +1,757 @@ +/*These files contain basic structures used frequently in the program and in computer +graphics in general. For more information, see the header file. + +-David Mayerich, 8/20/05*/ + +#include "rtsMath.h" + +//#include + +//using namespace std; + + + +point3D::point3D() +{ + x=0; y=0; z=0; +} + +point3D::point3D(double newx, double newy, double newz) +{ + x=newx; y=newy; z=newz; +} + +point3D point3D::operator +(vector3D param) +{ + point3D result; + result.x=x+param.x; + result.y=y+param.y; + result.z=z+param.z; + + return result; +} + +point3D point3D::operator -(vector3D param) +{ + point3D result; + result.x=x-param.x; + result.y=y-param.y; + result.z=z-param.z; + + return result; +} + +vector3D point3D::operator -(point3D param) +{ + vector3D result; + result.x=x-param.x; + result.y=y-param.y; + result.z=z-param.z; + + return result; +} + +void point3D::print() +{ + cout< m_x1) + return 0.0f; + if(y < m_y0 || y > m_y1) + return 0.0f; + + float x_size = m_x1 - m_x0; + float y_size = m_y1 - m_y0; + float scaled_x = (x-m_x0)/x_size; + float scaled_y = (y-m_y0)/y_size; + int x_index = scaled_x * m_x_resolution; + int y_index = scaled_y * m_y_resolution; + return m_values[y_index * m_x_resolution + x_index]; +} + +float* function2D::getBits() +{ + return m_values; +} + +void function2D::setBits(unsigned char* bits) +{ + //copy the given bits to the current function + //the member m_values can't just be set to bits because the datatypes may be different + for(int i=0; i m_values[current_max_index]) + current_max_index = i; + } + //cout<<"current max: "<>c; + float current_min = m_values[current_min_index]; + float current_max = m_values[current_max_index]; + //now loop through the function again and scale to the appropriate values + float scaled; + for(int i=0; i max) + m_values[i] = max; + } +} + +void function2D::Abs() +{ + for(int i=0; i +#include +using namespace std; + +class vector3D +{ +public: + float x; + float y; + float z; + + vector3D(); + vector3D(double newx, double newy, double newz); + vector3D operator+(vector3D param); + vector3D operator-(vector3D param); + double operator*(vector3D param); //inner product + vector3D cross(vector3D param); + vector3D operator*(double param); + + int normalize(); + double length(); + + void print(); +}; + + +class point3D +{ +public: + float x; + float y; + float z; + + point3D(); + point3D(double newx, double newy, double newz); + + //support for vector arithmetic + point3D operator+(vector3D param); + point3D operator-(vector3D param); + + vector3D operator-(point3D param); + + void print(); +}; + +class matrix4x4 +{ + + /*stored as: + | 0 4 8 12 | + | | + | 1 5 9 13 | + | | + | 2 6 10 14 | + | | + | 3 7 11 15 | + */ +public: + float matrix[16]; + matrix4x4(); + matrix4x4(float m00, float m01, float m02, float m03, + float m10, float m11, float m12, float m13, + float m20, float m21, float m22, float m23, + float m30, float m31, float m32, float m33); + matrix4x4(vector3D basis_x, vector3D basis_y, vector3D basis_z); + vector3D basis_x(); + vector3D basis_y(); + vector3D basis_z(); + point3D operator*(point3D param); + vector3D operator*(vector3D param); + double operator()(unsigned int row, unsigned int col); + void gl_set_matrix(float* gl_matrix); + void gl_get_matrix(float* gl_matrix); + matrix4x4 submatrix(unsigned int start_col, unsigned int start_row, unsigned int end_col, unsigned int end_row); + matrix4x4 transpose(); + void print(); +}; + + +class RGB +{ +public: + float r; + float g; + float b; +}; + +class RGBA +{ +public: + float r; + float g; + float b; + float a; + + RGBA(); + RGBA(double red, double green, double blue, double ambient); +}; + +class quaternion +{ +public: + float w; + float x; + float y; + float z; + + int normalize(); + quaternion operator*(quaternion param); + double* toMatrix(); + + quaternion(); + quaternion(double w, double x, double y, double z); + +}; + +class plane3D +{ +public: + point3D point; + vector3D normal; + + plane3D(); + plane3D(point3D point_on_plane, vector3D plane_normal); +}; + +class ray3D +{ +public: + point3D point; + vector3D direction; + + ray3D(); + ray3D(point3D start_point, vector3D direction); + ray3D(point3D first_point, point3D second_point); + + int intersect(plane3D plane, point3D& intersection_point); +}; + +class line3D +{ +private: + point3D m_p0; + point3D m_p1; + +public: + line3D(); + line3D(point3D p0, point3D p1); + + point3D get_point(double pos); //returns a point at pos = [0.0, 1.0] +}; + + +//at this point, this template class is only really working with floating point numbers (and doubles) +#define RTS_UNSIGNED_BYTE 1 +#define RTS_FLOAT 2 +#define RTS_DOUBLE 3 + +typedef unsigned int rtsBitType; + +class function2D +{ +public: + + function2D(float domain_x0, float domain_x1, float domain_y0, float domain_y1, int x_resolution, int y_resolution); + function2D(); + ~function2D(); + function2D(const function2D ©); //copy constructor + function2D& operator=(const function2D& f); + + void CreateGaussian(float mean_x, float mean_y, float std_dev); + void CreateConstant(float value); + void CreateCircleMask(float center_x, float center_y, float radius); + void Scale(float min, float max); //scales the function so that the range exists only in the specified bounds + void Clip(float min, float max); //clips the function so that the range exists only in the specified bounds + void Abs(); //sets every sample point to the absolute value + float Integral(); //returns the sum of the function + float Average(); + float operator ()(float x, float y); + + function2D operator*(function2D param); + function2D operator*(float param); + function2D operator+(function2D param); + function2D operator+(float param); + function2D operator-(function2D param); + + float* getBits(); + void setBits(float* bits); + void setBits(unsigned char* bits); + void setBits(double* bits); + void setBits(int* bits); + + +private: + float m_x0; + float m_x1; + float m_y0; + float m_y1; + int m_x_resolution; + int m_y_resolution; + float* m_values; +}; + + + + + + + + + +#endif diff --git a/rtsMatrix4x4.h b/rtsMatrix4x4.h new file mode 100755 index 0000000..4f053a5 --- /dev/null +++ b/rtsMatrix4x4.h @@ -0,0 +1,196 @@ +#include +#include +#include +#include + +#include "rtsVector3d.h" +#include "rtsPoint3d.h" + +using namespace std; +#ifndef RTSMATRIX4X4_H +#define RTSMATRIX4X4_H + +#define RTS_PI 3.14159 + +///This class represents a 4x4 matrix, which is often used to represent affine transformations on 3D points and vectors. + +/// +///This class is designed to work with point3d and vector3d. Data is stored internally in a column-major form which is compatible with OpenGL. +/// + +template +class matrix4x4 +{ + /*stored as: + | 0 4 8 12 | + | | + | 1 5 9 13 | + | | + | 2 6 10 14 | + | | + | 3 7 11 15 | + */ +public: + T m_matrix[16]; + + //constructors + matrix4x4(); /// operator*(vector3D rhs); /// operator*(point3D rhs); /// operator*(matrix4x4 rhs); /// +matrix4x4::matrix4x4() +{ + memset(m_matrix, 0, sizeof(T)*16); +} + +template +matrix4x4::matrix4x4(T c0r0, T c0r1, T c0r2, T c0r3, + T c1r0, T c1r1, T c1r2, T c1r3, + T c2r0, T c2r1, T c2r2, T c2r3, + T c3r0, T c3r1, T c3r2, T c3r3) +{ + + T new_matrix[16] = {c0r0,c0r1,c0r2,c0r3,c1r0,c1r1,c1r2,c1r3,c2r0,c2r1,c2r2,c2r3,c3r0,c3r1,c3r2,c3r3}; + memcpy(m_matrix, new_matrix, 16*sizeof(T)); +} + +template +vector3D matrix4x4::operator*(vector3D rhs) +{ + vector3D result; + result.x = m_matrix[0] * rhs.x + m_matrix[4] * rhs.y + m_matrix[8] * rhs.z; + result.y = m_matrix[1] * rhs.x + m_matrix[5] * rhs.y + m_matrix[9] * rhs.z; + result.z = m_matrix[2] * rhs.x + m_matrix[6] * rhs.y + m_matrix[10] * rhs.z; + return result; +} + +template +point3D matrix4x4::operator *(point3D rhs) +{ + point3D result; + result.x = m_matrix[0] * rhs.x + m_matrix[4] * rhs.y + m_matrix[8] * rhs.z + m_matrix[12]; + result.y = m_matrix[1] * rhs.x + m_matrix[5] * rhs.y + m_matrix[9] * rhs.z + m_matrix[13]; + result.z = m_matrix[2] * rhs.x + m_matrix[6] * rhs.y + m_matrix[10] * rhs.z + m_matrix[14]; + T w = m_matrix[3] + m_matrix[7] + m_matrix[11] + m_matrix[15]; + result.x/=w; + result.y/=w; + result.z/=w; + return result; +} + +template +matrix4x4 matrix4x4::operator *(matrix4x4 rhs) +{ + matrix4x4 result; + int i,j,r; + for(i = 0; i<4; i++) + for(j = 0; j<4; j++) + for(r=0; r<4; r++) + result(i, j) += (*this)(i, r) * rhs(r, j); + + return result; +} + + + + +template +void matrix4x4::SetIdentity() +{ + T new_matrix[16] = {1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1}; + memcpy(m_matrix, new_matrix, 16*sizeof(T)); +} + +template +void matrix4x4::SetTranslation(T x, T y, T z) +{ + T new_matrix[16] = {1,0,0,0,0,1,0,0,0,0,1,0,x,y,z,1}; + memcpy(m_matrix, new_matrix, 16*sizeof(T)); +} + +template +void matrix4x4::SetScale(T x, T y, T z) +{ + T new_matrix[16] = {x,0,0,0,0,y,0,0,0,0,z,0,0,0,0,1}; + memcpy(m_matrix, new_matrix, 16*sizeof(T)); +} + +template +void matrix4x4::SetRotation(T angle, T x, T y, T z) +{ + //create the axis of rotation + vector3D axis(x, y, z); + T length = axis.Length(); //make sure that it is normalized + if(length != 1) + axis.Normalize(); + + T c = cos(angle*RTS_PI/180.0); //compute the sine and cosine of angle + T s = sin(angle*RTS_PI/180.0); + + //create the matrix + m_matrix[0] = x*x*(1-c) + c; + m_matrix[1] = y*x*(1-c) + z*s; + m_matrix[2] = x*z*(1-c) - y*s; + m_matrix[4] = x*y*(1-c) - z*s; + m_matrix[5] = y*y*(1-c) + c; + m_matrix[6] = y*z*(1-c) + x*s; + m_matrix[8] = x*z*(1-c) + y*s; + m_matrix[9] = y*z*(1-c) - x*s; + m_matrix[10]= z*z*(1-c) + c; + m_matrix[15]= 1; +} + + +template +void matrix4x4::Print(int width, int precision) +{ + cout< +#include +#include +#include + +//itk includes +#include "../../VesselAnalysis/VesselAnalysis/VOL_to_ITK.h" +#include "itkDanielssonDistanceMapImageFilter.h" +#include "itkBinaryThresholdImageFilter.h" +#include "itkConstNeighborhoodIterator.h" +#include "itkExpandImageFilter.h" +#include "itkDiscreteGaussianImageFilter.h" +#include "itkCastImageFilter.h" + + +/* This code uses the octree library designed by Simon Perreault (http://nomis80.org/code/octree.html)*/ +#include "octree/octree.h" + +#define OCTREE_SIZE 1024 +#define BUFFER_ZONE 0 + + +using namespace std; + + + +//definitions for simple structures +typedef vector> FilamentType; +typedef point3D CoordType; +typedef vector NetworkType; + +struct EdgeType +{ + unsigned int v0; + unsigned int v1; + float avg_radius; + float min_radius; + float max_radius; + float volume; + float length; + bool valid; +}; + +struct NodeType +{ + CoordType p; + vector edges; + bool valid; +}; + +struct ConnectType //this structures stores the info necessary to combine two fibers +{ + unsigned int edge0; + unsigned int edge1; + unsigned int node0; + unsigned int node1; + list::iterator fiber0; + list::iterator fiber1; +}; + +struct ConnectableType +{ + FilamentType fiber; + bool front; + bool back; + unsigned int id; +}; + +struct AttributeType +{ + float TotalFiberLength; + int NumFibers; + int NumPoints; + float TotalVolume; + int NumDisconnectedFibers; + int NumBoundaryFibers; + int NumBifurcations; +}; + +struct BranchType +{ + float angle; + unsigned int branch_id; +}; + + +class rtsNetwork +{ +private: + int id; //used for swc output + ofstream outfile; //also for swc + NetworkType network; //list of filaments that make up the network + vector NodeList; //vector of endpoints + vector EdgeList; //vector of vessels as edges + vector3D boundary; + vector3D position; + + + float calcFiberLength(unsigned int f); + float calcFiberBend(unsigned int f); + float calcTotalLength(); + bool isBoundaryNode(unsigned int node); + vector3D calcTrajectory(FilamentType f, bool end); + bool compareTrajectories(CoordType p0, vector3D v0, CoordType p1, vector3D v1, float distance, float cosine_angle); + void calcGraph(); + vector getConnections(unsigned int node); + CoordType toTissue(CoordType grid_coord); + FilamentType combineFibers(FilamentType f0, bool endpoint0, FilamentType f1, bool endpoint1); + bool isConnectable(ConnectableType c0, ConnectableType c1, bool& c0_end, bool& c1_end, float distance, float cosine_angle); + void traverseGraph(int node, int parent_id); + void outputFiberToSWC(int edge, int node_from, int parent_id); + + vector getFiberAngles(unsigned int fiber); + void reset(); + +public: + //attribute variables + AttributeType Attributes; + + //control variables + point3D voxel_size; + + //cleaning + int cleanDegenerateEdges(float length); + int cleanRedundantEdges(); + int cleanBarbs(float length); + + //methods + rtsOBJ LoadOBJModel(const char* filename); + void AddOBJModel(const char* filename); + void SaveSWCModel(const char *filename, float root_x, float root_y); + void SaveSWCModel(const char *filename); + void Clean(float degenerate_length, float barb_length); + void CalculateAttributes(); + rtsOBJ Repair(float max_distance, float cos_angle); + rtsOBJ CreateModel(); + void printFiberStats(unsigned int fiber); + void ReMesh(float resample_length); + void SaveAngles(const char* filename); + void SaveBends(const char* filename); + void SaveLengths(const char* filename); + void SaveMathematicaGraph(const char* filename); + void SaveMathematicaNodeDistances(const char* filename); + void SetVoxelSize(float dx, float dy, float dz){voxel_size.x = dx; voxel_size.y = dy; voxel_size.z = dz;} + void RemoveTerminalComponents(); + void RemoveBoundaryComponents(); + void GetRadiusFromVolume(const char* filename, unsigned int threshold, unsigned int range); + void GetRadiusFromDistanceMap(const char *filename, int range); + point3D GetFiberRadius(unsigned int fiber); + void ScaleNetwork(float x, float y, float z); + void SetOutputPosition(float x, float y, float z); + + +}; +//private +void rtsNetwork::reset() +{ + vector::iterator e; + for(e=EdgeList.begin(); e!=EdgeList.end(); e++) + (*e).valid = true; + + vector::iterator n; + for(n=NodeList.begin(); n!=NodeList.end(); n++) + (*n).valid = true; +} + +float rtsNetwork::calcFiberBend(unsigned int f) +{ + /*calculates the bend of a fiber.*/ + + //find the line connecting the two endpoints + point3D p1 = toTissue(NodeList[EdgeList[f].v0].p); + point3D p2 = toTissue(NodeList[EdgeList[f].v1].p); + + //find the largest distance between the filament and the line between endpoints + FilamentType::iterator i; + float max_distance = 0; + for(i = network[f].begin(); i!= network[f].end(); i++) + { + point3D p0 = toTissue((*i)); + + //find the distance between the current point and the line made by the endpoints + float d = ((p0 - p1).X(p0-p2).Length())/(p2-p1).Length(); + if(d > max_distance) + max_distance = d; + } + float fiber_length = calcFiberLength(f); + if(max_distance/fiber_length > 0.5) + { + cout<<"Something's wrong."< length) + { + newNetwork.push_back(network[e]); + removed--; + } + + } + //if the fiber is not an end fiber + else + { + newNetwork.push_back(network[e]); + removed--; + } + + } + + network.clear(); + network = newNetwork; + calcGraph(); + + cout<<"Barbs removed: "<*/ + + //form lists of degenerate and non-degenerate edges + int removed = 0; + + list degenerate; + list complete; + + //iterate through each fiber and put it in the appropriate list + int numFibers = network.size(); + int f; + ConnectableType c; + for(f=0; f connected_edges; + vector shared_vertices; + int numEdges, numVerts, e, e0, e1, v; + int connectedEdge; + //for each degenerate edge + list::iterator i; + for(i=degenerate.begin(); i!=degenerate.end(); i++) + { +/*DEGENERATE CASE 1 +In this case, we remove edges that are parts of very small cycles (ex short edges that +bridge between a bifurcation, forming a small triangle). +*/ + //get all of the edges connected to that edge + connected_edges.clear(); + //add edges connected to v0 + v = EdgeList[(*i).id].v0; + numEdges = NodeList[v].edges.size(); + for(e=0; e3 && + NodeList[EdgeList[(*i).id].v0].edges.size() >3) + { + delete_fiber = true; + removed++; + EdgeList[(*i).id].valid = false; + } + + + + + if(!delete_fiber) + complete.push_back((*i)); + + } + + //re-create the network from + NetworkType newNetwork; + for(i = complete.begin(); i!=complete.end(); i++) + newNetwork.push_back((*i).fiber); + + network = newNetwork; + calcGraph(); + + return removed; + + + + +} +bool rtsNetwork::isBoundaryNode(unsigned int node) +{ + CoordType p; + + p = NodeList[node].p; + if(NodeList[node].edges.size() > 1) + return false; + if(p.x > BUFFER_ZONE && p.y > BUFFER_ZONE && p.z > BUFFER_ZONE && + p.x < boundary.x - BUFFER_ZONE && p.y < boundary.y - BUFFER_ZONE && p.z < boundary.z - BUFFER_ZONE) + return false; + else + return true; +} + + +bool rtsNetwork::isConnectable(ConnectableType c0, ConnectableType c1, bool& c0_end, bool& c1_end, float distance, float cosine_angle) +{ + //tests to see if two ConnectableType fibers can be connected. If so, the function + //returns true as well as the optimal connected endpoints as and . + //For these parameters, 0 = the first point on the fiber and 1 = the last point. + + if(c0.id == 1381 && c1.id == 1407) + cout<<"here"< t0; + vector3D t1; + if(c0.front == 0) + { + t0 = calcTrajectory(c0.fiber, 0); + if(c1.front == 0) + { + t1 = calcTrajectory(c1.fiber, 0); + if(compareTrajectories(c0.fiber.front(), t0, c1.fiber.front(), t1, distance, cosine_angle)) + { + c0_end = 0; + c1_end = 0; + return true; + } + } + if(c1.back == 0) + { + t1 = calcTrajectory(c1.fiber, 1); + if(compareTrajectories(c0.fiber.front(), t0, c1.fiber.back(), t1, distance, cosine_angle)) + { + c0_end = 0; + c1_end = 1; + return true; + } + } + } + if(c0.back == 0) + { + t0 = calcTrajectory(c0.fiber, 1); + if(c1.front == 0) + { + t1 = calcTrajectory(c1.fiber, 0); + if(compareTrajectories(c0.fiber.back(), t0, c1.fiber.front(), t1, distance, cosine_angle)) + { + c0_end = 1; + c1_end = 0; + return true; + } + } + if(c1.back == 0) + { + t1 = calcTrajectory(c1.fiber, 1); + if(compareTrajectories(c0.fiber.back(), t0, c1.fiber.back(), t1, distance, cosine_angle)) + { + c0_end = 1; + c1_end = 1; + return true; + } + } + } + + + return false; + +} +FilamentType rtsNetwork::combineFibers(FilamentType f0, bool endpoint0, FilamentType f1, bool endpoint1) +{ + + //create the new filament + FilamentType newFilament; + //insert the first filament + //if the valence-1 vertex is at the beginning + if(endpoint0 == 0) + { + //add the edge backwards + for(int v=f0.size() - 1; v>=0; v--) + newFilament.push_back(f0[v]); + } + else + { + //otherwise we can just copy the filament over + newFilament = f0; + } + + //insert the second filament + //if the valence-1 vertex is at the beginning + if(endpoint1 == 0) + { + //add the edge in forwards + for(int v=0; v=0; v--) + newFilament.push_back(f1[v]); + } + + return newFilament; +} +vector3D rtsNetwork::calcTrajectory(FilamentType f, bool end) +{ + //calculates the trajectory of a fiber at the given endpoint (0 = first, 1 = last) + + CoordType pEndpoint; + CoordType pPrevpoint; + if(end == 0) + { + pEndpoint = f.front(); + pPrevpoint = f[1]; + //pPrevpoint = f[ceil(f.size()/4.0)]; + } + else + { + pEndpoint = f.back(); + pPrevpoint = f[f.size() - 2]; + //pPrevpoint = f[floor(f.size()*3.0/4.0)]; + } + + //pPrevpoint = f[f.size()/2]; + + + vector3D result = toTissue(pEndpoint) - toTissue(pPrevpoint); + result.Normalize(); + return result; +} +bool rtsNetwork::compareTrajectories(CoordType p0, vector3D v0, CoordType p1, vector3D v1, float distance, float cosine_angle) +{ + //determines of two points/trajectory pairs are compatible for connection + vector3D difference = p1 - p0; + //test distance + if(difference.Length() <= distance) + { + difference.Normalize(); + if(v0*difference >= cosine_angle && v1*difference <= -cosine_angle) + return true; + } + return false; +} +vector rtsNetwork::getConnections(unsigned int node) +{ + return NodeList[node].edges; + +} +point3D rtsNetwork::toTissue(CoordType grid_coord) +{ + //converts a coordinate from the original voxel grid coordinates to tissue-space coordinates + return CoordType(grid_coord.x * voxel_size.x, + grid_coord.y * voxel_size.y, + grid_coord.z * voxel_size.z); + + //return grid_coord; +} + +float rtsNetwork::calcFiberLength(unsigned int f) +{ + //This function calculates the total length of the given fiber + + float result = 0.0; + + //find the length of each fiber + int vertNum, v; + + vertNum = network[f].size(); + for(v=1; v outPoint; + //if we are traversing the fiber front-to-back + if(EdgeList[e].v0 == node_from) + { + if(parent_id == -1) + { + p=0; + outPoint = network[e][p] + position; + outfile<=0; p--) + { + outPoint = network[e][p] + position; + outfile< rootSeed(root_x, root_y, 0); + float distance = 9999999; + int closest_node; + + //find the closest node to the root seed + for(node = 0; node != NodeList.size(); node++) + { + float length = (NodeList[node].p - rootSeed).Length(); + if(length < distance) + { + closest_node = node; + distance = length; + cout< Max) Max = temp; + } + + //place each point ID inside the octree + unsigned int id = 0; + Octree tree(OCTREE_SIZE); + tree.setEmptyValue(UINT_MAX); + unsigned int v0, v1; + + + for(f=0; f"< complete; + list incomplete; + + cout<<"Finding Valence-1 Fibers..."< + int numFibers = network.size(); + int f; + unsigned int v0; + unsigned int v1; + int numVerts, v; + for(f=0; f::iterator i; + list::iterator j; + list::iterator temp; + FilamentType newFiber; + bool endpoint0, endpoint1; + + int iIndex, jIndex; + + iIndex = 0; + for(i=incomplete.begin(); i!=incomplete.end(); i++) + { + jIndex = iIndex; + j = i; + while(j != incomplete.end() && i != incomplete.end()) + { + if(i!=j) + { + if(isConnectable((*i), (*j), endpoint0, endpoint1, max_distance, cos_angle)) + { + ConnectableType newConnectable; + newConnectable.fiber = combineFibers((*i).fiber, endpoint0, (*j).fiber, endpoint1); + //determine the new connectivity + if(endpoint0 == 0) + newConnectable.front = (*i).back; + else + newConnectable.front = (*i).front; + + if(endpoint1 == 0) + newConnectable.back = (*j).back; + else + newConnectable.back = (*j).front; + + //remove the previous connectables + temp = i; + i++; + iIndex++; + incomplete.erase(temp); + temp = j; + //this is just in case the fibers are next to each otehr + if(j == i) + { + i++; + iIndex++; + j = i; + jIndex = iIndex; + } + else + { + j = i; + jIndex = iIndex; + } + incomplete.erase(temp); + //insert the new connectable in the proper list + if(newConnectable.front == 0 || newConnectable.back == 0) + incomplete.push_back(newConnectable); + else + complete.push_back(newConnectable); + + + + //numVerts = newConnectable.fiber.size(); + //preview.objBegin(OBJ_LINE_STRIP); + //for(v=0; v newNetwork; + for(i=incomplete.begin(); i!=incomplete.end(); i++) + newNetwork.push_back((*i).fiber); + for(i=complete.begin(); i!=complete.end(); i++) + newNetwork.push_back((*i).fiber); + + network = newNetwork; + calcGraph(); + + + //build the model to return + preview = CreateModel(); + + return preview; + +} +void rtsNetwork::printFiberStats(unsigned int fiber) +{ + /* + cout<<"-----------------------------------------------------"< currentTrajectory; + vector3D branchTrajectory; + unsigned int f; + + //get the list of angles + vector angles = getFiberAngles(fiber); + + unsigned int node = EdgeList[fiber].v0; + int numBranches = NodeList[node].edges.size()-1; + cout<<"V0 Valence: "< distanceVector; + point3D prevPoint; + for(f=0; f= resample_length) + { + newFiber.push_back(network[f][v]); + prevPoint = network[f][v]; + } + } + + //deal with the last vertex + //newFiber.push_back(network[f][v]); + + distanceVector = toTissue(network[f][v]) - toTissue(prevPoint); + if(distanceVector.Length() >= resample_length || newFiber.size() == 1) + { + newFiber.push_back(network[f][v]); + } + else + { + //change the last point + newFiber[newFiber.size() - 1] = network[f][v]; + } + + + //cout<<"old: "< angles = getFiberAngles(f); + for(int a=0; a179 && angles[a].angle < 181) + { + //cout<<"ERROR"<90 && angles[a].angle < 90.01) + { + //cout<<"ERROR"<2) + outfile<2) + outfile<"<"< distance; + outfile<<"d = {"; + for(i=0; iSetSpacing(spacing); + SaveSlice(volume, 20, "original.bmp"); + //volume->ReleaseDataFlagOn(); + +/* + cout<<"Expanding Image..."< ResizeFilterType; + ResizeFilterType::Pointer resizeFilter = ResizeFilterType::New(); + resizeFilter->SetExpandFactors(resample); + resizeFilter->SetInput(volume); + resizeFilter->Update(); + VOLType::Pointer resizedImage = resizeFilter->GetOutput(); + SaveSlice(resizedImage, 20, "resized.bmp"); + cout<<"done."< BlurFilterType; + BlurFilterType::Pointer blurFilter = BlurFilterType::New(); + blurFilter->SetUseImageSpacingOn(); + float variance[3] = {0.61, 1.5, 0.61}; + blurFilter->SetVariance(variance); + blurFilter->SetMaximumKernelWidth(8); + blurFilter->SetInput(volume); + try + { + blurFilter->Update(); + } + catch(itk::ExceptionObject & exp) + { + std::cout<GetOutput(); + + typedef itk::CastImageFilter CastingFilterType; + CastingFilterType::Pointer castFilter = CastingFilterType::New(); + castFilter->SetInput(blurredImage); + castFilter->Update(); + VOLType::Pointer resizedImage = castFilter->GetOutput(); + + SaveSlice(resizedImage, 20, "resized.bmp"); + + + //threshold the input image + cout<<"Thresholding Volume..."< ThresholdFilterType; + ThresholdFilterType::Pointer thresholdFilter = ThresholdFilterType::New(); + thresholdFilter->SetInsideValue(255); + thresholdFilter->SetOutsideValue(0); + thresholdFilter->SetLowerThreshold(threshold); + thresholdFilter->SetUpperThreshold(255); + thresholdFilter->SetInput(resizedImage); + try + { + thresholdFilter->Update(); + } + catch(itk::ExceptionObject & exp) + { + std::cout<GetOutput(); + //volume->ReleaseData(); + //thresholdFilter->ReleaseDataFlagOn(); + + SaveSlice(thresholdImage, 20, "threshold.bmp"); + + cout<<"done."< DistanceFilterType; + DistanceFilterType::Pointer distanceFilter = DistanceFilterType::New(); + distanceFilter->SetInput(thresholdImage); + distanceFilter->UseImageSpacingOn(); + + try + { + distanceFilter->Update(); + } + catch(itk::ExceptionObject & exp) + { + std::cout<GetOutput(), 20, "distance.bmp"); + FloatType::Pointer distanceMap = distanceFilter->GetOutput(); + //SaveFloatRAW(distanceMap, "distanceMap.raw"); + cout<<"done."< NeighborhoodIteratorType; + NeighborhoodIteratorType::RadiusType radius; + radius.Fill(range); + NeighborhoodIteratorType i(radius, distanceMap, distanceMap->GetBufferedRegion()); + vector OffsetVector; + OffsetVector.resize((range*2+1)*(range*2+1)*(range*2+1)); + int x, y, z, j; + j=0; + for(x=-range; x<=range; x++) + for(y=-range; y<=range; y++) + for(z=-range; z<=range; z++) + { + OffsetVector[j][0]=x; + OffsetVector[j][1]=y; + OffsetVector[j][2]=z; + //cout<<"offset: "< position; + float total_radius, near_radius, total_volume, max_radius, min_radius; + FloatType::IndexType pixelIndex; + float prev_radius; + point3D p0, p1; + float height; + for(f=0; f max_radius) + max_radius = near_radius; + if(near_radius < min_radius) + min_radius = near_radius; + total_radius += near_radius; + if(v>0) + { + //compute the volume of the segment + p0 = toTissue(network[f][v-1]); + p1 = toTissue(network[f][v]); + height = (p1 - p0).Length(); + total_volume += ((3.14159*height)/3.0)*(prev_radius * prev_radius + near_radius*near_radius + prev_radius*near_radius); + + } + prev_radius = near_radius; + } + EdgeList[f].avg_radius = total_radius/numVertices; + EdgeList[f].min_radius = min_radius; + EdgeList[f].max_radius = max_radius; + EdgeList[f].volume = total_volume; + } + + cout<<"done."< NeighborhoodIteratorType; + NeighborhoodIteratorType::RadiusType radius; + radius.Fill(range); + NeighborhoodIteratorType i(radius, distanceMap, distanceMap->GetRequestedRegion()); + vector OffsetVector; + OffsetVector.resize((range*2+1)*(range*2+1)*(range*2+1)); + int x, y, z, j; + j=0; + for(x=-range; x<=range; x++) + for(y=-range; y<=range; y++) + for(z=-range; z<=range; z++) + { + OffsetVector[j][0]=x; + OffsetVector[j][1]=y; + OffsetVector[j][2]=z; + //cout<<"offset: "< position; + float total_radius, max_radius; + FloatType::IndexType pixelIndex; + for(f=0; f rtsNetwork::GetFiberRadius(unsigned int fiber) +{ + point3D result; + result.x = EdgeList[fiber].min_radius; + result.y = EdgeList[fiber].max_radius; + result.z = EdgeList[fiber].avg_radius; + return result; +} \ No newline at end of file diff --git a/rtsOctree.h b/rtsOctree.h new file mode 100755 index 0000000..fb60cf4 --- /dev/null +++ b/rtsOctree.h @@ -0,0 +1,70 @@ +#ifndef RTSOCTREE_H +#define RTSOCTREE_H + +#include "rtspoint3D.h" + +template +struct octree_node +{ + unsigned int center; + T data; + octree_node* ppp; + octree_node* ppn; + octree_node* pnp; + octree_node* pnn; + octree_node* npp; + octree_node* npn; + octree_node* nnp; + octree_node* nnn; + octree_node(); +} + +template +octree_node::octree_node() +{ + ppp = NULL; + ppn = NULL; + pnp = NULL; + pnn = NULL; + npp = NULL; + npn = NULL; + nnp = NULL; + nnn = NULL; +} + + +template +class rtsOctree +{ +public: + unsigned int num_leaves; + point3D center; + octree_node* root; + rtsOctree(unsigned int sizex, unsigned int sizey, unsigned int sizez); + void Insert(unsigned int x, unsigned int y, unsigned int z, T value); + +}; + +template +rtsOctree::rtsOctree(unsigned int sizex, unsigned int sizey, unsigned int sizez) +{ + center.x = sizex/2; + center.y = sizey/2; + center.z = sizez/2; + root = new octree_node(); + num_leaves = 1; +} + +template +void rtsOctree::Insert(unsigned int x, unsigned int y, unsigned int z, T value) +{ + point3D current; + point3D destination(x, y, z); + while(!(current == destination)) + { + + + + + +#endif \ No newline at end of file diff --git a/rtsParser.h b/rtsParser.h new file mode 100755 index 0000000..650c0dd --- /dev/null +++ b/rtsParser.h @@ -0,0 +1,279 @@ +#include +#include + +using namespace std; + +//define the parameter data types +#define RTS_ERROR 0 +#define RTS_OK 1 + + +#define RTS_STRING 2 +#define RTS_DOUBLE 3 + +struct parameter +{ + //name of the specified parameter + char* name; + int ID; + char* char_value; + double double_value; + int type; + bool set; +}; + +class rtsParser +{ +private: + vector parameters; + vector::iterator p_SearchParams(char* name); + bool p_SetParameter(char* name, char* value); + bool p_SetParameter(char* name, double value); + +public: + void AddParameter(char* name, int ID, int type); + void AddParameter(char* name, int type); + void OutputParameters(); + void Load(const char* filename); + int GetDoubleParameter(char* name, double& result); + int GetStringParameter(char* name, char*& result); +}; + +vector::iterator rtsParser::p_SearchParams(char *name) +{ + //search the parameters vector for a name matching the input parameter + + vector::iterator iter; + + //run through the vector + for(iter = parameters.begin(); iter != parameters.end(); iter++) + { + //if the name matches the parameter name, return the iterator + if(strcmp((*iter).name, name) == 0) + return iter; + } + + return parameters.end(); +} + +bool rtsParser::p_SetParameter(char *name, char *value) +{ + //sets the character value of a parameter + + //first, find the parameter + vector::iterator iter; + for(iter = parameters.begin(); iter != parameters.end(); iter++) + { + //if the parameter is found + if(strcmp((*iter).name, name) == 0) + { + //if the parameter type is wrong, return false + if((*iter).type != RTS_STRING) + return false; + //otherwise, set the parameter value + (*iter).char_value = value; + (*iter).set = true; + return true; + } + } + //if the parameter was not found, return false + return false; +} + +bool rtsParser::p_SetParameter(char *name, double value) +{ + //sets the character value of a parameter + + //first, find the parameter + vector::iterator iter; + for(iter = parameters.begin(); iter != parameters.end(); iter++) + { + //if the parameter is found + if(strcmp((*iter).name, name) == 0) + { + //if the parameter type is wrong, return false + if((*iter).type != RTS_DOUBLE) + return false; + //otherwise, set the parameter value + (*iter).double_value = value; + (*iter).set = true; + return true; + } + } + //if the parameter was not found, return false + return false; +} + +void rtsParser::Load(const char* filename) +{ + //loads a parameter file and fills the list with the parameter values + + //create an input stream and load the file + ifstream infile; + infile.open(filename); + + //create temporary variables to store values + char param_name[1000]; + vector::iterator iter; + + //for each line in the parameter file + while(!infile.eof()) + { + //get the parameter name token + infile.get(param_name, 100, ' '); + //find the proper parameter in the parameter list + iter = p_SearchParams(param_name); + + //test to make sure the parameter was found + if(iter == parameters.end()) + { + cout<<"Error, could not find parameter: "<>equals; + + //cout<<"infile>>equals: "<::iterator iter = p_SearchParams(name); + + //check for errors + if(iter == parameters.end()) + { + cout<<"Error finding parameter: "<::iterator iter = p_SearchParams(name); + + //check for errors + if(iter == parameters.end()) + { + cout<<"Error finding parameter: "<::iterator iter; + for(iter = parameters.begin(); iter!= parameters.end(); iter++) + { + //test to see if the parameter was set by the file + if((*iter).set) + { + cout<<"name: "<<(*iter).name; + + if((*iter).type == RTS_DOUBLE) + cout<<" value: "<<(*iter).double_value< for linear algebra operations. + +template class point3D +{ + //friend class vector3D; +public: + //data values + T x; + T y; + T z; + + point3D(); /// param); /// param); /// operator+(vector3D param); /// operator-(vector3D param); /// operator-(point3D param); /// operator point3D(); /// &rhs) + { + os<<"("< & operator=(const point3D & rhs) + { + if(this != &rhs) + { + x = rhs.x; + y = rhs.y; + z = rhs.z; + } + return *this; + }*/ + + void print(); +}; + +template +template +point3D::operator point3D() +{ + point3D cast_result(x, y, z); + return cast_result; +} + +template point3D::point3D() +{ + x=0; + y=0; + z=0; +} + +template point3D::point3D(T new_x, T new_y, T new_z) +{ + x=new_x; + y=new_y; + z=new_z; +} + +template +point3D point3D::operator -(vector3D param) +{ + point3D result; //create the result + + result.x = x-param.x; //perform the computation + result.y = y-param.y; + result.z = z-param.z; + + return result; +} + +template +vector3D point3D::operator -(point3D param) +{ + vector3D result; + result.x = x - param.x; + result.y = y - param.y; + result.z = z - param.z; + + return result; +} + +template +point3D point3D::operator+(vector3D param) +{ + point3D result; //create the result + + result.x = x+param.x; //perform the computation + result.y = y+param.y; + result.z = z+param.z; + + return result; +} + +template +bool point3D::operator ==(point3D param) +{ + if(x == param.x && y == param.y && z == param.z) + return true; + else + return false; +} + +template +bool point3D::operator !=(point3D param) +{ + if(x != param.x || y != param.y || z != param.z) + return true; + else + return false; +} + + + +template +void point3D::print() +{ + cout<<"("< +ostream& point3D::operator<<(ostream& os, point3D &rhs) +{ + os<<"("< +#include +using namespace std; + +void rtsProgressBar(int percent) +{ + stringstream bar; + static int x = 0; + string slash[4]; + slash[0] = "\\"; + slash[1] = "-"; + slash[2] = "/"; + slash[3] = "|"; + bar<<"["; + for(int i=0; i<40; i++) + { + if(percent > (float)i/(float)40 *100) + bar << "*"; + else + bar << " "; + } + bar<<"]"; + cout << "\r"; // carriage return back to beginning of line + cout << bar.str() << " " << slash[x] << " " << percent << " %"; // print the bars and percentage + x++; // increment to make the slash appear to rotate + if(x == 4) + x = 0; // reset slash animation +} \ No newline at end of file diff --git a/rtsQuaternion.h b/rtsQuaternion.h new file mode 100755 index 0000000..bef1331 --- /dev/null +++ b/rtsQuaternion.h @@ -0,0 +1,144 @@ +#include "rtsMatrix4x4.h" + +#ifndef RTS_QUATERNION_H +#define RTS_QUATERNION_H + +template +class rtsQuaternion +{ +public: + T w; + T x; + T y; + T z; + + void normalize(); + void CreateRotation(T theta, T axis_x, T axis_y, T axis_z); + rtsQuaternion operator*(rtsQuaternion &rhs); + matrix4x4 toMatrix(); + + + rtsQuaternion(); + rtsQuaternion(T w, T x, T y, T z); + +}; + +template +void rtsQuaternion::normalize() +{ + double length=sqrt(w*w + x*x + y*y + z*z); + w=w/length; + x=x/length; + y=y/length; + z=z/length; +} + +template +void rtsQuaternion::CreateRotation(T theta, T axis_x, T axis_y, T axis_z) +{ + //assign the given Euler rotation to this quaternion + w = cos(theta/2.0); + x = axis_x*sin(theta/2.0); + y = axis_y*sin(theta/2.0); + z = axis_z*sin(theta/2.0); + + +} + +template +rtsQuaternion rtsQuaternion::operator *(rtsQuaternion ¶m) +{ + float A, B, C, D, E, F, G, H; + + + A = (w + x)*(param.w + param.x); + B = (z - y)*(param.y - param.z); + C = (w - x)*(param.y + param.z); + D = (y + z)*(param.w - param.x); + E = (x + z)*(param.x + param.y); + F = (x - z)*(param.x - param.y); + G = (w + y)*(param.w - param.z); + H = (w - y)*(param.w + param.z); + + rtsQuaternion result; + result.w = B + (-E - F + G + H) /2; + result.x = A - (E + F + G + H)/2; + result.y = C + (E - F + G - H)/2; + result.z = D + (E - F - G + H)/2; + + return result; +} + +template +matrix4x4 rtsQuaternion::toMatrix() +{ + matrix4x4 result; + + + double wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2; + + + // calculate coefficients + x2 = x + x; y2 = y + y; + z2 = z + z; + xx = x * x2; xy = x * y2; xz = x * z2; + yy = y * y2; yz = y * z2; zz = z * z2; + wx = w * x2; wy = w * y2; wz = w * z2; + + result(0, 0) = 1.0 - (yy + zz); + result(0, 1) = xy - wz; + //m[0][0] = 1.0 - (yy + zz); m[1][0] = xy - wz; + + result(0, 2) = xz + wy; + result(0, 3) = 0.0; + //m[2][0] = xz + wy; m[3][0] = 0.0; + + result(1, 0) = xy + wz; + result(1, 1) = 1.0 - (xx + zz); + //m[0][1] = xy + wz; m[1][1] = 1.0 - (xx + zz); + + result(1, 2) = yz - wx; + result(1, 3) = 0.0; + //m[2][1] = yz - wx; m[3][1] = 0.0; + + result(2, 0) = xz - wy; + result(2, 1) = yz + wx; + //m[0][2] = xz - wy; m[1][2] = yz + wx; + + result(2, 2) = 1.0 - (xx + yy); + result(3, 2) = 0.0; + //m[2][2] = 1.0 - (xx + yy); m[3][2] = 0.0; + + result(3, 0) = 0.0; + result(3, 1) = 0.0; + result(3, 2) = 0.0; + result(3, 3) = 1.0; + //m[0][3] = 0; m[1][3] = 0; + //m[2][3] = 0; m[3][3] = 1; + /* + double* orientationmatrix=(double*)m; + char c; + + + double* result=new double[16]; + double* array=(double*)m; + for(int i=0; i<16; i++) + result[i]=array[i]; + */ + + return result; +} + +template +rtsQuaternion::rtsQuaternion() +{ + w=0.0; x=0.0; y=0.0; z=0.0; +} + +template +rtsQuaternion::rtsQuaternion(T c, T i, T j, T k) +{ + w=c; x=i; y=j; z=k; +} + +#endif diff --git a/rtsSkeleton.h b/rtsSkeleton.h new file mode 100755 index 0000000..b85d884 --- /dev/null +++ b/rtsSkeleton.h @@ -0,0 +1,107 @@ +#include +using namespace std; + +#include "rtsPoint3d.h" +#include "rts_itkVolume.h" +typedef vector> filament; + +#define BACKGROUND_NODE 0 +#define SKELETON_NODE 255 +#define ENDPOINT_NODE 128 +#define VISITED_NODE 64 + +class rtsSkeleton +{ + rts_itkVolume implicit_skeleton; + vector explicit_filaments; + vector> explicit_endpoints; + + void ComputeEndPoints(); + +public: + void ConstructExplicitSkeleton(); + void SmoothExplicitSkeleton(int iterations); + void SaveExplicitSkeleton(const char* filename); +} + +void rtsSkeleton::ComputeEndPoints() +{ + /*This function finds all of the filament end points in the implicit skeleton. + The end points are stored in the explicit_endpoints vector. + An end point is defined as a node with (n == 1) or (n > 2) connected components. + */ + + unsigned int max_x = implicit_skeleton.DimX(); + unsigned int max_y = implicit_skeleton.DimY(); + unsigned int max_z = implicit_skeleton.DimZ(); + unsigned int conn; + + indextype x, y, z; + for(x=0; x 2) //if the number of connected components meets the + //criteria, store the node in the explicit_endpoints vector. + { + explicit_endpoints.push_back(point3D(x, y, z)); + } + } + + } + + //tag the endpoints in the implicit function + vector>::iterator i; + for(i=explicit_endpoints.begin(); i!=explicit_endpoints.end(); i++) + implicit_skeleton.xyz(i->x, i->y, i->z) = ENDPOINT_NODE; + + //cout<<"Number of end points: "<>::iterator i; + rtsFunction3D local; + unsigned int x, y, z; + for(i = explicit_endpoints.begin(); i != explicit_endpoints.end(); i++) + { + //cout<<"Tracing Filament..."<print(); + local = getLocalRegion(i->x, i->y, i->z); + local(1, 1, 1) = 0; + //local.toConsole(); + for(x=0; x<3; x++) + for(y=0; y<3; y++) + for(z=0; z<3; z++) + if(local.xyz(x, y, z) > VISITED_NODE) + { + //cout<<(int)local.xyz(x, y, z)<x - 1 + x, + // i->y - 1 + y, + // i->z - 1 + z)<(i->x - 1 + x, + i->y - 1 + y, + i->z - 1 + z)); + } + //since we have tracked all filaments attached to an endpoint + //set the endpoint as visited + implicit_skeleton.xyz(i->x, i->y, i->z) = VISITED_NODE; + } + + //cout<<"Tracing complete"< +#include + +using namespace std; + +typedef vector> filament; +typedef unsigned int indextype; + +#define BACKGROUND_NODE 0 +#define SKELETON_NODE 255 +#define ENDPOINT_NODE 128 +#define VISITED_NODE 64 + +class rtsSkeletonizer +{ +private: + rts_itkVolume implicit_skeleton; + /*Key: + 0 - background node + 255 - skeleton node + 128 - endpoint node + */ + + vector explicit_filaments; + vector> explicit_endpoints; + + + +public: + rtsSkeletonizer(rts_itkVolume input); + unsigned int BackgroundComponents6(rts_itkVolume* function, + indextype x, + indextype y, + indextype z, + unsigned char threshold); + unsigned int rtsSkeletonizer::Peel(unsigned char isovalue); + int Neighbors26(rts_itkVolume* function, + indextype x, + indextype y, + indextype z, + unsigned char isovalue); + vector> FloodFill6(rts_itkVolume* function, indextype x, indextype y, indextype z, unsigned char target_value); + void FloodFill26(rts_itkVolume* function, int x, int y, int z, unsigned char target_value); + unsigned int Neighbors6(rts_itkVolume* function, indextype x, indextype y, indextype z, unsigned char threshold); + rts_itkVolume getImplicitResult(){return implicit_skeleton;} + unsigned int NumConnectedComponents(indextype x, indextype y, indextype z, unsigned char threshold); + + void ComputeEndPoints(); //find all of the filament end points + void TraceFilament(point3D p0, point3D p1); + rts_itkVolume getLocalRegion(unsigned int x, unsigned int y, unsigned int z); + + void ConstructExplicitSkeleton(); + void SmoothExplicitSkeleton(int iterations); + void SaveExplicitSkeleton(const char* filename); + + +}; + +void rtsSkeletonizer::SmoothExplicitSkeleton(int iterations) +{ + /*This function smooths the vessels by repeatedly taking the dual of the skeleton. + Branch points and end points are constrained to their initial positions. + */ + + vector::iterator f; + int num_verts, end_vert; + int v; + point3D new_vert; + + for(int i = 0; isize(); + end_vert = num_verts - 1; + + //take care of the first vertex + new_filament.push_back((*f)[0]); + + for(v=1; v::iterator i; + filament::iterator f; + for(i=explicit_filaments.begin(); i!=explicit_filaments.end(); i++) + { + output.objBegin(OBJ_LINE_STRIP); + //cout<<"start filament"<begin(); f!=i->end(); f++) + { + output.objVertex3f((*f).x, (*f).y, (*f).z); + //f->print(); + } + //cout<<"end filament"< rtsSkeletonizer::getLocalRegion(unsigned int x, unsigned int y, unsigned int z) +{ + rts_itkVolume local(3, 3, 3); + point3D corner; + indextype u, v, w; + corner = point3D(x-1, y-1, z-1); + for(u=0; u<3; u++) + for(v=0; v<3; v++) + for(w=0; w<3; w++) + local.SetPixel(u, v, w, implicit_skeleton.GetPixel(corner.x + u, corner.y + v, corner.z + w)); + return local; +} + + +void rtsSkeletonizer::TraceFilament(point3D p0, point3D p1) +{ + //create the new filament and start it with the two given points + filament result; + result.push_back(p0); + result.push_back(p1); + + //if(p0 == point3D(156, 433, 254)) + // cout<<"Stop here"< local; + point3D current = p1; + point3D next; + point3D possible_end; + int x, y, z; + int c; //possible connections + + while(1) //continue tracing until the next endpoint + { + c=0; + local = getLocalRegion(current.x, current.y, current.z); + //cout<<"Local Region at ("<(1, 1, 1) + vector3D(x, y, z); + } + //if it is an endpoint node, check for a termination + if(local(x, y, z) == ENDPOINT_NODE) + { + //if we are not backtracking to the start node + possible_end = current - vector3D(1, 1, 1) + vector3D(x, y, z); + if(possible_end != p0 || result.size() > 2) + { + //terminate the fiber + result.push_back(current - vector3D(1, 1, 1) + vector3D(x, y, z)); + explicit_filaments.push_back(result); + implicit_skeleton.SetPixel(current.x, current.y, current.z, VISITED_NODE); + return; + } + } + } + //return when there is nowhere to go + if(c == 0) + return; + //now we have the next node in the filament, go ahead and label the current + //one as traversed + implicit_skeleton.SetPixel(current.x, current.y, current.z, VISITED_NODE); + //now insert it into the fiber and move to the next node + result.push_back(next); + if(current == next) + { + //cout<<"I've been waiting for you Obi-Wan"<>::iterator i; + rts_itkVolume local; + unsigned int x, y, z; + for(i = explicit_endpoints.begin(); i != explicit_endpoints.end(); i++) + { + //cout<<"Tracing Filament..."<print(); + local = getLocalRegion(i->x, i->y, i->z); + local.SetPixel(1, 1, 1, 0); + //local.toConsole(); + for(x=0; x<3; x++) + for(y=0; y<3; y++) + for(z=0; z<3; z++) + if(local.GetPixel(x, y, z) > VISITED_NODE) + { + //cout<<(int)local.xyz(x, y, z)<x - 1 + x, + // i->y - 1 + y, + // i->z - 1 + z)<(i->x - 1 + x, + i->y - 1 + y, + i->z - 1 + z)); + } + //since we have tracked all filaments attached to an endpoint + //set the endpoint as visited + implicit_skeleton.SetPixel(i->x, i->y, i->z, VISITED_NODE); + } + + //cout<<"Tracing complete"< input) +{ + implicit_skeleton = input; +} + +void rtsSkeletonizer::ComputeEndPoints() +{ + /*This function finds all of the filament end points in the implicit skeleton. + The end points are stored in the explicit_endpoints vector. + An end point is defined as a node with (n == 1) or (n > 2) connected components. + */ + + unsigned int max_x = implicit_skeleton.DimX(); + unsigned int max_y = implicit_skeleton.DimY(); + unsigned int max_z = implicit_skeleton.DimZ(); + unsigned int conn; + + indextype x, y, z; + for(x=0; x 2) //if the number of connected components meets the + //criteria, store the node in the explicit_endpoints vector. + { + explicit_endpoints.push_back(point3D(x, y, z)); + } + } + + } + + //tag the endpoints in the implicit function + vector>::iterator i; + for(i=explicit_endpoints.begin(); i!=explicit_endpoints.end(); i++) + implicit_skeleton.SetPixel(i->x, i->y, i->z, ENDPOINT_NODE); + + //cout<<"Number of end points: "< local(3, 3, 3); + + + local = getLocalRegion(x, y, z); +// local.toConsole(); + local.SetPixel(1, 1, 1, 0); +// local.toConsole(); + + indextype xi, yi, zi; + //iterate through each voxel + for(xi=0; xi<3; xi++) + for(yi=0; yi<3; yi++) + for(zi=0; zi<3; zi++) + if(local(xi, yi, zi) >= threshold) + { + FloodFill6(&local, xi, yi, zi, 0); + result++; + } + /* + if(result == 1 || result > 2) + { + cout<* function, + indextype x, + indextype y, + indextype z, + unsigned char threshold) +{ + /** + This function computes the number of 6-connected background components in the local region of (x, y, z). + This computation is performed by testing all 6 possible voxels that can connect to the specified node. If + a background node is found, the entire background component associated with that node is filled and the counter + is incremented by 1. The value n specifies the connectivity domain for the flood fill. + The definition of background components is that specified by He, Kischell, Rioult and Holmes. + **/ + + //see if there is at least one BG component + if(Neighbors6(function, x, y, z, threshold) == 6) + return 0; + + + //retrieve the local region of the function + rts_itkVolume local(3, 3, 3); + point3D corner(x-1, y-1, z-1); + indextype u, v, w; + for(u=0; u<3; u++) + for(v=0; v<3; v++) + for(w=0; w<3; w++) + local.SetPixel(u, v, w, function->GetPixel(corner.x + u, corner.y + v, corner.z + w)); + + //threshold the background to find inside/outside points + local.Binary(threshold, 1); + //fill points that are not in the connectivity domain + /*if(n == 18) + { + local(0, 0, 0) = 1; + local(0, 0, 2) = 1; + local(0, 2, 0) = 1; + local(0, 2, 2) = 1; + local(2, 0, 0) = 1; + local(2, 0, 2) = 1; + local(2, 2, 0) = 1; + local(2, 2, 2) = 1; + }*/ + //local.toConsole(); + + //search all 6 possible connected points. If a background node is found, fill the component + unsigned int components = 0; + if(local(0, 1, 1) == 0) + { + components++; + FloodFill6(&local, 0, 1, 1, 1); + } + if(local(2, 1, 1) == 0) + { + components++; + FloodFill6(&local, 2, 1, 1, 1); + } + if(local(1, 0, 1) == 0) + { + components++; + FloodFill6(&local, 1, 0, 1, 1); + } + if(local(1, 2, 1) == 0) + { + components++; + FloodFill6(&local, 1, 2, 1, 1); + } + if(local(1, 1, 0) == 0) + { + components++; + FloodFill6(&local, 1, 1, 0, 1); + } + if(local(1, 1, 2) == 0) + { + components++; + FloodFill6(&local, 1, 1, 2, 1); + } + + return components; +} + +unsigned int rtsSkeletonizer::Neighbors6(rts_itkVolume* function, indextype x, indextype y, indextype z, unsigned char threshold) +{ + + unsigned int neighbors = 0; + if(function->GetPixel(x+1, y, z) >= threshold) + neighbors++; + if(function->GetPixel(x-1, y, z) >= threshold) + neighbors++; + if(function->GetPixel(x, y+1, z) >= threshold) + neighbors++; + if(function->GetPixel(x, y-1, z) >= threshold) + neighbors++; + if(function->GetPixel(x, y, z+1) >= threshold) + neighbors++; + if(function->GetPixel(x, y, z-1) >= threshold) + neighbors++; + + return neighbors; +} + +int rtsSkeletonizer::Neighbors26(rts_itkVolume* function, + indextype x, + indextype y, + indextype z, + unsigned char isovalue) +{ + int neighbors = 0; + int u,v,w; + + for(u=-1; u<=1; u++) + for(v=-1; v<=1; v++) + for(w=-1; w<=1; w++) + if(function->GetPixel(x+u, y+v, z+w) >= isovalue) + neighbors++; + if(function->GetPixel(x, y, z) > isovalue) + neighbors--; + + return neighbors; +} + +unsigned int rtsSkeletonizer::Peel(unsigned char isovalue) +{ + /** + Removes one layer of pixels from the specified isosurface. + **/ + + unsigned int res_x = implicit_skeleton.DimX(); + unsigned int res_y = implicit_skeleton.DimY(); + unsigned int res_z = implicit_skeleton.DimZ(); + vector> border_nodes; //get the border nodes for the image + indextype x, y, z; + int condition; + for(x=0; x= isovalue && BackgroundComponents6(&implicit_skeleton, x, y, z, isovalue) == 1 && Neighbors26(&implicit_skeleton, x, y, z, isovalue) != 1) + { + condition = 0; + //now find the border pairs. A border point must meet two of the following conditions to be a border pair. + //south border: s(p) is background + if(implicit_skeleton(x, y-1, z) < isovalue) + condition++; + //north border: n(p) is background, s(p) and s(s(p)) are foreground + if(implicit_skeleton(x, y+1, z) < isovalue && implicit_skeleton(x, y-1, z) >= isovalue && implicit_skeleton(x, y-2, z) >= isovalue) + condition++; + //west border: w(p) is background + if(implicit_skeleton(x-1, y, z) < isovalue) + condition++; + //east border: e(p) is background, w(p) and w(w(p)) are foreground + if(implicit_skeleton(x+1, y, z) < isovalue && implicit_skeleton(x-1, y, z) >= isovalue && implicit_skeleton(x-2, y, z) >= isovalue) + condition++; + //up border: u(p) is background + if(implicit_skeleton(x, y, z-1) < isovalue) + condition++; + //down border: d(p) is background, u(p) and u(u(p)) are foreground + if(implicit_skeleton(x, y, z+1) < isovalue && implicit_skeleton(x, y, z-1) >= isovalue && implicit_skeleton(x, y, z-2) >= isovalue) + condition++; + + if(condition > 1) + border_nodes.push_back(point3D(x, y, z)); + } + //cout<<"Number of border nodes: "< local(3, 3, 3); //store the region local to the current voxel + int nodes_before, nodes_after; //number of neighboring nodes before and after the filling operation + point3D fill_start; + vector>::iterator i; + + /* + Here we determine if a point can be removed by looking at the number of foreground connected + components in the local region. If there is more than one connected component + */ + unsigned int removed = 0; + for(i=border_nodes.begin(); i 0) + fill_start = point3D(x, y, z); + + //fill the local region + FloodFill26(&local, fill_start.x, fill_start.y, fill_start.z, 2); + //get the number of filled neighbors + nodes_after = Neighbors26(&local, 1, 1, 1, 2); + if(nodes_after == nodes_before) + { + implicit_skeleton.SetPixel((*i).x, (*i).y, (*i).z, 0); + removed++; + } + + } + return removed; +} + +vector> rtsSkeletonizer::FloodFill6(rts_itkVolume* function, indextype x, indextype y, indextype z, unsigned char target_value) +{ + //create a vector containing all of the filled nodes + vector> result; + + unsigned char old_value = function->GetPixel(x, y, z); //find the old value (the value being flood-filled) + if(target_value == old_value) //if the target value is the same as the old value, nothing to do + return result; + + queue> Q; //create a queue for neighboring points + point3D current(x, y, z); //start with the current point + function->SetPixel(current.x, current.y, current.z, target_value); + point3D next; + Q.push(current); + indextype u, v, w; + + + while(!Q.empty()) //continue until the queue is empty + { + current = Q.front(); //get the first element from the queue + Q.pop(); + + if(current.x != function->DimY() - 1) + if(function->GetPixel(current.x + 1, current.y, current.z) == old_value) + { + function->SetPixel(current.x + 1, current.y, current.z, target_value); + result.push_back(point3D(current.x + 1, current.y, current.z)); + Q.push(point3D(current.x + 1, current.y, current.z)); + } + if(current.x != 0) + if(function->GetPixel(current.x - 1, current.y, current.z) == old_value) + { + function->SetPixel(current.x - 1, current.y, current.z, target_value); + result.push_back(point3D(current.x - 1, current.y, current.z)); + Q.push(point3D(current.x - 1, current.y, current.z)); + } + if(current.y != function->DimY() - 1) + if(function->GetPixel(current.x, current.y +1, current.z) == old_value) + { + function->SetPixel(current.x, current.y+1, current.z, target_value); + result.push_back(point3D(current.x, current.y+1, current.z)); + Q.push(point3D(current.x, current.y+1, current.z)); + } + if(current.y != 0) + if(function->GetPixel(current.x, current.y-1, current.z) == old_value) + { + function->SetPixel(current.x, current.y-1, current.z, target_value); + result.push_back(point3D(current.x, current.y-1, current.z)); + Q.push(point3D(current.x, current.y-1, current.z)); + } + if(current.z != function->DimZ() - 1) + if(function->GetPixel(current.x, current.y, current.z+1) == old_value) + { + function->SetPixel(current.x, current.y, current.z+1, target_value); + result.push_back(point3D(current.x, current.y, current.z+1)); + Q.push(point3D(current.x, current.y, current.z+1)); + } + if(current.z != 0) + if(function->GetPixel(current.x, current.y, current.z-1) == old_value) + { + function->SetPixel(current.x, current.y, current.z-1, target_value); + result.push_back(point3D(current.x, current.y, current.z-1)); + Q.push(point3D(current.x, current.y, current.z-1)); + } + + } + + return result; + +} + +void rtsSkeletonizer::FloodFill26(rts_itkVolume* function, int x, int y, int z, unsigned char target_value) +{ + unsigned char old_value = function->GetPixel(x, y, z); + if(target_value == old_value) + return; + + queue> Q; + point3D current(x, y, z); + point3D next; + Q.push(current); + indextype u, v, w; + while(!Q.empty()) + { + current = Q.front(); + if(function->GetPixel(current.x, current.y, current.z) == old_value) + function->SetPixel(current.x, current.y, current.z, target_value); + Q.pop(); + + unsigned int res_x = function->DimX(); + unsigned int res_y = function->DimY(); + unsigned int res_z = function->DimZ(); + for(u=-1; u<=1; u++) + for(v=-1; v<=1; v++) + for(w=-1; w<=1; w++) + { + next.x = current.x + u; + next.y = current.y + v; + next.z = current.z + w; + + if(next.x >= 0 && next.x < res_x && + next.y >= 0 && next.y < res_y && + next.z >= 0 && next.z < res_z && + function->GetPixel(next.x, next.y, next.z) == old_value) + { + function->SetPixel(next.x, next.y, next.z, target_value); + Q.push(next); + } + } + } + + +} + + + + + + + +#endif \ No newline at end of file diff --git a/rtsSourceCode.h b/rtsSourceCode.h new file mode 100755 index 0000000..0ff6c25 --- /dev/null +++ b/rtsSourceCode.h @@ -0,0 +1,65 @@ +#ifndef RTSSOURCECODE_H +#define RTSSOURCECODE_H + +#include +#include +#include +#include + +using namespace std; + +///This class defines generic source code that can be loaded from text files. It is primarily used by the rts_glShaderProgram class for GLSL programming. + +class rtsSourceCode +{ +public: + vector source; //the actual source code + void clear() /// min_chars) + total_chars = num_chars; + else + total_chars = min_chars; + result = new char[total_chars + 1]; + //initialize the string to 0's + for(int i=0; i= start_index && (j < start_index + num_length)) + { + filename[j] = number[j - start_index]; + } + //otherwise output the mask value + else + filename[j] = mask[j]; + } + filename[length] = 0; + result[i] = filename; + } + return result; +} + + +unsigned char* rtsCalculateDifferenceImage(int length, unsigned char* a, unsigned char* b) +{ + //calculates the difference between two images and returns the absolute value + unsigned char* result = new unsigned char[length]; + for(int i=0; i +#include +#include +#include +#include "rtsMath.h" + +using namespace std; + +char* rtsInt_to_String(int num, int min_chars); +char** rtsGetFileList(const char* mask, unsigned int start, unsigned int end); +unsigned char* rtsCalculateDifferenceImage(int length, unsigned char* a, unsigned char* b); +unsigned int rtsSumPixels(int length, unsigned char* pixels); +unsigned char* rts2DGaussian(int width, int height, double std_dev); +unsigned char* rtsInvertImage(int width, int height, unsigned char* pixels); +unsigned char* rtsMultiplyImages(int width, int height, unsigned char* pixels_a, unsigned char* pixels_b); + +#endif \ No newline at end of file diff --git a/rtsVector3d.h b/rtsVector3d.h new file mode 100755 index 0000000..38ff66d --- /dev/null +++ b/rtsVector3d.h @@ -0,0 +1,164 @@ +///This class is used to store information for a 3D vector. +#include +#include +using namespace std; + +#ifndef RTSVECTOR3D_H +#define RTSVECTOR3D_H + + +template class vector3D +{ + //friend class point3D; +public: + //data values + T x; + T y; + T z; + + vector3D(); /// operator+(vector3D param); /// operator-(vector3D param); /// param); /// operator*(T param); /// X(vector3D param); /// operator*(const T lhs, vector3D rhs){return rhs*lhs;} /// Times(vector3D param); /// Normalize(); /// operator vector3D(); /// &rhs) + { + os<<"("< +template +vector3D::operator vector3D() +{ + vector3D cast_result(x, y, z); + return cast_result; +} + +template vector3D::vector3D() +{ + x=0; + y=0; + z=0; +} + +template vector3D::vector3D(T new_x, T new_y, T new_z) +{ + x=new_x; + y=new_y; + z=new_z; +} + +template +vector3D vector3D::operator -(vector3D param) +{ + vector3D result; //create the result + + result.x = x-param.x; //perform the computation + result.y = y-param.y; + result.z = z-param.z; + + return result; +} + +template +vector3D vector3D::operator+(vector3D param) +{ + vector3D result; //create the result + + result.x = x+param.x; //perform the computation + result.y = y+param.y; + result.z = z+param.z; + + return result; +} + +template +vector3D vector3D::Times(vector3D param) +{ + vector3D result; //create the result + + result.x = x*param.x; //perform the computation + result.y = y*param.y; + result.z = z*param.z; + + return result; +} + +template +vector3D vector3D::operator*(T param) +{ + vector3D result; //create the result + + result.x = x*param; //perform the computation + result.y = y*param; + result.z = z*param; + + return result; +} + +template +T vector3D::operator *(vector3D param) +{ + //This function computes the dot product between two vectors + return x*param.x + y*param.y + z*param.z; +} + +template +vector3D vector3D::X(vector3D param) +{ + vector3D result; + result.x=y*param.z - z*param.y; + result.y=z*param.x - x*param.z; + result.z=x*param.y - y*param.x; + + return result; +} + +template +vector3D vector3D::Normalize() +{ + T length = Length(); + if(length ==0.0) + { + x = y = z = 0; + } + else + { + x/= length; + y /=length; + z /=length; + } + return *this; +} + +template +T vector3D::Length() +{ + return sqrt(x*x + y*y + z*z); +} + +template +void vector3D::print() +{ + cout<<"["<insert(front_back, 0, 0, 0); + this->insert(front_back, 0, 0, m_size_z-1); + this->insert(left_right, 0, 0, 0); + this->insert(left_right, m_size_x-1, 0, 0); + this->insert(top_bottom, 0, 0, 0); + this->insert(top_bottom, 0, m_size_y-1, 0); + +} + +void rtsVolume::invert() +{ + //inverts the data stored in the volume + unsigned int length = m_size_x*m_size_y*m_size_z; + for(int i=0; i= threshold) + m_data[i] = 255; +} + +void rtsVolume::blit3D(const unsigned char* source, + unsigned int s_sx, unsigned int s_sy, unsigned int s_sz, + unsigned char* dest, + unsigned int d_px, unsigned int d_py, unsigned int d_pz, + unsigned int d_sx, unsigned int d_sy, unsigned int d_sz) +{ + unsigned int ps, pd; //stores the mapping for the source point to the dest point + //find the maximum points that can be blit to (in case source overlaps the edges of dest) + unsigned int blit_size_x = min(s_sx, d_sx - d_px); + unsigned int blit_size_y = min(s_sy, d_sy - d_py); + unsigned int blit_size_z = min(s_sz, d_sz - d_pz); + + unsigned int source_z_offset = s_sx * s_sy; + unsigned int dest_z_offset = d_sx * d_sy; + + unsigned int z,y; + for(z=0; z +#include +#include + +using namespace std; + +class rtsVolume +{ + +private: + unsigned char* m_data; //pointer to the volume data + unsigned int m_size_x; //variables specifying the size of the volume + unsigned int m_size_y; + unsigned int m_size_z; + + //static function for copying 3D data from one pointer to another + //this function does not test boundaries so can quite easily crash + void blit3D(const unsigned char* source, + unsigned int s_sx, unsigned int s_sy, unsigned int s_sz, + unsigned char* dest, + unsigned int d_px, unsigned int d_py, unsigned int d_pz, + unsigned int d_sx, unsigned int d_sy, unsigned int d_sz); + +public: + rtsVolume(); + //construct a blank volume of a given size + rtsVolume(unsigned int size_x, unsigned int size_y, unsigned int size_z); + //construct a volume from specified data + rtsVolume(const unsigned char* data, unsigned int size_x, unsigned int size_y, unsigned int size_z); + rtsVolume(const rtsVolume &original); //copy constructor + ~rtsVolume(); + + //overloaded operators + rtsVolume& operator=(const rtsVolume& original); + inline unsigned char operator()(unsigned int x, unsigned int y, unsigned int z); + + //load and save methods + void open(const char* filename); + void save(const char* filename); + /*Allow resizing of the canvas. This resizes the volume without + resizing the existing data within the volume*/ + void resize_canvas(unsigned int size_x, unsigned int size_y, unsigned int size_z); + void insert(const rtsVolume source, unsigned int pos_x, unsigned int pos_y, unsigned int pos_z); + void blacken_border(); + void invert(); + void blacken(unsigned char threshold); + void whiten(unsigned char threshold); + + //get functions + unsigned char* get_bits(); + unsigned int get_dimx() {return m_size_x;} + unsigned int get_dimy() {return m_size_y;} + unsigned int get_dimz() {return m_size_z;} + + + +}; + + + +#endif \ No newline at end of file diff --git a/rts_cudaBrewer.h b/rts_cudaBrewer.h new file mode 100755 index 0000000..885188d --- /dev/null +++ b/rts_cudaBrewer.h @@ -0,0 +1,59 @@ +#include "rtsVector3d.h" +#include "cudaHandleError.h" + +#define BREWER_CTRL_PTS 11 +texture cudaTexBrewer; +cudaArray* gpuBrewer; + + +__device__ float4 colorBrewer(float val, float min_range, float max_range, float min_fade = 0.000) +{ + float t = (val - min_range)/(max_range - min_range)*((float)(BREWER_CTRL_PTS-2)/BREWER_CTRL_PTS); + float shift = 1.0/BREWER_CTRL_PTS; + float4 color = tex1D(cudaTexBrewer, t+shift); + if(t < min_fade) + color.w = (val - min_range)/(max_range - min_range)/min_fade; + return color; +} + + +void rts_cudaInitBrewer() +{ + //allocate CPU space + float4 cpuColorMap[BREWER_CTRL_PTS]; + + //define control points + cpuColorMap[0] = make_float4(0.192157f, 0.211765f, 0.584314f, 1.0f); + cpuColorMap[1] = make_float4(0.270588f, 0.458824f, 0.705882f, 1.0f); + cpuColorMap[2] = make_float4(0.454902f, 0.678431f, 0.819608f, 1.0f); + cpuColorMap[3] = make_float4(0.670588f, 0.85098f, 0.913725f, 1.0f); + cpuColorMap[4] = make_float4(0.878431f, 0.952941f, 0.972549f, 1.0f); + cpuColorMap[5] = make_float4(1.0f, 1.0f, 0.74902f, 1.0f); + cpuColorMap[6] = make_float4(0.996078f, 0.878431f, 0.564706f, 1.0f); + cpuColorMap[7] = make_float4(0.992157f, 0.682353f, 0.380392f, 1.0f); + cpuColorMap[8] = make_float4(0.956863f, 0.427451f, 0.262745f, 1.0f); + cpuColorMap[9] = make_float4(0.843137f, 0.188235f, 0.152941f, 1.0f); + cpuColorMap[10] = make_float4(0.647059f, 0.0f, 0.14902f, 1.0f); + + + int width = BREWER_CTRL_PTS; + int height = 0; + + + // allocate array and copy colormap data + cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(32, 32, 32, 32, cudaChannelFormatKindFloat); + + HANDLE_ERROR(cudaMallocArray(&gpuBrewer, &channelDesc, width, height)); + + cudaMemcpyToArray(gpuBrewer, 0, 0, cpuColorMap, sizeof(float4)*width, cudaMemcpyHostToDevice); + + // set texture parameters + cudaTexBrewer.addressMode[0] = cudaAddressModeClamp; + //texBrewer.addressMode[1] = cudaAddressModeClamp; + cudaTexBrewer.filterMode = cudaFilterModeLinear; + cudaTexBrewer.normalized = true; // access with normalized texture coordinates + + // Bind the array to the texture + HANDLE_ERROR( cudaBindTextureToArray( cudaTexBrewer, gpuBrewer, channelDesc)); + +} diff --git a/rts_cudaCufftShift.h b/rts_cudaCufftShift.h new file mode 100755 index 0000000..c42cde4 --- /dev/null +++ b/rts_cudaCufftShift.h @@ -0,0 +1,65 @@ +#ifndef CUDA_CUFFT_SHIFT_H +#define CUDA_CUFFT_SHIFT_H + +#define BLOCK_SIZE 16 + +__global__ void devCufftShift(char* gpuSource, int sE, int sX, int sY, int sZ) +{ + int ix = blockIdx.x * blockDim.x + threadIdx.x; + int blocks_per_slice = sY/blockDim.y + 1; + int iy = (blockIdx.y % blocks_per_slice)*blockDim.y + threadIdx.y; + int iz = blockIdx.y/blocks_per_slice; + + if(ix >= sX || iy >= sY || iz >= sZ/2) + return; + + //array index + int i = iz*sX*sY*sE + iy*sX*sE + ix*sE; + + int iSwap = (iz + sZ/2)*sX*sY*sE; + + if(iy < sY/2) + iSwap += (iy + sY/2)*sX*sE; + else + iSwap += (iy - sY/2)*sX*sE; + + if(ix < sX/2) + iSwap += (ix + sX/2)*sE; + else + iSwap += (ix - sX/2)*sE; + //iSwap = (iz + sZ/2)*sX*sY*sE + (iy + sY/2)*sX*sE + (ix + sX/2)*sE; + + char temp; + for(int e=0; e>>(gpuSource, elementSize, sX, sY, sZ); + + + +} + + +#endif \ No newline at end of file diff --git a/rts_glBrewer.glsl b/rts_glBrewer.glsl new file mode 100755 index 0000000..e69de29 --- /dev/null +++ b/rts_glBrewer.glsl diff --git a/rts_glBrewer.h b/rts_glBrewer.h new file mode 100755 index 0000000..18ca3e4 --- /dev/null +++ b/rts_glBrewer.h @@ -0,0 +1,17 @@ +#include "rtsPoint3d.h" + +void rts_glBrewerPts(point3D* brewerPts) +{ + //define control points + brewerPts[0] = point3D(0.192157f, 0.211765f, 0.584314f); + brewerPts[1] = point3D(0.270588f, 0.458824f, 0.705882f); + brewerPts[2] = point3D(0.454902f, 0.678431f, 0.819608f); + brewerPts[3] = point3D(0.670588f, 0.85098f, 0.913725f); + brewerPts[4] = point3D(0.878431f, 0.952941f, 0.972549f); + brewerPts[5] = point3D(1.0f, 1.0f, 0.74902f); + brewerPts[6] = point3D(0.996078f, 0.878431f, 0.564706f); + brewerPts[7] = point3D(0.992157f, 0.682353f, 0.380392f); + brewerPts[8] = point3D(0.956863f, 0.427451f, 0.262745f); + brewerPts[9] = point3D(0.843137f, 0.188235f, 0.152941f); + brewerPts[10] = point3D(0.647059f, 0.0f, 0.14902f); +} \ No newline at end of file diff --git a/rts_glFilamentNetwork.cpp b/rts_glFilamentNetwork.cpp new file mode 100755 index 0000000..404260f --- /dev/null +++ b/rts_glFilamentNetwork.cpp @@ -0,0 +1,17 @@ +#include "rts_glFilamentNetwork.h" + +void rts_glFilamentNetwork::glRender() +{ + ((rts_glOBJ*)network)->glRender(); +} + +void rts_glFilamentNetwork::glRenderSelected() +{ + ((rts_glOBJ*)network)->glRenderSelected(); +} + +int rts_glFilamentNetwork::LoadFIB(const char* filename) +{ + ((rts_glOBJ*)network)->Invalidate(); + return fib_load(filename); +} \ No newline at end of file diff --git a/rts_glFilamentNetwork.h b/rts_glFilamentNetwork.h new file mode 100755 index 0000000..00c9114 --- /dev/null +++ b/rts_glFilamentNetwork.h @@ -0,0 +1,26 @@ +#ifndef RTS_GLFILAMENTNETWORK_H +#define RTS_GLFILAMENTNETWORK_H + +#include "rtsFilamentNetwork.h" +#include "rts_glOBJ.h" +#include +#include +#include + +class rts_glFilamentNetwork:public rtsFilamentNetwork +{ +public: + rts_glFilamentNetwork(){network = new rts_glOBJ();} + void glRender(); + void glRenderSelected(); + + int LoadFIB(const char* filename); //overload the parent function to reset the display list + + void Pick(unsigned int x, unsigned int y, unsigned int size_x, unsigned int size_y) + { + ((rts_glOBJ*)network)->Pick(x, y, size_x, size_y); + } +}; + + +#endif \ No newline at end of file diff --git a/rts_glIntegrateTexture.cpp b/rts_glIntegrateTexture.cpp new file mode 100755 index 0000000..e69de29 --- /dev/null +++ b/rts_glIntegrateTexture.cpp diff --git a/rts_glIntegrateTexture.h b/rts_glIntegrateTexture.h new file mode 100755 index 0000000..2e86d67 --- /dev/null +++ b/rts_glIntegrateTexture.h @@ -0,0 +1,172 @@ +/*This class performs integration across a series of rectangular +texture samples. Basically, this is a downsample using a large box +filter and can be used to sum the results of multiple calculations +that are combined in a single texture.*/ + +#include "rts_glRenderToTexture.h" +#include "rts_glShaderProgram.h" + +#define MEAN 0 +#define SUM 1 +#define MIN 2 +#define MAX 3 + + +class rts_glIntegrateTexture +{ +private: + int x_sample_size; + int y_sample_size; + int x_sample_num; + int y_sample_num; + + rts_glShaderProgram x_pass_mean; + rts_glShaderProgram y_pass_mean; + + rts_glShaderProgram x_pass_min; + rts_glShaderProgram y_pass_min; + + rts_glShaderProgram x_pass_max; + rts_glShaderProgram y_pass_max; + + //this is a two-pass downsample + rts_glRenderToTexture x_pass; + rts_glRenderToTexture y_pass; + + void initialize_shaders(); + inline void x_pass_enable(int type, rts_glTextureMap texture); + inline void x_pass_disable(int type); + inline void y_pass_enable(int type); + inline void y_pass_disable(int type); + +public: + //initialize the integrator with the number and size of samples + void Init(int x_size, int y_size, + int samples_x, int samples_y, + rts_glTextureMap test); + + void Integrate(float* result, rts_glTextureMap texture, int type = MEAN); + rts_glTextureMap getResultTexture(){return y_pass.GetTexture(0);} +}; + +void rts_glIntegrateTexture::initialize_shaders() +{ + //load and initialize the integration shaders + x_pass_mean.AttachShader(GL_FRAGMENT_SHADER, + "x_pass_mean.glsl"); + x_pass_mean.Compile(); + x_pass_mean.Link(); + cout<<"x_pass_mean.glsl"< 4) + glBegin(GL_POLYGON); + else if(primitives[id].p.size() == 4) + glBegin(GL_QUADS); + else if(primitives[id].p.size() == 3) + glBegin(GL_TRIANGLES); + else + return; + + //now run through each vertex + unsigned int num_vertices = primitives[id].p.size(); + for(unsigned int v=0; v::iterator p; + for(p = selected_primitives.begin(); p!=selected_primitives.end(); p++) + f_RenderPrimitive(*p); + } + return OBJ_OK; +} + + +void rts_glOBJ::SelectPrimitive(unsigned int primitive) +{ + //adds a primitive to the selection list + selected_primitives.push_back(primitive); + selected_primitives.unique(); +} + +void rts_glOBJ::UnselectPrimitive(unsigned int primitive) +{ + selected_primitives.remove(primitive); +} + +void rts_glOBJ::SelectMultipleHits(GLuint* buffer, unsigned int num_hits) +{ + GLuint* hit_entry = buffer; + GLuint num_names; + GLuint nearest_name; + GLuint minZ = 0xffffffff; + + //push the hits into the selection buffer + for(int h=0; h::iterator p; + for(p = selected_primitives.begin(); p != selected_primitives.end(); p++) + { + primitive selected_prim = primitives[(*p)]; + //create a new primitive + primitive new_prim; + new_prim.mask = selected_prim.mask; + new_prim.type = selected_prim.type; + + //for each vertex in the primitive + int num_vertices = selected_prim.p.size(); + for(int v = 0; v selected_v; + + list::iterator p; //selected primitive + vector::iterator v; //vertex + + //insert all selected vertex indices into selected_v + for(p = selected_primitives.begin(); p!=selected_primitives.end(); p++) + { + for(v=primitives[(*p)].p.begin(); v!=primitives[(*p)].p.end(); v++) + { + selected_v.push_back((*v).v); + } + } + selected_v.unique(); //remove redundant entries + + //now find all primitives connected to these vertices + int num_primitives = primitives.size(); + int prim; + list::iterator s_v; + for(prim =0; prim* vertex_to_prim = new vector[v_list.size()]; + int num_primitives = primitives.size(); + int p; + int num_vertices, v; + int vertex; + for(p=0; p selected_verts; + list::iterator sel; + for(sel = selected_primitives.begin(); sel != selected_primitives.end(); sel++) + { + num_vertices = primitives[(*sel)].p.size(); + for(v=0; v::iterator s_v; + for(s_v = selected_verts.begin(); s_v != selected_verts.end(); s_v++) + { + num_primitives = vertex_to_prim[(*s_v)].size(); + for(p=0; p +#include +#include +#include + +using namespace std; + +#define BUFSIZE 20000 + +#define OBJ_NOT_SELECTED 0x0000 +#define OBJ_SELECTED 0x0001 +#define OBJ_SELECTED_PRIMITIVES 0x0002 + +#define RTS_GLOBJ_SINGLE_NEW_SELECTION 0 +#define RTS_GLOBJ_SINGLE_ADD_SELECTION 1 +#define RTS_GLOBJ_SINGLE_SUB_SELECTION 2 + +#define RTS_GLOBJ_MULTI_NEW_SELECTION 3 +#define RTS_GLOBJ_MULTI_ADD_SELECTION 4 +#define RTS_GLOBJ_MULTI_SUB_SELECTION 5 + +class rts_glOBJ : public rtsOBJ +{ +private: + int is_selected; //the object, or part of the object, is selected + list selected_primitives; + + //rendering variables + GLint dl; + bool dl_valid; //true if the display list is valid + + OBJint f_CreateDisplayList(); + + void f_RenderPointList(unsigned int pointlist); + void f_RenderLineStrip(unsigned int line); + void f_RenderFace(unsigned int face); + + OBJint f_RenderTexCoord(vertex_texture &texcoord); + OBJint f_RenderNormal(vertex_normal &normal); + OBJint f_RenderVertex(vertex_position &v); + OBJint f_RenderPrimitive(unsigned int id); + + void SelectMultipleHits(GLuint* buffer, unsigned int num_hits); + void SelectClosestHit(GLuint* buffer, unsigned int num_hits); + void SelectPrimitive(unsigned int primitive); + void UnselectMultipleHits(GLuint* buffer, unsigned int num_hits); + void UnselectClosestHit(GLuint* buffer, unsigned int num_hits); + void UnselectPrimitive(unsigned int primitive); + +public: + //constructors + //basic + rts_glOBJ() + { + is_selected = false; + dl_valid = false; + cout< +#include +#include "rts_glTextureMap.h" + +using namespace std; + +class rts_glRenderToTexture +{ +private: + bool init; + + GLuint fbo; //framebuffer object + int width; //width and height of the framebuffer + int height; + vector textures; + +public: + //constructors + rts_glRenderToTexture(){init = false; fbo = 0;} + rts_glRenderToTexture(int width, int height){Init(width, height);} + + void Init(int width, int height); //initialization + void Clean(); + + void AddTexture(GLenum target, + GLint internalformat = 1, + GLenum format = GL_LUMINANCE, + GLenum datatype = GL_UNSIGNED_BYTE, + GLint interpolation = GL_NEAREST); + void BeginTexture(int texture){textures[texture].BeginTexture();} + void EndTexture(int texture){textures[texture].EndTexture();} + rts_glTextureMap GetTexture(int texture){return textures[texture];} + + void BeginRender(int texture); + void EndRender(); + + int Width(){return width;} + int Height(){return height;} + void UseMaxViewport(){glViewport(0, 0, width, height);} + +}; + +#endif diff --git a/rts_glRenderableDTGrid.cpp b/rts_glRenderableDTGrid.cpp new file mode 100755 index 0000000..1a24fcc --- /dev/null +++ b/rts_glRenderableDTGrid.cpp @@ -0,0 +1,260 @@ +#include "rts_glRenderableDTGrid.h" + + +/*ITERATOR INITIALIZATION*/ +void rts_glRenderableDTGrid::init_iter_ppp() +{ + m_iterator = begin(); + m_iter_type = PPP; +} +void rts_glRenderableDTGrid::init_iter_nnn() +{ + m_iterator = last(); + m_iter_type = NNN; +} +void rts_glRenderableDTGrid::init_iter_ppn() +{ + m_iterator = begin(); //put the iterator at the beginning of the data set + + if(m_iterator.grid->acc.size() > 1) //if there is more than one pcolumn + { + m_iterator.loc.iv = m_iterator.grid->proj2D.value[1].to_value - 1; + m_iterator.loc.z = zCoord[m_iterator.grid->proj2D.value[1].to_coord - 1]; + } + else + { + m_iterator.loc.iv = value.size() - 1; + m_iterator.loc.z = zCoord.back(); + } + m_iter_type = PPN; +} + +void rts_glRenderableDTGrid::init_iter_npp() +{ + //set the 1D iterator location + m_iterator.Iterator2D.Iterator1D.loc.iv = proj2D.proj1D.value.size()-1; //start at the last 1D p-column + m_iterator.Iterator2D.Iterator1D.loc.ic = proj2D.proj1D.xCoord.size() - 2; + m_iterator.Iterator2D.Iterator1D.loc.x = proj2D.proj1D.xCoord[m_iterator.Iterator2D.Iterator1D.loc.ic+1]; + m_iterator.Iterator2D.Iterator1D.value = proj2D.proj1D.value[m_iterator.Iterator2D.Iterator1D.loc.iv]; + m_iterator.Iterator2D.Iterator1D.grid = &(proj2D.proj1D); + + //set the 2D iterator location + m_iterator.Iterator2D.loc.iv = proj2D.proj1D.value[m_iterator.Iterator2D.Iterator1D.loc.iv].to_value; + m_iterator.Iterator2D.loc.ic = proj2D.proj1D.value[m_iterator.Iterator2D.Iterator1D.loc.iv].to_coord; + m_iterator.Iterator2D.loc.y = proj2D.yCoord[m_iterator.Iterator2D.loc.ic]; + m_iterator.Iterator2D.value = proj2D.value[m_iterator.Iterator2D.loc.iv]; + m_iterator.Iterator2D.grid = &(proj2D); + + //set the 3D iterator location + m_iterator.loc.iv = proj2D.value[m_iterator.Iterator2D.loc.iv].to_value; + m_iterator.loc.ic = proj2D.value[m_iterator.Iterator2D.loc.iv].to_coord; + m_iterator.loc.z = zCoord[m_iterator.loc.ic]; + m_iterator.value = value[m_iterator.loc.iv]; + m_iterator.grid = this; + + m_iter_type = NPP; +} + +void rts_glRenderableDTGrid::iter_next_npp() +{ + //if we are at the end of a p-column + if(m_iterator.loc.iv == value.size() - 1 || //if we are at the end of the last p-column or + (m_iterator.Iterator2D.loc.iv != m_iterator.grid->proj2D.value.size() - 1 && + m_iterator.loc.iv == proj2D.value[m_iterator.Iterator2D.loc.iv + 1].to_value - 1)) //we are at the end of a p-column + { + iter_next_npx(m_iterator.Iterator2D); //increment the 2D iterator + m_iterator.loc.iv = proj2D.value[m_iterator.Iterator2D.loc.iv].to_value; + m_iterator.loc.ic = proj2D.value[m_iterator.Iterator2D.loc.iv].to_coord; + m_iterator.loc.z = zCoord[m_iterator.loc.ic]; + } + //if we are at the end of a connected component + else if(m_iterator.loc.z == zCoord[m_iterator.loc.ic+1]) + { + m_iterator.loc.iv++; + m_iterator.loc.ic+=2; + m_iterator.loc.z = zCoord[m_iterator.loc.ic]; + } + //else if we are in a p-column + else + { + m_iterator.loc.iv++; + m_iterator.loc.z++; + } + m_iterator.value = value[m_iterator.loc.iv]; +} + +void rts_glRenderableDTGrid::iter_next_ppn() +{ + //if we are at the beginning of a p-column + if(m_iterator.loc.z == zCoord[m_iterator.loc.ic] && + m_iterator.loc.ic == proj2D.value[m_iterator.Iterator2D.loc.iv].to_coord) + { + m_iterator.Iterator2D.increment(); //move to the next p-column + if(m_iterator.Iterator2D.loc.iv >= proj2D.value.size()) //return + return; + //now update the 3D locator + if(m_iterator.Iterator2D.loc.iv == proj2D.value.size() - 1) //if this is the last p-column + { + m_iterator.loc.iv = value.size() - 1; + m_iterator.loc.ic = zCoord.size() - 2; + m_iterator.loc.z = zCoord.back(); + } + else + { + m_iterator.loc.iv = proj2D.value[m_iterator.Iterator2D.loc.iv+1].to_value - 1; + m_iterator.loc.ic = proj2D.value[m_iterator.Iterator2D.loc.iv+1].to_coord - 2; + m_iterator.loc.z = zCoord[m_iterator.loc.ic + 1]; + } + } + //if we are at the beginning of a connected component + else if(m_iterator.loc.z == zCoord[m_iterator.loc.ic]) + { + m_iterator.loc.iv-=1; + m_iterator.loc.ic-=2; + m_iterator.loc.z = zCoord[m_iterator.loc.ic + 1]; + } + //if we're in the middle of a connected component + else + { + m_iterator.loc.iv--; + m_iterator.loc.z--; + } + m_iterator.value = value[m_iterator.loc.iv]; +} + +void rts_glRenderableDTGrid::iter_next_npx(rtsDTGrid2D::iterator &i2d) +{ + //if we are at the end of a p-column + if(i2d.loc.iv == i2d.grid->value.size() - 1 || //if this is the last p-column + (i2d.Iterator1D.loc.iv != i2d.grid->proj1D.value.size() - 1 && //we are not in the last p-column and + i2d.loc.iv == i2d.grid->proj1D.value[i2d.Iterator1D.loc.iv+1].to_value - 1)) + { + //if(i2d.Iterator1D.loc.iv == 0) //if it is the first p-column + // return; + i2d.Iterator1D.decrement(); //decrement the 1D iterator + //update the 2D locator + i2d.loc.iv = i2d.grid->proj1D.value[i2d.Iterator1D.loc.iv].to_value; + i2d.loc.ic = i2d.grid->proj1D.value[i2d.Iterator1D.loc.iv].to_coord; + i2d.loc.y = i2d.grid->yCoord[i2d.loc.ic]; + } + //if we are at the end of a connected component + else if(i2d.loc.y == i2d.grid->yCoord[i2d.loc.ic+1]) + { + i2d.loc.iv++; + i2d.loc.ic+=2; + i2d.loc.y = i2d.grid->yCoord[i2d.loc.ic]; + } + else + { + i2d.loc.iv++; + i2d.loc.y++; + } + //set value + i2d.value = i2d.grid->value[i2d.loc.iv]; +} + + +void rts_glRenderableDTGrid::iter_next() +{ + if(m_iter_type == PPP) + m_iterator.increment(); + if(m_iter_type == NNN) + m_iterator.decrement(); + if(m_iter_type == PPN) + iter_next_ppn(); + if(m_iter_type == NPP) + iter_next_npp(); +} +void rts_glRenderableDTGrid::RenderPoints(unsigned int size, float camera_x, float camera_y, float camera_z) +{ + /*This function renders a single point to the screen for each voxel in the + DT-Grid. + */ + //determine which directions to iterate + if(camera_x > 0) + { + if(camera_y > 0) + { + if(camera_z > 0) + { + //cout<<"+++"< 0) + { + //cout<<"+-+"< 0) + { + if(camera_z > 0) + { + //cout<<"-++"< 0) + { + //cout<<"--+"< +{ +private: + IteratorType m_iter_type; + rtsDTGrid3D::iterator m_iterator; + void init_iter_ppp(); + void init_iter_ppn(); + void iter_next_ppn(); + void init_iter_npp(); + void iter_next_npp(); + void init_iter_nnn(); + void iter_next_npx(rtsDTGrid2D::iterator &i2d); + void iter_next(); +public: + void RenderPoints(unsigned int size, float camera_x, float camera_y, float camera_z); + +}; + + +#endif \ No newline at end of file diff --git a/rts_glShaderObject.h b/rts_glShaderObject.h new file mode 100755 index 0000000..85a96c5 --- /dev/null +++ b/rts_glShaderObject.h @@ -0,0 +1,115 @@ +#ifndef RTS_GLSHADERS +#define RTS_GLSHADERS + +#include +//#include "windows.h" +#include +#include "rtsSourceCode.h" + +class rts_glShaderObject +{ +private: + void init() + { + id = 0; + compiled = false; + type = GL_FRAGMENT_SHADER; + } +public: + bool compiled; + GLenum type; + rtsSourceCode source; + GLuint id; + string log; + + rts_glShaderObject(GLenum type, const char* filename) + { + init(); //initialize the shader + SetType(type); //set the shader type + LoadSource(filename); //load the source code + } + rts_glShaderObject(GLenum type, rtsSourceCode sourceCode) + { + init(); //initialize the shader + SetType(type); //set the shader type + source = sourceCode; + } + rts_glShaderObject() + { + init(); + } + rts_glShaderObject(GLenum type) + { + init(); + SetType(type); + } + void LoadSource(const char* filename) + { + source = rtsSourceCode(filename); //get the shader source code + + } + void SetType(GLenum type) + { + if(id != 0) //if a shader currently exists, delete it + { + glDeleteShader(id); + id = 0; + } + type = type; + id = glCreateShader(type); //create a shader object + if(id == 0) //if a shader was not created, log an error + { + log = "Error getting shader ID from OpenGL"; + return; + } + } + void UploadSource() + { + //create the structure for the shader source code + GLsizei count = source.source.size(); + GLchar** code_string = new GLchar*[count]; + GLint* length = new GLint[count]; + for(int l = 0; l + +using namespace std; + +class rts_glShaderProgram +{ +private: + void get_uniforms() + { + GLint num_uniforms; + glGetProgramiv(id, GL_ACTIVE_UNIFORMS, &num_uniforms); //get the number of uniform variables + GLint max_name_length; + glGetProgramiv(id, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_name_length); //get the maximum uniform name length + GLchar* name_buffer = new GLchar[max_name_length]; //create a buffer to store the name + GLsizei length; //I'm not using these yet + GLint size; + GLenum type; //variable's data type + GLint location; //GPU location of the variable + for(int i=0; i shader_list; //list of opengl shaders + vector uniform_list; //list of active uniform variables + vector texture_list; //list of texture maps + + rts_glShaderProgram() + { + linked = false; + id = 0; + } + void AttachShader(rts_glShaderObject shader) + { + if(id == 0) + { + Init(); + } + if(shader.id == 0) //if the shader is invalid + { + log = "Shader is invalid"; + return; + } + + //attach the shader to the program + glAttachShader(id, shader.id); //attach the shader to the program in OpenGL + CHECK_OPENGL_ERROR + shader_list.push_back(shader); //push the shader onto our list for later access + } + //type = GL_FRAGMENT_SHADER or GL_VERTEX_SHADER + void AttachShader(GLenum type, const char* filename) + { + rts_glShaderObject shader(type, filename); + AttachShader(shader); + } + void AttachShader(GLenum type, rtsSourceCode source) + { + rts_glShaderObject shader(type, source); + AttachShader(shader); + } + void PrintLog() + { + cout<::iterator iter; + for(iter = shader_list.begin(); iter != shader_list.end(); iter++) + { + (*iter).Compile(); + //(*iter).PrintLog(); + } + } + void Link() + { + glLinkProgram(id); //link the current shader program + GLint link_status; //test to see if the link went alright + glGetProgramiv(id, GL_LINK_STATUS, &link_status); + if(link_status != GL_TRUE) + { + linked = false; + } + else + linked = true; + + GLsizei length; + GLchar buffer[1000]; + glGetProgramInfoLog(id, 1000, &length, buffer); + log = buffer; + + get_uniforms(); //create the list of active uniform variables + } + void BeginProgram() + { + CHECK_OPENGL_ERROR + if(id == 0) //if the program is invalid, return + { + log = "Invalid program, cannot use."; + return; + } + if(!linked) + { + cout<<"Shader Program used without being linked."< 0) + glActiveTexture(GL_TEXTURE0); + CHECK_OPENGL_ERROR + + //return to OpenGL default shading + glUseProgram(0); + CHECK_OPENGL_ERROR + } + void PrintUniforms() + { + cout<<"Shader Uniforms: "< +#include + +using namespace std; + +enum rtsUniformEnum {RTS_FLOAT, RTS_INT, RTS_BOOL, RTS_FLOAT_MATRIX}; + +///This class stores a single uniform variable for GLSL and is designed to be used by the rts_glShaderProgram class. +struct rts_glShaderUniform +{ +public: + string name; //the name of the variable + GLint location; //the location in the program + void* p_value; //pointer to the global data representing the value in main memory + GLenum type; //variable type (float, int, vec2, etc.) + //rtsUniformEnum rts_type; //type of variable in rts format + //unsigned int num; //the number of values required by the variable (1 for float, 2 for vec2, etc.) + string log; + + //void convert_type(GLenum gl_type); //converts the OpenGL data type to something useful for rts + void submit_to_gpu() + { + if(location < 0) + return; + if(p_value == NULL) + { + cout<<"Error in uniform address: "<(width, height, depth); //assign the texture size + //get_type(); //guess the type based on the size + texture_type = type; //set the type of texture + glEnable(texture_type); //enable the texture map + CHECK_OPENGL_ERROR + glBindTexture(texture_type, name); //bind the texture for editing + CHECK_OPENGL_ERROR + set_wrapping(); //set the texture wrapping parameters + CHECK_OPENGL_ERROR + glTexParameteri(texture_type, GL_TEXTURE_MAG_FILTER, interpolation); //set filtering + CHECK_OPENGL_ERROR + glTexParameteri(texture_type, GL_TEXTURE_MIN_FILTER, interpolation); + CHECK_OPENGL_ERROR + internal_format = internalformat; //set the number of components per pixel + pixel_format = format; //set the pixel format + data_type = datatype; //set the data type + SetBits(bits); //send the bits to the OpenGL driver + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //replace the specified vertex color + CHECK_OPENGL_ERROR + glDisable(texture_type); +} \ No newline at end of file diff --git a/rts_glTextureMap.h b/rts_glTextureMap.h new file mode 100755 index 0000000..9ab7736 --- /dev/null +++ b/rts_glTextureMap.h @@ -0,0 +1,260 @@ +#ifndef RTS_GLTEXTUREMAP_H +#define RTS_GLTEXTUREMAP_H + +#include +#include "rtsVector3d.h" +#include "CHECK_OPENGL_ERROR.h" +#include + +///This class stores an OpenGL texture map and is used by rts_glShaderProgram. +class rts_glTextureMap +{ +private: + void get_type() //guesses the texture type based on the size + { + if(size.y == 0) + texture_type = GL_TEXTURE_1D; + else if(size.z == 0) + texture_type = GL_TEXTURE_2D; + else + texture_type = GL_TEXTURE_3D; + } + void set_wrapping() //set the texture wrapping based on the dimensions + { + CHECK_OPENGL_ERROR + switch(texture_type) + { + case GL_TEXTURE_3D: + glTexParameteri(texture_type, GL_TEXTURE_WRAP_R_EXT, GL_REPEAT); + case GL_TEXTURE_2D: + glTexParameteri(texture_type, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); + case GL_TEXTURE_1D: + glTexParameteri(texture_type, GL_TEXTURE_WRAP_S, GL_REPEAT); + break; + case GL_TEXTURE_RECTANGLE_ARB: + glTexParameteri(texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + break; + + default: + break; + } + CHECK_OPENGL_ERROR + } + //void set_bits(GLvoid* bits); +public: + vector3D size; //vector representing the size of the texture + GLuint name; //texture name assigned by OpenGL + GLenum texture_type; //1D, 2D, 3D + GLint internal_format; //number of components (ex. 4 for RGBA) + GLenum pixel_format; //type of data (RGBA, LUMINANCE) + GLenum data_type; //data type of the bits (float, int, etc.) + + //constructor + rts_glTextureMap() + { + name = 0; + } + + void BeginTexture() + { + glEnable(texture_type); + glBindTexture(texture_type, name); + CHECK_OPENGL_ERROR + } + void EndTexture() + { + glDisable(texture_type); + CHECK_OPENGL_ERROR + } + + ///Creates an OpenGL texture map. This function requires basic information about the texture map as well as a pointer to the bit data describing the texture. + void Init(GLvoid *bits, + GLenum type = GL_TEXTURE_2D, + GLsizei width = 256, + GLsizei height = 256, + GLsizei depth = 0, + GLint internalformat = 1, + GLenum format = GL_LUMINANCE, + GLenum datatype = GL_UNSIGNED_BYTE, + GLint interpolation = GL_LINEAR) + { + CHECK_OPENGL_ERROR + if(name != 0) + glDeleteTextures(1, &name); + + + CHECK_OPENGL_ERROR + if(datatype == GL_FLOAT) + { + glPixelStorei(GL_PACK_ALIGNMENT, 4); + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); //I honestly don't know what this does but it fixes problems + } + else if(datatype == GL_UNSIGNED_BYTE) + { + //glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + //glPixelStorei(GL_PACK_ALIGNMENT, 1); + } + else if(datatype == GL_UNSIGNED_SHORT) + { + //glPixelStorei(GL_UNPACK_ALIGNMENT, 2); + //glPixelStorei(GL_PACK_ALIGNMENT, 2); + } + CHECK_OPENGL_ERROR + glGenTextures(1, &name); //get the texture name from OpenGL + //cout<<"OpenGL Name: "<(width, height, depth); //assign the texture size + //get_type(); //guess the type based on the size + texture_type = type; //set the type of texture + glEnable(texture_type); //enable the texture map + CHECK_OPENGL_ERROR + glBindTexture(texture_type, name); //bind the texture for editing + CHECK_OPENGL_ERROR + set_wrapping(); //set the texture wrapping parameters + CHECK_OPENGL_ERROR + glTexParameteri(texture_type, GL_TEXTURE_MAG_FILTER, interpolation); //set filtering + CHECK_OPENGL_ERROR + glTexParameteri(texture_type, GL_TEXTURE_MIN_FILTER, interpolation); + CHECK_OPENGL_ERROR + internal_format = internalformat; //set the number of components per pixel + pixel_format = format; //set the pixel format + data_type = datatype; //set the data type + SetBits(bits); //send the bits to the OpenGL driver + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //replace the specified vertex color + CHECK_OPENGL_ERROR + glDisable(texture_type); + + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + } + void Clean() + { + if(name != 0) + { + glDeleteTextures(1, &name); + CHECK_OPENGL_ERROR + name = 0; + } + } + void SetBits(GLvoid *bits) + { + glEnable(texture_type); //enable the texture map + CHECK_OPENGL_ERROR + glBindTexture(texture_type, name); + CHECK_OPENGL_ERROR + + switch(texture_type) + { + case GL_TEXTURE_3D: + glTexImage3D(texture_type, 0, internal_format, size.x, size.y, size.z, 0, pixel_format, data_type, bits); + CHECK_OPENGL_ERROR + break; + case GL_TEXTURE_2D: + case GL_TEXTURE_RECTANGLE_ARB: + glTexImage2D(texture_type, 0, internal_format, size.x, size.y, 0, pixel_format, data_type, bits); + CHECK_OPENGL_ERROR + break; + case GL_TEXTURE_1D: + glTexImage1D(texture_type, 0, internal_format, size.x, 0, pixel_format, data_type, bits); + CHECK_OPENGL_ERROR + break; + default: + //glTexImage2D(texture_type, 0, internal_format, size.x, size.y, 0, pixel_format, data_type, bits); + break; + } + CHECK_OPENGL_ERROR + } + void ResetBits(GLvoid *bits) + { + glEnable(texture_type); //enable the texture map + CHECK_OPENGL_ERROR + glBindTexture(texture_type, name); + CHECK_OPENGL_ERROR + + switch(texture_type) + { + case GL_TEXTURE_3D: + //glTexImage3D(texture_type, 0, internal_format, size.x, size.y, size.z, 0, pixel_format, data_type, bits); + break; + case GL_TEXTURE_2D: + case GL_TEXTURE_RECTANGLE_ARB: + glTexSubImage2D(texture_type, 0, 0, 0, size.x, size.y, pixel_format, data_type, bits); + CHECK_OPENGL_ERROR + break; + case GL_TEXTURE_1D: + //glTexImage1D(texture_type, 0, internal_format, size.x, 0, pixel_format, data_type, bits); + break; + default: + //glTexImage2D(texture_type, 0, internal_format, size.x, size.y, 0, pixel_format, data_type, bits); + break; + } + glDisable(texture_type); + CHECK_OPENGL_ERROR + } + void* GetBits(GLenum format, GLenum type) + { + //returns the texture data + + int components; + switch(format) + { + case GL_RED: + case GL_GREEN: + case GL_BLUE: + case GL_ALPHA: + case GL_LUMINANCE: + components = 1; + break; + case GL_LUMINANCE_ALPHA: + components = 2; + break; + case GL_RGB: + case GL_BGR: + components = 3; + break; + case GL_RGBA: + case GL_BGRA: + components = 4; + break; + } + + int type_size; + switch(type) + { + case GL_UNSIGNED_BYTE: + case GL_BYTE: + type_size = sizeof(char); + break; + case GL_UNSIGNED_SHORT: + case GL_SHORT: + type_size = sizeof(short); + break; + case GL_UNSIGNED_INT: + case GL_INT: + type_size = sizeof(int); + break; + case GL_FLOAT: + type_size = sizeof(float); + break; + } + + //allocate memory for the texture + void* result = malloc(components*type_size * size.x * size.y); + + BeginTexture(); + glGetTexImage(texture_type, 0, format, type, result); + + CHECK_OPENGL_ERROR + EndTexture(); + + + return result; + + } +}; + +#define RTS_UNKNOWN 0 + +#endif \ No newline at end of file diff --git a/rts_glTrueEyes.h b/rts_glTrueEyes.h new file mode 100755 index 0000000..1a8809e --- /dev/null +++ b/rts_glTrueEyes.h @@ -0,0 +1,304 @@ +#include +#include + +#include "rtsCamera.h" +#include "rtsSourceCode.h" +#include "rts_glShaderProgram.h" +using namespace std; + +#include + +class rts_glTrueEyes +{ + static int glut_window; + + static rts_glShaderProgram shader; + static string source_file; + static rtsCamera camera; + static int mouse_x; + static int mouse_y; + static float camera_pos[3]; + static float volume_size[3]; + static rts_glTextureMap volume; + + static bool zooming; + + static void DrawCube() + { + float sx = volume_size[0]/2; + float sy = volume_size[1]/2; + float sz = volume_size[2]/2; + float tx = volume_size[0]/2; + float ty = volume_size[1]/2; + float tz = volume_size[2]/2; + + glBegin(GL_QUADS); + glTexCoord3f(-tx, -ty, -tz); + glVertex3f(-sx, -sy, -sz); + glTexCoord3f(-tx, ty, -tz); + glVertex3f(-sx, sy, -sz); + glTexCoord3f(tx, ty, -tz); + glVertex3f(sx, sy, -sz); + glTexCoord3f(tx, -ty, -tz); + glVertex3f(sx, -sy, -sz); + + glTexCoord3f(-tx, -ty, tz); + glVertex3f(-sx, -sy, sz); + glTexCoord3f(-tx, ty, tz); + glVertex3f(-sx, sy, sz); + glTexCoord3f(tx, ty, tz); + glVertex3f(sx, sy, sz); + glTexCoord3f(tx, -ty, tz); + glVertex3f(sx, -sy, sz); + + glTexCoord3f(-tx, -ty, -tz); + glVertex3f(-sx, -sy, -sz); + glTexCoord3f(-tx, -ty, tz); + glVertex3f(-sx, -sy, sz); + glTexCoord3f(tx, -ty, tz); + glVertex3f(sx, -sy, sz); + glTexCoord3f(tx, -ty, -tz); + glVertex3f(sx, -sy, -sz); + + glTexCoord3f(-tx, ty, -tz); + glVertex3f(-sx, sy, -sz); + glTexCoord3f(-tx, ty, tz); + glVertex3f(-sx, sy, sz); + glTexCoord3f(tx, ty, tz); + glVertex3f(sx, sy, sz); + glTexCoord3f(tx, ty, -tz); + glVertex3f(sx, sy, -sz); + + glTexCoord3f(-tx, -ty, -tz); + glVertex3f(-sx, -sy, -sz); + glTexCoord3f(-tx, -ty, tz); + glVertex3f(-sx, -sy, sz); + glTexCoord3f(-tx, ty, tz); + glVertex3f(-sx, sy, sz); + glTexCoord3f(-tx, ty, -tz); + glVertex3f(-sx, sy, -sz); + + glTexCoord3f(tx, -ty, -tz); + glVertex3f(sx, -sy, -sz); + glTexCoord3f(tx, -ty, tz); + glVertex3f(sx, -sy, sz); + glTexCoord3f(tx, ty, tz); + glVertex3f(sx, sy, sz); + glTexCoord3f(tx, ty, -tz); + glVertex3f(sx, sy, -sz); + glEnd(); + } + + static void DisplayFunction() + { + + + //set up the viewport and projection + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glViewport(0, 0, glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT)); + float aspect_ratio = (float)glutGet(GLUT_WINDOW_WIDTH)/(float)glutGet(GLUT_WINDOW_HEIGHT); + gluPerspective(camera.getFOV(), aspect_ratio, 0.01, 10); + + //clear the screen + glClear(GL_COLOR_BUFFER_BIT); + glClear(GL_DEPTH_BUFFER_BIT); + + + //set up the camera + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + point3D pos = camera.getPosition(); + vector3D up = camera.getUp(); + gluLookAt(pos.x, pos.y, pos.z, 0, 0, 0, up.x, up.y, up.z); + + //draw a cube + glColor3f(1.0, 0.0, 0.0); + shader.UpdateGlobalUniforms(); + shader.BeginProgram(); + DrawCube(); + shader.EndProgram(); + + glutSwapBuffers(); + } + static void IdleFunction() + { + glutPostRedisplay(); + } + + static void MouseDrag(int x, int y) + { + int dx = x - mouse_x; + int dy = y - mouse_y; + + if(zooming) + { + camera.Zoom(dy); + } + else + { + + camera.OrbitFocus(-dx*0.01, dy*0.01); + point3D pos = camera.getPosition(); + camera_pos[0] = pos.x; + camera_pos[1] = pos.y; + camera_pos[2] = pos.z; + } + + mouse_x = x; + mouse_y = y; + + glutPostRedisplay(); + + } + + static void MouseMove(int x, int y) + { + mouse_x = x; + mouse_y = y; + + } + static void KeyPress(unsigned char key, int x, int y) + { + //reload the shader + if(key == 'r' || key == 'R') + { + UpdateShader(); + + + } + + } + + static void MousePress(int button, int state, int x, int y) + { + if(state == GLUT_DOWN && button == GLUT_MIDDLE_BUTTON) + zooming = true; + else + zooming = false; + } + + static void UpdateShader() + { + //load the source code + shader.Clean(); + shader.AttachShader(GL_FRAGMENT_SHADER, source_file.c_str()); + + //compile the shader + shader.Compile(); + shader.PrintLog(); + shader.Link(); + shader.PrintLog(); + + if(!shader.linked) + { + cout<<"Error linking shader."< 0) + texture_volume.blacken(m_min_threshold); + if(m_max_threshold < 255) + texture_volume.whiten(m_max_threshold); + + + + //if we are optimizing the texture, make the dimensions a power-of-two + if(m_optimize) + { + PD.StartTimer(RESIZE_DATA); + //find the maximum dimension + unsigned int max_dimension = max(max(m_source.get_dimx(), m_source.get_dimy()), m_source.get_dimz()); + + unsigned int new_dimension = 2; + //calculate the new dimension + while(new_dimension < max_dimension) + new_dimension *= 2; + //resize the texture volume + texture_volume.resize_canvas(new_dimension, new_dimension, new_dimension); + PD.EndTimer(RESIZE_DATA); + } + + //apply the new image to the texture + glBindTexture(GL_TEXTURE_3D, m_volume_texture); + unsigned int dimx = texture_volume.get_dimx(); + unsigned int dimy = texture_volume.get_dimy(); + unsigned int dimz = texture_volume.get_dimz(); + m_texture_size = vector3D((double)dimx, (double)dimy, (double)dimz); + unsigned char* bits = texture_volume.get_bits(); + glTexImage3D(GL_TEXTURE_3D, 0, GL_ALPHA8, dimx, dimy, dimz, 0, GL_ALPHA, + GL_UNSIGNED_BYTE, bits); + + PD.EndTimer(LOAD_TEXTURE); + +} + + + + diff --git a/rts_glVolumeViewer.h b/rts_glVolumeViewer.h new file mode 100755 index 0000000..b40344a --- /dev/null +++ b/rts_glVolumeViewer.h @@ -0,0 +1,67 @@ +#ifndef RTS_GLVOLUMEVIEWER_H +#define RTS_GLVOLUMEVIEWER_H + +#include +#include +#include +#include +//#include +#include +#include +//#include +#include "rtsMath.h" +#include "rtsVolume.h" +#include "rts_glUtilities.h" + +class rts_glVolumeViewer +{ +private: + + rtsVolume m_source; + GLuint m_volume_texture; + vector3D m_texture_size; //size of the volume being viewed (in voxels) + vector3D m_voxel_size; + bool m_optimize; //optimization flag (use more texture space for faster viz) + + point3D m_p; //position of the volume (0,0,0) corner in space + vector3D m_dimensions; + + double m_alpha_scale; + unsigned char m_min_threshold; //min and max thresholds to be displayed + unsigned char m_max_threshold; + + unsigned int m_num_planes; + + GLuint m_dl_planes; //planes display list + + + double m_inner_radius; //radius of the inscribed sphere + double m_outer_radius; //radius of the circumscribed sphere + + void m_draw_plane(point3D p, vector3D n, vector3D u); //draws a camera-oriented plane at point with normal n + void m_load_texture(); + + +public: + rts_glVolumeViewer(); + //rts_glVolumeViewer(rtsVolume volume_data, point3D position); + rts_glVolumeViewer(rtsVolume volume_data, + point3D position, + vector3D voxel_size); + void SetSize(float x, float y, float z); + void SetVoxelSize(float x, float y, float z); + vector3D GetSize(); + vector3D GetVoxelSize(); + void RenderBoundingBox(); + void RenderCameraSlice(point3D eye_point, vector3D camera_up, float slice_number = 0.0); + void RenderVolume(point3D eye_point, vector3D camera_up); + void SetAlphaScale(double scale){m_alpha_scale = scale;} + void SetNumPlanes(unsigned int planes); + void SetThreshold(unsigned char lower, unsigned char upper); + void Optimize(bool flag); + void Invert(); +}; + + + +#endif \ No newline at end of file diff --git a/rts_glutRenderWindow.h b/rts_glutRenderWindow.h new file mode 100755 index 0000000..aa97a19 --- /dev/null +++ b/rts_glutRenderWindow.h @@ -0,0 +1,155 @@ +#include +#include +#include "rtsQuaternion.h" +#include "rtsCamera.h" + +float d_angle = 0.05; + +rtsCamera rts_glut_camera; +unsigned int mouse_x; +unsigned int mouse_y; +int mouse_button; + + +//user display function pointer +void (*UserDisplay)(void); + + + +/*void KeyboardFunction(unsigned char key, int x, int y) +{ + if(key == 27) + exit(0); + +}*/ + +/*void SpecialKeys(int key, int x, int y) +{ + rtsQuaternion new_rotation; + + if(key == GLUT_KEY_UP) + rts_glut_camera.OrbitFocus(0, d_angle); + if(key == GLUT_KEY_DOWN) + rts_glut_camera.OrbitFocus(0, -d_angle); + if(key == GLUT_KEY_LEFT) + rts_glut_camera.OrbitFocus(d_angle, 0.0); + if(key == GLUT_KEY_RIGHT) + rts_glut_camera.OrbitFocus(-d_angle, 0.0); +}*/ + +void MouseDrag(int x, int y) +{ + int dx = x - mouse_x; + int dy = y - mouse_y; + + if(mouse_button == GLUT_LEFT_BUTTON) + rts_glut_camera.OrbitFocus(-dx*0.01, dy*0.01); + else if(mouse_button == GLUT_MIDDLE_BUTTON) + rts_glut_camera.Zoom(dy*rts_glut_camera.getFOV()/60.0); + + mouse_x = x; + mouse_y = y; + +} + +void MouseMove(int x, int y) +{ + mouse_x = x; + mouse_y = y; +} + +void MouseClick(int button, int state, int x, int y) +{ + if(state == GLUT_DOWN) + mouse_button = button; + + +} + +void IdleFunction() +{ + glutPostRedisplay(); +} + +void RenderCamera() +{ + //set viewport + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glViewport(0, 0, glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT)); + + //compute the aspect ratio + float aspect_ratio = (float)glutGet(GLUT_WINDOW_WIDTH)/(float)glutGet(GLUT_WINDOW_HEIGHT); + gluPerspective(rts_glut_camera.getFOV(), aspect_ratio, 0.01, 10.0); + + //render the camera + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + point3D camera_position = rts_glut_camera.getPosition(); + vector3D camera_up = rts_glut_camera.getUp(); + gluLookAt(camera_position.x, + camera_position.y, + camera_position.z, + 0.0, 0.0, 0.0, + camera_up.x, + camera_up.y, + camera_up.z); +} + +void rts_glutInitialize(const char* WindowName, int width = 1024, int height = 768) +{ + char *myargv [1]; + int myargc=1; + myargv [0]=strdup ("AppName"); + glutInit(&myargc, myargv); + + glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); + glutInitWindowSize(width, height); + glutInitWindowPosition(200,0); + glutCreateWindow(WindowName); + + //initialize GLEW + GLenum err = glewInit(); + if(err != GLEW_OK) + fprintf(stderr, "Error: %s\n", glewGetErrorString(err)); + if (!glewIsSupported("GL_VERSION_2_0")) + { + printf("OpenGL 2.0 not supported\n"); + //exit(1); + } + glEnable(GL_DEPTH_TEST); + + glClearColor(1.0, 1.0, 1.0, 0.0); + + rts_glut_camera.setPosition(0.0, 0.0, -1.0); + rts_glut_camera.setFOV(60); + rts_glut_camera.LookAt(0.0, 0.0, 0.0, 0.0, 1.0, 0.0); +} + +void DisplayFunction() +{ + RenderCamera(); + UserDisplay(); + glutSwapBuffers(); +} + +void rts_glutStart(void (*display_func)(void)) +{ + //glutSpecialFunc(SpecialKeys); + //glutKeyboardFunc(KeyboardFunction); + glutDisplayFunc(DisplayFunction); + glutMotionFunc(MouseDrag); + glutMouseFunc(MouseClick); + glutPassiveMotionFunc(MouseMove); + UserDisplay = display_func; + glutIdleFunc(IdleFunction); + + + + //glutReshapeFunc(ReshapeFunction); + //glutMouseFunc(MouseFunction); + //glutMotionFunc(MotionFunction); + glutMainLoop(); + +} diff --git a/rts_itkFunctions.h b/rts_itkFunctions.h new file mode 100755 index 0000000..b95669a --- /dev/null +++ b/rts_itkFunctions.h @@ -0,0 +1,168 @@ +#include "itkImage.h" +#include "itkImageFileReader.h" +#include "itkRAWImageIO.h" +#include "itkImageRegionIteratorWithIndex.h" + +typedef itk::Image VOLType; + +VOLType::Pointer rts_itkNewVOL(int x, int y, int z) +{ + //Create a new image and allocate the desired amount of space + //typedef itk::Image ImageType; + VOLType::Pointer result = VOLType::New(); + VOLType::RegionType region; + VOLType::SizeType size = {x, y, z}; + region.SetSize(size); + VOLType::IndexType index = {0, 0, 0}; + region.SetIndex(index); + result->SetRegions(region); + result->Allocate(); + + return result; + +} + +VOLType::Pointer rts_itkLoadVOL(const char* filename, unsigned int max_slices = 512) +{ + //first load the header information + ifstream infile(filename, ios::in | ios::binary); //create the files stream + if(!infile) + return VOLType::New(); + + unsigned int size_x, size_y, size_z; //create variables to store the size of the data set + //load the dimensions of the data set + infile.read((char*)&size_x, sizeof(int)); //load the file header + infile.read((char*)&size_y, sizeof(int)); + infile.read((char*)&size_z, sizeof(int)); + + //close the file + infile.close(); + + + VOLType::Pointer volume; + + + //create the reader + typedef itk::ImageFileReader ReaderType; + typedef itk::RawImageIO RawType; + + ReaderType::Pointer reader = ReaderType::New(); + RawType::Pointer rawIO = RawType::New(); + + + + reader->SetImageIO(rawIO); + reader->SetFileName(filename); + + //set the raw IO parameters + rawIO->SetFileTypeToBinary(); + + + //set the format of the RAW file + rawIO->SetHeaderSize(12); + rawIO->SetDimensions(0, size_x); + rawIO->SetDimensions(1, size_y); + + if(size_z < max_slices) + rawIO->SetDimensions(2, size_z); + else + rawIO->SetDimensions(2, max_slices); + + //read the file + try + { + reader->Update(); + } + catch(itk::ExceptionObject & exp) + { + std::cout<GetOutput(); + + return volume; +} +VOLType::Pointer rts_itkLoadRAW(const char* filename, unsigned int size_x, unsigned int size_y, unsigned int size_z) +{ + //first load the header information + ifstream infile(filename, ios::in | ios::binary); //create the files stream + if(!infile) + return VOLType::New(); + + + + //close the file + infile.close(); + + + VOLType::Pointer volume; + + + //create the reader + typedef itk::ImageFileReader ReaderType; + typedef itk::RawImageIO RawType; + + ReaderType::Pointer reader = ReaderType::New(); + RawType::Pointer rawIO = RawType::New(); + + + + reader->SetImageIO(rawIO); + reader->SetFileName(filename); + + //set the raw IO parameters + rawIO->SetFileTypeToBinary(); + + + //set the format of the RAW file + rawIO->SetHeaderSize(0); + rawIO->SetDimensions(0, size_x); + rawIO->SetDimensions(1, size_y); + rawIO->SetDimensions(2, size_z); + + + //read the file + try + { + reader->Update(); + } + catch(itk::ExceptionObject & exp) + { + std::cout<GetOutput(); + + return volume; +} +void rts_itkSaveVOL(VOLType::Pointer itk_image, const char* filename) +{ + typedef itk::ImageRegionIteratorWithIndex IteratorType; + IteratorType i(itk_image, itk_image->GetLargestPossibleRegion()); + + //create variables for size and position + VOLType::IndexType index; + VOLType::SizeType size; + //get the volume size + size = itk_image->GetLargestPossibleRegion().GetSize(); + unsigned char* buffer = new unsigned char[size[0]*size[1]*size[2]]; + + for(i.GoToBegin(); !i.IsAtEnd(); ++i) + { + index = i.GetIndex(); + buffer[index[0] + size[0] * (index[1] + index[2] * size[1])] = i.Get(); + } + + + ofstream outfile(filename, ios::out | ios::binary); //create the binary file stream + + //write the volume size to the file + outfile.write((char*)&size[0], sizeof(int)); + outfile.write((char*)&size[1], sizeof(int)); + outfile.write((char*)&size[2], sizeof(int)); + + outfile.write((char*)buffer, sizeof(char)*size[0]*size[1]*size[2]); + outfile.close(); +} \ No newline at end of file diff --git a/rts_itkImage.h b/rts_itkImage.h new file mode 100755 index 0000000..7e8747d --- /dev/null +++ b/rts_itkImage.h @@ -0,0 +1,334 @@ +#ifndef _RTS_ITK_IMAGE_H +#define _RTS_ITK_IMAGE_H + +#include "itkImage.h" +#include "itkImageFileReader.h" +#include "itkImageFileWriter.h" +#include "itkCastImageFilter.h" +#include "itkRescaleIntensityImageFilter.h" +#include "rtsDTGrid2D.h" + +#include + +using namespace std; + + + +template +class rts_itkImage +{ +public: + typedef itk::Image ITKImageType; + typedef typename ITKImageType::Pointer ITKPointerType; + ITKPointerType image_source; + +public: + rts_itkImage(); + rts_itkImage(int res_x, int res_y); + void Allocate(int res_x, int res_y); + void LoadImage(string filename); + void LoadRAW(int header_size, int res_x, int res_y, string filename); + void SaveImage(string filename); + void SaveRAW(string filename); + void CastAndSaveImage(string filename); + void RescaleImage(T min, T max); + void InsertDTGrid(rtsDTGrid2D* grid, bool debug = 0); + T* GetPointer(); + rts_itkImage SubImage(int px, int py, int sx, int sy); + + void SetPixel(int x, int y, T value); + T GetPixel(int x, int y); + + //element-wise operators + rts_itkImage operator+(T rhs); + + int DimX(){return image_source->GetLargestPossibleRegion().GetSize()[0];} + int DimY(){return image_source->GetLargestPossibleRegion().GetSize()[1];} + + +}; + +template +rts_itkImage rts_itkImage::operator+(T rhs) +{ + rts_itkImage result(DimX(), DimY()); + + int x, y; + for(x=0; x +void rts_itkImage::SetPixel(int x, int y, T value) +{ + ITKImageType::IndexType index; + index[0] = x; + index[1] = y; + image_source->SetPixel(index, value); +} + +template +T rts_itkImage::GetPixel(int x, int y) +{ + ITKImageType::IndexType index; + index[0] = x; + index[1] = y; + return image_source->GetPixel(index); +} + +template +rts_itkImage::rts_itkImage() +{ + if(image_source.IsNotNull()) + image_source = NULL; + image_source = ITKImageType::New(); +} + +template +rts_itkImage::rts_itkImage(int res_x, int res_y) +{ + Allocate(res_x, res_y); +} + +template +void rts_itkImage::Allocate(int res_x, int res_y) +{ + if(image_source.IsNotNull()) + { + image_source = NULL; + } + + image_source = ITKImageType::New(); + + ITKImageType::RegionType region; + ITKImageType::SizeType size; + size[0] = res_x; + size[1] = res_y; + + region.SetSize(size); + image_source->SetRegions(region); + + try + { + image_source->Allocate(); + } + catch(itk::ExceptionObject & exp) + { + std::cout< +rts_itkImage rts_itkImage::SubImage(int px, int py, int sx, int sy) +{ + /*This function returns the sub-volume specified by a corner point and size*/ + + //first make sure that the sub-volume is contained within the image + if(px < 0) {sx += px; px = 0;} + if(py < 0) {sy += py; py = 0;} + if(px >= DimX()) px = DimX() - 1; + if(py >= DimY()) py = DimY() - 1; + if(px + sx > DimX()) sx = DimX() - px - 1; + if(py + sy > DimY()) sy = DimY() - py - 1; + + cout< destination(sx, sy); + + //get an iterator for the destination volume + itk::ImageRegionIterator d(destination.image_source, destination.image_source->GetLargestPossibleRegion()); + + //get an iterator for the source region + ITKImageType::RegionType region; + ITKImageType::IndexType index; + ITKImageType::SizeType size; + index[0] = px; index[1] = py; + size[0] = sx; size[1] = sy; + region.SetIndex(index); + region.SetSize(size); + itk::ImageRegionIterator s(image_source, region); + + //copy the data from source region to destination volume + for(s.GoToBegin(), d.GoToBegin(); + !s.IsAtEnd(); + s++, d++) + d.Set(s.Get()); + + return destination; + +} + +template +T* rts_itkImage::GetPointer() +{ + return image_source->GetBufferPointer(); +} + +template +void rts_itkImage::LoadImage(string filename) +{ + typedef itk::ImageFileReader ReaderType; + ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(filename.c_str()); + image_source = reader->GetOutput(); + + try + { + reader->Update(); + } + catch(itk::ExceptionObject & exp) + { + std::cout< +void rts_itkImage::LoadRAW(int header_size, int size_x, + int size_y, string filename) +{ + Allocate(size_x, size_y); + + + ifstream infile(filename.c_str(), ios::out | ios::binary); //create the files stream + if(!infile) + return; + //first read the header + char* header = new char[header_size]; + infile.read((char*)header, header_size); + + //now read the actual data + infile.read((char*)image_source->GetBufferPointer(), DimX()*DimY()*sizeof(T)); + + infile.close(); +} + +template +void rts_itkImage::SaveImage(string filename) +{ + typedef itk::ImageFileWriter WriterType; + WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(filename.c_str()); + writer->SetInput(image_source); + + try + { + writer->Update(); + } + catch(itk::ExceptionObject & exp) + { + std::cout< +void rts_itkImage::SaveRAW(string filename) +{ + ofstream outfile(filename.c_str(), ios::out | ios::binary); //create the files stream + if(!outfile) + return; + + outfile.write((char*)image_source->GetBufferPointer(), DimX()*DimY()*sizeof(T)); + outfile.close(); +} + +template +void rts_itkImage::CastAndSaveImage(string filename) +{ + //create the destination image + typedef itk::Image DestinationType; + DestinationType::Pointer dest_image = DestinationType::New(); + + //create the casting filter + typedef itk::CastImageFilter CastFilterType; + CastFilterType::Pointer castFilter = CastFilterType::New(); + castFilter->SetInput(image_source); + + + //cast the current image + dest_image = castFilter->GetOutput(); + + //save the result + typedef itk::ImageFileWriter WriterType; + WriterType::Pointer writer = WriterType::New(); + writer->SetFileName(filename.c_str()); + writer->SetInput(dest_image); + + try + { + writer->Update(); + } + catch(itk::ExceptionObject & exp) + { + std::cout< +void rts_itkImage::RescaleImage(T min_v, T max_v) +{ + typedef itk::RescaleIntensityImageFilter RescaleFilter; + RescaleFilter::Pointer rescaleFilter = RescaleFilter::New(); + rescaleFilter->SetInput(image_source); + rescaleFilter->SetOutputMinimum(min_v); + rescaleFilter->SetOutputMaximum(max_v); + image_source = rescaleFilter->GetOutput(); + rescaleFilter->Update(); +} + +template +void rts_itkImage::InsertDTGrid(rtsDTGrid2D* grid, bool debug = false) +{ + //find the extents of the DT Grid + int min_x, min_y, max_x, max_y; + grid->getBounds(min_x, min_y, max_x, max_y); + + //allocate the appropriate amount of space + ITKImageType::RegionType region; + ITKImageType::SizeType size; + size[0] = (max_x - min_x) + 1; + size[1] = (max_y - min_y) + 1; + region.SetSize(size); + image_source->SetRegions(region); + + try + { + image_source->Allocate(); + } + catch(itk::ExceptionObject & exp) + { + std::cout<FillBuffer(grid->background); + + //copy values from the DT Grid to the image + ITKImageType::IndexType index; //create an image index + rtsDTGrid2D::iterator i; //create an iterator + + for(i = grid->begin(); i!= grid->after(); i++) + { + index[0] = i.X1() - min_x; + index[1] = i.X2() - min_y; + image_source->SetPixel(index, i.Value()); + + //cout< +#include "itkImage.h" +#include "itkImageFileReader.h" +#include "itkImageFileWriter.h" +#include "itkRawImageIO.h" +#include "itkImageRegionIterator.h" +#include +#include "rtsFilename.h" +#include "rtsDTGrid3D.h" +using namespace std; + +#include "itkRescaleIntensityImageFilter.h" + +#include "rts_itkImage.h" + +void rtsProgressBar(int percent); + +template class rts_itkVolume +{ +public: + typedef int uint; + typedef itk::Image ITKVolumeType; + typedef typename ITKVolumeType::Pointer PointerType; + typedef itk::Image ITKSliceType; + + //typedef itk::Image ITKVolumeType; +private: + //pointer to the data + PointerType imageData; + + char* UnicodeToANSI(wchar_t* unicodestr) + { + int a = wcslen(unicodestr)+1; + char *ansistr = new char[a]; + ::WideCharToMultiByte(CP_ACP, + 0, + unicodestr, + -1, + ansistr, + a, + NULL, + NULL); + return ansistr; + + } + + BSTR ANSIToUnicode(const char* ansistr) + { + /*On a side note: This BSTR crap isn't the way to go. + Try to use wchar_t (Unicode) where possible. Already changed it in + the above function because it was causing a bug.*/ + + int a = strlen(ansistr); + BSTR unicodestr = SysAllocStringLen(NULL, a); + ::MultiByteToWideChar(CP_ACP, 0, ansistr, a, unicodestr, a); + return unicodestr; + } + +public: + //construct an implicit function with a size of 1 + rts_itkVolume(); ///GetBufferPointer();} + T GetMin(); + T GetMax(); + + void SetITKPointer(PointerType pointer){imageData = pointer;} + uint DimX(){return imageData->GetLargestPossibleRegion().GetSize()[0];} + uint DimY(){return imageData->GetLargestPossibleRegion().GetSize()[1];} + uint DimZ(){return imageData->GetLargestPossibleRegion().GetSize()[2];} + + float VoxelSizeX(){return imageData->GetSpacing()[0];} + float VoxelSizeY(){return imageData->GetSpacing()[1];} + float VoxelSizeZ(){return imageData->GetSpacing()[2];} + void SetPixel(uint x, uint y, uint z, T value); + void SetSlice(rts_itkImage image, int slice); + T GetPixel(uint x, uint y, uint z); + rts_itkImage GetSlice(int slice); + rts_itkVolume SubVolume(uint px, uint py, uint pz, uint sx, uint sy, uint sz); + + //mathematica operations + T operator=(T rhs); + rts_itkVolume operator-(T rhs); + rts_itkVolume operator+(T rhs); + rts_itkVolume operator-(rts_itkVolume rhs); + + void Print(ostream &os); + + //simple data processing + void Rescale(T new_min, T new_max); + void Binary(T threshold, T true_value); ///* grid, bool debug = false); +}; + +template +rts_itkVolume rts_itkVolume::SubVolume(uint px, uint py, uint pz, uint sx, uint sy, uint sz) +{ + /*This function returns the sub-volume specified by a corner point and size*/ + + //first make sure that the sub-volume is contained within the image + if(px < 0) {sx += px; px = 0;} + if(py < 0) {sy += py; py = 0;} + if(pz < 0) {sz += pz; pz = 0;} + if(px >= DimX()) px = DimX() - 1; + if(py >= DimY()) py = DimY() - 1; + if(pz >= DimZ()) pz = DimZ() - 1; + if(px + sx > DimX()) sx = DimX() - px - 1; + if(py + sy > DimY()) sy = DimY() - py - 1; + if(pz + sz > DimZ()) sz = DimZ() - pz - 1; + + //cout< d(destination.imageData, destination.imageData->GetLargestPossibleRegion()); + + //get an iterator for the source region + ITKVolumeType::RegionType region; + ITKVolumeType::IndexType index; + ITKVolumeType::SizeType size; + index[0] = px; index[1] = py; index[2] = pz; + size[0] = sx; size[1] = sy; size[2] = sz; + region.SetIndex(index); + region.SetSize(size); + itk::ImageRegionIterator s(imageData, region); + + //copy the data from source region to destination volume + for(s.GoToBegin(), d.GoToBegin(); + !s.IsAtEnd(); + s++, d++) + d.Set(s.Get()); + + return destination; + +} + +template +T rts_itkVolume::operator=(T rhs) +{ + /*itk::ImageRegionIterator i(imageData, imageData->GetLargestPossibleRegion()); + + for(i.GoToBegin(); !i.IsAtEnd(); i++) + i.Set(rhs); +*/ + imageData->FillBuffer(rhs); + return rhs; +} +template +rts_itkVolume rts_itkVolume::operator-(T rhs) +{ + rts_itkVolume result(DimX(), DimY(), DimZ()); + + itk::ImageRegionIterator w(result.imageData, result.imageData->GetLargestPossibleRegion()); + itk::ImageRegionIterator r(imageData, imageData->GetLargestPossibleRegion()); + + for(r.GoToBegin(), w.GoToBegin(); !r.IsAtEnd(); r++, w++) + w.Set(r.Get() - rhs); + + return result; +} + +template +rts_itkVolume rts_itkVolume::operator+(T rhs) +{ + rts_itkVolume result(DimX(), DimY(), DimZ()); + + itk::ImageRegionIterator w(result.imageData, result.imageData->GetLargestPossibleRegion()); + itk::ImageRegionIterator r(imageData, imageData->GetLargestPossibleRegion()); + + for(r.GoToBegin(), w.GoToBegin(); !r.IsAtEnd(); r++, w++) + w.Set(r.Get() + rhs); + + return result; +} + +template +rts_itkVolume rts_itkVolume::operator-(rts_itkVolume rhs) +{ + rts_itkVolume result(DimX(), DimY(), DimZ()); + + itk::ImageRegionIterator w(result.imageData, result.imageData->GetLargestPossibleRegion()); + itk::ImageRegionIterator r(rhs.imageData, rhs.imageData->GetLargestPossibleRegion()); + itk::ImageRegionIterator l(imageData, imageData->GetLargestPossibleRegion()); + + for(r.GoToBegin(), l.GoToBegin(), w.GoToBegin(); + !r.IsAtEnd(); + r++, l++, w++) + w.Set(l.Get() - r.Get()); + + return result; +} + +template +void rts_itkVolume::Print(ostream &os) +{ + ITKVolumeType::SizeType size; + size = imageData->GetLargestPossibleRegion().GetSize(); + + int x, y, z; + for(z=0; z +rts_itkVolume::rts_itkVolume() +{ + imageData = ITKVolumeType::New(); +} + +template +rts_itkVolume::rts_itkVolume(uint res_x, uint res_y, uint res_z) +{ + imageData = ITKVolumeType::New(); + + itk::Image::RegionType region; + itk::Image::SizeType size; + size[0] = res_x; + size[1] = res_y; + size[2] = res_z; + + region.SetSize(size); + imageData->SetRegions(region); + + try + { + imageData->Allocate(); + } + catch(itk::ExceptionObject & exp) + { + std::cout< +void rts_itkVolume::Init(uint res_x, uint res_y, uint res_z) +{ + itk::Image::RegionType region; + itk::Image::SizeType size; + size[0] = res_x; + size[1] = res_y; + size[2] = res_z; + + region.SetSize(size); + imageData->SetRegions(region); + + + try + { + imageData->Allocate(); + } + catch(itk::ExceptionObject & exp) + { + std::cout< +void rts_itkVolume::SetSpacing(float voxel_x, float voxel_y, float voxel_z) +{ + float spacing[3]; + spacing[0] = voxel_x; spacing[1]= voxel_y; spacing[2] = voxel_z; + imageData->SetSpacing(spacing); +} + + +template +inline T rts_itkVolume::GetPixel(uint x, uint y, uint z) +{ + T result; + if(x < 0 || x >= DimX() || y < 0 || y >= DimY() || z < 0 || z >= DimZ()) + { + memset(&result, 0, sizeof(T)); + return result; + } + + itk::Image::IndexType index; + index[0] = x; index[1] = y; index[2] = z; + return imageData->GetPixel(index); +} + +template +inline T rts_itkVolume::GetMin() +{ + int ix, iy, iz; + T currentMin = GetPixel(0, 0, 0); + T n; + for(ix=0; ix +inline T rts_itkVolume::GetMax() +{ + int ix, iy, iz; + T currentMax = GetPixel(0, 0, 0); + T n; + for(ix=0; ix currentMax) + currentMax = n; + } + return currentMax; +} + +template +inline T rts_itkVolume::operator ()(uint x, uint y, uint z) +{ + return GetPixel(x, y, z); +} + + + +template +void rts_itkVolume::LoadRAW(uint header_size, uint size_x, + uint size_y, uint size_z, string filename) +{ + ITKVolumeType::RegionType region; + ITKVolumeType::SizeType size; + size[0] = size_x; + size[1] = size_y; + size[2] = size_z; + region.SetSize(size); + imageData->SetRegions(region); + + try + { + imageData->Allocate(); + } + catch(itk::ExceptionObject & exp) + { + std::cout<GetBufferPointer(), DimX()*DimY()*DimZ()*sizeof(T)); + + infile.close(); +} + +template +void rts_itkVolume::LoadRAV(string filename) +{ + + //open the file + ifstream infile(filename.c_str(), ios::out | ios::binary); //create the files stream + if(!infile) + return; + + //first read the header + int dimx, dimy, dimz, bytesize; + infile.read((char*)&dimx, sizeof(int)); + infile.read((char*)&dimy, sizeof(int)); + infile.read((char*)&dimz, sizeof(int)); + infile.read((char*)&bytesize, sizeof(int)); + + //allocate space for the image + ITKVolumeType::RegionType region; + ITKVolumeType::SizeType size; + size[0] = dimx; + size[1] = dimy; + size[2] = dimz; + region.SetSize(size); + imageData->SetRegions(region); + try + { + imageData->Allocate(); + } + catch(itk::ExceptionObject & exp) + { + std::cout<GetBufferPointer(), DimX()*DimY()*DimZ()*sizeof(T)); + + infile.close(); +} + +template +void rts_itkVolume::LoadVOL(string filename) +{ + + //open the file + ifstream infile(filename.c_str(), ios::out | ios::binary); //create the files stream + if(!infile) + return; + + //first read the header + int dimx, dimy, dimz, bytesize; + infile.read((char*)&dimx, sizeof(int)); + infile.read((char*)&dimy, sizeof(int)); + infile.read((char*)&dimz, sizeof(int)); + + //allocate space for the image + ITKVolumeType::RegionType region; + ITKVolumeType::SizeType size; + size[0] = dimx; + size[1] = dimy; + size[2] = dimz; + region.SetSize(size); + imageData->SetRegions(region); + try + { + imageData->Allocate(); + } + catch(itk::ExceptionObject & exp) + { + std::cout<GetBufferPointer(), DimX()*DimY()*DimZ()*sizeof(T)); + + infile.close(); +} + +template +void rts_itkVolume::LoadStack(string directory, string filename_mask, int max_files = -1) +{ + /*Load a list of file names based on the user-specified mask*/ + //create the complete mask + if(directory[directory.size() - 1] != '/') + directory += '/'; + + string full_mask = directory; + full_mask += filename_mask; + + //create a temporary vector to store the file names + vector fileList; + //create a handle for the search + HANDLE search_handle; + WIN32_FIND_DATA found_data; + + //start the search + BSTR unicodestr = ANSIToUnicode(full_mask.c_str()); + search_handle = FindFirstFile(unicodestr, &found_data); + ::SysFreeString(unicodestr); + + //if there are no files, return + if(search_handle == INVALID_HANDLE_VALUE) + return; + + string new_file; + char* ansistr = UnicodeToANSI(found_data.cFileName); + //char* ansistr = (char*)found_data.cFileName; + //save the first filename + new_file = directory; + new_file += ansistr; + fileList.push_back(new_file); + delete[] ansistr; + + //now loop through the rest of the files + while(FindNextFile(search_handle, &found_data)) + { + char* ansistr = UnicodeToANSI(found_data.cFileName); + new_file = directory; + new_file += ansistr; + //cout< ReaderType; + ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(fileList[0].getString()); + ITKSliceType::Pointer image = reader->GetOutput(); + + try + { + reader->Update(); + } + catch(itk::ExceptionObject & exp) + { + std::cout<(fileList.size(), max_files); + cout<<"Loading: "<GetLargestPossibleRegion().GetSize(); //get the slice size + ITKVolumeType::SizeType volSize; //compute the volume size + volSize[0] = size[0]; + volSize[1] = size[1]; + volSize[2] = max_files; + + imageData = ITKVolumeType::New(); //create the volume + ITKVolumeType::RegionType region; + region.SetSize(volSize); + imageData->SetRegions(region); + imageData->Allocate(); //allocate space + + + + for(i=0; iSetFileName(fileList[i].getString()); + ITKSliceType::Pointer slice = reader->GetOutput(); + reader->Update(); + InsertSlice(i, slice); + //cout< +void rts_itkVolume::LoadSlice(string filename, int slice) +{ + //load the specified image + typedef itk::ImageFileReader ReaderType; + ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(filename.c_str()); + ITKSliceType::Pointer image = reader->GetOutput(); + + try + { + reader->Update(); + } + catch(itk::ExceptionObject & exp) + { + std::cout< +rts_itkImage rts_itkVolume::GetSlice(int slice) +{ + //create a new image + rts_itkImage outSlice(DimX(), DimY()); + + int x, y; + for(x=0; x +void rts_itkVolume::SetSlice(rts_itkImage image, int slice) +{ + int x, y; + for(x=0; x +void rts_itkVolume::SaveRAV(string filename) +{ + ofstream outfile(filename.c_str(), ios::out | ios::binary); //create the files stream + if(!outfile) + return; + + int dimx = DimX(); + int dimy = DimY(); + int dimz = DimZ(); + int bytesize = sizeof(T); + + outfile.write((char*)&dimx, sizeof(int)); + outfile.write((char*)&dimy, sizeof(int)); + outfile.write((char*)&dimz, sizeof(int)); + outfile.write((char*)&bytesize, sizeof(int)); + + outfile.write((char*)imageData->GetBufferPointer(), DimX()*DimY()*DimZ()*sizeof(T)); + outfile.close(); + +} + +template +void rts_itkVolume::SaveVOL(string filename) +{ + ofstream outfile(filename.c_str(), ios::out | ios::binary); //create the files stream + if(!outfile) + return; + + int dimx = DimX(); + int dimy = DimY(); + int dimz = DimZ(); + + outfile.write((char*)&dimx, sizeof(int)); + outfile.write((char*)&dimy, sizeof(int)); + outfile.write((char*)&dimz, sizeof(int)); + + outfile.write((char*)imageData->GetBufferPointer(), DimX()*DimY()*DimZ()*sizeof(T)); + outfile.close(); + +} + +template +void rts_itkVolume::InsertSlice(uint z_position, typename ITKSliceType::Pointer slice) +{ + itk::Image::SizeType size = slice->GetLargestPossibleRegion().GetSize(); + itk::Image::IndexType index; + int x, y; + for(x=0; xGetPixel(index)); + } + + + +} + +template +void rts_itkVolume::SaveRAW(string filename) +{ + ofstream outfile(filename.c_str(), ios::out | ios::binary); //create the files stream + if(!outfile) + return; + + outfile.write((char*)imageData->GetBufferPointer(), DimX()*DimY()*DimZ()*sizeof(T)); + outfile.close(); +} + +template +void rts_itkVolume::SetPixel(uint x, uint y, uint z, T value) +{ + ITKVolumeType::IndexType index; + index[0] = x; + index[1] = y; + index[2] = z; + imageData->SetPixel(index, value); +} + +template +void rts_itkVolume::Rescale(T new_min, T new_max) +{ + typedef itk::RescaleIntensityImageFilter RescaleFilterType; + RescaleFilterType::Pointer rescaleFilter = RescaleFilterType::New(); + rescaleFilter->SetOutputMinimum(new_min); + rescaleFilter->SetOutputMaximum(new_max); + rescaleFilter->SetInput(imageData); + rescaleFilter->Update(); + + imageData = rescaleFilter->GetOutput(); +} + +template +void rts_itkVolume::Binary(T threshold, T true_value) +{ + /** + This function converts an implicit function into a binary or characteristic function describing the solid represented by the level + set at isovalue "threshold". All values below threshold are set to zero while all values above threshold are set to the specified + "true_value". In order to use this function, the data type T must be able to be set to 0. + **/ + int max_index = DimX() * DimY() * DimZ(); //find the size of the data array + int i; + T* ptrBits = imageData->GetBufferPointer(); + for(i=0; i= threshold) + ptrBits[i] = true_value; + else + ptrBits[i] = 0; +} + + +template +void rts_itkVolume::InsertDTGrid(rtsDTGrid3D* grid, bool debug = false) +{ + //find the extents of the DT Grid + int min_x, min_y, min_z, max_x, max_y, max_z; + grid->getBounds(min_x, min_y, min_z, max_x, max_y, max_z); + + //allocate the appropriate amount of space + ITKVolumeType::RegionType region; + ITKVolumeType::SizeType size; + size[0] = (max_x - min_x) + 1; + size[1] = (max_y - min_y) + 1; + size[2] = (max_z - min_z) + 1; + region.SetSize(size); + imageData->SetRegions(region); + + try + { + imageData->Allocate(); + } + catch(itk::ExceptionObject & exp) + { + std::cout<FillBuffer(grid->background); + + //copy values from the DT Grid to the image + ITKVolumeType::IndexType index; //create an image index + rtsDTGrid3D::iterator i; //create an iterator + + for(i = grid->begin(); i!= grid->after(); i++) + { + index[0] = i.X1() - min_x; + index[1] = i.X2() - min_y; + index[2] = i.X3() - min_z; + imageData->SetPixel(index, i.Value()); + + //cout< +rtsCamera::rtsCamera() +{ + position = point3D(0, 0, 0); + view_vector = vector3D(0, 0, -1); + up_vector = vector3D(0, 1, 0); + lookat_point = point3D(0, 0, -1); + + pers_view_angle = 60; + ortho_width = 1.0; + ortho_height = 1.0; + + near_plane = 1; + far_plane = 100; +} + +rtsCamera::LookAt( + +/* +rtsCamera::rtsCamera(rtsCameraState initial_state) +{ + m_camera_state = initial_state; + + //make sure that the view and lookat vectors are orthogonal + vector3D lookat = m_camera_state.lookat - m_camera_state.position; + vector3D up = m_camera_state.up; + vector3D side = lookat.X(up); + up = side.X(lookat); + up.Normalize(); + m_camera_state.up = up; +} + +rtsCameraState rtsCamera::getState() +{ + return m_camera_state; +} + + + + +void rtsCamera::setState(rtsCameraState camera_state) +{ + m_camera_state = camera_state; + + //re-orthogonalize the vectors + vector3D view = m_camera_state.lookat - m_camera_state.position; + vector3D side = view.X(m_camera_state.up); + m_camera_state.up = side.X(view); + m_camera_state.up.Normalize(); +} + +void rtsCamera::LookAt(point3D point) +{ + //looks at a point + + //find the new view vector + vector3D view = point - m_camera_state.position; + + //normalize the view vector + view.Normalize(); + + //prepare a new side vector and up vector + vector3D side; + vector3D up; + + //get the up vector + //if the new viewvector is at 0 or 180 degrees to the up vector + float cos_angle = view*m_camera_state.up; + if(cos_angle == 1.0f || cos_angle == -1.0f) + { + //re-calculate the up vector + up = m_camera_state.up.X(m_camera_state.lookat - m_camera_state.position); + } + else + { + //otherwise, just get the current up vector + up = m_camera_state.up; + } + + + //correct the up vector based on the new view vector + side = up.X(view); + up = view.X(side); + up.Normalize(); + + //change the camera state + m_camera_state.up = up; + m_camera_state.lookat = point; +} + +void rtsCamera::Position(point3D p) +{ + m_camera_state.position = p; +} + +void rtsCamera::Up(vector3D up) +{ + m_camera_state.up = up; +} + +void rtsCamera::DollyPosition(point3D p) +{ + vector3D adjustment = p-m_camera_state.position; + m_camera_state.position = p; + m_camera_state.lookat = m_camera_state.lookat + adjustment; +} + +point3D rtsCamera::getLookAtPoint() +{ + return m_camera_state.lookat; +} + + + +void rtsCamera::Pan(double x, double y) +{ + //first calculate the lookat and side vectors + vector3D lookatvector=m_camera_state.lookat - m_camera_state.position; + vector3D sidevector = lookatvector.X(m_camera_state.up); + sidevector.Normalize(); + + m_camera_state.position=m_camera_state.position+sidevector*x; + m_camera_state.lookat=m_camera_state.lookat+sidevector*x; + + vector3D upvector = lookatvector.X(sidevector); + upvector.Normalize(); + m_camera_state.position=m_camera_state.position+upvector*y; + m_camera_state.lookat=m_camera_state.lookat+upvector*y; +} + +void rtsCamera::RotateUpDown(double degrees) +{ + //first calculate the lookat and side vectors + vector3D lookatvector=m_camera_state.lookat-m_camera_state.position; + vector3D sidevector = lookatvector.X(m_camera_state.up); + m_camera_state.up=sidevector.X(lookatvector); + m_camera_state.up.Normalize(); + sidevector.Normalize(); + + //translate the look-at point to the origin (and the camera with it) + point3D origin = point3D(0.0, 0.0, 0.0); + vector3D translateCamera = origin-m_camera_state.lookat; + + point3D translatedCamera=m_camera_state.position+translateCamera; + + //the next step is to rotate the side vector so that it lines up with the z axis + double a=sidevector.x; + double b=sidevector.y; + double c=sidevector.z; + + double d=sqrt(b*b + c*c); + + //error correction for when we are already looking down the z-axis + if(d==0) + return; + + vector3D XZplane = vector3D(translatedCamera.x, + (translatedCamera.y*c/d - translatedCamera.z*b/d), + (translatedCamera.y*b/d + translatedCamera.z*c/d)); + + vector3D Zaxis = vector3D(XZplane.x*d - XZplane.z*a, + XZplane.y, + XZplane.x*a + XZplane.z*d); + + vector3D rotated = vector3D(Zaxis.x*cos(TORADIANS(degrees)) - Zaxis.y*sin(TORADIANS(degrees)), + Zaxis.x*sin(TORADIANS(degrees)) + Zaxis.y*cos(TORADIANS(degrees)), + Zaxis.z); + + vector3D XZout = vector3D( rotated.x*(d/(a*a + d*d)) + rotated.z*(a/(a*a + d*d)), + rotated.y, + rotated.x*(-a/(a*a+d*d)) + rotated.z*(d/(a*a + d*d))); + + vector3D result = vector3D( XZout.x, + XZout.y*(c*d/(b*b + c*c)) + XZout.z*(b*d/(b*b + c*c)), + XZout.y*(-b*d/(b*b + c*c)) + XZout.z*(c*d/(b*b + c*c))); + + result=result-translateCamera; + + m_camera_state.position.x=result.x; + m_camera_state.position.y=result.y; + m_camera_state.position.z=result.z; + +} + +void rtsCamera::Yaw(double degrees) +{ + //basically, we have to rotate the look-at point around the up vector + //first, translate the look-at point so that the camera is at the origin + point3D origin(0.0, 0.0, 0.0); + point3D temp_lookat = m_camera_state.lookat - (m_camera_state.position - origin); + + //create a rotation matrix to rotate the lookat point around the up vector + float x=m_camera_state.up.x; + float y=m_camera_state.up.y; + float z=m_camera_state.up.z; + float c=cos(TORADIANS(-degrees)); + float s=sin(TORADIANS(-degrees)); + float t=1.0 - cos(TORADIANS(-degrees)); + float m00 = t*x*x + c; + float m01 = t*x*y + s*z; + float m02 = t*x*z - s*y; + float m03 = 0; + float m10 = t*x*y - s*z; + float m11 = t*y*y + c; + float m12 = t*y*z + s*x; + float m13 = 0; + float m20 = t*x*z + s*y; + float m21 = t*y*z - s*x; + float m22 = t*z*z + c; + float m23 = 0; + float m30 = 0; + float m31 = 0; + float m32 = 0; + float m33 = 1; + matrix4x4 rotation(m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, + m30, m31, m32, m33); + point3D result = rotation*temp_lookat + (m_camera_state.position - origin); + m_camera_state.lookat = result; +} + +void rtsCamera::Pitch(double degrees) +{ + //basically, we have to rotate the look-at point and up vector around the side vector + //first, translate the look-at point so that the camera is at the origin + point3D origin(0.0, 0.0, 0.0); + + //find all three necessary vectors + vector3D temp_lookat = m_camera_state.lookat - m_camera_state.position; + double lookat_length = temp_lookat.Length(); + vector3D temp_up = m_camera_state.up; + vector3D temp_side = temp_lookat.X(temp_up); + temp_lookat.Normalize(); + temp_up.Normalize(); + temp_side.Normalize(); + + + //create a rotation matrix to rotate around the side vector + float x=temp_side.x; + float y=temp_side.y; + float z=temp_side.z; + float c=cos(TORADIANS(degrees)); + float s=sin(TORADIANS(degrees)); + float t=1.0 - cos(TORADIANS(degrees)); + float m00 = t*x*x + c; + float m01 = t*x*y + s*z; + float m02 = t*x*z - s*y; + float m03 = 0; + float m10 = t*x*y - s*z; + float m11 = t*y*y + c; + float m12 = t*y*z + s*x; + float m13 = 0; + float m20 = t*x*z + s*y; + float m21 = t*y*z - s*x; + float m22 = t*z*z + c; + float m23 = 0; + float m30 = 0; + float m31 = 0; + float m32 = 0; + float m33 = 1; + matrix4x4 rotation(m00, m01, m02, m03, + m10, m11, m12, m13, + m20, m21, m22, m23, + m30, m31, m32, m33); + + //rotate the up and look-at vectors around the side vector + vector3D result_lookat = rotation*temp_lookat; + vector3D result_up = rotation*temp_up; + result_lookat.Normalize(); + result_up.Normalize(); + + m_camera_state.lookat = m_camera_state.position + result_lookat * lookat_length; + m_camera_state.up = result_up; +} + + +void rtsCamera::RotateLeftRight(double degrees) +//this function rotates the camera around the up vector (which always points along hte positive +//Y world axis). +{ + //translate the look-at point to the origin (and the camera with it) + point3D origin = point3D(0.0, 0.0, 0.0); + vector3D translateCamera = origin-m_camera_state.lookat; + + point3D translatedCamera=m_camera_state.position+translateCamera; + + + //perform the rotation around the look-at point + //using the y-axis as the rotation axis + point3D newcamera; + newcamera.x=translatedCamera.x*cos(TORADIANS(degrees)) - translatedCamera.z*sin(TORADIANS(degrees)); + newcamera.z=translatedCamera.x*sin(TORADIANS(degrees)) + translatedCamera.z*cos(TORADIANS(degrees)); + newcamera.y=translatedCamera.y; + + vector3D newup; + newup.x=m_camera_state.up.x*cos(TORADIANS(degrees)) - m_camera_state.up.z*sin(TORADIANS(degrees)); + newup.z=m_camera_state.up.x*sin(TORADIANS(degrees)) + m_camera_state.up.z*cos(TORADIANS(degrees)); + newup.y=m_camera_state.up.y; + + //translate the lookat point back to it's original position (along with the camera) + newcamera=newcamera-translateCamera; + + m_camera_state.position.x=newcamera.x; + m_camera_state.position.y=newcamera.y; + m_camera_state.position.z=newcamera.z; + + m_camera_state.up.x=newup.x; + m_camera_state.up.y=newup.y; + m_camera_state.up.z=newup.z; + m_camera_state.up.Normalize(); + +} + +void rtsCamera::Forward(double distance) +{ + //calculate the lookat vector (direction of travel) + vector3D old_lookat=m_camera_state.lookat-m_camera_state.position; + old_lookat.Normalize(); + + //calculate the new position of the camera + point3D new_position = m_camera_state.position+old_lookat*distance; + //now calculate the new lookat vector + vector3D new_lookat=m_camera_state.lookat-new_position; + //find the length of the new lookat vector + + //move the camera to the new position + m_camera_state.position = new_position; +} + +void rtsCamera::ScaleForward(double factor, double min, double max) +{ + //This function moves the camera forward, scaling the magnitude + //of the motion by the length of the view vector. Basically, the closer + //the camera is to the lookat point, the slower the camera moves. + + //calculate the lookat vector (direction of travel) + vector3D lookatvector=m_camera_state.lookat-m_camera_state.position; + //find the length of the view vector + double length = lookatvector.Length(); + //normalize + lookatvector.Normalize(); + + //prevent motion if the bounds would be passed + double new_distance = length - (factor*length); + if(new_distance < min || new_distance > max) + factor = 0; + //move the camera + m_camera_state.position=m_camera_state.position+lookatvector*factor*length; + lookatvector=m_camera_state.lookat-m_camera_state.position; + +} + +void rtsCamera::DollyLeftRight(double distance) +{ + //calculate the side vector vector (direction of travel) + vector3D lookatvector=m_camera_state.lookat-m_camera_state.position; + vector3D side = lookatvector.X(m_camera_state.up); + side.Normalize(); + + m_camera_state.position=m_camera_state.position+side*distance; + m_camera_state.lookat = m_camera_state.lookat + side*distance; + //lookatvector=m_camera_state.lookat-m_camera_state.position; +} + +void rtsCamera::DollyUpDown(double distance) +{ + //move along the up vector + m_camera_state.up.Normalize(); + + m_camera_state.position=m_camera_state.position+m_camera_state.up*distance; + m_camera_state.lookat = m_camera_state.lookat + m_camera_state.up*distance; + //lookatvector=m_camera_state.lookat-m_camera_state.position; +} + +void rtsCamera::Zoom(double angle) +{ + m_camera_state.pers_view_angle += angle; +} + +*/ \ No newline at end of file diff --git a/rts_old_Camera.h b/rts_old_Camera.h new file mode 100755 index 0000000..4b542e8 --- /dev/null +++ b/rts_old_Camera.h @@ -0,0 +1,77 @@ +#include "rtsLinearAlgebra.h" + +#ifndef _RTSMATH_H +#define _RTSMATH_H + +#define CAMERA_UP -1 +#define CAMERA_DOWN 1 +#define CAMERA_LEFT -1 +#define CAMERA_RIGHT 1 + +struct rtsCameraState +{ + point3D position; + point3D lookat; + vector3D up; + float pers_view_angle; + float ortho_width; + float ortho_height; + float near_plane; + float far_plane; +}; + +class rtsCamera +{ + //members + point3D position; + vector3D view_vector; + vector3D up_vector; + point3D lookat_point; + float pers_view_angle; + float ortho_width; + float ortho_height; + float near_plane; + float far_plane; + +public: + + + //constructors + rtsCamera(); + ~rtsCamera(){}; + + //methods + void LookAt(point3D pos, point3D lookat, vector3D up); + /* + void RotateUpDown(double degrees); + void RotateLeftRight(double degrees); + void Pan(double x, double y); + void Yaw(double degrees); + void Pitch(double degrees); + void Forward(double distance); + void ScaleForward(double factor, double min = 0, double max = 999999); + void DollyLeftRight(double distance); + void DollyUpDown(double distance); + void Zoom(double angle); + void LookAt(point3D point); + void Position(point3D point); + void Up(vector3D up); + void DollyPosition(point3D point); //moves the camera but keeps the current orientation + */ + + //get methods + rtsCameraState getState(); + vector3D getView(){return view_vector;} + vector3D getUp(){return up_vector;} + point3D getPosition(){return position;} + point3D getLookAt(){return lookat_point;} + double getViewAngle(){return pers_view_angle;} + double getNearPlane(){return near_plane;} + double getFarPlane(){return far_plane;} + double getOrthoWidth(){return ortho_width;} + double getOrthoHeight(){return ortho_height;} + + +}; + +#endif \ No newline at end of file diff --git a/rts_vtkFunctions.h b/rts_vtkFunctions.h new file mode 100755 index 0000000..00d0572 --- /dev/null +++ b/rts_vtkFunctions.h @@ -0,0 +1,55 @@ +#include "vtkImageData.h" +#include "rtsVolume.h" +#include "rtsImplicit3D.h" + +/*vtkImageData* rtsVolume2vtkImageData(rtsVolume* inputVolume, int data_type) +{ + vtkImageData* outputImageData = vtkImageData::New(); + outputImageData->SetScalarType(data_type); + outputImageData->SetDimensions(inputVolume->get_dimx(), inputVolume->get_dimy(), inputVolume->get_dimz()); + unsigned char* scalar_pointer = (unsigned char*)outputImageData->GetScalarPointer(); + unsigned char* volume_pointer = inputVolume->get_bits(); + unsigned int vol_size = inputVolume->get_dimx()*inputVolume->get_dimy()*inputVolume->get_dimz(); + for(int i=0; i +vtkImageData* rtsImplicit3D2vtkImageData(rtsImplicit3D* in_function, int data_type) +{ + //create the vtkImageData class for storing a uniform grid + vtkImageData* outputImageData = vtkImageData::New(); + //set the data type of the scalar field + outputImageData->SetScalarType(data_type); + //set the dimensions of the image data based on the function resolution + outputImageData->SetDimensions(in_function->DimX(), in_function->DimY(), in_function->DimZ()); + //get a pointer to the scalar field data and the function data + unsigned char* scalar_pointer = (unsigned char*)outputImageData->GetScalarPointer(); + unsigned char* volume_pointer = (unsigned char*)in_function->GetBits(); + unsigned int vol_size; + switch(data_type) + { + case VTK_UNSIGNED_CHAR: + vol_size = sizeof(char)*in_function->DimX()*in_function->DimY()*in_function->DimZ(); + break; + case VTK_DOUBLE: + vol_size = sizeof(double)*in_function->DimX()*in_function->DimY()*in_function->DimZ(); + break; + default: + exit(1); + } + + memcpy(scalar_pointer, volume_pointer, vol_size); + + //for(int i=0; i +using namespace std; + + +#pragma comment( lib, "comctl32" ) + +#include +#include +#include +#include + +bool rtsOpenFileDialog( char *filename, int filenameSize, const char *filetypes="All Files (*.*)\0*.*;") +{ + OPENFILENAME *ofn = (OPENFILENAME*)GlobalAlloc(GMEM_FIXED,sizeof(OPENFILENAME)); + ZeroMemory(ofn, sizeof(OPENFILENAME)); + ofn->lStructSize = sizeof(OPENFILENAME); + ofn->hwndOwner = NULL; + ofn->lpstrFile = filename; + cout<lpstrFile<nMaxFile = filenameSize; + ofn->lpstrFilter = filetypes ? filetypes : "All Files (*.*)\0*.*;"; + ofn->nFilterIndex = 0; + ofn->lpstrFileTitle = NULL; + ofn->nMaxFileTitle = 0; + ofn->lpstrInitialDir = NULL; + ofn->Flags = OFN_ENABLESIZING | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST +|OFN_EXPLORER | OFN_HIDEREADONLY; + + //allow multiple files to be loaded if the user says so + //if(multi) ofn->Flags = ofn->Flags | OFN_ALLOWMULTISELECT; + + BOOL success = GetOpenFileNameA(ofn); + //DWORD myfoo = CommDlgExtendedError(); + GlobalFree(ofn); + return success; +} + +bool rtsSaveFileDialog( char *filename, int filenameSize, const char *filetypes="All Files (*.*)\0*.*;" ) +{ + OPENFILENAME *ofn = (OPENFILENAME*)GlobalAlloc(GMEM_FIXED,sizeof(OPENFILENAME)); + ZeroMemory(ofn, sizeof(OPENFILENAME)); + ofn->lStructSize = sizeof(OPENFILENAME); + ofn->hwndOwner = NULL; + ofn->lpstrFile = filename; + ofn->nMaxFile = filenameSize; + ofn->lpstrFilter = filetypes ? filetypes : "All Files (*.*)\0*.*;"; + ofn->nFilterIndex = 0; + ofn->lpstrFileTitle = NULL; + ofn->nMaxFileTitle = 0; + ofn->lpstrInitialDir = NULL; + ofn->Flags = OFN_ENABLESIZING | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST +|OFN_EXPLORER | OFN_HIDEREADONLY; + BOOL success = GetSaveFileNameA(ofn); + //DWORD myfoo = CommDlgExtendedError(); + GlobalFree(ofn); + return success; +} + +bool rts_winBrowseFolderDialog(char* title, char* foldername) +{ + BROWSEINFO* bi = (BROWSEINFO*)GlobalAlloc(GMEM_FIXED,sizeof(BROWSEINFO)); + ZeroMemory(bi, sizeof(BROWSEINFO)); + char directory[MAX_PATH] = ""; + + bi->pszDisplayName = directory; + bi->lpszTitle = title; + bi->pidlRoot = NULL; + bi->lpfn = NULL; + bi->ulFlags = 0; + PIDLIST_ABSOLUTE pID = SHBrowseForFolder(bi); + + SHGetPathFromIDList(pID, foldername); + + return true; + +} \ No newline at end of file diff --git a/rts_winFileDialog.h b/rts_winFileDialog.h new file mode 100755 index 0000000..0e4f5db --- /dev/null +++ b/rts_winFileDialog.h @@ -0,0 +1,18 @@ +/* +1) Make sure to not use Unicode characters. Using the Unicode character set does some +strange stuff involving LPWSTR and LPWCHAR. +2) Make sure an empty string is passed: + char filename[255] = ""; + rtsOpenFileDialog(filename, 255); +*/ + +#pragma comment( lib, "comctl32" ) + +#include +#include +#include +#include + +bool rtsOpenFileDialog( char *filename, int filenameSize, const char *filetypes); +bool rtsSaveFileDialog( char *filename, int filenameSize, const char *filetypes); +bool rts_winBrowseFolderDialog( char* title, char* foldername); diff --git a/rts_winFiles.h b/rts_winFiles.h new file mode 100755 index 0000000..9fabeaa --- /dev/null +++ b/rts_winFiles.h @@ -0,0 +1,41 @@ +#include "rtsFilename.h" + +#include +#include + + +vector rts_winGetFileList(const char* mask) +{ + /*This function returns a list of file names based on the mask passed by + the user. The value returned is the number of rtsFilename elements in the + file_list parameter.*/ + + //create a temporary vector to store the file names + vector result; + //create a handle for the search + HANDLE search_handle; + WIN32_FIND_DATA found_data; + + //start the search + search_handle = FindFirstFile((LPCSTR)mask, &found_data); + + //loop through the rest of the data + rtsFilename new_file; + if(search_handle != INVALID_HANDLE_VALUE) + { + //save the first filename + new_file = found_data.cFileName; + result.push_back(new_file); + + //now loop through the rest of the files + while(FindNextFile(search_handle, &found_data)) + { + new_file = found_data.cFileName; + result.push_back(new_file); + } + } + + return result; +} + + diff --git a/rtsf_LoadTexture.h b/rtsf_LoadTexture.h new file mode 100755 index 0000000..24bc0fc --- /dev/null +++ b/rtsf_LoadTexture.h @@ -0,0 +1,77 @@ +#include "cimg/cimg.h" +#include "rtsFunction3D.h" +#include "rtspoint3D.h" + +using namespace cimg_library; + +typedef point3D RGB; + +rtsFunction3D rtsf_LoadTexture(const char* filename) +{ + + CImg image(filename); + + unsigned int max_x = image.dimx(); + unsigned int max_y = image.dimy(); + unsigned int max_z = image.dimz(); + + rtsFunction3D bits(max_x, max_y, max_z); + + unsigned int x, y, z; + for(x = 0; x rtsf_LoadGrayTexture(const char* filename) +{ + + CImg image(filename); + + //CImgDisplay main_disp(image); + //while(true); + + unsigned int dim_x = image.dimx(); + unsigned int dim_y = image.dimy(); + unsigned int dim_z = image.dimz(); + + rtsFunction3D bits(dim_x, dim_y, dim_z); + + + float r, g, b; + float greyscale; + float max_length = sqrt(3.0f); + + unsigned int x, y, z; + for(x = 0; x + +template +class rtsAABB +{ +public: + point3D minimum; + point3D maximum; + + //overloaded operators + rtsAABB operator+(rtsAABB param); + rtsAABB getGridAlignedAABB(); + inline bool isIn(T x, T y, T z); +}; + +template +class rtsBoundingSphere +{ +public: + point3D center; + T radius; + + inline bool isIn(T x, T y, T z); +}; + +template +class rtsTGC +{ +public: + point3D posA; + point3D posB; + vector3D normA; + vector3D normB; + T radA; + T radB; + + rtsAABB BoundAABB(); +}; + +template +rtsAABB rtsAABB::operator+(rtsAABB param) +{ +/* This function creates an AABB by finding the minimum bound + of two other AABBs. +*/ + + rtsAABB result; + + result.minimum.x = min(minimum.x, param.minimum.x); + result.minimum.y = min(minimum.y, param.minimum.y); + result.minimum.z = min(minimum.z, param.minimum.z); + + result.maximum.x = max(maximum.x, param.maximum.x); + result.maximum.y = max(maximum.y, param.maximum.y); + result.maximum.z = max(maximum.z, param.maximum.z); + return result; +} + +template +inline bool rtsAABB::isIn(T x, T y, T z) +{ + if(x >= minimum.x && x <= maximum.x && + y >= minimum.y && y <= maximum.y && + z >= minimum.z && z <= maximum.z) + return true; + else + return false; +} + +template +inline bool rtsBoundingSphere::isIn(T x, T y, T z) +{ + vector3D to_point = center - point3D(x, y, z); + T length_squared = to_point*to_point; + if(length_squared < radius*radius) + return true; + else + return false; +} + +template +rtsAABB rtsAABB::getGridAlignedAABB() +{ +/* This function returns a version of the current AABB that is snapped + to a grid (ie the floor of the position and the ceiling of the size). +*/ + rtsAABB result; + result.minimum.x = floor(minimum.x); + result.minimum.y = floor(minimum.y); + result.minimum.z = floor(minimum.z); + result.maximum.x = ceil(maximum.x); + result.maximum.y = ceil(maximum.y); + result.maximum.z = ceil(maximum.z); + return result; +} + +template +rtsAABB rtsTGC::BoundAABB() +{ +/* This function returns an axis-aligned bounding box + that is the minimum bound for the given truncated-generalized cone. +*/ + //create a vector representing each axis + vector3D x(1.0, 0.0, 0.0); + vector3D y(0.0, 1.0, 0.0); + vector3D z(0.0, 0.0, 1.0); + + //store the extents + point3D a_extents(radA*(1.0 - fabs(normA*x)), + radA*(1.0 - fabs(normA*y)), + radA*(1.0 - fabs(normA*z))); + point3D b_extents(radB*(1.0 - fabs(normB*x)), + radB*(1.0 - fabs(normB*y)), + radB*(1.0 - fabs(normB*z))); + + //create the AABB + rtsAABB result; + + //calculate the bounding box information + //calculate bounding box position as the minima of all extents and positions + result.minimum.x = min(posA.x - a_extents.x, posB.x - b_extents.x); + result.minimum.y = min(posA.y - a_extents.y, posB.y - b_extents.y); + result.minimum.z = min(posA.z - a_extents.z, posB.z - b_extents.z); + + //now find the size of the block + result.maximum.x = max(posA.x + a_extents.x, posB.x + b_extents.x); + result.maximum.y = max(posA.y + a_extents.y, posB.y + b_extents.y); + result.maximum.z = max(posA.z + a_extents.z, posB.z + b_extents.z); + + return result; +} + + + + + + + + +#endif \ No newline at end of file diff --git a/temp_rtsSignedDistance.h b/temp_rtsSignedDistance.h new file mode 100755 index 0000000..ea17d37 --- /dev/null +++ b/temp_rtsSignedDistance.h @@ -0,0 +1,321 @@ +#include "rtsImplicit3D.h" +#include +using namespace std; + +#define DIST_MAX 255 +#define DIST_UNSIGNED 0 +#define DIST_SIGNED 1 + +float ComputeSurfaceDistance(point3D p0, point3D p1, float val0, float val1, float s) +{ + /*This function computes the distance from p0 to the surface, given two points p0 and p1 + on either side of the surface (with values v0 and v1 respectively). surface specifies + the value at the surface. + */ + + //compute the normalized position of the surface between p0 and p1 + float s_norm_pos = (s - val0) / (val1 - val0); + //compute the actual position of the surface + point3D s_pos = p0 + s_norm_pos * (p1 - p0); + //compute the distance from p0 to the surface + float result = (s_pos - p0).Length(); + //cout<<"distance: "<* function, float threshold, + rtsImplicit3D* &result, rtsImplicit3D* &mask) +{ + /*This function creates an initial signed distance function from a threshold image. + All voxels adjacent to the surface specified by the threshold are initialized with a + distance value. Low values are inside, high values are outside. + */ + //current and neighboring voxel flags (false = inside, true = outside) + bool c, x_p, x_n, y_p, y_n, z_p, z_n; + float d_xp, d_xn, d_yp, d_yn, d_zp, d_zn; + float in_out = 1; + + //boundary condition function and the mask + result = new rtsImplicit3D(function->DimX(), function->DimY(), function->DimZ()); + //get the parameterization + point3D min_domain= function->getMinDomain(); + point3D max_domain = function->getMaxDomain(); + result->Parameterize(min_domain.x, max_domain.x, min_domain.y, max_domain.y, min_domain.z, max_domain.z); + (*result) = DIST_MAX; + //create a mask + mask = new rtsImplicit3D(function->DimX(), function->DimY(), function->DimZ()); + (*mask) = false; + + cout<<"done making boundary condition function"< size(function->DimX(), function->DimY(), function->DimZ()); //get the function size + int x, y, z; + for(x=0; x= size.x) x_p = c; + else if((*function)(x+1, y, z) < threshold) x_p = false; + if(y-1 < 0) y_n = c; //Y + else if((*function)(x, y-1, z) < threshold) y_n = false; + if(y+1 >= size.y) y_p = c; + else if((*function)(x, y+1, z) < threshold) y_p = false; + if(z-1 < 0) z_n = c; //Z + else if((*function)(x, y, z-1) < threshold) z_n = false; + if(z+1 >= size.z) z_p = c; + else if((*function)(x, y, z+1) < threshold) z_p = false; + + //set the distance from the isosurface + if(c == false) + in_out = -1.0; + if(x_n != c) + (*result)(x, y, z) = min((*result)(x,y,z), + ComputeSurfaceDistance((*function).getParameter(x, y, z), + (*function).getParameter(x-1, y, z), + (*function)(x, y, z), + (*function)(x-1, y, z), + threshold) * in_out); + if(x_p != c) + (*result)(x, y, z) = min((*result)(x,y,z), + ComputeSurfaceDistance((*function).getParameter(x, y, z), + (*function).getParameter(x+1, y, z), + (*function)(x, y, z), + (*function)(x+1, y, z), + threshold) * in_out); + if(y_n != c) + (*result)(x, y, z) = min((*result)(x,y,z), + ComputeSurfaceDistance((*function).getParameter(x, y, z), + (*function).getParameter(x, y-1, z), + (*function)(x, y, z), + (*function)(x, y-1, z), + threshold) * in_out); + if(y_p != c) + (*result)(x, y, z) = min((*result)(x,y,z), + ComputeSurfaceDistance((*function).getParameter(x, y, z), + (*function).getParameter(x, y+1, z), + (*function)(x, y, z), + (*function)(x, y+1, z), + threshold) * in_out); + if(z_n != c) + (*result)(x, y, z) = min((*result)(x,y,z), + ComputeSurfaceDistance((*function).getParameter(x, y, z-1), + (*function).getParameter(x, y, z), + (*function)(x, y, z), + (*function)(x, y, z-1), + threshold) * in_out); + if(z_p != c) + (*result)(x, y, z) = min((*result)(x,y,z), + ComputeSurfaceDistance((*function).getParameter(x, y, z), + (*function).getParameter(x, y, z+1), + (*function)(x, y, z), + (*function)(x, y, z+1), + threshold) * in_out); + + //set the mask to 1 if the voxel is on an edge node + if(x_n != c || x_p != c || y_n != c || y_p != c || z_n != c || z_p != c) + (*mask)(x, y, z) = true; + } + + + //if a line between the two voxels crosses the surface + //find the distance between the voxel center and the surface + + + cout<<"done computing boundary conditions"<* function, + point3D point, + vector3D voxelsize, + int type = DIST_UNSIGNED) +{ + /*This function updates the manhattan distance from a surface using the manhattan + distance of its neighboring points. + */ + indextype x, y, z; + x=point.x; y=point.y, z=point.z; + int sign = 1; + float result = DIST_MAX; + float near_value; //the value of the neighbor being considered + float possible_value; + if(x!=0) + { + near_value = (*function)(x-1, y, z); + if(type == DIST_UNSIGNED) + result = min(result, near_value + voxelsize.x); + else if(type == DIST_SIGNED) + { + if(near_value<0) sign = -1; else sign = 1; //determine if the value is inside or outside + possible_value = sign*(fabs(near_value) + voxelsize.x); + if(fabs(possible_value) < fabs(result)) + result = possible_value; + } + + } + if(x!=function->DimX()-1) + { + near_value = (*function)(x+1, y, z); + if(type == DIST_UNSIGNED) + result = min(result, near_value + voxelsize.x); + else if(type == DIST_SIGNED) + { + if(near_value<0) sign = -1; else sign = 1; //determine if the value is inside or outside + possible_value = sign*(fabs(near_value) + voxelsize.x); + if(fabs(possible_value) < fabs(result)) + result = possible_value; + } + } + if(y!=0) + { + near_value = (*function)(x, y-1, z); + if(type == DIST_UNSIGNED) + result = min(result, near_value + voxelsize.y); + else if(type == DIST_SIGNED) + { + if(near_value<0) sign = -1; else sign = 1; //determine if the value is inside or outside + possible_value = sign*(fabs(near_value) + voxelsize.y); + if(fabs(possible_value) < fabs(result)) + result = possible_value; + } + } + if(y!=function->DimY()-1) + { + near_value = (*function)(x, y+1, z); + if(type == DIST_UNSIGNED) + result = min(result, near_value + voxelsize.y); + else if(type == DIST_SIGNED) + { + if(near_value<0) sign = -1; else sign = 1; //determine if the value is inside or outside + possible_value = sign*(fabs(near_value) + voxelsize.y); + if(fabs(possible_value) < fabs(result)) + result = possible_value; + } + } + if(z!=0) + { + near_value = (*function)(x, y, z-1); + if(type == DIST_UNSIGNED) + result = min(result, near_value + voxelsize.z); + else if(type == DIST_SIGNED) + { + if(near_value<0) sign = -1; else sign = 1; //determine if the value is inside or outside + possible_value = sign*(fabs(near_value) + voxelsize.z); + if(fabs(possible_value) < fabs(result)) + result = possible_value; + } + } + if(z!=function->DimZ()-1) + { + near_value = (*function)(x, y, z+1); + if(type == DIST_UNSIGNED) + result = min(result, near_value + voxelsize.z); + else if(type == DIST_SIGNED) + { + if(near_value<0) sign = -1; else sign = 1; //determine if the value is inside or outside + possible_value = sign*(fabs(near_value) + voxelsize.z); + if(fabs(possible_value) < fabs(result)) + result = possible_value; + } + } + return result; + +} +void Eikonal_Manhattan(rtsImplicit3D* &function, + rtsImplicit3D* mask, + int type = DIST_UNSIGNED) +{ + /*This function estimates the Eikonal equation based on the manhattan distance. The + function constantly increases values outwards from the boundary conditions. + */ + + //compute the distance between two voxels + vector3D voxel_size; + voxel_size.x = fabs(function->getParameter(0, 0, 0).x - function->getParameter(1, 0, 0).x); + voxel_size.y = fabs(function->getParameter(0, 0, 0).y - function->getParameter(0, 1, 0).y); + voxel_size.z = fabs(function->getParameter(0, 0, 0).z - function->getParameter(0, 0, 1).z); + + //use fast sweeping to compute the manhattan distance + //0:X 0:Y 0:Z + cout<<"first iteration..."<DimX(); x++) + for(y=0; yDimY(); y++) + for(z=0; zDimZ(); z++) + //if the current point is not a boundary value + if(!(*mask)(x, y, z)) + (*function)(x,y,z) = ManhattanDistance(function, point3D(x, y, z), voxel_size, type); + cout<<"done."<DimX(); x++) + for(y=0; yDimY(); y++) + for(z=function->DimZ()-1; z>=0; z--) + //if the current point is not a boundary value + if(!(*mask)(x, y, z)) + (*function)(x,y,z) = ManhattanDistance(function, point3D(x, y, z), voxel_size, type); + cout<<"done."<DimX(); x++) + for(y=function->DimY()-1; y>=0; y--) + for(z=0; zDimZ(); z++) + //if the current point is not a boundary value + if(!(*mask)(x, y, z)) + (*function)(x,y,z) = ManhattanDistance(function, point3D(x, y, z), voxel_size, type); + cout<<"done."<DimX(); x++) + for(y=function->DimY()-1; y>=0; y--) + for(z=function->DimZ()-1; z>=0; z--) + //if the current point is not a boundary value + if(!(*mask)(x, y, z)) + (*function)(x,y,z) = ManhattanDistance(function, point3D(x, y, z), voxel_size, type); + cout<<"done."<DimX()-1; x>=0; x--) + for(y=0; yDimY(); y++) + for(z=0; zDimZ(); z++) + //if the current point is not a boundary value + if(!(*mask)(x, y, z)) + (*function)(x,y,z) = ManhattanDistance(function, point3D(x, y, z), voxel_size, type); + cout<<"done."<DimX()-1; x>=0; x--) + for(y=0; yDimY(); y++) + for(z=function->DimZ()-1; z>=0; z--) + //if the current point is not a boundary value + if(!(*mask)(x, y, z)) + (*function)(x,y,z) = ManhattanDistance(function, point3D(x, y, z), voxel_size, type); + cout<<"done."<DimX()-1; x>=0; x--) + for(y=function->DimY()-1; y>=0; y--) + for(z=0; zDimZ(); z++) + //if the current point is not a boundary value + if(!(*mask)(x, y, z)) + (*function)(x,y,z) = ManhattanDistance(function, point3D(x, y, z), voxel_size, type); + cout<<"done."<DimX()-1; x>=0; x--) + for(y=function->DimY()-1; y>=0; y--) + for(z=function->DimZ()-1; z>=0; z--) + //if the current point is not a boundary value + if(!(*mask)(x, y, z)) + (*function)(x,y,z) = ManhattanDistance(function, point3D(x, y, z), voxel_size, type); + cout<<"done."<::iterator i; + int a, b; + point3D v_a, v_b; + glBegin(GL_LINES); //start rendering lines + for(i=m_edge_list.begin(); i!=m_edge_list.end(); i++) + { + v_a = (*i)->vertex_a->position; //get the positions of the two vertex edges + v_b = (*i)->vertex_b->position; + glVertex3f(v_a.x, v_a.y, v_a.z); //draw the vertices + glVertex3f(v_b.x, v_b.y, v_b.z); + } + glEnd(); //finish drawing +} + +void rts_glFilamentNetwork::RenderBranches() +{ + //for each vertex + vector::iterator i; + point3D v; + glBegin(GL_POINTS); + for(i=m_vertex_list.begin(); i!=m_vertex_list.end(); i++) + { + if((*i)->v_neighbors.size() > 2) + { + v = (*i)->position; + glVertex3f(v.x, v.y, v.z); + } + } + glEnd(); +} + +void rts_glFilamentNetwork::RenderFilaments() +{ + vector::iterator i; + int num_edges; + point3D v_a, v_b; + int e; + glBegin(GL_LINES); + for(i=m_filament_list.begin(); i!=m_filament_list.end(); i++) //for each filament + { + num_edges = (*i)->edges.size(); + for(e=0; eedges[e]->vertex_a->position; + v_b = (*i)->edges[e]->vertex_b->position; + glVertex3f(v_a.x, v_a.y, v_a.z); + glVertex3f(v_b.x, v_b.y, v_b.z); + } + } + glEnd(); +} + +void rts_glFilamentNetwork::RenderSelectedFilaments() +{ + vector::iterator f; + int num_edges; + point3D v_a, v_b; + int e; + glBegin(GL_LINES); + for(f=m_selected_list.begin(); f!=m_selected_list.end(); f++) + { + num_edges = m_filament_list[(*f)]->edges.size(); + for(e=0; eedges[e]->vertex_a->position; + v_b = m_filament_list[(*f)]->edges[e]->vertex_b->position; + glVertex3f(v_a.x, v_a.y, v_a.z); + glVertex3f(v_b.x, v_b.y, v_b.z); + } + } + glEnd(); +} + +void rts_glFilamentNetwork::RenderOrientationColor(double x, double y, double z, double r, double g, double b) +{ + vector::iterator i; + int num_edges; + point3D v_a, v_b; + + //orientation variables + vector3D orientation; + double cos_a; + vector3D A(x, y, z); + A.Normalize(); + + int e; + glBegin(GL_LINES); + for(i=m_filament_list.begin(); i!=m_filament_list.end(); i++) //for each filament + { + //set the color of the filament based on orientation + v_a = (*i)->vertex_a->position; + v_b = (*i)->vertex_b->position; + + + num_edges = (*i)->edges.size(); + for(e=0; eedges[e]->vertex_a->position; + v_b = (*i)->edges[e]->vertex_b->position; + + //determine color + orientation = (v_a - v_b).Normalize(); + cos_a = fabs(orientation*A); + glColor3f(r*cos_a, g*cos_a, b*cos_a); + + glVertex3f(v_a.x, v_a.y, v_a.z); + glVertex3f(v_b.x, v_b.y, v_b.z); + } + } + glEnd(); +} + +void rts_glFilamentNetwork::RenderEdgeDistanceColor(float r, float g, float b, float cutoff) +{ + vector::iterator e; + glBegin(GL_LINES); + point3D p; + double d; + double exp = 3; + for(e=m_edge_list.begin(); e!=m_edge_list.end(); e++) + { + d = (*e)->distance; + if(d1.0) d=1.0; + + glColor3f(pow((1.0-d),exp)*r, pow((1.0-d),exp)*g, pow((1.0-d),exp)*b); + p = (*e)->vertex_a->position; + glVertex3f(p.x, p.y, p.z); + p = (*e)->vertex_b->position; + glVertex3f(p.x, p.y, p.z); + } + } + glEnd(); +} + +void rts_glFilamentNetwork::RenderFilamentDistanceColor(float r, float g, float b, float cutoff) +{ + vector::iterator f; + unsigned int e; + unsigned int num_edges; + double d; + point3D v; + double exp = 3.0; + for(f = m_filament_list.begin(); f!=m_filament_list.end(); f++) + { + d = (*f)->distance; + if(d1.0) d=1.0; + if(d<0.0) d=0.0; + //cout<<"d: "<edges.size(); + glColor3f(pow((1.0-d), exp)*r, pow((1.0-d), exp)*g, pow((1.0-d), exp)*b); + glBegin(GL_LINES); + for(e=0; eedges[e]->vertex_a->position; + glVertex3f(v.x, v.y, v.z); + v = (*f)->edges[e]->vertex_b->position; + glVertex3f(v.x, v.y, v.z); + } + glEnd(); + } + } + +} + + +void rts_glFilamentNetwork::RenderRadiusColor(float min_r, float min_g, float min_b, + float max_r, float max_g, float max_b, + float min_radius, float max_radius) +{ + /*Render each segment with a color based on the radius of the filament + */ + + vector::iterator i; + int e; + int num_edges; + point3D v; + vector3D color_min(min_r, min_g, min_b); + vector3D color_max(max_r, max_g, max_b); + max_radius /= m_data_scale; + min_radius /= m_data_scale; + float diff = max_radius - min_radius; + float p; //parameter value (position between min and max radii) + vector3D color_p; + + for(i=m_filament_list.begin(); i!=m_filament_list.end(); i++) + { + glBegin(GL_LINES); + num_edges = (*i)->edges.size(); + for(e=0; eedges[e]->vertex_a->radius - min_radius)/diff; + //cout<<"p: "<edges[e]->vertex_a->position; + glVertex3f(v.x, v.y, v.z); + //determine the second color + p = ((*i)->edges[e]->vertex_b->radius - min_radius)/diff; + color_p = (1.0 - p)*color_min + (p)*color_max; + glColor3f(color_p.x, color_p.y, color_p.z); + //determine the vertex position + v = (*i)->edges[e]->vertex_b->position; + glVertex3f(v.x, v.y, v.z); + } + glEnd(); + } +} + +void rts_glFilamentNetwork::RenderEdgeBoundingBoxes() +{ + glMatrixMode(GL_MODELVIEW); //switch to the modelview matrix and store it + + vector::iterator e; + point3D center; + vector3D size; + for(e=m_edge_list.begin(); e!=m_edge_list.end(); e++) + { + glPushMatrix(); + size = (*e)->bounding_box.maximum - (*e)->bounding_box.minimum; + center = (*e)->bounding_box.minimum + 0.5*(size); + glTranslatef(center.x, center.y, center.z); + glScalef(size.x, + size.y, + size.z); + glutWireCube(1.0); + glPopMatrix(); + } + +} + +void rts_glFilamentNetwork::RenderFilamentBoundingBoxes() +{ + glMatrixMode(GL_MODELVIEW); //switch to the modelview matrix and store it + + vector::iterator f; + point3D center; + vector3D size; + for(f=m_filament_list.begin(); f!=m_filament_list.end(); f++) + { + glPushMatrix(); + size = (*f)->bounding_box.maximum - (*f)->bounding_box.minimum; + center = (*f)->bounding_box.minimum + 0.5*size; + glTranslatef(center.x, center.y, center.z); + glScalef(size.x, + size.y, + size.z); + glutWireCube(1.0); + glPopMatrix(); + } +} + +void rts_glFilamentNetwork::RenderCellSpheres() +{ + glMatrixMode(GL_MODELVIEW); + + vector::iterator c; + for(c=m_cell_list.begin(); c!=m_cell_list.end(); c++) + { + glPushMatrix(); + glTranslatef((*c)->position.x, (*c)->position.y, (*c)->position.z); + glutSolidSphere((*c)->radius, 10, 10); + glPopMatrix(); + } +} +void rts_glFilamentNetwork::RenderSelectedCells() +{ + glMatrixMode(GL_MODELVIEW); + + vector::iterator f; + vector::iterator c; + for(f = m_selected_list.begin(); f!=m_selected_list.end(); f++) + { + for(c=m_filament_list[(*f)]->cells.begin(); c!=m_filament_list[(*f)]->cells.end(); c++) + { + glPushMatrix(); + glTranslatef((*c)->position.x, (*c)->position.y, (*c)->position.z); + glutSolidSphere((*c)->radius, 10, 10); + glPopMatrix(); + } + } +} + +void rts_glFilamentNetwork::p_ProcessPickHits(GLuint num_hits, GLuint* buffer, + unsigned int start_filament, bool append, int max) +{ + //cout<<"hits "< max) + num_hits = max; + unsigned int h, n; + unsigned int num_names; + unsigned int name; + GLuint* ptr = buffer; //index into buffer array + for(h=0; h v_a, v_b; + int name = 0; + unsigned int total_hits = 0; + for(f=0; fedges.size(); + for(e = 0; eedges[e]->vertex_a->position; + v_b = m_filament_list[f]->edges[e]->vertex_b->position; + glVertex3f(v_a.x, v_a.y, v_a.z); + glVertex3f(v_b.x, v_b.y, v_b.z); + } + glEnd(); + name++; //increment the name + //We have to make sure that the name count doesn't exceed 64 + if(name == 64) //if the name hits 64, check for and store hits, then reset the name + { + hits = glRenderMode(GL_RENDER); + p_ProcessPickHits(hits, selection_buffer, f-63, append, max - total_hits); //process the hits (store selected fibers) + total_hits += hits; + if(total_hits >= max) //if we've reached the max, return + { + glPopMatrix(); + return; + } + name = 0; //reset the selection queue + glRenderMode(GL_SELECT); //change to selection mode + glInitNames(); //start naming objects + glPushName(0); //insert the first name + } + } + glFlush(); //finish rendering + hits = glRenderMode(GL_RENDER); //switch back to normal mode, get the number of hits + p_ProcessPickHits(hits, selection_buffer, f/64, append, max - total_hits); //get any left-over hits + total_hits += hits; + + glPopMatrix(); +} diff --git a/temp_rts_glFilamentNetwork.h b/temp_rts_glFilamentNetwork.h new file mode 100755 index 0000000..3d360d9 --- /dev/null +++ b/temp_rts_glFilamentNetwork.h @@ -0,0 +1,37 @@ +#ifndef RTS_GLFILAMENTNETWORK_H +#define RTS_GLFILAMENTNETWORK_H + +#include "temp_rtsFilamentNetwork.h" +#include +#include +#include + +class rts_glFilamentNetwork:public rtsFilamentNetwork +{ +private: + void p_ProcessPickHits(GLuint num_hits, GLuint* buffer, unsigned int start_filament, + bool append = false, int max = 1); +public: + + void RenderEdges(); + void RenderBranches(); + void RenderFilaments(); + void RenderOrientationColor(double x, double y, double z, double r, double g, double b); + void RenderSelectedFilaments(); + void RenderRadiusColor(float min_r, float min_g, float min_b, + float max_r, float max_g, float max_b, + float min_radius, float max_radius); + void RenderEdgeDistanceColor(float r, float g, float b, float cutoff); + void RenderFilamentDistanceColor(float r, float g, float b, float cutoff); + void RenderEdgeBoundingBoxes(); + void RenderFilamentBoundingBoxes(); + void RenderCellSpheres(); + void RenderSelectedCells(); + + //pick filaments based on the current projection + void PickFilaments(int x_center, int y_center, int width, int height, bool append = false, int max = 1); + +}; + + +#endif \ No newline at end of file diff --git a/validate/CMakeLists.txt b/validate/CMakeLists.txt new file mode 100755 index 0000000..2d54c3d --- /dev/null +++ b/validate/CMakeLists.txt @@ -0,0 +1,52 @@ +#Specify the version being used aswell as the language +cmake_minimum_required(VERSION 2.8) +#Name your project here +project(rts-validate) + +#set the module directory +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}") + +#set up CUDA +find_package(CUDA) + +#find OpenGL +find_package(OpenGL REQUIRED) + +#find GLUT +set(GLUT_ROOT_PATH $ENV{GLUT_ROOT_PATH}) +find_package(GLUT REQUIRED) + +#find GLEW +find_package(GLEW REQUIRED) + +#ask the user for the RTS location +set(RTS_ROOT_PATH $ENV{RTS_ROOT_PATH}) +find_package(RTS REQUIRED) + +#set the include directories +include_directories( + ${CMAKE_CURRENT_BINARY_DIR} + ${OPENGL_INCLUDE_DIR} + ${GLEW_INCLUDE_PATH} + ${GLUT_INCLUDE_DIR} + ${RTS_INCLUDE_DIR} +) + +#enable warnings +if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) + add_definitions(-Wall) +endif() + +#Assign source files to the appropriate variables +file(GLOB SRC_CPP "*.cpp") +file(GLOB SRC_H "*.h") +file(GLOB SRC_CU "*.cu") + +#create an executable +cuda_add_executable(rts-validate ${SRC_CPP} ${SRC_H} ${UI_H} ${SRC_CU}) + +#set the link libraries +target_link_libraries(rts-validate ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} ${GLEW_LIBRARY} ${CUDA_cufft_LIBRARY} ${GLUT_glut_LIBRARY}) + + + diff --git a/validate/FindRTS.cmake b/validate/FindRTS.cmake new file mode 100755 index 0000000..fbfcc44 --- /dev/null +++ b/validate/FindRTS.cmake @@ -0,0 +1,14 @@ +# Tries to find the RTS include directory + + FIND_PATH( RTS_INCLUDE_DIR NAMES rts_glShaderProgram.h + PATHS + ${CMAKE_CURRENT_SOURCE_DIR}/rts + ${RTS_ROOT_PATH} +) + +IF (RTS_FOUND) + #The following deprecated settings are for backwards compatibility with CMake1.4 + SET (RTS_INCLUDE_PATH ${RTS_INCLUDE_DIR}) +ENDIF(RTS_FOUND) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(RTS REQUIRED_VARS TRUE RTS_INCLUDE_DIR) diff --git a/validate/compare.h b/validate/compare.h new file mode 100644 index 0000000..3d4f4e6 --- /dev/null +++ b/validate/compare.h @@ -0,0 +1,27 @@ +#ifndef RTS_VALIDATE_COMPARE_H +#define RTS_VALIDATE_COMPARE_H + +#define N 5000 +#define epsilon 0.00001 + +#include +#include +#include +#include "rts/complex.h" + +template +static void compare(std::complex a, rts::complex b, std::string testName) +{ + T diffx = std::abs(a.real() - b.r); + T diffy = std::abs(a.imag() - b.i); + + if(diffx > epsilon || diffy > epsilon) + { + std::cout<<"Failed "< +#include +#include +#include +#include "rts/complex.h" +#include "rts/sbessel.h" + +#include "compare.h" + +typedef float precision; + +//typedef std::complex ptype; +typedef rts::complex ptype; + +void cpuValidateBessel() +{ + + //order + precision v = 5; + precision vm; + + //parameter + precision max_z = 5; + int nz = 20; + precision dz = max_z / nz; + + //bessel function results (first and second kind) + int S = sizeof(ptype) * (v + 1); + + ptype* jv = (ptype*)malloc(S); + ptype* yv = (ptype*)malloc(S); + ptype* hv = (ptype*)malloc(S); + + + std::cout<<"---------j_v(x)-------------"< z; + for(int iz = 0; iz < nz; iz++) + { + z = iz * dz; + + rts::sbesselj(v, z, jv); + + std::cout<(v, z, yv); + + std::cout<(v, z, hv); + + std::cout< +#include +#include "rts/complex.h" + +#include "compare.h" + +#define N 5 +#define epsilon 0.000001 + +template +void validateOperators() +{ + int precision = sizeof(T) * 8; + std::stringstream ss; + ss<<" ("< stdComplex0(x0, y0); + rts::complex rtsComplex0(x0, y0); + + std::complex stdComplex1(x1, y1); + rts::complex rtsComplex1(x1, y1); + + std::complex stdResult; + rts::complex rtsResult; + + //test addition + stdResult = stdComplex0 + stdComplex1; + rtsResult = rtsComplex0 + rtsComplex1; + compare(stdResult, rtsResult, std::string("Binary Addition") + bitString); + //test addition with real value + stdResult = stdComplex1.real() + stdComplex0; + rtsResult = rtsComplex1.r + rtsComplex0; + compare(stdResult, rtsResult, std::string("Addition with Real Value") + bitString); + + //test subtraction + stdResult = stdComplex0 - stdComplex1; + rtsResult = rtsComplex0 - rtsComplex1; + compare(stdResult, rtsResult, std::string("Binary Subtraction") + bitString); + //test subtraction with real value + stdResult = stdComplex1.real() - stdComplex0; + rtsResult = rtsComplex1.r - rtsComplex0; + compare(stdResult, rtsResult, std::string("Subtraction with Real Value") + bitString); + + //test multiplication + stdResult = stdComplex0 * stdComplex1; + rtsResult = rtsComplex0 * rtsComplex1; + compare(stdResult, rtsResult, std::string("Binary Multiplication") + bitString); + //test multiplication with real value + stdResult = stdComplex1.real() * stdComplex0; + rtsResult = rtsComplex1.r * rtsComplex0; + compare(stdResult, rtsResult, std::string("Multiplication with Real Value") + bitString); + + //test division + stdResult = stdComplex0 / stdComplex1; + rtsResult = rtsComplex0 / rtsComplex1; + compare(stdResult, rtsResult, std::string("Binary Division") + bitString); + //test division with real value + stdResult = stdComplex1.real() / stdComplex0; + rtsResult = rtsComplex1.r / rtsComplex0; + compare(stdResult, rtsResult, std::string("Division with Real Value") + bitString); + + //test abs() + stdResult = abs(stdComplex0); + rtsResult = abs(rtsComplex0); + compare(stdResult, rtsResult, std::string("abs()") + bitString); + + //test log() + stdResult = log(stdComplex0); + rtsResult = log(rtsComplex0); + compare(stdResult, rtsResult, std::string("log()") + bitString); + + //test exp() + stdResult = exp(stdComplex0); + rtsResult = exp(rtsComplex0); + compare(stdResult, rtsResult, std::string("exp()") + bitString); + + //test pow() + stdResult = pow(stdComplex0, (T)2.0); + rtsResult = pow(rtsComplex0, (T)2.0); + compare(stdResult, rtsResult, std::string("pow()") + bitString); + + //test sqrt() + stdResult = sqrt(stdComplex0); + rtsResult = rts::sqrt(rtsComplex0); + compare(stdResult, rtsResult, std::string("sqrt()") + bitString); + + //trigonometric functions + stdResult = sin(stdComplex0); + rtsResult = rts::sin(rtsComplex0); + compare(stdResult, rtsResult, std::string("sin()") + bitString); + + //trigonometric functions + stdResult = cos(stdComplex0); + rtsResult = rts::cos(rtsComplex0); + compare(stdResult, rtsResult, std::string("cos()") + bitString); + + //ASSIGNMENT OPERATORS + + // += + stdResult = stdComplex0; + stdResult += stdComplex1; + rtsResult = rtsComplex0; + rtsResult += rtsComplex1; + compare(stdResult, rtsResult, std::string("operator +=") + bitString); + + // *= + stdResult = stdComplex0; + stdResult *= stdComplex1; + rtsResult = rtsComplex0; + rtsResult *= rtsComplex1; + compare(stdResult, rtsResult, std::string("operator *=") + bitString); + + // /= + stdResult = stdComplex0; + stdResult /= stdComplex1; + rtsResult = rtsComplex0; + rtsResult /= rtsComplex1; + compare(stdResult, rtsResult, std::string("operator /=") + bitString); + + } +} + +void cpuValidateComplex() +{ + //validate both floating point and double precision + validateOperators(); + validateOperators(); + +} diff --git a/validate/validate-complex.cu b/validate/validate-complex.cu new file mode 100644 index 0000000..9e21509 --- /dev/null +++ b/validate/validate-complex.cu @@ -0,0 +1,172 @@ +#include +#include +#include "rts/complex.h" + +#include "compare.h" + + +template +__global__ void add(rts::complex a, rts::complex b, rts::complex* c) +{ + *c = a + b; +} + +template +__global__ void multiply(rts::complex a, rts::complex b, rts::complex* c) +{ + *c = a * b; +} + +template +__global__ void multiply(rts::complex a, T b, rts::complex* c) +{ + *c = a * b; +} + +template +__global__ void divide(rts::complex a, rts::complex b, rts::complex* c) +{ + *c = a / b; +} + +template +__global__ void log(rts::complex a, rts::complex* c) +{ + *c = rts::log(a); +} + +template +__global__ void sqrt(rts::complex a, rts::complex* c) +{ + *c = rts::sqrt(a); +} + +template +__global__ void exp(rts::complex a, rts::complex* c) +{ + *c = rts::exp(a); +} + +template +__global__ void pow(rts::complex a, rts::complex* c) +{ + *c = rts::pow(a, (T)2.0); +} + +template +__global__ void sin(rts::complex a, rts::complex* c) +{ + *c = rts::sin(a); +} + +template +__global__ void cos(rts::complex a, rts::complex* c) +{ + *c = rts::cos(a); +} + +template +void gpuValidateOperators() +{ + int precision = sizeof(T) * 8; + std::stringstream ss; + ss<<" ("<* gpuResult; + cudaMalloc((void**)&gpuResult, sizeof(rts::complex)); + + //validate complex binary functions + T x0, x1, y0, y1; + for(int i = 0; i stdComplex0(x0, y0); + rts::complex rtsComplex0(x0, y0); + + std::complex stdComplex1(x1, y1); + rts::complex rtsComplex1(x1, y1); + + std::complex stdResult; + rts::complex rtsResult; + + + //test addition + stdResult = stdComplex0 + stdComplex1; + add<<<1, 1>>>(rtsComplex0, rtsComplex1, gpuResult); + cudaMemcpy(&rtsResult, gpuResult, sizeof(rts::complex), cudaMemcpyDeviceToHost); + compare(stdResult, rtsResult, std::string("Binary Addition") + bitString); + //std::cout<>>(rtsComplex0, rtsComplex1, gpuResult); + cudaMemcpy(&rtsResult, gpuResult, sizeof(rts::complex), cudaMemcpyDeviceToHost); + compare(stdResult, rtsResult, std::string("Binary Multiplication") + bitString); + + //test multiplication with constant + stdResult = stdComplex0 * stdComplex1.real(); + multiply<<<1, 1>>>(rtsComplex0, rtsComplex1.r, gpuResult); + cudaMemcpy(&rtsResult, gpuResult, sizeof(rts::complex), cudaMemcpyDeviceToHost); + compare(stdResult, rtsResult, std::string("Multiplication with Real Value") + bitString); + + //test division + stdResult = stdComplex0 / stdComplex1; + divide<<<1, 1>>>(rtsComplex0, rtsComplex1, gpuResult); + cudaMemcpy(&rtsResult, gpuResult, sizeof(rts::complex), cudaMemcpyDeviceToHost); + compare(stdResult, rtsResult, std::string("Binary Division") + bitString); + + //test log() + stdResult = log(stdComplex0); + log<<<1, 1>>>(rtsComplex0, gpuResult); + cudaMemcpy(&rtsResult, gpuResult, sizeof(rts::complex), cudaMemcpyDeviceToHost); + compare(stdResult, rtsResult, std::string("log()") + bitString); + + //test exp() + stdResult = exp(stdComplex0); + exp<<<1, 1>>>(rtsComplex0, gpuResult); + cudaMemcpy(&rtsResult, gpuResult, sizeof(rts::complex), cudaMemcpyDeviceToHost); + compare(stdResult, rtsResult, std::string("exp()") + bitString); + + //test pow() + stdResult = pow(stdComplex0, 2); + pow<<<1, 1>>>(rtsComplex0, gpuResult); + cudaMemcpy(&rtsResult, gpuResult, sizeof(rts::complex), cudaMemcpyDeviceToHost); + compare(stdResult, rtsResult, std::string("pow()") + bitString); + + //test sqrt() + stdResult = sqrt(stdComplex0); + sqrt<<<1, 1>>>(rtsComplex0, gpuResult); + cudaMemcpy(&rtsResult, gpuResult, sizeof(rts::complex), cudaMemcpyDeviceToHost); + compare(stdResult, rtsResult, std::string("sqrt()") + bitString); + + //trigonometric functions + stdResult = sin(stdComplex0); + sin<<<1, 1>>>(rtsComplex0, gpuResult); + cudaMemcpy(&rtsResult, gpuResult, sizeof(rts::complex), cudaMemcpyDeviceToHost); + compare(stdResult, rtsResult, std::string("sin()") + bitString); + + //trigonometric functions + stdResult = cos(stdComplex0); + cos<<<1, 1>>>(rtsComplex0, gpuResult); + cudaMemcpy(&rtsResult, gpuResult, sizeof(rts::complex), cudaMemcpyDeviceToHost); + compare(stdResult, rtsResult, std::string("cos()") + bitString); + + + } + cudaFree(gpuResult); + +} + +void gpuValidateComplex() +{ + + gpuValidateOperators(); + //gpuValidateOperators(); +} diff --git a/validate/validate-legendre.cpp b/validate/validate-legendre.cpp new file mode 100644 index 0000000..3ef7ea7 --- /dev/null +++ b/validate/validate-legendre.cpp @@ -0,0 +1,43 @@ +#include +#include +#include +#include +#include "rts/legendre.h" + +#include "compare.h" + +typedef float precision; +int l = 0; + + +void cpuValidateLegendre() +{ + + //order + precision v = 5; + precision vm; + + //parameter + precision max_z = 2; + int nz = 20; + precision dz = max_z / nz; + + //bessel function results (first and second kind) + int S = sizeof(precision) * (v + 1); + + precision* P = (precision*)malloc(S); + + + std::cout<<"---------j_v(x)-------------"<(v, z, P); + + std::cout<