├── .gitignore ├── ZZSARAP ├── common.h ├── Geometry2D.h ├── ZZSARAP.vcxproj.filters ├── ArapDeform.h ├── Geometry2D.cpp ├── main.cpp ├── ZZSARAP.vcxproj ├── ArapDeform.cpp └── triangle.h ├── README.md └── ZZSARAP.sln /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | *.sdf 3 | *.opensdf 4 | */Debug/* 5 | */Release/* 6 | *.tlog 7 | *.idb 8 | */Test/* 9 | */x64/* -------------------------------------------------------------------------------- /ZZSARAP/common.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_H_ 2 | #define COMMON_H_ 3 | #include 4 | 5 | using Eigen::Vector2i; 6 | using Eigen::Vector2d; 7 | using Eigen::Vector2f; 8 | 9 | extern "C" 10 | { 11 | #include "triangle.h" 12 | } 13 | 14 | #ifdef ANSI_DECLARATORS 15 | extern "C" void triangulate(char *, struct triangulateio *, struct triangulateio *, 16 | struct triangulateio *); 17 | extern "C" void trifree(VOIDD *memptr); 18 | #else /* not ANSI_DECLARATORS */ 19 | void triangulate(); 20 | void trifree(); 21 | #endif /* not ANSI_DECLARATORS */ 22 | 23 | typedef Vector2i v2i; 24 | typedef Vector2d v2d; 25 | typedef Vector2f v2f; 26 | 27 | #endif -------------------------------------------------------------------------------- /ZZSARAP/Geometry2D.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "common.h" 3 | #include "ArapDeform.h" 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | using namespace zzs; 9 | 10 | class Geometry2D 11 | { 12 | public: 13 | Geometry2D(void); 14 | ~Geometry2D(void); 15 | 16 | /* 2D triangle mesh 17 | triangulateio is the basic structure of Triangle. The tasks are: 18 | 1. what's the form of your input? 19 | 2. change your input to get its corresponding triangulateio 20 | 3. what's the form of your output? 21 | 4. get your output from triangulateio 22 | */ 23 | static void InitTriangulateio (triangulateio ** pptio); 24 | static void FreeTriangulateio (triangulateio ** pptio, bool in = false); 25 | 26 | static triangulateio * InputToTriangulateio (const std::vector & input_points, const std::vector & input_segments); 27 | static triangulateio * ComputeMeshByTriangle (triangulateio * tio); 28 | static void TriangulateioToOutput (triangulateio * tio, vector & vertices, vector& triangles); 29 | }; 30 | 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a direct implementation of Igarashi's Siggraph 05 paper[1]. Just to understand how to calculate Eq(5)-(8), so I just implement the first step of the algorithm, i.e., I just do the scale free construction. There are some derivations on how to express the matrix G in Eq(5) in my source code. 2 | 3 | The libraries I used in this code include: (1) Jonathan Richard Shewchuk's Triangle[3], the code is contained in my source code; (2) Freeglut library [4]; and (3) Eigen [5]. If you want to use this code, please download these library accordingly. 4 | 5 | Operations: 6 | Left click - add mesh vertices 7 | 8 | "A" or "a" - build mesh 9 | 10 | Right click - add control points 11 | 12 | Left drag - mesh deformation 13 | 14 | "C" or "c" - clear the mesh 15 | 16 | "V" or "v" - clear the control points 17 | 18 | If you want to know how to implement the whole paper, please refer to Ryan Schmidt's implementation [2]. 19 | 20 | Reference 21 | 22 | [1] Takeo Igarashi, Tomer Moscovich, John F. Hughes, "As-Rigid-As-Possible Shape Manipulation", ACM Transactions on Computer Graphics, Vol.24, No.3, ACM SIGGRAPH 2005, Los Angels, USA, 2005. 23 | 24 | [2] http://www.dgp.toronto.edu/~rms/software/Deform2D/ 25 | 26 | [3] https://www.cs.cmu.edu/~quake/triangle.html 27 | 28 | [4] http://freeglut.sourceforge.net/ 29 | 30 | [5] http://eigen.tuxfamily.org/ 31 | -------------------------------------------------------------------------------- /ZZSARAP/ZZSARAP.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | 32 | 33 | Header Files 34 | 35 | 36 | Header Files 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | -------------------------------------------------------------------------------- /ZZSARAP/ArapDeform.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | #include "common.h" 7 | 8 | using namespace Eigen; 9 | typedef Eigen::Vector2f Point; 10 | 11 | namespace zzs { 12 | struct Vertex 13 | { 14 | v2f vPosition; 15 | Vertex(){vPosition << 0,0;} 16 | 17 | Vertex(float x, float y) 18 | { 19 | vPosition << x,y; 20 | } 21 | 22 | }; 23 | 24 | struct Triangle 25 | { 26 | size_t nVertices[3]; 27 | 28 | // definition of each vertex in triangle-local coordinate system 29 | v2f vTriCoords[3]; 30 | }; 31 | 32 | struct Constraint 33 | { 34 | size_t nVertex; // point index 35 | v2f vConstrainedPos; // the current position of the constraint point 36 | 37 | Constraint(){nVertex = 0; vConstrainedPos = Eigen::Vector2f::Zero();} 38 | Constraint(size_t nVert, const v2f &vPos) 39 | { 40 | nVertex = nVert; 41 | vConstrainedPos = vPos; 42 | } 43 | 44 | bool operator <(const Constraint& c2) const 45 | { 46 | return nVertex < c2.nVertex; 47 | } 48 | }; 49 | 50 | class ArapDeform 51 | { 52 | public: 53 | ArapDeform(void); 54 | ~ArapDeform(void); 55 | 56 | // add point to build mesh 57 | void setAddPoint(); 58 | void addPoint(Vertex &); 59 | 60 | // use the newly add point to build mesh 61 | // precompute the triangle local coordinate 62 | void buildMesh(); 63 | 64 | void clearData(); 65 | const std::vector & getVerts() const; 66 | const std::vector & getDeformedVerts() const; 67 | const std::vector & getTriangles() const; 68 | 69 | size_t findHitVertex(float x, float y); 70 | void setVertex(size_t index, Point position); 71 | 72 | // Precompute Gprime and B 73 | void updateConstraints(const std::set& selected); 74 | void updateMesh(bool isRigid); 75 | 76 | bool isAddPoint() const; 77 | 78 | private: 79 | // initial input 80 | std::vector m_vInitialVertices; 81 | std::vector m_vTriangles; 82 | 83 | // output 84 | std::vector m_vDeformedVertices; 85 | 86 | // control points 87 | std::set m_vConstraints; 88 | 89 | bool bAddPt; 90 | int nBoundaryPoints; 91 | 92 | // these three matrix should be precompute according to Eq(6)-(8) 93 | MatrixXd m_G; 94 | MatrixXd m_Gprime; 95 | MatrixXd m_B; 96 | 97 | // m_FirstMatrix = -G'.inverse() * B 98 | MatrixXd m_FirstMatrix; 99 | 100 | std::vector m_vVertexMap; 101 | }; 102 | } -------------------------------------------------------------------------------- /ZZSARAP.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZZSARAP", "ZZSARAP\ZZSARAP.vcxproj", "{9AFE06C2-A380-4201-A5D3-2FE66C61E8B1}" 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test", "Test\Test.vcxproj", "{6C43244F-1C13-436A-9AB1-FDB4CD5AA48F}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Mixed Platforms = Debug|Mixed Platforms 11 | Debug|Win32 = Debug|Win32 12 | Debug|x64 = Debug|x64 13 | Release|Mixed Platforms = Release|Mixed Platforms 14 | Release|Win32 = Release|Win32 15 | Release|x64 = Release|x64 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {9AFE06C2-A380-4201-A5D3-2FE66C61E8B1}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 19 | {9AFE06C2-A380-4201-A5D3-2FE66C61E8B1}.Debug|Mixed Platforms.Build.0 = Debug|Win32 20 | {9AFE06C2-A380-4201-A5D3-2FE66C61E8B1}.Debug|Win32.ActiveCfg = Debug|Win32 21 | {9AFE06C2-A380-4201-A5D3-2FE66C61E8B1}.Debug|Win32.Build.0 = Debug|Win32 22 | {9AFE06C2-A380-4201-A5D3-2FE66C61E8B1}.Debug|x64.ActiveCfg = Debug|x64 23 | {9AFE06C2-A380-4201-A5D3-2FE66C61E8B1}.Debug|x64.Build.0 = Debug|x64 24 | {9AFE06C2-A380-4201-A5D3-2FE66C61E8B1}.Release|Mixed Platforms.ActiveCfg = Release|Win32 25 | {9AFE06C2-A380-4201-A5D3-2FE66C61E8B1}.Release|Mixed Platforms.Build.0 = Release|Win32 26 | {9AFE06C2-A380-4201-A5D3-2FE66C61E8B1}.Release|Win32.ActiveCfg = Release|Win32 27 | {9AFE06C2-A380-4201-A5D3-2FE66C61E8B1}.Release|Win32.Build.0 = Release|Win32 28 | {9AFE06C2-A380-4201-A5D3-2FE66C61E8B1}.Release|x64.ActiveCfg = Release|x64 29 | {9AFE06C2-A380-4201-A5D3-2FE66C61E8B1}.Release|x64.Build.0 = Release|x64 30 | {6C43244F-1C13-436A-9AB1-FDB4CD5AA48F}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 31 | {6C43244F-1C13-436A-9AB1-FDB4CD5AA48F}.Debug|Mixed Platforms.Build.0 = Debug|Win32 32 | {6C43244F-1C13-436A-9AB1-FDB4CD5AA48F}.Debug|Win32.ActiveCfg = Debug|Win32 33 | {6C43244F-1C13-436A-9AB1-FDB4CD5AA48F}.Debug|Win32.Build.0 = Debug|Win32 34 | {6C43244F-1C13-436A-9AB1-FDB4CD5AA48F}.Debug|x64.ActiveCfg = Debug|Win32 35 | {6C43244F-1C13-436A-9AB1-FDB4CD5AA48F}.Release|Mixed Platforms.ActiveCfg = Release|Win32 36 | {6C43244F-1C13-436A-9AB1-FDB4CD5AA48F}.Release|Mixed Platforms.Build.0 = Release|Win32 37 | {6C43244F-1C13-436A-9AB1-FDB4CD5AA48F}.Release|Win32.ActiveCfg = Release|Win32 38 | {6C43244F-1C13-436A-9AB1-FDB4CD5AA48F}.Release|Win32.Build.0 = Release|Win32 39 | {6C43244F-1C13-436A-9AB1-FDB4CD5AA48F}.Release|x64.ActiveCfg = Release|Win32 40 | EndGlobalSection 41 | GlobalSection(SolutionProperties) = preSolution 42 | HideSolutionNode = FALSE 43 | EndGlobalSection 44 | EndGlobal 45 | -------------------------------------------------------------------------------- /ZZSARAP/Geometry2D.cpp: -------------------------------------------------------------------------------- 1 | #include "Geometry2D.h" 2 | #include 3 | 4 | Geometry2D::Geometry2D(void) 5 | { 6 | } 7 | 8 | 9 | Geometry2D::~Geometry2D(void) 10 | { 11 | } 12 | 13 | void Geometry2D::InitTriangulateio(triangulateio ** pptio) 14 | { 15 | (*pptio) = (triangulateio*)malloc(sizeof(triangulateio)); 16 | 17 | struct triangulateio * tio = (*pptio); 18 | 19 | tio->pointlist = 0; 20 | tio->pointattributelist = 0; 21 | tio->pointmarkerlist = 0; 22 | tio->numberofpoints = 0; 23 | tio->numberofpointattributes = 0; 24 | 25 | tio->trianglelist = 0; 26 | tio->triangleattributelist = 0; 27 | tio->trianglearealist = 0; 28 | tio->neighborlist = 0; 29 | tio->numberoftriangles = 0; 30 | tio->numberofcorners = 0; 31 | tio->numberoftriangleattributes = 0; 32 | 33 | tio->segmentlist = 0; 34 | tio->segmentmarkerlist = 0; 35 | tio->numberofsegments = 0; 36 | 37 | tio->holelist = 0; 38 | tio->numberofholes = 0; 39 | 40 | tio->regionlist = 0; 41 | tio->numberofregions = 0; 42 | 43 | tio->edgelist = 0; 44 | tio->edgemarkerlist = 0; 45 | tio->normlist = 0; 46 | tio->numberofedges = 0; 47 | } 48 | 49 | void Geometry2D::FreeTriangulateio(triangulateio ** pptio, bool in) 50 | { 51 | struct triangulateio * tio = (*pptio); 52 | if(tio->pointlist != 0) free(tio->pointlist); 53 | if(tio->pointattributelist != 0) free(tio->pointattributelist); 54 | if(tio->pointmarkerlist != 0) free(tio->pointmarkerlist); 55 | 56 | if(tio->trianglelist != 0) free(tio->trianglelist); 57 | if(tio->triangleattributelist != 0) free(tio->triangleattributelist); 58 | if(tio->trianglearealist != 0) free(tio->trianglearealist); 59 | if(tio->neighborlist != 0) free(tio->neighborlist); 60 | 61 | if(tio->segmentlist != 0) free(tio->segmentlist); 62 | if(tio->segmentmarkerlist != 0) free(tio->segmentmarkerlist); 63 | 64 | if(in) // only allocalte mem for "in" triangulateio 65 | if(tio->holelist != 0) 66 | free(tio->holelist); 67 | 68 | if(in) // only allocalte mem for "in" triangulateio 69 | if(tio->regionlist != 0) 70 | free(tio->regionlist); 71 | 72 | if(tio->edgelist != 0) free(tio->edgelist); 73 | if(tio->edgemarkerlist != 0) free(tio->edgemarkerlist); 74 | if(tio->normlist != 0) free(tio->normlist); 75 | 76 | free(*pptio); 77 | (*pptio) = 0; 78 | } 79 | 80 | triangulateio * Geometry2D::InputToTriangulateio(const std::vector & input_points, const std::vector & input_segments) 81 | { 82 | struct triangulateio * ans; 83 | Geometry2D::InitTriangulateio(&ans); 84 | 85 | ans->numberofpoints = (int)(input_points.size()); 86 | 87 | if(ans->numberofpoints == 0) return ans; 88 | 89 | ans->pointlist = (REAL *) malloc(ans->numberofpoints * 2 * sizeof(REAL)); 90 | 91 | for(int i = 0;inumberofpoints;i++) 92 | { 93 | ans->pointlist[i*2] = input_points[i][0]; 94 | ans->pointlist[i*2+1]= input_points[i][1]; 95 | } 96 | 97 | ans->numberofsegments = (int)(input_segments.size()); 98 | 99 | if (ans->numberofsegments > 0) 100 | { 101 | ans->segmentlist = (int *)malloc(ans->numberofsegments * 2 * sizeof(int)); 102 | 103 | for(int i = 0;inumberofsegments;i++) 104 | { 105 | ans->segmentlist[i*2] = input_segments[i][0]; 106 | ans->segmentlist[i*2+1] = input_segments[i][1]; 107 | } 108 | } 109 | 110 | 111 | return ans; 112 | } 113 | 114 | triangulateio* Geometry2D::ComputeMeshByTriangle(triangulateio * tio) 115 | { 116 | struct triangulateio * ans, * vorout; 117 | Geometry2D::InitTriangulateio(&ans); 118 | Geometry2D::InitTriangulateio(&vorout); 119 | 120 | //triangulate("zpqa500Q",tio,ans,vorout); 121 | triangulate("zpcQY",tio,ans,vorout); 122 | 123 | Geometry2D::FreeTriangulateio(&vorout); 124 | 125 | return ans; 126 | } 127 | 128 | void Geometry2D::TriangulateioToOutput(triangulateio * tio, vector & vertices, vector& triangles) 129 | { 130 | for(int i = 0;inumberofpoints;i++) 131 | { 132 | Vertex v(tio->pointlist[i*2], tio->pointlist[i*2+1]); 133 | vertices.push_back(v); 134 | } 135 | 136 | for(int i = 0;inumberoftriangles;i++) 137 | { 138 | unsigned int tri[3] = { tio->trianglelist[i * 3] , tio->trianglelist[i * 3 + 1], tio->trianglelist[i * 3 + 2] }; 139 | Triangle t; 140 | for (int j = 0; j < 3; j++) 141 | { 142 | t.nVertices[j] = tri[j]; 143 | } 144 | triangles.push_back(t); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /ZZSARAP/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "ArapDeform.h" 7 | #include "common.h" 8 | 9 | using namespace std; 10 | using namespace zzs; 11 | 12 | using Eigen::MatrixXd; 13 | 14 | int winID; 15 | int winWidth = 800; 16 | int winHeight = 600; 17 | 18 | set m_Selected; 19 | size_t m_nSelected = std::numeric_limits::max(); 20 | 21 | ArapDeform m_deform; 22 | 23 | void display(void) 24 | { 25 | glClear(GL_COLOR_BUFFER_BIT); 26 | glViewport (0, 0, (GLsizei) winWidth, (GLsizei) winHeight); 27 | glMatrixMode(GL_PROJECTION); 28 | glLoadIdentity(); 29 | gluOrtho2D(0, winWidth, winHeight, 0); 30 | 31 | glMatrixMode(GL_MODELVIEW); 32 | glLoadIdentity(); 33 | 34 | glPushMatrix(); 35 | 36 | glPointSize(5.0f); 37 | 38 | const std::vector& verts = m_deform.getDeformedVerts(); 39 | const size_t np = verts.size(); 40 | 41 | if (m_deform.isAddPoint()) 42 | { 43 | glColor3f(0.0, 1.0, 0.0); 44 | glBegin(GL_POINTS); 45 | 46 | for (int i = 0; i < np; i++) 47 | { 48 | glVertex2f(verts[i].vPosition[0], verts[i].vPosition[1]); 49 | } 50 | glEnd(); 51 | }else 52 | { 53 | glColor3f(0.0, 0.0, 1.0); 54 | glBegin(GL_POINTS); 55 | 56 | for (int i = 0; i < np; i++) 57 | { 58 | glVertex2f(verts[i].vPosition[0], verts[i].vPosition[1]); 59 | } 60 | glEnd(); 61 | 62 | // todo: draw triangles 63 | const std::vector& vTriangles = m_deform.getTriangles(); 64 | const size_t nt = vTriangles.size(); 65 | 66 | glBegin(GL_LINES); 67 | for (int i = 0; i < nt; i++) 68 | { 69 | const size_t * tri = vTriangles[i].nVertices; 70 | 71 | glVertex2f(verts[tri[0]].vPosition[0], verts[tri[0]].vPosition[1]); 72 | glVertex2f(verts[tri[1]].vPosition[0], verts[tri[1]].vPosition[1]); 73 | 74 | glVertex2f(verts[tri[1]].vPosition[0], verts[tri[1]].vPosition[1]); 75 | glVertex2f(verts[tri[2]].vPosition[0], verts[tri[2]].vPosition[1]); 76 | 77 | glVertex2f(verts[tri[2]].vPosition[0], verts[tri[2]].vPosition[1]); 78 | glVertex2f(verts[tri[0]].vPosition[0], verts[tri[0]].vPosition[1]); 79 | } 80 | glEnd(); 81 | } 82 | 83 | // draw controllers 84 | glColor3f(1.0, 0.0, 0.0); 85 | std::set::iterator cur(m_Selected.begin()), end(m_Selected.end()); 86 | glBegin(GL_POINTS); 87 | 88 | while ( cur != end ) { 89 | size_t nSelected = *cur++; 90 | glVertex2f(verts[nSelected].vPosition[0], verts[nSelected].vPosition[1]); 91 | } 92 | glEnd(); 93 | 94 | //glFlush(); 95 | glPopMatrix(); 96 | 97 | glutSwapBuffers(); 98 | } 99 | 100 | void keyboardCommon(unsigned char key, int x, int y){ 101 | 102 | if (key == 27) 103 | { 104 | glutDestroyWindow(winID); 105 | } 106 | if ((key == 'A')||(key == 'a')) 107 | { 108 | m_deform.setAddPoint(); 109 | if (!m_deform.isAddPoint()) 110 | { 111 | m_deform.buildMesh(); 112 | } 113 | } 114 | 115 | if ((key == 'C')||(key == 'c')) 116 | { 117 | cout << "Clear every thing!" << endl; 118 | 119 | m_nSelected = std::numeric_limits::max(); 120 | m_Selected.clear(); 121 | m_deform.clearData(); 122 | } 123 | 124 | if ((key == 'v')||(key == 'V')) 125 | { 126 | cout << "Clear constraints!" << endl; 127 | m_Selected.clear(); 128 | m_nSelected = std::numeric_limits::max(); 129 | } 130 | 131 | glutPostRedisplay(); 132 | } 133 | 134 | 135 | void spinDisplay(void) 136 | { 137 | glutPostRedisplay(); 138 | } 139 | 140 | void init(void) 141 | { 142 | glClearColor (1.0, 1.0, 1.0, 0.0); 143 | glShadeModel (GL_FLAT); 144 | } 145 | 146 | void reshape(int w, int h) 147 | { 148 | winWidth = w; 149 | winHeight = h; 150 | } 151 | 152 | void mouse(int button, int state, int x, int y) 153 | { 154 | switch (button) { 155 | case GLUT_LEFT_BUTTON: 156 | if (state == GLUT_DOWN) 157 | { 158 | //glutIdleFunc(spinDisplay); 159 | cout << "Current mouse position: " << x << " " <::max(); 170 | m_deform.updateConstraints(m_Selected); 171 | }else 172 | { 173 | m_nSelected = m_deform.findHitVertex((float)x, (float)y); 174 | if(m_Selected.find(m_nSelected) == m_Selected.end()) 175 | m_nSelected = std::numeric_limits::max(); 176 | } 177 | }else 178 | { 179 | m_nSelected = std::numeric_limits::max(); 180 | } 181 | 182 | break; 183 | case GLUT_MIDDLE_BUTTON: 184 | case GLUT_RIGHT_BUTTON: 185 | if (state == GLUT_DOWN) 186 | { 187 | cout << "Add control point at point: " << x << " " << y << endl; 188 | size_t nHit = m_deform.findHitVertex((float)x, (float)y); 189 | if (nHit < std::numeric_limits::max()) 190 | { 191 | cout << "Find the vertex" << endl; 192 | if(m_Selected.find(nHit) == m_Selected.end()) 193 | m_Selected.insert(nHit); 194 | else 195 | { 196 | m_Selected.erase(nHit); 197 | } 198 | // once modified the constraints, we should update them 199 | // i.e., precompute Gprime and B 200 | m_deform.updateConstraints(m_Selected); 201 | } 202 | else 203 | { 204 | cout << "Doesn't find the vertex" << endl; 205 | } 206 | 207 | } 208 | 209 | break; 210 | default: 211 | break; 212 | } 213 | 214 | glutPostRedisplay(); 215 | } 216 | 217 | 218 | void OnMouseMove(int x, int y) 219 | { 220 | if ( m_nSelected != std::numeric_limits::max() ) { 221 | Point newPos(x, y); 222 | m_deform.setVertex(m_nSelected, newPos); 223 | m_deform.updateMesh(false); 224 | glutPostRedisplay(); 225 | } 226 | } 227 | 228 | void main(int argc, char** argv) 229 | { 230 | glutInit(&argc, argv); 231 | glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB); 232 | glutInitWindowSize (winWidth, winHeight); 233 | glutInitWindowPosition (100, 100); 234 | winID = glutCreateWindow ("Test OpenGL"); 235 | init (); 236 | glutDisplayFunc(display); 237 | glutReshapeFunc(reshape); 238 | glutKeyboardFunc(keyboardCommon); 239 | glutMotionFunc( OnMouseMove ); 240 | glutMouseFunc(mouse); 241 | glutMainLoop(); 242 | } -------------------------------------------------------------------------------- /ZZSARAP/ZZSARAP.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | {9AFE06C2-A380-4201-A5D3-2FE66C61E8B1} 35 | ZZSARAP 36 | 37 | 38 | 39 | Application 40 | true 41 | v110 42 | MultiByte 43 | 44 | 45 | Application 46 | true 47 | v110 48 | MultiByte 49 | 50 | 51 | Application 52 | false 53 | v110 54 | true 55 | MultiByte 56 | 57 | 58 | Application 59 | false 60 | v110 61 | true 62 | MultiByte 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | D:\Libs\freeglut-2.8.1\include;$(IncludePath) 82 | D:\Libs\freeglut-2.8.1\lib\x64\Debug;$(LibraryPath) 83 | 84 | 85 | D:\Libs\freeglut-2.8.1\include;D:\Libs\eigen-eigen-10219c95fe65;$(IncludePath) 86 | D:\Libs\freeglut-2.8.1\lib\x64\Debug;$(LibraryPath) 87 | 88 | 89 | 90 | Level3 91 | Disabled 92 | true 93 | 94 | 95 | true 96 | 97 | 98 | 99 | 100 | Level3 101 | Disabled 102 | true 103 | 104 | 105 | true 106 | 107 | 108 | 109 | 110 | Level3 111 | MaxSpeed 112 | true 113 | true 114 | true 115 | 116 | 117 | true 118 | true 119 | true 120 | 121 | 122 | 123 | 124 | Level3 125 | MaxSpeed 126 | true 127 | true 128 | true 129 | 130 | 131 | true 132 | true 133 | true 134 | 135 | 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /ZZSARAP/ArapDeform.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "ArapDeform.h" 4 | #include "Geometry2D.h" 5 | #include "triangle.h" 6 | #include "common.h" 7 | 8 | using namespace zzs; 9 | using namespace std; 10 | 11 | ArapDeform::ArapDeform(void) 12 | { 13 | // initial input 14 | clearData(); 15 | nBoundaryPoints = 10; 16 | } 17 | 18 | 19 | ArapDeform::~ArapDeform(void) 20 | { 21 | } 22 | 23 | void ArapDeform::setAddPoint() 24 | { 25 | bAddPt = !bAddPt; 26 | } 27 | 28 | bool ArapDeform::isAddPoint() const 29 | { 30 | return bAddPt; 31 | } 32 | 33 | void ArapDeform::buildMesh() 34 | { 35 | if(m_vInitialVertices.size() < 3) 36 | { 37 | cout << "Not enough points for triangle, please add more points!"<< endl; 38 | return; 39 | } 40 | 41 | vector vPoints; 42 | vPoints.clear(); 43 | 44 | for (int i = 0; i < m_vInitialVertices.size(); i++) 45 | { 46 | vPoints.push_back(v2d(m_vInitialVertices[i].vPosition[0], m_vInitialVertices[i].vPosition[1])); 47 | } 48 | 49 | std::vector segments; 50 | segments.clear(); 51 | triangulateio *in = Geometry2D::InputToTriangulateio(vPoints, segments); 52 | triangulateio *out= Geometry2D::ComputeMeshByTriangle(in); 53 | 54 | vector vertices; 55 | vertices.clear(); 56 | m_vTriangles.clear(); 57 | 58 | Geometry2D::TriangulateioToOutput(out, vertices, m_vTriangles); 59 | //cout << "Compare initial vertices and final vertices" << endl; 60 | //cout << vertices.size() << " " << m_vInitialVertices.size() << endl; 61 | // 62 | //for (int i = 0; i < vertices.size(); i++) 63 | //{ 64 | // cout << vertices[i].vPosition.transpose() << " <=> " << m_vInitialVertices[i].vPosition.transpose() << endl; 65 | //} 66 | 67 | // let's setup triangle-local coordinate systems 68 | size_t nTriangle = m_vTriangles.size(); 69 | for (size_t i = 0; i < nTriangle; i++) 70 | { 71 | Triangle &t = m_vTriangles[i]; 72 | for (size_t j = 0; j < 3; j++) 73 | { 74 | size_t n0 = j; 75 | size_t n1 = (j + 1) % 3; 76 | size_t n2 = (j + 2) % 3; 77 | 78 | v2f v0 = m_vInitialVertices[t.nVertices[n0]].vPosition; 79 | v2f v1 = m_vInitialVertices[t.nVertices[n1]].vPosition; 80 | v2f v2 = m_vInitialVertices[t.nVertices[n2]].vPosition; 81 | 82 | // find coordinate system 83 | v2f v01(v1 - v0); 84 | v2f v01N(v01); 85 | v01N.normalize(); 86 | v2f v01Rot90(v01.y(), -v01.x()); 87 | v2f v01Rot90N(v01Rot90); 88 | v01Rot90N.normalize(); 89 | 90 | // express v2 in coordinate system 91 | v2f vLocal(v2 - v0); 92 | float fX = vLocal.dot(v01) / v01.squaredNorm(); 93 | float fY = vLocal.dot(v01Rot90) / v01Rot90.squaredNorm(); 94 | #if 0 95 | // check v2 is right or not 96 | v2f v2test(v0 + fX * v01 + fY * v01Rot90); 97 | float fLength = (v2test - v2).norm(); 98 | 99 | cout << "compare v2: " << fLength << endl; 100 | #endif 101 | t.vTriCoords[j] = v2f(fX, fY); 102 | 103 | } 104 | } 105 | 106 | 107 | Geometry2D::FreeTriangulateio(&in); 108 | Geometry2D::FreeTriangulateio(&out); 109 | } 110 | 111 | void ArapDeform::clearData() 112 | { 113 | // initial input 114 | m_vInitialVertices.clear(); 115 | m_vTriangles.clear(); 116 | 117 | // output 118 | m_vDeformedVertices.clear(); 119 | 120 | // control points 121 | m_vConstraints.clear(); 122 | 123 | bAddPt = true; 124 | } 125 | 126 | void ArapDeform::addPoint(Vertex &v) 127 | { 128 | m_vInitialVertices.push_back(v); 129 | m_vDeformedVertices.push_back(v); 130 | } 131 | 132 | const std::vector & ArapDeform::getVerts() const 133 | { 134 | return m_vInitialVertices; 135 | } 136 | 137 | const std::vector & ArapDeform::getTriangles() const 138 | { 139 | return m_vTriangles; 140 | } 141 | 142 | const std::vector & ArapDeform::getDeformedVerts() const 143 | { 144 | return m_vDeformedVertices; 145 | } 146 | 147 | size_t ArapDeform::findHitVertex(float x, float y) 148 | { 149 | size_t nVerts = m_vDeformedVertices.size(); 150 | float fx, fy; 151 | 152 | for (size_t i = 0; i < nVerts; i++) 153 | { 154 | fx = m_vDeformedVertices[i].vPosition[0]; 155 | fy = m_vDeformedVertices[i].vPosition[1]; 156 | double disSquare = (x - fx) * (x - fx) + (y - fy) * (y - fy); 157 | if (disSquare < 25) 158 | { 159 | return i; 160 | } 161 | } 162 | 163 | return std::numeric_limits::max(); 164 | } 165 | 166 | void ArapDeform::setVertex(size_t index, Point position) 167 | { 168 | m_vDeformedVertices[index].vPosition = position; 169 | 170 | 171 | 172 | } 173 | 174 | void ExtractSubMatrix( MatrixXd & mFrom, int nRowOffset, int nColOffset, MatrixXd & mTo ) 175 | { 176 | int nRows = mTo.rows(); 177 | int nCols = mTo.cols(); 178 | 179 | for ( int i = 0; i < nRows; ++i ) { 180 | for ( int j = 0; j < nCols; ++j ) { 181 | mTo(i,j) = mFrom( i + nRowOffset, j + nColOffset ); 182 | } 183 | } 184 | } 185 | 186 | 187 | // In this function, we are going to calculate the Gprime and B of Eq(8) 188 | void ArapDeform::updateConstraints(const std::set& selected) 189 | { 190 | std::set::iterator cur(selected.begin()), end(selected.end()); 191 | size_t nSelected; 192 | m_vConstraints.clear(); 193 | 194 | while (cur != end) 195 | { 196 | nSelected = *cur++; 197 | Constraint c(nSelected, m_vInitialVertices[nSelected].vPosition); 198 | m_vConstraints.insert(c); 199 | } 200 | 201 | cout << "Finished update constraints! --> " << m_vConstraints.size() << endl; 202 | size_t nDeformedVerts = m_vDeformedVertices.size(); 203 | size_t nInitialVerts = m_vInitialVertices.size(); 204 | 205 | for (size_t i = 0; i < nDeformedVerts; i++) 206 | { 207 | if (selected.find(i) == end) 208 | { 209 | m_vDeformedVertices[i].vPosition = m_vInitialVertices[i].vPosition; 210 | } 211 | } 212 | 213 | 214 | cout << "No. of deformed vertices and intial vertices: " << nDeformedVerts << " " << nInitialVerts << endl; 215 | 216 | // resize matrix G and clear to zero 217 | size_t nGsize = 2 * nInitialVerts; 218 | m_G.resize(nGsize, nGsize); 219 | 220 | for (size_t i = 0; i < nGsize; i++) 221 | { 222 | for (size_t j = 0; j < nGsize; j++) 223 | { 224 | m_G(i,j) = 0; 225 | } 226 | } 227 | 228 | size_t nConstraints = m_vConstraints.size(); 229 | size_t nFreeVerts = nInitialVerts - nConstraints; 230 | 231 | // m_vVertexMap is used to reorder the v', the free vertices are put in the front 232 | // and the control vertices are put in the back 233 | m_vVertexMap.resize(nInitialVerts); 234 | size_t nRow = 0; 235 | for (size_t i = 0; i < nInitialVerts; i++) 236 | { 237 | Constraint c(i, v2f::Zero()); 238 | if (m_vConstraints.find(c) != m_vConstraints.end()) 239 | { 240 | continue; 241 | } 242 | m_vVertexMap[i] = nRow++; 243 | } 244 | 245 | if (nRow != nFreeVerts) 246 | { 247 | cerr << "Free vertices number doesn't match." << endl; 248 | } 249 | 250 | std::set::iterator cur1(m_vConstraints.begin()), end1(m_vConstraints.end()); 251 | while (cur1 != end1) 252 | { 253 | const Constraint &c = (*cur1); 254 | m_vVertexMap[c.nVertex] = nRow++; 255 | cur1++; 256 | } 257 | 258 | if (nRow != nInitialVerts) 259 | { 260 | cerr << "Total vertices number doesn't match." << endl; 261 | } 262 | 263 | // Now, let's fill in the matrix G 264 | // let's explain a little logic here 265 | // according to Eq(1), let the coordinate of v0, v1 and v2 be (v0x, v0y), (v1x, v1y) and (v2x, v2y), respectively 266 | // so Eq(1) can be rewrited as 267 | // (v2x, v2y) = (v0x, v0y) + x * (v1x - v0x, v1y - v0y) + y * (v1y - v0y, v0x - v1x) 268 | // thus Eq(3) can be rewrited as 269 | // E = ||((1 - x) * v0x - y * v0y + x * v1x + y * v1y - v2x, y * v0x + (1 - x) * v0y - y * v1x + x * v1y - v2y)||^2 270 | // = v' * G * v 271 | // = (v0x, v0y, v1x, v1y, v2x, v2y)' * G * (v0x, v0y, v1x, v1y, v2x, v2y) 272 | // where G = A' * A, and 273 | // A = [1 - x, -y, x, y, -1, 0; 274 | // y, 1 - x, -y, x, 0, -1] 275 | // So G = 276 | //[ (x - 1)*(x - 1) + y*y, 0, - x*(x - 1) - y*y, y, x - 1, -y; 277 | // 0, (x - 1)*(x - 1) + y*y, -y, - x*(x - 1) - y*y, y, x - 1; 278 | // - x*(x - 1) - y*y, -y, x*x + y*y, y*x - x*y, -x, y; 279 | // y, - x*(x - 1) - y*y, x*y - y*x, x*x + y*y, -y, -x; 280 | // x - 1, y, -x, -y, 1, 0; 281 | // -y, x - 1, y, -x, 0, 1] 282 | // and E = v' * G * v 283 | // = v' * Gtri * v, 284 | // where Gtri = 285 | //[ (x - 1)*(x - 1) + y*y, 0, -2x*(x - 1) - 2y*y, 2y, 2x - 2, -2y; 286 | // 0, (x - 1)*(x - 1) + y*y, -2y, -2x*(x - 1) - 2y*y, 2y, 2x - 2; 287 | // 0, 0, x*x + y*y, 0, -2x, 2y; 288 | // 0, 0, 0, x*x + y*y, -2y, -2x; 289 | // 0, 0, 0, 0, 1, 0; 290 | // 0, 0, 0, 0, 0, 1] 291 | 292 | 293 | const size_t nTriangles = m_vTriangles.size(); 294 | for (size_t i = 0; i < nTriangles; i++) 295 | { 296 | Triangle & t = m_vTriangles[i]; 297 | for (int j= 0; j < 3; j++) 298 | { 299 | int n0x = 2 * m_vVertexMap[ t.nVertices[j] ]; 300 | int n0y = n0x + 1; 301 | int n1x = 2 * m_vVertexMap[ t.nVertices[(j+1)%3] ]; 302 | int n1y = n1x + 1; 303 | int n2x = 2 * m_vVertexMap[ t.nVertices[(j+2)%3] ]; 304 | int n2y = n2x + 1; 305 | float x = t.vTriCoords[j].x(); 306 | float y = t.vTriCoords[j].y(); 307 | 308 | // n0x,n?? elems, the first line of matrix Gtri as explained earlier 309 | m_G(n0x, n0x) += 1 - 2*x + x*x + y*y; 310 | m_G(n0x, n1x) += 2*x - 2*x*x - 2*y*y; 311 | m_G(n0x, n1y) += 2*y; 312 | m_G(n0x, n2x) += -2 + 2*x; 313 | m_G(n0x, n2y) += -2 * y; 314 | 315 | // n0y,n?? elems, the second line of matrix Gtri 316 | m_G(n0y, n0y) += 1 - 2*x + x*x + y*y; 317 | m_G(n0y, n1x) += -2*y; 318 | m_G(n0y, n1y) += 2*x - 2*x*x - 2*y*y; 319 | m_G(n0y, n2x) += 2*y; 320 | m_G(n0y, n2y) += -2 + 2*x; 321 | 322 | // n1x,n?? elems, the third line of matrix Gtri 323 | m_G(n1x, n1x) += x*x + y*y; 324 | m_G(n1x, n2x) += -2*x; 325 | m_G(n1x, n2y) += 2*y; 326 | 327 | // n1y,n?? elems, the fourth line of matrix Gtri 328 | m_G(n1y, n1y) += x*x + y*y; 329 | m_G(n1y, n2x) += -2*y; 330 | m_G(n1y, n2y) += -2*x; 331 | 332 | // final 2 elems, the fifth and sixth line of Gtri 333 | m_G(n2x, n2x) += 1; 334 | m_G(n2y, n2y) += 1; 335 | } 336 | } 337 | 338 | //cout << "G's size is " << m_G.rows() << " * "<::iterator cur(m_vConstraints.begin()), end(m_vConstraints.end()); 369 | while ( cur != end ) { 370 | const Constraint & c = *cur++; 371 | //vQ[ 2*k ] = c.vConstrainedPos.x(); 372 | //vQ[ 2*k + 1] = c.vConstrainedPos.y(); 373 | vQ[2 * k] = m_vDeformedVertices[c.nVertex].vPosition.x(); 374 | vQ[2 * k + 1] = m_vDeformedVertices[c.nVertex].vPosition.y(); 375 | ++k; 376 | } 377 | 378 | Eigen::VectorXd vU = m_FirstMatrix * vQ; 379 | const size_t nVerts = m_vDeformedVertices.size(); 380 | 381 | //cout << "=================================" << endl; 382 | //cout << "update new positions" << endl; 383 | for (size_t i = 0; i < nVerts; i++) 384 | { 385 | Constraint c(i, v2f::Zero()); 386 | if (m_vConstraints.find(c) != m_vConstraints.end()) 387 | { 388 | continue; 389 | } 390 | 391 | int nRow = m_vVertexMap[i]; 392 | double fX = vU[2 * nRow]; 393 | double fY = vU[2 * nRow + 1]; 394 | 395 | //cout << "new vs old positions: (" << fX << ", " << fY << " ) <--> " << m_vDeformedVertices[i].vPosition.transpose() << endl; 396 | 397 | m_vDeformedVertices[i].vPosition = v2f(fX, fY); 398 | 399 | 400 | } 401 | 402 | if (isRigid) 403 | { 404 | // perform step 2 - scaling and step 3 fitting 405 | } 406 | } -------------------------------------------------------------------------------- /ZZSARAP/triangle.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************/ 2 | /* */ 3 | /* (triangle.h) */ 4 | /* */ 5 | /* Include file for programs that call Triangle. */ 6 | /* */ 7 | /* Accompanies Triangle Version 1.6 */ 8 | /* July 28, 2005 */ 9 | /* */ 10 | /* Copyright 1996, 2005 */ 11 | /* Jonathan Richard Shewchuk */ 12 | /* 2360 Woolsey #H */ 13 | /* Berkeley, California 94705-1927 */ 14 | /* jrs@cs.berkeley.edu */ 15 | /* */ 16 | /*****************************************************************************/ 17 | 18 | /*****************************************************************************/ 19 | /* */ 20 | /* How to call Triangle from another program */ 21 | /* */ 22 | /* */ 23 | /* If you haven't read Triangle's instructions (run "triangle -h" to read */ 24 | /* them), you won't understand what follows. */ 25 | /* */ 26 | /* Triangle must be compiled into an object file (triangle.o) with the */ 27 | /* TRILIBRARY symbol defined (generally by using the -DTRILIBRARY compiler */ 28 | /* switch). The makefile included with Triangle will do this for you if */ 29 | /* you run "make trilibrary". The resulting object file can be called via */ 30 | /* the procedure triangulate(). */ 31 | /* */ 32 | /* If the size of the object file is important to you, you may wish to */ 33 | /* generate a reduced version of triangle.o. The REDUCED symbol gets rid */ 34 | /* of all features that are primarily of research interest. Specifically, */ 35 | /* the -DREDUCED switch eliminates Triangle's -i, -F, -s, and -C switches. */ 36 | /* The CDT_ONLY symbol gets rid of all meshing algorithms above and beyond */ 37 | /* constrained Delaunay triangulation. Specifically, the -DCDT_ONLY switch */ 38 | /* eliminates Triangle's -r, -q, -a, -u, -D, -Y, -S, and -s switches. */ 39 | /* */ 40 | /* IMPORTANT: These definitions (TRILIBRARY, REDUCED, CDT_ONLY) must be */ 41 | /* made in the makefile or in triangle.c itself. Putting these definitions */ 42 | /* in this file (triangle.h) will not create the desired effect. */ 43 | /* */ 44 | /* */ 45 | /* The calling convention for triangulate() follows. */ 46 | /* */ 47 | /* void triangulate(triswitches, in, out, vorout) */ 48 | /* char *triswitches; */ 49 | /* struct triangulateio *in; */ 50 | /* struct triangulateio *out; */ 51 | /* struct triangulateio *vorout; */ 52 | /* */ 53 | /* `triswitches' is a string containing the command line switches you wish */ 54 | /* to invoke. No initial dash is required. Some suggestions: */ 55 | /* */ 56 | /* - You'll probably find it convenient to use the `z' switch so that */ 57 | /* points (and other items) are numbered from zero. This simplifies */ 58 | /* indexing, because the first item of any type always starts at index */ 59 | /* [0] of the corresponding array, whether that item's number is zero or */ 60 | /* one. */ 61 | /* - You'll probably want to use the `Q' (quiet) switch in your final code, */ 62 | /* but you can take advantage of Triangle's printed output (including the */ 63 | /* `V' switch) while debugging. */ 64 | /* - If you are not using the `q', `a', `u', `D', `j', or `s' switches, */ 65 | /* then the output points will be identical to the input points, except */ 66 | /* possibly for the boundary markers. If you don't need the boundary */ 67 | /* markers, you should use the `N' (no nodes output) switch to save */ 68 | /* memory. (If you do need boundary markers, but need to save memory, a */ 69 | /* good nasty trick is to set out->pointlist equal to in->pointlist */ 70 | /* before calling triangulate(), so that Triangle overwrites the input */ 71 | /* points with identical copies.) */ 72 | /* - The `I' (no iteration numbers) and `g' (.off file output) switches */ 73 | /* have no effect when Triangle is compiled with TRILIBRARY defined. */ 74 | /* */ 75 | /* `in', `out', and `vorout' are descriptions of the input, the output, */ 76 | /* and the Voronoi output. If the `v' (Voronoi output) switch is not used, */ 77 | /* `vorout' may be NULL. `in' and `out' may never be NULL. */ 78 | /* */ 79 | /* Certain fields of the input and output structures must be initialized, */ 80 | /* as described below. */ 81 | /* */ 82 | /*****************************************************************************/ 83 | 84 | /*****************************************************************************/ 85 | /* */ 86 | /* The `triangulateio' structure. */ 87 | /* */ 88 | /* Used to pass data into and out of the triangulate() procedure. */ 89 | /* */ 90 | /* */ 91 | /* Arrays are used to store points, triangles, markers, and so forth. In */ 92 | /* all cases, the first item in any array is stored starting at index [0]. */ 93 | /* However, that item is item number `1' unless the `z' switch is used, in */ 94 | /* which case it is item number `0'. Hence, you may find it easier to */ 95 | /* index points (and triangles in the neighbor list) if you use the `z' */ 96 | /* switch. Unless, of course, you're calling Triangle from a Fortran */ 97 | /* program. */ 98 | /* */ 99 | /* Description of fields (except the `numberof' fields, which are obvious): */ 100 | /* */ 101 | /* `pointlist': An array of point coordinates. The first point's x */ 102 | /* coordinate is at index [0] and its y coordinate at index [1], followed */ 103 | /* by the coordinates of the remaining points. Each point occupies two */ 104 | /* REALs. */ 105 | /* `pointattributelist': An array of point attributes. Each point's */ 106 | /* attributes occupy `numberofpointattributes' REALs. */ 107 | /* `pointmarkerlist': An array of point markers; one int per point. */ 108 | /* */ 109 | /* `trianglelist': An array of triangle corners. The first triangle's */ 110 | /* first corner is at index [0], followed by its other two corners in */ 111 | /* counterclockwise order, followed by any other nodes if the triangle */ 112 | /* represents a nonlinear element. Each triangle occupies */ 113 | /* `numberofcorners' ints. */ 114 | /* `triangleattributelist': An array of triangle attributes. Each */ 115 | /* triangle's attributes occupy `numberoftriangleattributes' REALs. */ 116 | /* `trianglearealist': An array of triangle area constraints; one REAL per */ 117 | /* triangle. Input only. */ 118 | /* `neighborlist': An array of triangle neighbors; three ints per */ 119 | /* triangle. Output only. */ 120 | /* */ 121 | /* `segmentlist': An array of segment endpoints. The first segment's */ 122 | /* endpoints are at indices [0] and [1], followed by the remaining */ 123 | /* segments. Two ints per segment. */ 124 | /* `segmentmarkerlist': An array of segment markers; one int per segment. */ 125 | /* */ 126 | /* `holelist': An array of holes. The first hole's x and y coordinates */ 127 | /* are at indices [0] and [1], followed by the remaining holes. Two */ 128 | /* REALs per hole. Input only, although the pointer is copied to the */ 129 | /* output structure for your convenience. */ 130 | /* */ 131 | /* `regionlist': An array of regional attributes and area constraints. */ 132 | /* The first constraint's x and y coordinates are at indices [0] and [1], */ 133 | /* followed by the regional attribute at index [2], followed by the */ 134 | /* maximum area at index [3], followed by the remaining area constraints. */ 135 | /* Four REALs per area constraint. Note that each regional attribute is */ 136 | /* used only if you select the `A' switch, and each area constraint is */ 137 | /* used only if you select the `a' switch (with no number following), but */ 138 | /* omitting one of these switches does not change the memory layout. */ 139 | /* Input only, although the pointer is copied to the output structure for */ 140 | /* your convenience. */ 141 | /* */ 142 | /* `edgelist': An array of edge endpoints. The first edge's endpoints are */ 143 | /* at indices [0] and [1], followed by the remaining edges. Two ints per */ 144 | /* edge. Output only. */ 145 | /* `edgemarkerlist': An array of edge markers; one int per edge. Output */ 146 | /* only. */ 147 | /* `normlist': An array of normal vectors, used for infinite rays in */ 148 | /* Voronoi diagrams. The first normal vector's x and y magnitudes are */ 149 | /* at indices [0] and [1], followed by the remaining vectors. For each */ 150 | /* finite edge in a Voronoi diagram, the normal vector written is the */ 151 | /* zero vector. Two REALs per edge. Output only. */ 152 | /* */ 153 | /* */ 154 | /* Any input fields that Triangle will examine must be initialized. */ 155 | /* Furthermore, for each output array that Triangle will write to, you */ 156 | /* must either provide space by setting the appropriate pointer to point */ 157 | /* to the space you want the data written to, or you must initialize the */ 158 | /* pointer to NULL, which tells Triangle to allocate space for the results. */ 159 | /* The latter option is preferable, because Triangle always knows exactly */ 160 | /* how much space to allocate. The former option is provided mainly for */ 161 | /* people who need to call Triangle from Fortran code, though it also makes */ 162 | /* possible some nasty space-saving tricks, like writing the output to the */ 163 | /* same arrays as the input. */ 164 | /* */ 165 | /* Triangle will not free() any input or output arrays, including those it */ 166 | /* allocates itself; that's up to you. You should free arrays allocated by */ 167 | /* Triangle by calling the trifree() procedure defined below. (By default, */ 168 | /* trifree() just calls the standard free() library procedure, but */ 169 | /* applications that call triangulate() may replace trimalloc() and */ 170 | /* trifree() in triangle.c to use specialized memory allocators.) */ 171 | /* */ 172 | /* Here's a guide to help you decide which fields you must initialize */ 173 | /* before you call triangulate(). */ 174 | /* */ 175 | /* `in': */ 176 | /* */ 177 | /* - `pointlist' must always point to a list of points; `numberofpoints' */ 178 | /* and `numberofpointattributes' must be properly set. */ 179 | /* `pointmarkerlist' must either be set to NULL (in which case all */ 180 | /* markers default to zero), or must point to a list of markers. If */ 181 | /* `numberofpointattributes' is not zero, `pointattributelist' must */ 182 | /* point to a list of point attributes. */ 183 | /* - If the `r' switch is used, `trianglelist' must point to a list of */ 184 | /* triangles, and `numberoftriangles', `numberofcorners', and */ 185 | /* `numberoftriangleattributes' must be properly set. If */ 186 | /* `numberoftriangleattributes' is not zero, `triangleattributelist' */ 187 | /* must point to a list of triangle attributes. If the `a' switch is */ 188 | /* used (with no number following), `trianglearealist' must point to a */ 189 | /* list of triangle area constraints. `neighborlist' may be ignored. */ 190 | /* - If the `p' switch is used, `segmentlist' must point to a list of */ 191 | /* segments, `numberofsegments' must be properly set, and */ 192 | /* `segmentmarkerlist' must either be set to NULL (in which case all */ 193 | /* markers default to zero), or must point to a list of markers. */ 194 | /* - If the `p' switch is used without the `r' switch, then */ 195 | /* `numberofholes' and `numberofregions' must be properly set. If */ 196 | /* `numberofholes' is not zero, `holelist' must point to a list of */ 197 | /* holes. If `numberofregions' is not zero, `regionlist' must point to */ 198 | /* a list of region constraints. */ 199 | /* - If the `p' switch is used, `holelist', `numberofholes', */ 200 | /* `regionlist', and `numberofregions' is copied to `out'. (You can */ 201 | /* nonetheless get away with not initializing them if the `r' switch is */ 202 | /* used.) */ 203 | /* - `edgelist', `edgemarkerlist', `normlist', and `numberofedges' may be */ 204 | /* ignored. */ 205 | /* */ 206 | /* `out': */ 207 | /* */ 208 | /* - `pointlist' must be initialized (NULL or pointing to memory) unless */ 209 | /* the `N' switch is used. `pointmarkerlist' must be initialized */ 210 | /* unless the `N' or `B' switch is used. If `N' is not used and */ 211 | /* `in->numberofpointattributes' is not zero, `pointattributelist' must */ 212 | /* be initialized. */ 213 | /* - `trianglelist' must be initialized unless the `E' switch is used. */ 214 | /* `neighborlist' must be initialized if the `n' switch is used. If */ 215 | /* the `E' switch is not used and (`in->numberofelementattributes' is */ 216 | /* not zero or the `A' switch is used), `elementattributelist' must be */ 217 | /* initialized. `trianglearealist' may be ignored. */ 218 | /* - `segmentlist' must be initialized if the `p' or `c' switch is used, */ 219 | /* and the `P' switch is not used. `segmentmarkerlist' must also be */ 220 | /* initialized under these circumstances unless the `B' switch is used. */ 221 | /* - `edgelist' must be initialized if the `e' switch is used. */ 222 | /* `edgemarkerlist' must be initialized if the `e' switch is used and */ 223 | /* the `B' switch is not. */ 224 | /* - `holelist', `regionlist', `normlist', and all scalars may be ignored.*/ 225 | /* */ 226 | /* `vorout' (only needed if `v' switch is used): */ 227 | /* */ 228 | /* - `pointlist' must be initialized. If `in->numberofpointattributes' */ 229 | /* is not zero, `pointattributelist' must be initialized. */ 230 | /* `pointmarkerlist' may be ignored. */ 231 | /* - `edgelist' and `normlist' must both be initialized. */ 232 | /* `edgemarkerlist' may be ignored. */ 233 | /* - Everything else may be ignored. */ 234 | /* */ 235 | /* After a call to triangulate(), the valid fields of `out' and `vorout' */ 236 | /* will depend, in an obvious way, on the choice of switches used. Note */ 237 | /* that when the `p' switch is used, the pointers `holelist' and */ 238 | /* `regionlist' are copied from `in' to `out', but no new space is */ 239 | /* allocated; be careful that you don't free() the same array twice. On */ 240 | /* the other hand, Triangle will never copy the `pointlist' pointer (or any */ 241 | /* others); new space is allocated for `out->pointlist', or if the `N' */ 242 | /* switch is used, `out->pointlist' remains uninitialized. */ 243 | /* */ 244 | /* All of the meaningful `numberof' fields will be properly set; for */ 245 | /* instance, `numberofedges' will represent the number of edges in the */ 246 | /* triangulation whether or not the edges were written. If segments are */ 247 | /* not used, `numberofsegments' will indicate the number of boundary edges. */ 248 | /* */ 249 | /*****************************************************************************/ 250 | 251 | #ifndef _TRIANGLE_H_ 252 | #define _TRIANGLE_H_ 253 | 254 | #define ANSI_DECLARATORS 255 | #define VOIDD int 256 | #define REAL double 257 | 258 | struct triangulateio { 259 | REAL *pointlist; /* In / out */ 260 | REAL *pointattributelist; /* In / out */ 261 | int *pointmarkerlist; /* In / out */ 262 | int numberofpoints; /* In / out */ 263 | int numberofpointattributes; /* In / out */ 264 | 265 | int *trianglelist; /* In / out */ 266 | REAL *triangleattributelist; /* In / out */ 267 | REAL *trianglearealist; /* In only */ 268 | int *neighborlist; /* Out only */ 269 | int numberoftriangles; /* In / out */ 270 | int numberofcorners; /* In / out */ 271 | int numberoftriangleattributes; /* In / out */ 272 | 273 | int *segmentlist; /* In / out */ 274 | int *segmentmarkerlist; /* In / out */ 275 | int numberofsegments; /* In / out */ 276 | 277 | REAL *holelist; /* In / pointer to array copied out */ 278 | int numberofholes; /* In / copied out */ 279 | 280 | REAL *regionlist; /* In / pointer to array copied out */ 281 | int numberofregions; /* In / copied out */ 282 | 283 | int *edgelist; /* Out only */ 284 | int *edgemarkerlist; /* Not used with Voronoi diagram; out only */ 285 | REAL *normlist; /* Used only with Voronoi diagram; out only */ 286 | int numberofedges; /* Out only */ 287 | }; 288 | 289 | #ifdef ANSI_DECLARATORS 290 | void triangulate(char *, struct triangulateio *, struct triangulateio *, 291 | struct triangulateio *); 292 | void trifree(VOIDD *memptr); 293 | #else /* not ANSI_DECLARATORS */ 294 | void triangulate(); 295 | void trifree(); 296 | #endif /* not ANSI_DECLARATORS */ 297 | 298 | #endif 299 | --------------------------------------------------------------------------------