├── Debug ├── QSlimCros.exe ├── QSlimCros.ilk └── QSlimCros.pdb ├── QSlimCros.sdf ├── QSlimCros.sln ├── QSlimCros.suo ├── QSlimCros ├── Debug │ ├── CL.read.1.tlog │ ├── CL.write.1.tlog │ ├── QSlim.obj │ ├── QSlimBase.obj │ ├── QSlimCros.Build.CppClean.log │ ├── QSlimCros.exe.intermediate.manifest │ ├── QSlimCros.lastbuildstate │ ├── QSlimCros.log │ ├── QSlimCros.write.1.tlog │ ├── cl.command.1.tlog │ ├── link.command.1.tlog │ ├── link.read.1.tlog │ ├── link.write.1.tlog │ ├── main.obj │ ├── mt.command.1.tlog │ ├── mt.read.1.tlog │ ├── mt.write.1.tlog │ ├── vc100.idb │ └── vc100.pdb ├── Mesh.h ├── QSlim.cpp ├── QSlim.h ├── QSlimCros.vcxproj ├── QSlimCros.vcxproj.filters ├── QSlimCros.vcxproj.user ├── Release │ ├── CL.read.1.tlog │ ├── CL.write.1.tlog │ ├── QSlim.obj │ ├── QSlimBase.obj │ ├── QSlimCros.Build.CppClean.log │ ├── QSlimCros.exe.intermediate.manifest │ ├── QSlimCros.lastbuildstate │ ├── QSlimCros.log │ ├── QSlimCros.vcxprojResolveAssemblyReference.cache │ ├── QSlimCros.write.1.tlog │ ├── cl.command.1.tlog │ ├── link.command.1.tlog │ ├── link.read.1.tlog │ ├── link.write.1.tlog │ ├── main.obj │ ├── mt.command.1.tlog │ ├── mt.read.1.tlog │ ├── mt.write.1.tlog │ └── vc100.pdb └── main.cpp ├── README.md ├── Release ├── QSlimCros.exe └── QSlimCros.pdb └── ipch └── qslimcros-8cef9581 └── qslimcros-3f8e8143.ipch /Debug/QSlimCros.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/Debug/QSlimCros.exe -------------------------------------------------------------------------------- /Debug/QSlimCros.ilk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/Debug/QSlimCros.ilk -------------------------------------------------------------------------------- /Debug/QSlimCros.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/Debug/QSlimCros.pdb -------------------------------------------------------------------------------- /QSlimCros.sdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros.sdf -------------------------------------------------------------------------------- /QSlimCros.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QSlimCros", "QSlimCros\QSlimCros.vcxproj", "{AAC1ED99-C116-4FA9-A71D-58E05A7D79D0}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {AAC1ED99-C116-4FA9-A71D-58E05A7D79D0}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {AAC1ED99-C116-4FA9-A71D-58E05A7D79D0}.Debug|Win32.Build.0 = Debug|Win32 14 | {AAC1ED99-C116-4FA9-A71D-58E05A7D79D0}.Release|Win32.ActiveCfg = Release|Win32 15 | {AAC1ED99-C116-4FA9-A71D-58E05A7D79D0}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /QSlimCros.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros.suo -------------------------------------------------------------------------------- /QSlimCros/Debug/CL.read.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Debug/CL.read.1.tlog -------------------------------------------------------------------------------- /QSlimCros/Debug/CL.write.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Debug/CL.write.1.tlog -------------------------------------------------------------------------------- /QSlimCros/Debug/QSlim.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Debug/QSlim.obj -------------------------------------------------------------------------------- /QSlimCros/Debug/QSlimBase.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Debug/QSlimBase.obj -------------------------------------------------------------------------------- /QSlimCros/Debug/QSlimCros.Build.CppClean.log: -------------------------------------------------------------------------------- 1 | F:\WORKSPACECSHARP\C++PROJ\QSLIMCROS\DEBUG\QSLIMCROS.EXE 2 | F:\WORKSPACECSHARP\C++PROJ\QSLIMCROS\DEBUG\QSLIMCROS.ILK 3 | F:\WORKSPACECSHARP\C++PROJ\QSLIMCROS\DEBUG\QSLIMCROS.PDB 4 | F:\workspacecsharp\C++Proj\QSlimCros\QSlimCros\Debug\cl.command.1.tlog 5 | F:\workspacecsharp\C++Proj\QSlimCros\QSlimCros\Debug\CL.read.1.tlog 6 | F:\workspacecsharp\C++Proj\QSlimCros\QSlimCros\Debug\CL.write.1.tlog 7 | F:\workspacecsharp\C++Proj\QSlimCros\QSlimCros\Debug\link.command.1.tlog 8 | F:\workspacecsharp\C++Proj\QSlimCros\QSlimCros\Debug\link.read.1.tlog 9 | F:\workspacecsharp\C++Proj\QSlimCros\QSlimCros\Debug\link.write.1.tlog 10 | F:\WORKSPACECSHARP\C++PROJ\QSLIMCROS\QSLIMCROS\DEBUG\MAIN.OBJ 11 | F:\workspacecsharp\C++Proj\QSlimCros\QSlimCros\Debug\mt.command.1.tlog 12 | F:\workspacecsharp\C++Proj\QSlimCros\QSlimCros\Debug\mt.read.1.tlog 13 | F:\workspacecsharp\C++Proj\QSlimCros\QSlimCros\Debug\mt.write.1.tlog 14 | F:\WORKSPACECSHARP\C++PROJ\QSLIMCROS\QSLIMCROS\DEBUG\QSLIM.OBJ 15 | F:\WORKSPACECSHARP\C++PROJ\QSLIMCROS\QSLIMCROS\DEBUG\QSLIMBASE.OBJ 16 | F:\WORKSPACECSHARP\C++PROJ\QSLIMCROS\QSLIMCROS\DEBUG\QSLIMCROS.EXE.INTERMEDIATE.MANIFEST 17 | F:\workspacecsharp\C++Proj\QSlimCros\QSlimCros\Debug\QSlimCros.write.1.tlog 18 | F:\workspacecsharp\C++Proj\QSlimCros\QSlimCros\Debug\vc100.idb 19 | F:\WORKSPACECSHARP\C++PROJ\QSLIMCROS\QSLIMCROS\DEBUG\VC100.PDB 20 | -------------------------------------------------------------------------------- /QSlimCros/Debug/QSlimCros.exe.intermediate.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /QSlimCros/Debug/QSlimCros.lastbuildstate: -------------------------------------------------------------------------------- 1 | #v4.0:v100:false 2 | Debug|Win32|F:\workspacecsharp\C++Proj\QSlimCros\| 3 | -------------------------------------------------------------------------------- /QSlimCros/Debug/QSlimCros.log: -------------------------------------------------------------------------------- 1 | Build started 2014/1/27 21:54:46. 2 | 1>Project "F:\workspacecsharp\C++Proj\QSlimCros\QSlimCros\QSlimCros.vcxproj" on node 2 (build target(s)). 3 | 1>InitializeBuildStatus: 4 | Creating "Debug\QSlimCros.unsuccessfulbuild" because "AlwaysCreate" was specified. 5 | ClCompile: 6 | D:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\CL.exe /c /ZI /nologo /W3 /WX- /Od /Oy- /D _MBCS /Gm /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Fo"Debug\\" /Fd"Debug\vc100.pdb" /Gd /TP /analyze- /errorReport:prompt main.cpp 7 | main.cpp 8 | 1>f:\workspacecsharp\c++proj\qslimcros\qslimcros\main.cpp(83): warning C4244: 'argument' : conversion from 'real' to 'float', possible loss of data 9 | 1>f:\workspacecsharp\c++proj\qslimcros\qslimcros\main.cpp(83): warning C4244: 'argument' : conversion from 'real' to 'float', possible loss of data 10 | 1>f:\workspacecsharp\c++proj\qslimcros\qslimcros\main.cpp(83): warning C4244: 'argument' : conversion from 'real' to 'float', possible loss of data 11 | Link: 12 | D:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\link.exe /ERRORREPORT:PROMPT /OUT:"F:\workspacecsharp\C++Proj\QSlimCros\Debug\QSlimCros.exe" /NOLOGO kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /MANIFEST /ManifestFile:"Debug\QSlimCros.exe.intermediate.manifest" /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"F:\workspacecsharp\C++Proj\QSlimCros\Debug\QSlimCros.pdb" /TLBID:1 /DYNAMICBASE /NXCOMPAT /IMPLIB:"F:\workspacecsharp\C++Proj\QSlimCros\Debug\QSlimCros.lib" /MACHINE:X86 Debug\main.obj 13 | Debug\QSlim.obj 14 | Debug\QSlimBase.obj 15 | LINK : F:\workspacecsharp\C++Proj\QSlimCros\Debug\QSlimCros.exe not found or not built by the last incremental link; performing full link 16 | QSlimCros.vcxproj -> F:\workspacecsharp\C++Proj\QSlimCros\Debug\QSlimCros.exe 17 | Manifest: 18 | C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\mt.exe /nologo /verbose /outputresource:"F:\workspacecsharp\C++Proj\QSlimCros\Debug\QSlimCros.exe;#1" /manifest Debug\QSlimCros.exe.intermediate.manifest 19 | FinalizeBuildStatus: 20 | Deleting file "Debug\QSlimCros.unsuccessfulbuild". 21 | Touching "Debug\QSlimCros.lastbuildstate". 22 | 1>Done Building Project "F:\workspacecsharp\C++Proj\QSlimCros\QSlimCros\QSlimCros.vcxproj" (build target(s)). 23 | 24 | Build succeeded. 25 | 26 | Time Elapsed 00:00:00.97 27 | -------------------------------------------------------------------------------- /QSlimCros/Debug/QSlimCros.write.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Debug/QSlimCros.write.1.tlog -------------------------------------------------------------------------------- /QSlimCros/Debug/cl.command.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Debug/cl.command.1.tlog -------------------------------------------------------------------------------- /QSlimCros/Debug/link.command.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Debug/link.command.1.tlog -------------------------------------------------------------------------------- /QSlimCros/Debug/link.read.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Debug/link.read.1.tlog -------------------------------------------------------------------------------- /QSlimCros/Debug/link.write.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Debug/link.write.1.tlog -------------------------------------------------------------------------------- /QSlimCros/Debug/main.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Debug/main.obj -------------------------------------------------------------------------------- /QSlimCros/Debug/mt.command.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Debug/mt.command.1.tlog -------------------------------------------------------------------------------- /QSlimCros/Debug/mt.read.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Debug/mt.read.1.tlog -------------------------------------------------------------------------------- /QSlimCros/Debug/mt.write.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Debug/mt.write.1.tlog -------------------------------------------------------------------------------- /QSlimCros/Debug/vc100.idb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Debug/vc100.idb -------------------------------------------------------------------------------- /QSlimCros/Debug/vc100.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Debug/vc100.pdb -------------------------------------------------------------------------------- /QSlimCros/Mesh.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE_H 2 | #define BASE_H 3 | #define _CRT_SECURE_NO_WARNINGS 4 | #include 5 | #include 6 | struct Point3d 7 | { 8 | public: 9 | float X; 10 | float Y; 11 | float Z; 12 | Point3d() 13 | { 14 | X = 0; 15 | Y = 0; 16 | Z = 0; 17 | } 18 | ~Point3d() 19 | { 20 | } 21 | Point3d(float x, float y, float z) 22 | { 23 | this->X = x; 24 | this->Y = y; 25 | this->Z = z; 26 | } 27 | }; 28 | struct Triangle 29 | { 30 | public : 31 | int P0Index; 32 | int P1Index; 33 | int P2Index; 34 | Triangle(int p0index, int p1index, int p2index) 35 | { 36 | this->P0Index=p0index; 37 | this->P1Index=p1index; 38 | this->P2Index=p2index; 39 | } 40 | Triangle() 41 | { 42 | P0Index=-1; 43 | P1Index=-1; 44 | P2Index=-1; 45 | } 46 | }; 47 | struct Vector 48 | { 49 | public: 50 | float X; 51 | float Y; 52 | float Z; 53 | Vector() 54 | { 55 | X = 0; 56 | Y = 0; 57 | Z = 0; 58 | } 59 | ~Vector() 60 | { 61 | } 62 | Vector(float x, float y, float z) 63 | { 64 | this->X = x; 65 | this->Y = y; 66 | this->Z = z; 67 | } 68 | }; 69 | Vector CaculateTriangleNormal(Point3d& p0, Point3d& p1, Point3d& p2) 70 | { 71 | Vector Normal; 72 | float v1x = p1.X - p0.X; 73 | float v1y = p1.Y - p0.Y; 74 | float v1z = p1.Z - p0.Z; 75 | float v2x = p2.X - p1.X; 76 | float v2y = p2.Y - p1.Y; 77 | float v2z = p2.Z - p1.Z; 78 | Normal.X= v1y * v2z - v1z * v2y; 79 | Normal.Y = v1z * v2x - v1x * v2z; 80 | Normal.Z = v1x * v2y - v1y * v2x; 81 | float len = (float)sqrt(Normal.X * Normal.X + Normal.Y * Normal.Y + Normal.Z * Normal.Z); 82 | if (len == 0) 83 | { 84 | } 85 | else 86 | { 87 | Normal.X /= len; 88 | Normal.Y /= len; 89 | Normal.Z /= len; 90 | } 91 | return Normal; 92 | } 93 | class Mesh 94 | { 95 | public: 96 | std::vector Vertices; 97 | std::vector Faces; 98 | std::vector FaceNormals; 99 | std::vector VertexNormals; 100 | std::vector*> AdjacentFacesPerVertex; 101 | std::vector*> AdjacentVerticesPerVertex; 102 | Mesh() 103 | { 104 | } 105 | ~Mesh() 106 | { 107 | } 108 | int AddVertex(Point3d& toAdd) 109 | { 110 | int index = Vertices.size(); 111 | Vertices.push_back(toAdd); 112 | return index; 113 | } 114 | int AddFace(Triangle& tri) 115 | { 116 | int index = Faces.size(); 117 | Faces.push_back(tri); 118 | return index; 119 | } 120 | void CaculateFaceNormals() 121 | { 122 | FaceNormals.reserve(Faces.size()); 123 | for(size_t i=0;i& tlist = *(AdjacentFacesPerVertex[i]); 145 | if(tlist.size()!=0) 146 | { 147 | for (size_t j = 0; i < tlist.size(); j++) 148 | { 149 | sumx += FaceNormals[tlist[j]].X; 150 | sumy += FaceNormals[tlist[j]].Y; 151 | sumz += FaceNormals[tlist[j]].Z; 152 | } 153 | VertexNormals.push_back(Vector(sumx / tlist.size(), sumy / tlist.size(), sumz /tlist.size())); 154 | } 155 | else 156 | { 157 | VertexNormals.push_back(Vector(0,0,0)); 158 | } 159 | } 160 | } 161 | void CaculateAdjacentFacesPerVertex() 162 | { 163 | AdjacentFacesPerVertex.reserve(Vertices.size()); 164 | for (size_t i = 0; i < Vertices.size(); i++) 165 | { 166 | std::vector* list=new std::vector(); 167 | list->reserve(4); 168 | AdjacentFacesPerVertex.push_back(list); 169 | } 170 | for (size_t i = 0; i < Faces.size(); i++) 171 | { 172 | Triangle& t = Faces[i]; 173 | std::vector *t0list= AdjacentFacesPerVertex[t.P0Index]; 174 | std::vector *t1list= AdjacentFacesPerVertex[t.P1Index]; 175 | std::vector *t2list= AdjacentFacesPerVertex[t.P2Index]; 176 | t0list->push_back(i); 177 | t1list->push_back(i); 178 | t2list->push_back(i); 179 | } 180 | } 181 | void CaculateAdjacentVerticesPerVertex() 182 | { 183 | AdjacentVerticesPerVertex.reserve(Vertices.size()); 184 | for (size_t i = 0; i < Vertices.size(); i++) 185 | { 186 | std::vector* list=new std::vector(); 187 | list->reserve(4); 188 | AdjacentVerticesPerVertex.push_back(list); 189 | } 190 | for (size_t i = 0; i < Faces.size(); i++) 191 | { 192 | Triangle &t = Faces[i]; 193 | std::vector *p0list= AdjacentVerticesPerVertex[t.P0Index]; 194 | std::vector *p1list= AdjacentVerticesPerVertex[t.P1Index]; 195 | std::vector *p2list= AdjacentVerticesPerVertex[t.P2Index]; 196 | if (std::find(p0list->begin(), p0list->end(), t.P1Index)==p0list->end()) 197 | p0list->push_back(t.P1Index); 198 | if (std::find(p0list->begin(), p0list->end(), t.P2Index)==p0list->end()) 199 | p0list->push_back(t.P2Index); 200 | if (std::find(p1list->begin(), p1list->end(), t.P0Index)==p1list->end()) 201 | p1list->push_back(t.P0Index); 202 | if (std::find(p1list->begin(), p1list->end(), t.P2Index)==p1list->end()) 203 | p1list->push_back(t.P2Index); 204 | if (std::find(p2list->begin(), p2list->end(), t.P0Index)==p2list->end()) 205 | p2list->push_back(t.P0Index); 206 | if (std::find(p2list->begin(), p2list->end(), t.P1Index)==p2list->end()) 207 | p2list->push_back(t.P1Index); 208 | } 209 | } 210 | void LaplacianSmooth(int time) 211 | { 212 | if(AdjacentVerticesPerVertex.size()==0) 213 | CaculateAdjacentVerticesPerVertex(); 214 | Point3d* tempPos=new Point3d[Vertices.size()]; 215 | for(int k=0;k& adjlist =*(AdjacentVerticesPerVertex[i]); 223 | size_t adjcount=adjlist.size(); 224 | if(adjcount==0) 225 | continue; 226 | for (size_t j = 0; j < adjcount; j++) 227 | { 228 | xav += Vertices[adjlist[j]].X; 229 | yav += Vertices[adjlist[j]].Y; 230 | zav += Vertices[adjlist[j]].Z; 231 | } 232 | xav /= adjcount; 233 | yav /= adjcount; 234 | zav /= adjcount; 235 | tempPos[i].X = xav; 236 | tempPos[i].Y = yav; 237 | tempPos[i].Z = zav; 238 | } 239 | for (size_t i = 0; i < Vertices.size(); i++) 240 | { 241 | Vertices[i].X = tempPos[i].X; 242 | Vertices[i].Y = tempPos[i].Y; 243 | Vertices[i].Z = tempPos[i].Z; 244 | } 245 | } 246 | delete[] tempPos; 247 | } 248 | }; 249 | class PlyManager 250 | { 251 | public: 252 | static void Output(Mesh& mesh,const char* filename); 253 | static void ReadFile(Mesh& mesh,const char* fileName); 254 | private: 255 | static void AWriteV(FILE* sw, double v1, double v2, double v3,unsigned char r,unsigned char g,unsigned char b); 256 | static void AWriteF(FILE* sw, long i1, long i2, long i3); 257 | }; 258 | void PlyManager::AWriteV(FILE* file, double v1, double v2, double v3,unsigned char r,unsigned char g,unsigned char b) 259 | { 260 | fprintf(file,"%.2f %.2f %.2f %d %d %d\n",v1,v2,v3,r,g,b); 261 | } 262 | void PlyManager::AWriteF(FILE* file, long i1, long i2, long i3) 263 | { 264 | fprintf(file,"%d %d %d %d\n",3,i1,i2,i3); 265 | } 266 | void PlyManager::ReadFile(Mesh& mesh,const char* fileName) 267 | { 268 | long vcount=0; 269 | long fcount=0; 270 | FILE * nfile = fopen(fileName,"r"); 271 | fscanf(nfile,"ply\nformat ascii 1.0\ncomment VCGLIB generated\nelement vertex %d\n",&vcount); 272 | fscanf(nfile,"property float x\nproperty float y\nproperty float z\nproperty uchar red\nproperty uchar green\nproperty uchar blue\nelement face %d\n",&fcount); 273 | fscanf(nfile,"property list int int vertex_indices\nend_header\n"); 274 | float v1=0,v2=0,v3=0; 275 | int r=0,g=0,b=0; 276 | long i1=0,i2=0,i3=0; 277 | for(long i=0;isetHeapPos(i); 39 | ref(j).obj->setHeapPos(j); 40 | } 41 | void Heap::upheap(int i) 42 | { 43 | if( i==0 ) return; 44 | 45 | if( ref(i).import > ref(parent(i)).import ) { 46 | swap(i,parent(i)); 47 | upheap(parent(i)); 48 | } 49 | } 50 | void Heap::downheap(int i) 51 | { 52 | if (i>=size) return; // perhaps just extracted the last 53 | 54 | int largest = i, 55 | l = left(i), 56 | r = right(i); 57 | 58 | if( l ref(largest).import ) largest = l; 59 | if( r ref(largest).import ) largest = r; 60 | 61 | if( largest != i ) { 62 | swap(i,largest); 63 | downheap(largest); 64 | } 65 | } 66 | void Heap::insert(Heapable *t,float v) 67 | { 68 | if( size == maxLength() ) 69 | { 70 | cerr << "NOTE: Growing heap from " << size << " to " << 2*size << endl; 71 | resize(2*size); 72 | } 73 | 74 | int i = size++; 75 | 76 | ref(i).obj = t; 77 | ref(i).import = v; 78 | 79 | ref(i).obj->setHeapPos(i); 80 | 81 | upheap(i); 82 | } 83 | void Heap::update(Heapable *t,float v) 84 | { 85 | int i = t->getHeapPos(); 86 | 87 | if( i >= size ) 88 | { 89 | cerr << "WARNING: Attempting to update past end of heap!" << endl; 90 | return; 91 | } 92 | else if( i == NOT_IN_HEAP ) 93 | { 94 | cerr << "WARNING: Attempting to update object not in heap!" << endl; 95 | return; 96 | } 97 | 98 | float old=ref(i).import; 99 | ref(i).import = v; 100 | 101 | if( vnotInHeap(); 116 | 117 | return &ref(size); 118 | } 119 | heap_node *Heap::kill(int i) 120 | { 121 | if( i>=size ) 122 | cerr << "WARNING: Attempt to delete invalid heap node." << endl; 123 | 124 | swap(i, size-1); 125 | size--; 126 | ref(size).obj->notInHeap(); 127 | 128 | if( ref(i).import < ref(size).import ) 129 | downheap(i); 130 | else 131 | upheap(i); 132 | 133 | 134 | return &ref(size); 135 | } 136 | 137 | Mat4 Mat4::identity(Vec4(1,0,0,0),Vec4(0,1,0,0),Vec4(0,0,1,0),Vec4(0,0,0,1)); 138 | Mat4 Mat4::zero(Vec4(0,0,0,0),Vec4(0,0,0,0),Vec4(0,0,0,0),Vec4(0,0,0,0)); 139 | Mat4 Mat4::unit(Vec4(1,1,1,1),Vec4(1,1,1,1),Vec4(1,1,1,1),Vec4(1,1,1,1)); 140 | Mat4 Mat4::trans(real x, real y, real z) 141 | { 142 | return Mat4(Vec4(1,0,0,x), 143 | Vec4(0,1,0,y), 144 | Vec4(0,0,1,z), 145 | Vec4(0,0,0,1)); 146 | } 147 | Mat4 Mat4::scale(real x, real y, real z) 148 | { 149 | return Mat4(Vec4(x,0,0,0), 150 | Vec4(0,y,0,0), 151 | Vec4(0,0,z,0), 152 | Vec4(0,0,0,1)); 153 | } 154 | Mat4 Mat4::xrot(real a) 155 | { 156 | real c = cos(a); 157 | real s = sin(a); 158 | 159 | return Mat4(Vec4(1, 0, 0, 0), 160 | Vec4(0, c,-s, 0), 161 | Vec4(0, s, c, 0), 162 | Vec4(0, 0, 0, 1)); 163 | } 164 | Mat4 Mat4::yrot(real a) 165 | { 166 | real c = cos(a); 167 | real s = sin(a); 168 | return Mat4(Vec4(c, 0, s, 0),Vec4(0, 1, 0, 0),Vec4(-s,0, c, 0),Vec4(0, 0, 0, 1)); 169 | } 170 | Mat4 Mat4::zrot(real a) 171 | { 172 | real c = cos(a); 173 | real s = sin(a); 174 | return Mat4(Vec4(c,-s, 0, 0),Vec4(s, c, 0, 0),Vec4(0, 0, 1, 0),Vec4(0, 0, 0, 1)); 175 | } 176 | Mat4 Mat4::operator*(const Mat4& m) const 177 | { 178 | Mat4 A; 179 | int i,j; 180 | for(i=0;i<4;i++) 181 | for(j=0;j<4;j++) 182 | A(i,j) = row[i]*m.col(j); 183 | 184 | return A; 185 | } 186 | real Mat4::det() const 187 | { 188 | return row[0] * cross(row[1], row[2], row[3]); 189 | } 190 | Mat4 Mat4::transpose() const 191 | { 192 | return Mat4(col(0), col(1), col(2), col(3)); 193 | } 194 | Mat4 Mat4::adjoint() const 195 | { 196 | Mat4 A; 197 | A.row[0] = cross( row[1], row[2], row[3]); 198 | A.row[1] = cross(-row[0], row[2], row[3]); 199 | A.row[2] = cross( row[0], row[1], row[3]); 200 | A.row[3] = cross(-row[0], row[1], row[2]); 201 | return A; 202 | } 203 | real Mat4::cramerInverse(Mat4& inv) const 204 | { 205 | Mat4 A = adjoint(); 206 | real d = A.row[0] * row[0]; 207 | 208 | if( d==0.0 ) 209 | return 0.0; 210 | 211 | inv = A.transpose() / d; 212 | return d; 213 | } 214 | #define SWAP(a, b, t) {t = a; a = b; b = t;} 215 | real Mat4::inverse(Mat4& B) const 216 | { 217 | Mat4 A(*this); 218 | int i, j, k; 219 | real max, t, det, pivot; 220 | for (i=0; i<4; i++) /* put identity matrix in B */ 221 | for (j=0; j<4; j++) 222 | B(i, j) = (real)(i==j); 223 | det = 1.0; 224 | for (i=0; i<4; i++) { /* eliminate in column i, below diag */ 225 | max = -1.; 226 | for (k=i; k<4; k++) /* find pivot for column i */ 227 | if (fabs(A(k, i)) > max) { 228 | max = fabs(A(k, i)); 229 | j = k; 230 | } 231 | if (max<=0.) return 0.; /* if no nonzero pivot, PUNT */ 232 | if (j!=i) { /* swap rows i and j */ 233 | for (k=i; k<4; k++) 234 | SWAP(A(i, k), A(j, k), t); 235 | for (k=0; k<4; k++) 236 | SWAP(B(i, k), B(j, k), t); 237 | det = -det; 238 | } 239 | pivot = A(i, i); 240 | det *= pivot; 241 | for (k=i+1; k<4; k++) /* only do elems to right of pivot */ 242 | A(i, k) /= pivot; 243 | for (k=0; k<4; k++) 244 | B(i, k) /= pivot; 245 | for (j=i+1; j<4; j++) { /* eliminate in rows below i */ 246 | t = A(j, i); /* we're gonna zero this guy */ 247 | for (k=i+1; k<4; k++) /* subtract scaled row i from row j */ 248 | A(j, k) -= A(i, k)*t; /* (ignore k<=i, we know they're 0) */ 249 | for (k=0; k<4; k++) 250 | B(j, k) -= B(i, k)*t; 251 | } 252 | } 253 | for (i=4-1; i>0; i--) { /* eliminate in column i, above diag */ 254 | for (j=0; j= 0 ) 300 | cell.remove(index); 301 | else 302 | cerr << "WARNING: ProxGrid -- removing non-member point." << endl; 303 | } 304 | void ProxGrid::maybe_collect_points(Vec3 *v, buffer& close,ProxGrid_Cell& cell) 305 | { 306 | for(int i=0; i& close) 315 | { 316 | int i, j, k; 317 | cell_for_point(*v, &i, &j, &k); 318 | for(int dk=-1; dk<2; dk++) 319 | for(int dj=-1; dj<2; dj++) 320 | for(int di=-1; di<2; di++) 321 | { 322 | if( i+di>=0 && j+dj>=0 && k+dk>=0 323 | && i+di= 0) continue; 366 | /* project proj onto segment pf[(i+0)%3]--pf[(i+1)%3] */ 367 | 368 | vvi[0] = pf[(i+1) % 3][0] - pf[i][0]; 369 | vvi[1] = pf[(i+1) % 3][1] - pf[i][1]; 370 | vvi[2] = pf[(i+1) % 3][2] - pf[i][2]; 371 | 372 | vppi[0] = proj[0] - pf[i][0]; 373 | vppi[1] = proj[1] - pf[i][1]; 374 | vppi[2] = proj[2] - pf[i][2]; 375 | 376 | d12sq = DOTP(vvi, vvi); 377 | don12 = DOTP(vvi, vppi); 378 | 379 | if (don12<=0) { 380 | d2 = Distance2(pf[i], proj); 381 | if (d2 >= mind2) continue; 382 | mind2=d2; cba[i]=1; cba[(i+1)%3]=0; cba[(i+2)%3]=0; 383 | } 384 | else { 385 | if (don12 >= d12sq) { 386 | d2 = Distance2(pf[(i+1)%3], proj); 387 | if (d2>=mind2) continue; 388 | mind2=d2; cba[i]=0; cba[(i+1)%3]=1; cba[(i+2)%3]=0; 389 | } 390 | else { 391 | a = don12/d12sq; 392 | cba[i]=1-a; cba[(i+1)%3]=a; cba[(i+2)%3]=0; 393 | break; 394 | } 395 | } 396 | } 397 | 398 | bary[0] = cba[0]; bary[1] = cba[1]; bary[2] = cba[2]; 399 | } 400 | static void ProjectPtri(const real *point, const real *v1, const real *v2, const real *v3, real *bary) 401 | { 402 | int i; 403 | real localv2[3], localv3[3], vpp1[3]; 404 | real v22,v33,v23,v2pp1,v3pp1; 405 | real a1,a2,a3,denom; 406 | 407 | for (i = 0; i < 3; i++){ 408 | localv2[i] = v2[i] - v1[i]; 409 | localv3[i] = v3[i] - v1[i]; 410 | vpp1[i] = point[i] - v1[i]; 411 | } 412 | 413 | v22 = DOTP(localv2, localv2); 414 | v33 = DOTP(localv3, localv3); 415 | v23 = DOTP(localv2, localv3); 416 | v2pp1 = DOTP(localv2, vpp1); 417 | v3pp1 = DOTP(localv3, vpp1); 418 | 419 | if (!v22) v22=1; /* recover if v2==0 */ 420 | if (!v33) v33=1; /* recover if v3==0 */ 421 | 422 | denom = ( v33 - v23 * v23 / v22); 423 | if (!denom) { 424 | a2 = a3 = 1.0/3.0; /* recover if v23*v23==v22*v33 */ 425 | } 426 | else { 427 | a3=(v3pp1-v23/v22*v2pp1)/denom; 428 | a2=(v2pp1-a3*v23)/v22; 429 | } 430 | a1 = 1 - a2 - a3; 431 | 432 | bary[0] = a1; bary[1] = a2; bary[2] = a3; 433 | 434 | if ((a1 < 0) || (a2 < 0) || (a3 < 0)){ 435 | Projecth(v1,v2,v3,bary); 436 | return; 437 | } 438 | } 439 | 440 | real __gfx_hoppe_dist(const Face3& f, const Vec3& v) 441 | { 442 | Vec3 bary; 443 | 444 | const Vec3& v0 = f.vertexPos(0); 445 | const Vec3& v1 = f.vertexPos(1); 446 | const Vec3& v2 = f.vertexPos(2); 447 | 448 | ProjectPtri(v.raw(), v0.raw(), v1.raw(), v2.raw(), bary.raw()); 449 | 450 | Vec3 p = bary[X]*v0 + bary[Y]*v1 + bary[Z]*v2; 451 | 452 | Vec3 diff = v - p; 453 | 454 | return diff*diff; 455 | } 456 | 457 | void Bounds::reset() 458 | { 459 | min[X] = min[Y] = min[Z] = HUGE; 460 | max[X] = max[Y] = max[Z] = -HUGE; 461 | 462 | center[X] = center[Y] = center[Z] = 0.0; 463 | radius = 0.0; 464 | 465 | points = 0; 466 | } 467 | void Bounds::addPoint(const Vec3& v) 468 | { 469 | if( v[X] < min[X] ) min[X] = v[X]; 470 | if( v[Y] < min[Y] ) min[Y] = v[Y]; 471 | if( v[Z] < min[Z] ) min[Z] = v[Z]; 472 | 473 | if( v[X] > max[X] ) max[X] = v[X]; 474 | if( v[Y] > max[Y] ) max[Y] = v[Y]; 475 | if( v[Z] > max[Z] ) max[Z] = v[Z]; 476 | 477 | 478 | center += v; 479 | 480 | points++; 481 | } 482 | void Bounds::complete() 483 | { 484 | center /= (real)points; 485 | Vec3 R1 = max-center; 486 | Vec3 R2 = min-center; 487 | radius = MAX(length(R1), length(R2)); 488 | } 489 | void Plane::calcFrom(const Vec3& p1, const Vec3& p2, const Vec3& p3) 490 | { 491 | Vec3 v1 = p2-p1; 492 | Vec3 v2 = p3-p1; 493 | 494 | n = v1 ^ v2; 495 | unitize(n); 496 | 497 | d = -n*p1; 498 | } 499 | void Plane::calcFrom(const array& verts) 500 | { 501 | n[X] = n[Y] = n[Z] = 0.0; 502 | 503 | int i; 504 | for(i=0; iremapEndpoint(this, v); 556 | } 557 | kill(); 558 | } 559 | } 560 | Edge::Edge(Vertex *a, Vertex *b) 561 | { 562 | v1 = a; 563 | v1->linkEdge(this); 564 | face_uses = new buffer(2); 565 | twin = new Edge(this, b); 566 | } 567 | Edge::Edge(Edge *sibling, Vertex *org) 568 | { 569 | v1 = org; 570 | v1->linkEdge(this); 571 | face_uses = sibling->face_uses; 572 | twin = sibling; 573 | } 574 | Edge::~Edge() 575 | { 576 | if( twin ) 577 | { 578 | face_uses->free(); 579 | delete face_uses; 580 | twin->twin = NULL; 581 | delete twin; 582 | } 583 | } 584 | void Edge::kill() 585 | { 586 | if( isValid() ) 587 | { 588 | org()->unlinkEdge(this); 589 | dest()->unlinkEdge(sym()); 590 | markInvalid(); 591 | twin->markInvalid(); 592 | face_uses->reset(); 593 | } 594 | } 595 | void Edge::linkFace(Face *face) 596 | { 597 | face_uses->add(face); 598 | } 599 | void Edge::unlinkFace(Face *face) 600 | { 601 | int index = face_uses->find(face); 602 | face_uses->remove(index); 603 | if( face_uses->length() == 0 ) 604 | kill(); 605 | } 606 | void Edge::remapTo(Edge *e) 607 | { 608 | if( e != this ) 609 | { 610 | for(int i=0; ilength(); i++) 611 | { 612 | (*face_uses)(i)->remapEdge(this, e); 613 | } 614 | kill(); 615 | } 616 | } 617 | void Edge::remapEndpoint(Vertex *from, Vertex *to) 618 | { 619 | if( org()==from ) 620 | { 621 | v1 = to; 622 | to->linkEdge(this); 623 | } 624 | else if( dest()==from ) 625 | { 626 | this->twin->v1=NULL; 627 | twin->v1 = to; 628 | to->linkEdge(twin); 629 | } 630 | else 631 | { 632 | cerr << "WARNING remapEndpoint: Illegal endpoint." << endl; 633 | } 634 | for(int i=0; ilength(); i++) 635 | { 636 | face_uses->ref(i)->invalidatePlane(); 637 | } 638 | } 639 | Face::Face(Edge *e0, Edge *e1, Edge *e2): Face3(*e0->org(), *e1->org(), *e2->org()) 640 | { 641 | edges[0] = e0; 642 | edges[1] = e1; 643 | edges[2] = e2; 644 | edges[0]->linkFace(this); 645 | edges[1]->linkFace(this); 646 | edges[2]->linkFace(this); 647 | } 648 | void Face::kill() 649 | { 650 | if( isValid() ) 651 | { 652 | if( edge(0)->isValid() ) 653 | edge(0)->unlinkFace(this); 654 | 655 | if( edge(1)->isValid() ) 656 | edge(1)->unlinkFace(this); 657 | 658 | if( edge(2)->isValid() ) 659 | edge(2)->unlinkFace(this); 660 | 661 | markInvalid(); 662 | } 663 | } 664 | void Face::remapEdge(Edge *from, Edge *to) 665 | { 666 | for(int i=0; i<3; i++) 667 | { 668 | if( edges[i] == from ) 669 | { 670 | edges[i] = to; 671 | to->linkFace(this); 672 | } 673 | else if( edges[i] == from->sym() ) 674 | { 675 | edges[i] = to->sym(); 676 | to->sym()->linkFace(this); 677 | } 678 | } 679 | 680 | invalidatePlane(); 681 | } 682 | void untagFaceLoop(Vertex *v) 683 | { 684 | edge_buffer& edges = v->edgeUses(); 685 | for(int j=0; jfaceUses(); 688 | for(int k=0; kuntag(); 690 | } 691 | } 692 | void collectFaceLoop(Vertex *v, face_buffer& loop) 693 | { 694 | edge_buffer& edges = v->edgeUses(); 695 | 696 | for(int j=0; jfaceUses(); 699 | for(int k=0; kisTagged() ) 701 | { 702 | loop.add(faces(k)); 703 | faces(k)->tag(); 704 | } 705 | } 706 | } 707 | int classifyEdge(Edge *e) 708 | { 709 | int cls = e->faceUses().length(); 710 | if( cls>3 ) cls=3; 711 | return cls; 712 | } 713 | int classifyVertex(Vertex *v) 714 | { 715 | int border_count = 0; 716 | const edge_buffer& edges = v->edgeUses(); 717 | 718 | for(int i=0; i 0); 726 | } 727 | 728 | 729 | double setup_time, init_time, slim_time, write_time; 730 | int face_target = 0; 731 | real error_tolerance = HUGE; 732 | bool will_use_plane_constraint = true; 733 | bool will_use_vertex_constraint = false; 734 | bool will_preserve_boundaries = false; 735 | bool will_preserve_mesh_quality = false; 736 | bool will_constrain_boundaries = false; 737 | real boundary_constraint_weight = 1.0; 738 | bool will_weight_by_area = false; 739 | int placement_policy = PLACE_OPTIMAL; 740 | real pair_selection_tolerance = 0.0; 741 | Model M0; 742 | 743 | 744 | int Model::in_Vertex(const Vec3& p) 745 | { 746 | Vertex *v = newVertex(p[X], p[Y], p[Z]); 747 | bounds.addPoint(p); 748 | return vertCount() - 1; 749 | } 750 | int Model::in_Face(int a, int b, int c) 751 | { 752 | Vertex *v1 = vertices(a); 753 | Vertex *v2 = vertices(b); 754 | Vertex *v3 = vertices(c); 755 | 756 | Face *t = newFace(v1, v2, v3); 757 | 758 | return faceCount() - 1; 759 | } 760 | Vec3 Model::synthesizeNormal(Vertex *v) 761 | { 762 | Vec3 n(0,0,0); 763 | int n_count = 0; 764 | 765 | edge_buffer& edges = v->edgeUses(); 766 | for(int i=0; ifaceUses(); 769 | 770 | for(int j=0; jplane().normal(); 773 | n_count++; 774 | } 775 | } 776 | 777 | if( n_count ) 778 | n /= (real)n_count; 779 | else 780 | { 781 | cerr << "Vertex with no normals!!: " << v->uniqID; 782 | cerr << " / " << v->tempID << endl; 783 | } 784 | return n; 785 | } 786 | Vertex *Model::newVertex(real x, real y, real z) 787 | { 788 | Vertex *v = new Vertex(x, y, z); 789 | v->uniqID = vertices.add(v); 790 | validVertCount++; 791 | 792 | return v; 793 | } 794 | Edge *Model::newEdge(Vertex *a, Vertex *b) 795 | { 796 | Edge *e = new Edge(a, b); 797 | 798 | e->uniqID = edges.add(e); 799 | e->sym()->uniqID = e->uniqID; 800 | 801 | validEdgeCount++; 802 | 803 | return e; 804 | } 805 | static Edge *get_edge(Model *m, Vertex *org, Vertex *v) 806 | { 807 | edge_buffer& edge_uses = org->edgeUses(); 808 | 809 | for(int i=0; idest() == v ) 811 | return edge_uses(i); 812 | 813 | Edge *e = m->newEdge(org, v); 814 | 815 | return e; 816 | } 817 | Face *Model::newFace(Vertex *v1, Vertex *v2, Vertex *v3) 818 | { 819 | Edge *e0 = get_edge(this, v1, v2); // v1->edgeTo(m, v2); 820 | Edge *e1 = get_edge(this, v2, v3); // v2->edgeTo(m, v3); 821 | Edge *e2 = get_edge(this, v3, v1); // v3->edgeTo(m, v1); 822 | Face *t = new Face(e0, e1, e2); 823 | t->uniqID = faces.add(t); 824 | validFaceCount++; 825 | 826 | return t; 827 | } 828 | void Model::killVertex(Vertex *v) 829 | { 830 | if( v->isValid() ) 831 | { 832 | v->kill(); 833 | validVertCount--; 834 | } 835 | } 836 | void Model::killEdge(Edge *e) 837 | { 838 | if( e->isValid() ) 839 | { 840 | e->kill(); 841 | validEdgeCount--; 842 | } 843 | } 844 | void Model::killFace(Face *f) 845 | { 846 | if( f->isValid() ) 847 | { 848 | f->kill(); 849 | validFaceCount--; 850 | } 851 | } 852 | void Model::reshapeVertex(Vertex *v, real x, real y, real z) 853 | { 854 | v->set(x, y, z); 855 | } 856 | void Model::remapVertex(Vertex *from, Vertex *to) 857 | { 858 | from->remapTo(to); 859 | } 860 | void Model::maybeFixFace(Face *F) 861 | { 862 | Vertex *v0=F->vertex(0); Vertex *v1=F->vertex(1); Vertex *v2=F->vertex(2); 863 | Edge *e0 = F->edge(0); Edge *e1 = F->edge(1); Edge *e2 = F->edge(2); 864 | 865 | bool a=(v0 == v1), b=(v0 == v2), c=(v1 == v2); 866 | 867 | if( a && c ) 868 | { 869 | // This triangle has been reduced to a point 870 | killEdge(e0); 871 | killEdge(e1); 872 | killEdge(e2); 873 | 874 | killFace(F); 875 | } 876 | // 877 | // In the following 3 cases, the triangle has become an edge 878 | else if( a ) 879 | { 880 | killEdge(e0); 881 | e1->remapTo(e2->sym()); 882 | killFace(F); 883 | } 884 | else if( b ) 885 | { 886 | killEdge(e2); 887 | e0->remapTo(e1->sym()); 888 | killFace(F); 889 | } 890 | else if( c ) 891 | { 892 | killEdge(e1); 893 | e0->remapTo(e2->sym()); 894 | killFace(F); 895 | } 896 | else 897 | { 898 | // This triangle remains non-degenerate 899 | } 900 | } 901 | void Model::removeDegeneracy(face_buffer& changed) 902 | { 903 | for(int i=0; iremapTo(v1); 930 | removeDegeneracy(changed); 931 | } 932 | 933 | Mat4 quadrix_vertex_constraint(const Vec3& v) 934 | { 935 | Mat4 L(Mat4::identity); 936 | 937 | L(0,3) = -v[0]; 938 | L(1,3) = -v[1]; 939 | L(2,3) = -v[2]; 940 | L(3,3) = v*v; 941 | 942 | L(3,0) = L(0,3); 943 | L(3,1) = L(1,3); 944 | L(3,2) = L(2,3); 945 | 946 | return L; 947 | } 948 | Mat4 quadrix_plane_constraint(real a, real b, real c, real d) 949 | { 950 | Mat4 K(Mat4::zero); 951 | 952 | K(0,0) = a*a; K(0,1) = a*b; K(0,2) = a*c; K(0,3) = a*d; 953 | K(1,0) =K(0,1); K(1,1) = b*b; K(1,2) = b*c; K(1,3) = b*d; 954 | K(2,0) =K(0,2); K(2,1) =K(1,2); K(2,2) = c*c; K(2,3) = c*d; 955 | K(3,0) =K(0,3); K(3,1) =K(1,3); K(3,2) =K(2,3);K(3,3) = d*d; 956 | 957 | return K; 958 | } 959 | Mat4 quadrix_plane_constraint(const Vec3& n, real d) 960 | { 961 | return quadrix_plane_constraint(n[X], n[Y], n[Z], d); 962 | } 963 | Mat4 quadrix_plane_constraint(Face& T) 964 | { 965 | const Plane& p = T.plane(); 966 | real a,b,c,d; 967 | p.coeffs(&a, &b, &c, &d); 968 | 969 | return quadrix_plane_constraint(a, b, c, d); 970 | } 971 | Mat4 quadrix_plane_constraint(const Vec3& v1, const Vec3& v2, const Vec3& v3) 972 | { 973 | Plane P(v1,v2,v3); 974 | real a,b,c,d; 975 | P.coeffs(&a, &b, &c, &d); 976 | return quadrix_plane_constraint(a, b, c, d); 977 | } 978 | real quadrix_evaluate_vertex(const Vec3& v, const Mat4& K) 979 | { 980 | real x=v[X], y=v[Y], z=v[Z]; 981 | return x*x*K(0,0) + 2*x*y*K(0,1) + 2*x*z*K(0,2) + 2*x*K(0,3) 982 | + y*y*K(1,1) + 2*y*z*K(1,2) + 2*y*K(1,3) 983 | + z*z*K(2,2) + 2*z*K(2,3) 984 | + K(3,3); 985 | } 986 | static bool is_border(Edge *e ) 987 | { 988 | return classifyEdge(e) == EDGE_BORDER; 989 | } 990 | bool check_for_discontinuity(Edge *e) 991 | { 992 | return is_border(e); 993 | } 994 | Mat4 quadrix_discontinuity_constraint(Edge *edge, const Vec3& n) 995 | { 996 | Vec3& org = *edge->org(); 997 | Vec3& dest = *edge->dest(); 998 | Vec3 e = dest - org; 999 | 1000 | Vec3 n2 = e ^ n; 1001 | unitize(n2); 1002 | 1003 | real d = -n2 * org; 1004 | return quadrix_plane_constraint(n2, d); 1005 | } 1006 | Mat4 quadrix_discontinuity_constraint(Edge *edge) 1007 | { 1008 | Mat4 D(Mat4::zero); 1009 | 1010 | face_buffer& faces = edge->faceUses(); 1011 | 1012 | for(int i=0; iplane().normal()); 1014 | 1015 | return D; 1016 | } 1017 | bool quadrix_find_local_fit(const Mat4& K,const Vec3& v1, const Vec3& v2, Vec3& candidate) 1018 | { 1019 | 1020 | Vec3 v3 = (v1 + v2) / 2; 1021 | 1022 | bool try_midpoint = placement_policy > PLACE_ENDPOINTS; 1023 | 1024 | real c1 = quadrix_evaluate_vertex(v1, K); 1025 | real c2 = quadrix_evaluate_vertex(v2, K); 1026 | real c3; 1027 | if( try_midpoint ) c3 = quadrix_evaluate_vertex(v3, K); 1028 | 1029 | if( c11.0 ) a=1.0; 1062 | 1063 | 1064 | candidate = a*d + v2; 1065 | return true; 1066 | } 1067 | bool quadrix_find_best_fit(const Mat4& Q, Vec3& candidate) 1068 | { 1069 | Mat4 K = Q; 1070 | K(3,0) = K(3,1) = K(3,2) = 0.0; K(3,3) = 1; 1071 | Mat4 M; 1072 | real det = K.inverse(M); 1073 | if( FEQ(det, 0.0, 1e-12) ) 1074 | return false; 1075 | candidate[X] = M(0,3); 1076 | candidate[Y] = M(1,3); 1077 | candidate[Z] = M(2,3); 1078 | return true; 1079 | } 1080 | real quadrix_pair_target(const Mat4& Q,Vertex *v1,Vertex *v2,Vec3& candidate) 1081 | { 1082 | int policy = placement_policy; 1083 | 1084 | // 1085 | // This analytic boundary preservation isn't really necessary. The 1086 | // boundary constraint quadrics are quite effective. But, I've left it 1087 | // in anyway. 1088 | // 1089 | if( will_preserve_boundaries ) 1090 | { 1091 | int c1 = classifyVertex(v1); 1092 | int c2 = classifyVertex(v2); 1093 | 1094 | if( c1 > c2 ) 1095 | { 1096 | candidate = *v1; 1097 | return quadrix_evaluate_vertex(candidate, Q); 1098 | } 1099 | else if( c2 > c1 ) 1100 | { 1101 | candidate = *v2; 1102 | return quadrix_evaluate_vertex(candidate, Q); 1103 | } 1104 | else if( c1>0 && policy>PLACE_LINE ) 1105 | policy = PLACE_LINE; 1106 | 1107 | //if( policy == PLACE_OPTIMAL ) assert(c1==0 && c2==0); 1108 | } 1109 | 1110 | switch( policy ) 1111 | { 1112 | case PLACE_OPTIMAL: 1113 | if( quadrix_find_best_fit(Q, candidate) ) 1114 | break; 1115 | 1116 | case PLACE_LINE: 1117 | if( quadrix_find_line_fit(Q, *v1, *v2, candidate) ) 1118 | break; 1119 | 1120 | default: 1121 | quadrix_find_local_fit(Q, *v1, *v2, candidate); 1122 | break; 1123 | } 1124 | 1125 | return quadrix_evaluate_vertex(candidate, Q); 1126 | } 1127 | 1128 | 1129 | class pair_info : public Heapable 1130 | { 1131 | public: 1132 | Vertex *v0, *v1; 1133 | Vec3 candidate; 1134 | real cost; 1135 | pair_info(Vertex *a,Vertex *b) { v0=a; v1=b; cost=HUGE; } 1136 | bool isValid() { return v0->isValid() && v1->isValid(); } 1137 | }; 1138 | typedef buffer pair_buffer; 1139 | class vert_info 1140 | { 1141 | public: 1142 | pair_buffer pairs; 1143 | Mat4 Q; 1144 | real norm; 1145 | vert_info() : Q(Mat4::zero) { pairs.init(2); norm=0.0; } 1146 | }; 1147 | int will_draw_pairs = 0; 1148 | static Heap *heap; 1149 | static array vinfo; 1150 | static real proximity_limit; 1151 | static inline vert_info& vertex_info(Vertex *v) 1152 | { 1153 | return vinfo(v->validID()); 1154 | } 1155 | static bool check_for_pair(Vertex *v0, Vertex *v1) 1156 | { 1157 | const pair_buffer& pairs = vertex_info(v0).pairs; 1158 | 1159 | for(int i=0; iv0==v1 || pairs(i)->v1==v1 ) 1162 | return true; 1163 | } 1164 | 1165 | return false; 1166 | } 1167 | static pair_info *new_pair(Vertex *v0, Vertex *v1) 1168 | { 1169 | vert_info& v0_info = vertex_info(v0); 1170 | vert_info& v1_info = vertex_info(v1); 1171 | 1172 | pair_info *pair = new pair_info(v0,v1); 1173 | v0_info.pairs.add(pair); 1174 | v1_info.pairs.add(pair); 1175 | 1176 | return pair; 1177 | } 1178 | static void delete_pair(pair_info *pair) 1179 | { 1180 | vert_info& v0_info = vertex_info(pair->v0); 1181 | vert_info& v1_info = vertex_info(pair->v1); 1182 | v0_info.pairs.remove(v0_info.pairs.find(pair)); 1183 | v1_info.pairs.remove(v1_info.pairs.find(pair)); 1184 | if( pair->isInHeap() ) 1185 | heap->kill(pair->getHeapPos()); 1186 | delete pair; 1187 | } 1188 | static bool pair_is_valid(Vertex *u, Vertex *v) 1189 | { 1190 | return norm2(*u - *v) < proximity_limit; 1191 | } 1192 | static int predict_face(Face& F, Vertex *v1, Vertex *v2, Vec3& vnew,Vec3& f1, Vec3& f2, Vec3& f3) 1193 | { 1194 | int nmapped = 0; 1195 | if( F.vertex(0) == v1 || F.vertex(0) == v2 ) 1196 | { f1 = vnew; nmapped++; } 1197 | else f1 = *F.vertex(0); 1198 | if( F.vertex(1) == v1 || F.vertex(1) == v2 ) 1199 | { f2 = vnew; nmapped++; } 1200 | else f2 = *F.vertex(1); 1201 | if( F.vertex(2) == v1 || F.vertex(2) == v2 ) 1202 | { f3 = vnew; nmapped++; } 1203 | else f3 = *F.vertex(2); 1204 | return nmapped; 1205 | } 1206 | #define MESH_INVERSION_PENALTY 1e9 1207 | static real pair_mesh_penalty(Model& M, Vertex *v1, Vertex *v2, Vec3& vnew) 1208 | { 1209 | static face_buffer changed; 1210 | changed.reset(); 1211 | M.contractionRegion(v1, v2, changed); 1212 | real Nmin = 0; 1213 | for(int i=0; i delta ) Nmin = delta; 1224 | } 1225 | } 1226 | if( Nmin < 0.0 ) 1227 | return MESH_INVERSION_PENALTY; 1228 | else 1229 | return 0.0; 1230 | } 1231 | static void compute_pair_info(pair_info *pair) 1232 | { 1233 | Vertex *v0 = pair->v0; 1234 | Vertex *v1 = pair->v1; 1235 | vert_info& v0_info = vertex_info(v0); 1236 | vert_info& v1_info = vertex_info(v1); 1237 | Mat4 Q = v0_info.Q + v1_info.Q; 1238 | real norm = v0_info.norm + v1_info.norm; 1239 | pair->cost = quadrix_pair_target(Q, v0, v1, pair->candidate); 1240 | if( will_weight_by_area ) 1241 | pair->cost /= norm; 1242 | if( will_preserve_mesh_quality ) 1243 | pair->cost += pair_mesh_penalty(M0, v0, v1, pair->candidate); 1244 | if( pair->isInHeap() ) 1245 | { 1246 | heap->update(pair, (float)-pair->cost); 1247 | } 1248 | else 1249 | { 1250 | heap->insert(pair, (float)-pair->cost); 1251 | } 1252 | } 1253 | static void do_contract(Model& m, pair_info *pair) 1254 | { 1255 | Vertex *v0 = pair->v0; Vertex *v1 = pair->v1; 1256 | vert_info& v0_info = vertex_info(v0); 1257 | vert_info& v1_info = vertex_info(v1); 1258 | Vec3 vnew = pair->candidate; 1259 | int i; 1260 | v0_info.Q += v1_info.Q; 1261 | v0_info.norm += v1_info.norm; 1262 | static face_buffer changed; 1263 | changed.reset(); 1264 | m.contract(v0, v1, vnew, changed); 1265 | delete_pair(pair); 1266 | for(i=0; iv0 == v1 ) u = p->v1; 1279 | else if( p->v1 == v1) u = p->v0; 1280 | else cerr << "YOW! This is a bogus pair." << endl; 1281 | if( !check_for_pair(u, v0) ) 1282 | { 1283 | p->v0 = v0; 1284 | p->v1 = u; 1285 | v0_info.pairs.add(p); 1286 | compute_pair_info(p); 1287 | } 1288 | else 1289 | condemned.add(p); 1290 | } 1291 | for(i=0; i 0 ) 1298 | { 1299 | Q = vinfo(v->uniqID).Q; 1300 | return true; 1301 | } 1302 | else 1303 | return false; 1304 | } 1305 | void decimate_contract(Model& m) 1306 | { 1307 | heap_node *top; 1308 | pair_info *pair; 1309 | 1310 | for(;;) 1311 | { 1312 | top = heap->extract(); 1313 | if( !top ) return; 1314 | pair = (pair_info *)top->obj; 1315 | 1316 | // 1317 | // This may or may not be necessary. I'm just not quite 1318 | // willing to assume that all the junk has been removed from the 1319 | // heap. 1320 | if( pair->isValid() ) 1321 | break; 1322 | 1323 | delete_pair(pair); 1324 | } 1325 | 1326 | do_contract(m, pair); 1327 | 1328 | //if( logfile && (selected_output&OUTPUT_COST) ) 1329 | // *logfile << "#$cost " << m.validFaceCount << " " 1330 | // << pair->cost << endl; 1331 | 1332 | M0.validVertCount--; // Attempt to maintain valid vertex information 1333 | } 1334 | real decimate_error(Vertex *v) 1335 | { 1336 | vert_info& info = vertex_info(v); 1337 | 1338 | real err = quadrix_evaluate_vertex(*v, info.Q); 1339 | 1340 | if( will_weight_by_area ) 1341 | err /= info.norm; 1342 | 1343 | return err; 1344 | } 1345 | real decimate_min_error() 1346 | { 1347 | heap_node *top; 1348 | pair_info *pair; 1349 | 1350 | for(;;) 1351 | { 1352 | top = heap->top(); 1353 | if( !top ) return -1.0; 1354 | pair = (pair_info *)top->obj; 1355 | 1356 | if( pair->isValid() ) 1357 | break; 1358 | 1359 | top = heap->extract(); 1360 | delete_pair(pair); 1361 | } 1362 | 1363 | return pair->cost; 1364 | } 1365 | real decimate_max_error(Model& m) 1366 | { 1367 | real max_err = 0; 1368 | for(int i=0; iisValid() ) 1370 | { 1371 | max_err = MAX(max_err, decimate_error(m.vertex(i))); 1372 | } 1373 | return max_err; 1374 | } 1375 | void decimate_init(Model& m, real limit) 1376 | { 1377 | int i,j; 1378 | vinfo.init(m.vertCount()); 1379 | cout << " Decimate: Distributing shape constraints." << endl; 1380 | if( will_use_vertex_constraint ) 1381 | for(i=0; iisValid() ) 1385 | vertex_info(v).Q = quadrix_vertex_constraint(*v); 1386 | } 1387 | 1388 | for(i=0; iisValid() ) 1390 | { 1391 | if( will_use_plane_constraint ) 1392 | { 1393 | Mat4 Q = quadrix_plane_constraint(*m.face(i)); 1394 | real norm = 0.0; 1395 | 1396 | if( will_weight_by_area ) 1397 | { 1398 | norm = m.face(i)->area(); 1399 | Q *= norm; 1400 | } 1401 | 1402 | for(j=0; j<3; j++) 1403 | { 1404 | vertex_info(m.face(i)->vertex(j)).Q += Q; 1405 | vertex_info(m.face(i)->vertex(j)).norm += norm; 1406 | 1407 | } 1408 | } 1409 | } 1410 | 1411 | if( will_constrain_boundaries ) 1412 | { 1413 | cout << " Decimate: Accumulating discontinuity constraints." << endl; 1414 | for(i=0; iisValid() && check_for_discontinuity(m.edge(i)) ) 1416 | { 1417 | Mat4 B = quadrix_discontinuity_constraint(m.edge(i)); 1418 | real norm = 0.0; 1419 | 1420 | if( will_weight_by_area ) 1421 | { 1422 | norm = norm2(*m.edge(i)->org() - *m.edge(i)->dest()); 1423 | B *= norm; 1424 | } 1425 | 1426 | B *= boundary_constraint_weight; 1427 | vertex_info(m.edge(i)->org()).Q += B; 1428 | vertex_info(m.edge(i)->org()).norm += norm; 1429 | vertex_info(m.edge(i)->dest()).Q += B; 1430 | vertex_info(m.edge(i)->dest()).norm += norm; 1431 | } 1432 | } 1433 | 1434 | cout << " Decimate: Allocating heap." << endl; 1435 | heap = new Heap(m.validEdgeCount); 1436 | 1437 | int pair_count = 0; 1438 | 1439 | cout << " Decimate: Collecting pairs [edges]." << endl; 1440 | for(i=0; iisValid() ) 1442 | { 1443 | pair_info *pair = new_pair(m.edge(i)->org(), m.edge(i)->dest()); 1444 | compute_pair_info(pair); 1445 | pair_count++; 1446 | } 1447 | 1448 | if( limit<0 ) 1449 | { 1450 | limit = m.bounds.radius * 0.05; 1451 | cout << " Decimate: Auto-limiting at 5% of model radius." << endl; 1452 | } 1453 | proximity_limit = limit * limit; 1454 | if( proximity_limit > 0 ) 1455 | { 1456 | cout << " Decimate: Collecting pairs [limit="< nearby(32); 1462 | for(i=0; iisValid() && v2->isValid() ) 1473 | { 1474 | if( !check_for_pair(v1,v2) ) 1475 | { 1476 | pair_info *pair = new_pair(v1,v2); 1477 | compute_pair_info(pair); 1478 | pair_count++; 1479 | } 1480 | } 1481 | 1482 | } 1483 | } 1484 | } 1485 | else 1486 | cout << " Decimate: Ignoring non-edge pairs [limit=0]." << endl; 1487 | 1488 | cout << " Decimate: Designated " << pair_count << " pairs." << endl; 1489 | } -------------------------------------------------------------------------------- /QSlimCros/QSlim.h: -------------------------------------------------------------------------------- 1 | #ifndef QSLIM_H 2 | #define QSLIM_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | #define M_PI 3.14159265358979323846 11 | #define FEQ_EPS 1e-6 12 | #define FEQ_EPS2 1e-12 13 | inline bool FEQ(double a,double b,double eps=FEQ_EPS) { return fabs(a-b)(b))?(b):(a)) 16 | #define MAX(a,b) (((a)>(b))?(a):(b)) 17 | typedef double real; 18 | enum Axis {X=0, Y=1, Z=2, W=3}; 19 | template 20 | inline T min(T a, T b) { return (a < b)?a:b; } 21 | template 22 | inline T max(T a, T b) { return (a > b)?a:b; } 23 | class Vec2 { 24 | private: 25 | real elt[2]; 26 | protected: 27 | inline void copy(const Vec2& v); 28 | public: 29 | Vec2(real x=0, real y=0) { elt[0]=x; elt[1]=y; } 30 | Vec2(const Vec2& v) { copy(v); } 31 | Vec2(const real *v) { elt[0]=v[0]; elt[1]=v[1]; } 32 | real& operator()(int i) { return elt[i]; } 33 | real operator()(int i) const { return elt[i]; } 34 | real& operator[](int i) { return elt[i]; } 35 | real operator[](int i) const { return elt[i]; } 36 | real *raw() { return elt; } 37 | const real *raw() const { return elt; } 38 | inline bool operator==(const Vec2& v) const; 39 | inline bool operator!=(const Vec2& v) const; 40 | inline void set(real x, real y) { elt[0]=x; elt[1]=y; } 41 | inline Vec2& operator=(const Vec2& v); 42 | inline Vec2& operator+=(const Vec2& v); 43 | inline Vec2& operator-=(const Vec2& v); 44 | inline Vec2& operator*=(real s); 45 | inline Vec2& operator/=(real s); 46 | inline Vec2 operator+(const Vec2& v) const; 47 | inline Vec2 operator-(const Vec2& v) const; 48 | inline Vec2 operator-() const; 49 | inline Vec2 operator*(real s) const; 50 | inline Vec2 operator/(real s) const; 51 | inline real operator*(const Vec2& v) const; 52 | }; 53 | inline void Vec2::copy(const Vec2& v) 54 | { 55 | elt[0]=v.elt[0]; elt[1]=v.elt[1]; 56 | } 57 | inline bool Vec2::operator==(const Vec2& v) const 58 | { 59 | real dx=elt[X]-v[X], dy=elt[Y]-v[Y]; 60 | return (dx*dx + dy*dy) < FEQ_EPS2; 61 | } 62 | inline bool Vec2::operator!=(const Vec2& v) const 63 | { 64 | real dx=elt[X]-v[X], dy=elt[Y]-v[Y]; 65 | return (dx*dx + dy*dy) > FEQ_EPS2; 66 | } 67 | inline Vec2& Vec2::operator=(const Vec2& v) 68 | { 69 | copy(v); 70 | return *this; 71 | } 72 | inline Vec2& Vec2::operator+=(const Vec2& v) 73 | { 74 | elt[0] += v[0]; elt[1] += v[1]; 75 | return *this; 76 | } 77 | inline Vec2& Vec2::operator-=(const Vec2& v) 78 | { 79 | elt[0] -= v[0]; elt[1] -= v[1]; 80 | return *this; 81 | } 82 | inline Vec2& Vec2::operator*=(real s) 83 | { 84 | elt[0] *= s; elt[1] *= s; 85 | return *this; 86 | } 87 | inline Vec2& Vec2::operator/=(real s) 88 | { 89 | elt[0] /= s; elt[1] /= s; 90 | return *this; 91 | } 92 | inline Vec2 Vec2::operator+(const Vec2& v) const 93 | { 94 | return Vec2(elt[0]+v[0], elt[1]+v[1]); 95 | } 96 | inline Vec2 Vec2::operator-(const Vec2& v) const 97 | { 98 | return Vec2(elt[0]-v[0], elt[1]-v[1]); 99 | } 100 | inline Vec2 Vec2::operator-() const 101 | { 102 | return Vec2(-elt[0], -elt[1]); 103 | } 104 | inline Vec2 Vec2::operator*(real s) const 105 | { 106 | return Vec2(elt[0]*s, elt[1]*s); 107 | } 108 | inline Vec2 Vec2::operator/(real s) const 109 | { 110 | return Vec2(elt[0]/s, elt[1]/s); 111 | } 112 | inline real Vec2::operator*(const Vec2& v) const 113 | { 114 | return elt[0]*v[0] + elt[1]*v[1]; 115 | } 116 | inline Vec2 operator*(real s, const Vec2& v) { return v*s; } 117 | inline real norm(const Vec2& v) { return sqrt(v[0]*v[0] + v[1]*v[1]); } 118 | inline real norm2(const Vec2& v) { return v[0]*v[0] + v[1]*v[1]; } 119 | inline real length(const Vec2& v) { return norm(v); } 120 | inline real unitize(Vec2& v) 121 | { 122 | real l=norm2(v); 123 | if( l!=1.0 && l!=0.0 ) 124 | { 125 | l = sqrt(l); 126 | v /= l; 127 | } 128 | return l; 129 | } 130 | class Vec3 { 131 | private: 132 | real elt[3]; 133 | protected: 134 | inline void copy(const Vec3& v); 135 | public: 136 | Vec3(real x=0, real y=0, real z=0) { elt[0]=x; elt[1]=y; elt[2]=z; } 137 | Vec3(const Vec3& v) { copy(v); } 138 | Vec3(const real *v) { elt[0]=v[0]; elt[1]=v[1]; elt[2]=v[2]; } 139 | real& operator()(int i) { return elt[i]; } 140 | real operator()(int i) const { return elt[i]; } 141 | real& operator[](int i) { return elt[i]; } 142 | real operator[](int i) const { return elt[i]; } 143 | real *raw() { return elt; } 144 | const real *raw() const { return elt; } 145 | inline bool operator==(const Vec3& v) const; 146 | inline bool operator!=(const Vec3& v) const; 147 | inline void set(real x, real y, real z) { elt[0]=x; elt[1]=y; elt[2]=z; } 148 | inline Vec3& operator=(const Vec3& v); 149 | inline Vec3& operator+=(const Vec3& v); 150 | inline Vec3& operator-=(const Vec3& v); 151 | inline Vec3& operator*=(real s); 152 | inline Vec3& operator/=(real s); 153 | inline Vec3 operator+(const Vec3& v) const; 154 | inline Vec3 operator-(const Vec3& v) const; 155 | inline Vec3 operator-() const; 156 | inline Vec3 operator*(real s) const; 157 | inline Vec3 operator/(real s) const; 158 | inline real operator*(const Vec3& v) const; 159 | inline Vec3 operator^(const Vec3& v) const; 160 | }; 161 | inline void Vec3::copy(const Vec3& v) 162 | { 163 | elt[0]=v.elt[0]; elt[1]=v.elt[1]; elt[2]=v.elt[2]; 164 | } 165 | inline bool Vec3::operator==(const Vec3& v) const 166 | { 167 | real dx=elt[X]-v[X], dy=elt[Y]-v[Y], dz=elt[Z]-v[Z]; 168 | return (dx*dx + dy*dy + dz*dz) < FEQ_EPS2; 169 | } 170 | inline bool Vec3::operator!=(const Vec3& v) const 171 | { 172 | real dx=elt[X]-v[X], dy=elt[Y]-v[Y], dz=elt[Z]-v[Z]; 173 | return (dx*dx + dy*dy + dz*dz) > FEQ_EPS2; 174 | } 175 | inline Vec3& Vec3::operator=(const Vec3& v) 176 | { 177 | copy(v); 178 | return *this; 179 | } 180 | inline Vec3& Vec3::operator+=(const Vec3& v) 181 | { 182 | elt[0] += v[0]; elt[1] += v[1]; elt[2] += v[2]; 183 | return *this; 184 | } 185 | inline Vec3& Vec3::operator-=(const Vec3& v) 186 | { 187 | elt[0] -= v[0]; elt[1] -= v[1]; elt[2] -= v[2]; 188 | return *this; 189 | } 190 | inline Vec3& Vec3::operator*=(real s) 191 | { 192 | elt[0] *= s; elt[1] *= s; elt[2] *= s; 193 | return *this; 194 | } 195 | inline Vec3& Vec3::operator/=(real s) 196 | { 197 | elt[0] /= s; elt[1] /= s; elt[2] /= s; 198 | return *this; 199 | } 200 | inline Vec3 Vec3::operator+(const Vec3& v) const 201 | { 202 | return Vec3(elt[0]+v[0], elt[1]+v[1], elt[2]+v[2]); 203 | } 204 | inline Vec3 Vec3::operator-(const Vec3& v) const 205 | { 206 | return Vec3(elt[0]-v[0], elt[1]-v[1], elt[2]-v[2]); 207 | } 208 | inline Vec3 Vec3::operator-() const 209 | { 210 | return Vec3(-elt[0], -elt[1], -elt[2]); 211 | } 212 | inline Vec3 Vec3::operator*(real s) const 213 | { 214 | return Vec3(elt[0]*s, elt[1]*s, elt[2]*s); 215 | } 216 | inline Vec3 Vec3::operator/(real s) const 217 | { 218 | return Vec3(elt[0]/s, elt[1]/s, elt[2]/s); 219 | } 220 | inline real Vec3::operator*(const Vec3& v) const 221 | { 222 | return elt[0]*v[0] + elt[1]*v[1] + elt[2]*v[2]; 223 | } 224 | inline Vec3 Vec3::operator^(const Vec3& v) const 225 | { 226 | Vec3 w( elt[1]*v[2] - v[1]*elt[2], 227 | -elt[0]*v[2] + v[0]*elt[2], 228 | elt[0]*v[1] - v[0]*elt[1] ); 229 | return w; 230 | } 231 | inline Vec3 operator*(real s, const Vec3& v) { return v*s; } 232 | inline real norm(const Vec3& v) 233 | { 234 | return sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); 235 | } 236 | inline real norm2(const Vec3& v) 237 | { 238 | return v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; 239 | } 240 | inline real length(const Vec3& v) { return norm(v); } 241 | inline real unitize(Vec3& v) 242 | { 243 | real l=norm2(v); 244 | if( l!=1.0 && l!=0.0 ) 245 | { 246 | l = sqrt(l); 247 | v /= l; 248 | } 249 | return l; 250 | } 251 | class Vec4 { 252 | private: 253 | real elt[4]; 254 | protected: 255 | inline void copy(const Vec4& v); 256 | public: 257 | Vec4(real x=0, real y=0, real z=0, real w=0) { 258 | elt[0]=x; elt[1]=y; elt[2]=z; elt[3]=w; 259 | } 260 | Vec4(const Vec4& v) { copy(v); } 261 | Vec4(const Vec3& v,real w) {elt[0]=v[0];elt[1]=v[1];elt[2]=v[2];elt[3]=w;} 262 | Vec4(const real *v) { elt[0]=v[0]; elt[1]=v[1]; elt[2]=v[2]; elt[3]=v[3]; } 263 | real& operator()(int i) { return elt[i]; } 264 | real operator()(int i) const { return elt[i]; } 265 | real& operator[](int i) { return elt[i]; } 266 | const real& operator[](int i) const { return elt[i]; } 267 | real *raw() { return elt; } 268 | const real *raw() const { return elt; } 269 | inline bool operator==(const Vec4&) const; 270 | inline bool operator!=(const Vec4&) const; 271 | inline void set(real x, real y, real z, real w){ 272 | elt[0]=x; elt[1]=y; elt[2]=z; elt[3]=w; 273 | } 274 | inline Vec4& operator=(const Vec4& v); 275 | inline Vec4& operator+=(const Vec4& v); 276 | inline Vec4& operator-=(const Vec4& v); 277 | inline Vec4& operator*=(real s); 278 | inline Vec4& operator/=(real s); 279 | inline Vec4 operator+(const Vec4& v) const; 280 | inline Vec4 operator-(const Vec4& v) const; 281 | inline Vec4 operator-() const; 282 | inline Vec4 operator*(real s) const; 283 | inline Vec4 operator/(real s) const; 284 | inline real operator*(const Vec4& v) const; 285 | }; 286 | inline void Vec4::copy(const Vec4& v) 287 | { 288 | elt[0]=v.elt[0]; elt[1]=v.elt[1]; elt[2]=v.elt[2]; elt[3]=v.elt[3]; 289 | } 290 | inline bool Vec4::operator==(const Vec4& v) const 291 | { 292 | real dx=elt[X]-v[X], dy=elt[Y]-v[Y], dz=elt[Z]-v[Z], dw=elt[W]-v[W]; 293 | return (dx*dx + dy*dy + dz*dz + dw*dw) < FEQ_EPS2; 294 | } 295 | inline bool Vec4::operator!=(const Vec4& v) const 296 | { 297 | real dx=elt[X]-v[X], dy=elt[Y]-v[Y], dz=elt[Z]-v[Z], dw=elt[W]-v[W]; 298 | return (dx*dx + dy*dy + dz*dz + dw*dw) > FEQ_EPS2; 299 | } 300 | inline Vec4& Vec4::operator=(const Vec4& v) 301 | { 302 | copy(v); 303 | return *this; 304 | } 305 | inline Vec4& Vec4::operator+=(const Vec4& v) 306 | { 307 | elt[0] += v[0]; elt[1] += v[1]; elt[2] += v[2]; elt[3] += v[3]; 308 | return *this; 309 | } 310 | inline Vec4& Vec4::operator-=(const Vec4& v) 311 | { 312 | elt[0] -= v[0]; elt[1] -= v[1]; elt[2] -= v[2]; elt[3] -= v[3]; 313 | return *this; 314 | } 315 | inline Vec4& Vec4::operator*=(real s) 316 | { 317 | elt[0] *= s; elt[1] *= s; elt[2] *= s; elt[3] *= s; 318 | return *this; 319 | } 320 | inline Vec4& Vec4::operator/=(real s) 321 | { 322 | elt[0] /= s; elt[1] /= s; elt[2] /= s; elt[3] /= s; 323 | return *this; 324 | } 325 | inline Vec4 Vec4::operator+(const Vec4& v) const 326 | { 327 | return Vec4(elt[0]+v[0], elt[1]+v[1], elt[2]+v[2], elt[3]+v[3]); 328 | } 329 | inline Vec4 Vec4::operator-(const Vec4& v) const 330 | { 331 | return Vec4(elt[0]-v[0], elt[1]-v[1], elt[2]-v[2], elt[3]-v[3]); 332 | } 333 | inline Vec4 Vec4::operator-() const 334 | { 335 | return Vec4(-elt[0], -elt[1], -elt[2], -elt[3]); 336 | } 337 | inline Vec4 Vec4::operator*(real s) const 338 | { 339 | return Vec4(elt[0]*s, elt[1]*s, elt[2]*s, elt[3]*s); 340 | } 341 | inline Vec4 Vec4::operator/(real s) const 342 | { 343 | return Vec4(elt[0]/s, elt[1]/s, elt[2]/s, elt[3]/s); 344 | } 345 | inline real Vec4::operator*(const Vec4& v) const 346 | { 347 | return elt[0]*v[0] + elt[1]*v[1] + elt[2]*v[2] + elt[3]*v[3]; 348 | } 349 | inline Vec4 operator*(real s, const Vec4& v) { return v*s; } 350 | inline Vec4 cross(const Vec4& a, const Vec4& b, const Vec4& c) 351 | { 352 | Vec4 result; 353 | 354 | real d1 = (b[Z] * c[W]) - (b[W] * c[Z]); 355 | real d2 = (b[Y] * c[W]) - (b[W] * c[Y]); 356 | real d3 = (b[Y] * c[Z]) - (b[Z] * c[Y]); 357 | real d4 = (b[X] * c[W]) - (b[W] * c[X]); 358 | real d5 = (b[X] * c[Z]) - (b[Z] * c[X]); 359 | real d6 = (b[X] * c[Y]) - (b[Y] * c[X]); 360 | 361 | result[X] = - a[Y] * d1 + a[Z] * d2 - a[W] * d3; 362 | result[Y] = a[X] * d1 - a[Z] * d4 + a[W] * d5; 363 | result[Z] = - a[X] * d2 + a[Y] * d4 - a[W] * d6; 364 | result[W] = a[X] * d3 - a[Y] * d5 + a[Z] * d6; 365 | 366 | return result; 367 | } 368 | inline real norm(const Vec4& v) 369 | { 370 | return sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2] + v[3]*v[3]); 371 | } 372 | inline real norm2(const Vec4& v) 373 | { 374 | return v[0]*v[0] + v[1]*v[1] + v[2]*v[2] + v[3]*v[3]; 375 | } 376 | inline real length(const Vec4& v) { return norm(v); } 377 | inline real unitize(Vec4& v) 378 | { 379 | real l=norm2(v); 380 | if( l!=1.0 && l!=0.0 ) 381 | { 382 | l = sqrt(l); 383 | v /= l; 384 | } 385 | return l; 386 | } 387 | template 388 | class array { 389 | protected: 390 | T *data; 391 | int len; 392 | public: 393 | array() { data=NULL; len=0; } 394 | array(int l) { init(l); } 395 | ~array() { free(); } 396 | inline void init(int l); 397 | inline void free(); 398 | inline void resize(int l); 399 | inline T& ref(int i); 400 | inline T& operator[](int i) { return data[i]; } 401 | inline T& operator()(int i) { return ref(i); } 402 | inline const T& ref(int i) const; 403 | inline const T& operator[](int i) const { return data[i]; } 404 | inline const T& operator()(int i) const { return ref(i); } 405 | inline int length() const { return len; } 406 | inline int maxLength() const { return len; } 407 | }; 408 | template 409 | inline void array::init(int l) 410 | { 411 | data = new T[l]; 412 | len = l; 413 | } 414 | template 415 | inline void array::free() 416 | { 417 | if( data ) 418 | { 419 | delete[] data; 420 | data = NULL; 421 | } 422 | } 423 | template 424 | inline T& array::ref(int i) 425 | { 426 | return data[i]; 427 | } 428 | template 429 | inline const T& array::ref(int i) const 430 | { 431 | return data[i]; 432 | } 433 | template 434 | inline void array::resize(int l) 435 | { 436 | T *old = data; 437 | data = new T[l]; 438 | data = (T *)memcpy(data,old,MIN(len,l)*sizeof(T)); 439 | len = l; 440 | delete[] old; 441 | } 442 | extern Vec3 randomPoint(const Vec3&, const Vec3&); // on segment 443 | extern Vec3 randomPoint(const Vec3&, const Vec3&, const Vec3&); // in triangle 444 | extern real triangleArea(const Vec3&, const Vec3&, const Vec3&); 445 | extern real triangleCompactness(const Vec3&, const Vec3&, const Vec3&); 446 | class Bounds 447 | { 448 | public: 449 | Vec3 min, max; 450 | Vec3 center; 451 | real radius; 452 | unsigned int points; 453 | Bounds() { reset(); } 454 | void reset(); 455 | void addPoint(const Vec3&); 456 | void complete(); 457 | }; 458 | class Plane 459 | { 460 | Vec3 n; 461 | real d; 462 | public: 463 | Plane() : n(0,0,1) { d=0; } // -- this will define the XY plane 464 | Plane(const Vec3& p, const Vec3& q, const Vec3& r) { calcFrom(p,q,r); } 465 | Plane(const array& verts) { calcFrom(verts); } 466 | Plane(const Plane& p) { n=p.n; d=p.d; } 467 | void calcFrom(const Vec3& p, const Vec3& q, const Vec3& r); 468 | void calcFrom(const array&); 469 | bool isValid() const { return n[X]!=0.0 || n[Y]!=0.0 || n[Z]!= 0.0; } 470 | void markInvalid() { n[X] = n[Y] = n[Z] = 0.0; } 471 | real distTo(const Vec3& p) const { return n*p + d; } 472 | const Vec3& normal() const { return n; } 473 | void coeffs(real *a, real *b, real *c, real *dd) const { 474 | *a=n[X]; *b=n[Y]; *c=n[Z]; *dd=d; 475 | } 476 | Vec4 coeffs() const { return Vec4(n,d); } 477 | }; 478 | class Face3 479 | { 480 | protected: 481 | Plane P; 482 | private: 483 | void recalcPlane() { P.calcFrom(vertexPos(0),vertexPos(1),vertexPos(2)); } 484 | void recalcPlane(const Vec3& a,const Vec3& b,const Vec3& c) 485 | { P.calcFrom(a,b,c); } 486 | public: 487 | Face3(const Vec3& a,const Vec3& b,const Vec3& c) 488 | : P(a,b,c) 489 | { } 490 | virtual const Vec3& vertexPos(int i) const = 0; 491 | virtual void vertexPos(int i, const Vec3&) = 0; 492 | const Plane& plane() { if(!P.isValid()) recalcPlane(); return P;} 493 | void invalidatePlane() { P.markInvalid(); } 494 | real distTo(const Vec3& p) const; 495 | real area(); 496 | }; 497 | inline real random1() 498 | { 499 | //#if defined(WIN32) || defined(GFX_USE_RAND) 500 | return (real)rand() / (real)LONG_MAX; 501 | //#else 502 | // return (real)random() / (real)LONG_MAX; 503 | //#endif 504 | } 505 | extern Vec3 randomPoint(const Vec3& v1, const Vec3& v2); 506 | extern Vec3 randomPoint(const Vec3& v1, const Vec3& v2, const Vec3& v3); 507 | extern real triangleArea(const Vec3& v1, const Vec3& v2, const Vec3& v3); 508 | #define ROOT3 1.732050807568877 509 | #define FOUR_ROOT3 6.928203230275509 510 | extern real triangleCompactness(const Vec3& v1, const Vec3& v2, const Vec3& v3); 511 | extern real __gfx_hoppe_dist(const Face3& f, const Vec3& v); 512 | #define DOTP(a, b) (a[0] * b[0] + a[1] * b[1] + a[2] * b[2]) 513 | template 514 | class buffer : public array { 515 | protected: 516 | int fill; 517 | public: 518 | buffer() { init(8); } 519 | buffer(int l) { init(l); } 520 | inline void init(int l) { array::init(l); fill=0; } 521 | inline int add(const T& t); 522 | inline void reset(); 523 | inline int find(const T&); 524 | inline T remove(int i); 525 | inline int addAll(const buffer& buf); 526 | inline void removeDuplicates(); 527 | inline int length() const { return fill; } 528 | inline int maxLength() const { return len; } 529 | }; 530 | template 531 | inline int buffer::add(const T& t) 532 | { 533 | if( fill == len ) 534 | resize( len*2 ); 535 | 536 | data[fill] = t; 537 | 538 | return fill++; 539 | } 540 | template 541 | inline void buffer::reset() 542 | { 543 | fill = 0; 544 | } 545 | template 546 | inline int buffer::find(const T& t) 547 | { 548 | for(int i=0;i 555 | inline T buffer::remove(int i) 556 | { 557 | fill--; 558 | T temp = data[i]; 559 | data[i] = data[fill]; 560 | return temp; 561 | } 562 | template 563 | inline int buffer::addAll(const buffer& buf) 564 | { 565 | for(int i=0; i 571 | inline void buffer::removeDuplicates() 572 | { 573 | for(int i=0; i { 606 | int size; 607 | void swap(int i, int j); 608 | int parent(int i) { return (i-1)/2; } 609 | int left(int i) { return 2*i+1; } 610 | int right(int i) { return 2*i+2; } 611 | void upheap(int i); 612 | void downheap(int i); 613 | public: 614 | Heap() { size=0; } 615 | Heap(int s) : array(s) { size=0; } 616 | void insert(Heapable *, float); 617 | void update(Heapable *, float); 618 | heap_node *extract(); 619 | heap_node *top() { return size<1 ? (heap_node *)NULL : &ref(0); } 620 | heap_node *kill(int i); 621 | }; 622 | 623 | class NPrim 624 | { 625 | public: 626 | int uniqID; 627 | inline bool isValid() { return uniqID >= 0; } 628 | inline void markInvalid() { if( uniqID>=0 ) uniqID = -uniqID-1; } 629 | inline void markValid() { if( uniqID<0 ) uniqID = -uniqID-1; } 630 | inline int validID() { return (uniqID<0)?(-uniqID-1):uniqID; } 631 | }; 632 | class NTaggedPrim : public NPrim 633 | { 634 | public: 635 | int tempID; 636 | inline void untag() { tempID = 0; } 637 | inline void tag(int t=1) { tempID = t; } 638 | inline bool isTagged() { return tempID!=0; } 639 | }; 640 | class Vertex; 641 | class Edge; 642 | class Face; 643 | typedef buffer vert_buffer; 644 | typedef buffer edge_buffer; 645 | typedef buffer face_buffer; 646 | extern void untagFaceLoop(Vertex *v); 647 | extern void collectFaceLoop(Vertex *v, face_buffer& faces); 648 | #define EDGE_BOGUS 0 649 | #define EDGE_BORDER 1 650 | #define EDGE_MANIFOLD 2 651 | #define EDGE_NONMANIFOLD 3 652 | extern int classifyEdge(Edge *); 653 | #define VERTEX_INTERIOR 0 654 | #define VERTEX_BORDER 1 655 | #define VERTEX_BORDER_ONLY 2 656 | extern int classifyVertex(Vertex *); 657 | class Vertex : public Vec3, public NTaggedPrim 658 | { 659 | edge_buffer edge_uses; 660 | public: 661 | Vertex(real x, real y, real z) : Vec3(x, y, z), edge_uses(6) { 662 | } 663 | void kill(); 664 | edge_buffer& edgeUses() { return edge_uses; } 665 | void linkEdge(Edge *); 666 | void unlinkEdge(Edge *); 667 | void remapTo(Vertex *v); 668 | }; 669 | class Edge : public NPrim 670 | { 671 | private: 672 | Vertex *v1; 673 | face_buffer *face_uses; 674 | Edge *twin; 675 | Edge(Edge *twin, Vertex *org); // the twin constructor 676 | public: 677 | Edge(Vertex *, Vertex *); 678 | ~Edge(); 679 | Vertex *org() { return v1; } 680 | Vertex *dest() { return twin->v1; } 681 | Edge *sym() { return twin; } 682 | void kill(); 683 | face_buffer& faceUses() { return *face_uses; } 684 | void linkFace(Face *); 685 | void unlinkFace(Face *); 686 | void remapEndpoint(Vertex *from, Vertex *to); 687 | void remapTo(Edge *); 688 | }; 689 | class Face : public Face3, public NTaggedPrim 690 | { 691 | Edge *edges[3]; 692 | public: 693 | Face(Edge *, Edge *, Edge *); 694 | const Vec3& vertexPos(int i) const { return *edges[i]->org(); } 695 | void vertexPos(int, const Vec3&) { 696 | //fatal_error("Face: can't directly set vertex position."); 697 | } 698 | Vertex *vertex(int i) { return edges[i]->org(); } 699 | const Vertex *vertex(int i) const { return edges[i]->org(); } 700 | Edge *edge(int i) { return edges[i]; } 701 | void kill(); 702 | void remapEdge(Edge *from, Edge *to); 703 | }; 704 | class Mat4 705 | { 706 | private: 707 | Vec4 row[4]; 708 | protected: 709 | inline void copy(const Mat4& m); 710 | inline Vec4 col(int i) const 711 | { return Vec4(row[0][i],row[1][i],row[2][i],row[3][i]); } 712 | public: 713 | static Mat4 identity; 714 | static Mat4 zero; 715 | static Mat4 unit; 716 | static Mat4 trans(real,real,real); 717 | static Mat4 scale(real,real,real); 718 | static Mat4 xrot(real); // 719 | static Mat4 yrot(real); // Arguments are in radians 720 | static Mat4 zrot(real); // 721 | Mat4() { copy(zero); } 722 | Mat4(const Vec4& r0,const Vec4& r1,const Vec4& r2,const Vec4& r3) 723 | { row[0]=r0; row[1]=r1; row[2]=r2; row[3]=r3; } 724 | Mat4(const Mat4& m) { copy(m); } 725 | real& operator()(int i, int j) { return row[i][j]; } 726 | real operator()(int i, int j) const { return row[i][j]; } 727 | const Vec4& operator[](int i) const { return row[i]; } 728 | inline int operator==(const Mat4&); 729 | inline Mat4& operator=(const Mat4& m) { copy(m); return *this; } 730 | inline Mat4& operator+=(const Mat4& m); 731 | inline Mat4& operator-=(const Mat4& m); 732 | inline Mat4& operator*=(real s); 733 | inline Mat4& operator/=(real s); 734 | inline Mat4 operator+(const Mat4& m) const; 735 | inline Mat4 operator-(const Mat4& m) const; 736 | inline Mat4 operator-() const; 737 | inline Mat4 operator*(real s) const; 738 | inline Mat4 operator/(real s) const; 739 | Mat4 operator*(const Mat4& m) const; 740 | inline Vec4 operator*(const Vec4& v) const; // [x y z w] 741 | inline Vec3 operator*(const Vec3& v) const; // [x y z w] 742 | real det() const; 743 | Mat4 transpose() const; 744 | Mat4 adjoint() const; 745 | real inverse(Mat4&) const; 746 | real cramerInverse(Mat4&) const; 747 | friend ostream& operator<<(ostream&, const Mat4&); 748 | friend istream& operator>>(istream&, Mat4&); 749 | }; 750 | inline void Mat4::copy(const Mat4& m) 751 | { 752 | row[0] = m.row[0]; row[1] = m.row[1]; 753 | row[2] = m.row[2]; row[3] = m.row[3]; 754 | } 755 | inline int Mat4::operator==(const Mat4& m) 756 | { 757 | return row[0]==m.row[0] && 758 | row[1]==m.row[1] && 759 | row[2]==m.row[2] && 760 | row[3]==m.row[3] ; 761 | } 762 | inline Mat4& Mat4::operator+=(const Mat4& m) 763 | { 764 | row[0] += m.row[0]; row[1] += m.row[1]; 765 | row[2] += m.row[2]; row[3] += m.row[3]; 766 | return *this; 767 | } 768 | inline Mat4& Mat4::operator-=(const Mat4& m) 769 | { 770 | row[0] -= m.row[0]; row[1] -= m.row[1]; 771 | row[2] -= m.row[2]; row[3] -= m.row[3]; 772 | return *this; 773 | } 774 | inline Mat4& Mat4::operator*=(real s) 775 | { 776 | row[0] *= s; row[1] *= s; row[2] *= s; row[3] *= s; 777 | return *this; 778 | } 779 | inline Mat4& Mat4::operator/=(real s) 780 | { 781 | row[0] /= s; row[1] /= s; row[2] /= s; row[3] /= s; 782 | return *this; 783 | } 784 | inline Mat4 Mat4::operator+(const Mat4& m) const 785 | { 786 | return Mat4(row[0]+m.row[0], 787 | row[1]+m.row[1], 788 | row[2]+m.row[2], 789 | row[3]+m.row[3]); 790 | } 791 | inline Mat4 Mat4::operator-(const Mat4& m) const 792 | { 793 | return Mat4(row[0]-m.row[0], 794 | row[1]-m.row[1], 795 | row[2]-m.row[2], 796 | row[3]-m.row[3]); 797 | } 798 | inline Mat4 Mat4::operator-() const 799 | { 800 | return Mat4(-row[0], -row[1], -row[2], -row[3]); 801 | } 802 | inline Mat4 Mat4::operator*(real s) const 803 | { 804 | return Mat4(row[0]*s, row[1]*s, row[2]*s, row[3]*s); 805 | } 806 | inline Mat4 Mat4::operator/(real s) const 807 | { 808 | return Mat4(row[0]/s, row[1]/s, row[2]/s, row[3]/s); 809 | } 810 | inline Vec4 Mat4::operator*(const Vec4& v) const 811 | { 812 | return Vec4(row[0]*v, row[1]*v, row[2]*v, row[3]*v); 813 | } 814 | inline Vec3 Mat4::operator*(const Vec3& v) const 815 | { 816 | Vec4 u=Vec4(v,1); 817 | real w=row[3]*u; 818 | 819 | if(w==0.0) 820 | return Vec3(row[0]*u, row[1]*u, row[2]*u); 821 | else 822 | return Vec3(row[0]*u/w, row[1]*u/w, row[2]*u/w); 823 | } 824 | template 825 | class array3 826 | { 827 | protected: 828 | T *data; 829 | int w, h, d; 830 | public: 831 | array3() { data=NULL; w=h=d=0; } 832 | array3(int w, int h, int d) { init(w,h,d); } 833 | ~array3() { free(); } 834 | inline void init(int w, int h, int d); 835 | inline void free(); 836 | inline T& ref(int i, int j, int k); 837 | inline T& operator()(int i,int j, int k) { return ref(i,j, k); } 838 | inline int width() const { return w; } 839 | inline int height() const { return h; } 840 | inline int depth() const { return d; } 841 | }; 842 | template 843 | inline void array3::init(int width, int height, int depth) 844 | { 845 | w = width; 846 | h = height; 847 | d = depth; 848 | data = new T[w*h*d]; 849 | } 850 | template 851 | inline void array3::free() 852 | { 853 | if( data ) 854 | { 855 | delete[] data; 856 | data = NULL; 857 | w = h = d = 0; 858 | } 859 | 860 | } 861 | template 862 | inline T& array3::ref(int i, int j, int k) 863 | { 864 | return data[k*w*h + j*w + i]; 865 | } 866 | class ProxGrid_Cell : public buffer 867 | { 868 | public: 869 | ProxGrid_Cell(): buffer(8) 870 | { } 871 | }; 872 | class ProxGrid 873 | { 874 | array3 cells; 875 | int xdiv, ydiv, zdiv; 876 | real cellsize; 877 | real cellsize2; 878 | Vec3 min, max; 879 | void cell_for_point(const Vec3&, int *i, int *j, int *k); 880 | void maybe_collect_points(Vec3 *v, buffer& close, 881 | ProxGrid_Cell& cell); 882 | public: 883 | ProxGrid(const Vec3& min, const Vec3& max, real dist); 884 | ~ProxGrid() { cells.free(); } 885 | void addPoint(Vec3 *); 886 | void removePoint(Vec3 *); 887 | void proximalPoints(Vec3 *, buffer&); 888 | }; 889 | 890 | extern int face_target; 891 | extern real error_tolerance; 892 | extern bool will_use_plane_constraint; 893 | extern bool will_use_vertex_constraint; 894 | extern bool will_preserve_boundaries; 895 | extern bool will_preserve_mesh_quality; 896 | extern bool will_constrain_boundaries; 897 | extern real boundary_constraint_weight; 898 | extern bool will_weight_by_area; 899 | #define PLACE_ENDPOINTS 0 900 | #define PLACE_ENDORMID 1 901 | #define PLACE_LINE 2 902 | #define PLACE_OPTIMAL 3 903 | extern int placement_policy; 904 | extern real pair_selection_tolerance; 905 | 906 | class Model //: public SMF_Model 907 | { 908 | protected: 909 | vert_buffer vertices; 910 | edge_buffer edges; 911 | face_buffer faces; 912 | private: 913 | void maybeFixFace(Face *); 914 | public: 915 | Model() { } 916 | Bounds bounds; 917 | int validVertCount; 918 | int validEdgeCount; 919 | int validFaceCount; 920 | Vertex *vertex(int i) { return vertices(i); } 921 | Edge *edge(int i) { return edges(i); } 922 | Face *face(int i) { return faces(i); } 923 | int vertCount() { return vertices.length(); } 924 | int edgeCount() { return edges.length(); } 925 | int faceCount() { return faces.length(); } 926 | vert_buffer& allVertices() { return vertices; } 927 | edge_buffer& allEdges() { return edges; } 928 | face_buffer& allFaces() { return faces; } 929 | Vertex *newVertex(real x=0.0, real y=0.0, real z=0.0); 930 | Edge *newEdge(Vertex *,Vertex *); 931 | Face *newFace(Vertex *, Vertex *, Vertex *); 932 | void killVertex(Vertex *); 933 | void killEdge(Edge *); 934 | void killFace(Face *); 935 | void reshapeVertex(Vertex *, real, real, real); 936 | void remapVertex(Vertex *from, Vertex *to); 937 | void contract(Vertex *v1, Vertex *v2, const Vec3& to,face_buffer& changed); 938 | void removeDegeneracy(face_buffer& changed); 939 | void contractionRegion(Vertex *v1, Vertex *v2, face_buffer& changed); 940 | void contractionRegion(Vertex *v1,const vert_buffer& vertices,face_buffer& changed); 941 | int in_Vertex(const Vec3&); 942 | int in_Face(int v1, int v2, int v3); 943 | Vec3 synthesizeNormal(Vertex *); 944 | }; 945 | extern Model M0; 946 | extern Mat4 quadrix_vertex_constraint(const Vec3&); 947 | extern Mat4 quadrix_plane_constraint(real a, real b, real c, real d); 948 | extern Mat4 quadrix_plane_constraint(Face& T); 949 | extern Mat4 quadrix_plane_constraint(const Vec3& n, real); 950 | extern Mat4 quadrix_plane_constraint(const Vec3&, const Vec3&, const Vec3&); 951 | extern real quadrix_evaluate_vertex(const Vec3& v, const Mat4& K); 952 | extern bool check_for_discontinuity(Edge *); 953 | extern Mat4 quadrix_discontinuity_constraint(Edge *, const Vec3&); 954 | extern Mat4 quadrix_discontinuity_constraint(Edge *); 955 | extern bool quadrix_find_local_fit(const Mat4& Q,const Vec3& v1, const Vec3& v2,Vec3& candidate); 956 | extern bool quadrix_find_line_fit(const Mat4& Q,const Vec3& v1, const Vec3& v2,Vec3& candidate); 957 | extern bool quadrix_find_best_fit(const Mat4& Q, Vec3& candidate); 958 | extern real quadrix_pair_target(const Mat4& Q,Vertex *v1,Vertex *v2,Vec3& candidate); 959 | 960 | extern Vertex *decimate_last_v0; 961 | extern Vertex *decimate_last_v1; 962 | extern bool decimate_quadric(Vertex *v, Mat4& Q); 963 | extern real decimate_min_error(); 964 | extern real decimate_max_error(Model& m); 965 | extern real decimate_error(Vertex *); 966 | extern void decimate_contract(Model& m); 967 | extern void decimate_init(Model& m, real limit); 968 | 969 | 970 | 971 | #endif -------------------------------------------------------------------------------- /QSlimCros/QSlimCros.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {AAC1ED99-C116-4FA9-A71D-58E05A7D79D0} 15 | QSlimCros 16 | 17 | 18 | 19 | Application 20 | true 21 | MultiByte 22 | 23 | 24 | Application 25 | false 26 | true 27 | MultiByte 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | Level3 43 | Disabled 44 | 45 | 46 | true 47 | 48 | 49 | 50 | 51 | Level3 52 | MaxSpeed 53 | true 54 | true 55 | 56 | 57 | true 58 | true 59 | true 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /QSlimCros/QSlimCros.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 | 26 | 27 | Header Files 28 | 29 | 30 | Header Files 31 | 32 | 33 | -------------------------------------------------------------------------------- /QSlimCros/QSlimCros.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /QSlimCros/Release/CL.read.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Release/CL.read.1.tlog -------------------------------------------------------------------------------- /QSlimCros/Release/CL.write.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Release/CL.write.1.tlog -------------------------------------------------------------------------------- /QSlimCros/Release/QSlim.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Release/QSlim.obj -------------------------------------------------------------------------------- /QSlimCros/Release/QSlimBase.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Release/QSlimBase.obj -------------------------------------------------------------------------------- /QSlimCros/Release/QSlimCros.Build.CppClean.log: -------------------------------------------------------------------------------- 1 | F:\workspacecsharp\C++Proj\QSlimCros\QSlimCros\Release\cl.command.1.tlog 2 | F:\workspacecsharp\C++Proj\QSlimCros\QSlimCros\Release\CL.read.1.tlog 3 | F:\workspacecsharp\C++Proj\QSlimCros\QSlimCros\Release\CL.write.1.tlog 4 | F:\workspacecsharp\C++Proj\QSlimCros\QSlimCros\Release\link.command.1.tlog 5 | F:\workspacecsharp\C++Proj\QSlimCros\QSlimCros\Release\link.read.1.tlog 6 | F:\workspacecsharp\C++Proj\QSlimCros\QSlimCros\Release\link.write.1.tlog 7 | F:\WORKSPACECSHARP\C++PROJ\QSLIMCROS\QSLIMCROS\RELEASE\MAIN.OBJ 8 | F:\workspacecsharp\C++Proj\QSlimCros\QSlimCros\Release\mt.command.1.tlog 9 | F:\workspacecsharp\C++Proj\QSlimCros\QSlimCros\Release\mt.read.1.tlog 10 | F:\workspacecsharp\C++Proj\QSlimCros\QSlimCros\Release\mt.write.1.tlog 11 | F:\WORKSPACECSHARP\C++PROJ\QSLIMCROS\QSLIMCROS\RELEASE\QSLIM.OBJ 12 | F:\WORKSPACECSHARP\C++PROJ\QSLIMCROS\QSLIMCROS\RELEASE\QSLIMBASE.OBJ 13 | F:\WORKSPACECSHARP\C++PROJ\QSLIMCROS\QSLIMCROS\RELEASE\QSLIMCROS.EXE.INTERMEDIATE.MANIFEST 14 | F:\workspacecsharp\C++Proj\QSlimCros\QSlimCros\Release\QSlimCros.vcxprojResolveAssemblyReference.cache 15 | F:\workspacecsharp\C++Proj\QSlimCros\QSlimCros\Release\QSlimCros.write.1.tlog 16 | F:\WORKSPACECSHARP\C++PROJ\QSLIMCROS\QSLIMCROS\RELEASE\VC100.PDB 17 | F:\WORKSPACECSHARP\C++PROJ\QSLIMCROS\RELEASE\QSLIMCROS.EXE 18 | F:\WORKSPACECSHARP\C++PROJ\QSLIMCROS\RELEASE\QSLIMCROS.PDB 19 | -------------------------------------------------------------------------------- /QSlimCros/Release/QSlimCros.exe.intermediate.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /QSlimCros/Release/QSlimCros.lastbuildstate: -------------------------------------------------------------------------------- 1 | #v4.0:v100:false 2 | Release|Win32|F:\workspacecsharp\RecentProject\SimplifiedQSlimLibrary\| 3 | -------------------------------------------------------------------------------- /QSlimCros/Release/QSlimCros.log: -------------------------------------------------------------------------------- 1 | Build started 2014/2/14 20:57:57. 2 | 1>Project "F:\workspacecsharp\RecentProject\SimplifiedQSlimLibrary\QSlimCros\QSlimCros.vcxproj" on node 2 (build target(s)). 3 | 1>InitializeBuildStatus: 4 | Creating "Release\QSlimCros.unsuccessfulbuild" because "AlwaysCreate" was specified. 5 | ClCompile: 6 | D:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\CL.exe /c /Zi /nologo /W3 /WX- /O2 /Oi /Oy- /GL /D _MBCS /Gm- /EHsc /MD /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Fo"Release\\" /Fd"Release\vc100.pdb" /Gd /TP /analyze- /errorReport:prompt main.cpp QSlim.cpp 7 | main.cpp 8 | QSlim.cpp 9 | Link: 10 | D:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\link.exe /ERRORREPORT:PROMPT /OUT:"F:\workspacecsharp\RecentProject\SimplifiedQSlimLibrary\Release\QSlimCros.exe" /NOLOGO kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /MANIFEST /ManifestFile:"Release\QSlimCros.exe.intermediate.manifest" /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"F:\workspacecsharp\RecentProject\SimplifiedQSlimLibrary\Release\QSlimCros.pdb" /OPT:REF /OPT:ICF /LTCG /TLBID:1 /DYNAMICBASE /NXCOMPAT /IMPLIB:"F:\workspacecsharp\RecentProject\SimplifiedQSlimLibrary\Release\QSlimCros.lib" /MACHINE:X86 Release\main.obj 11 | Release\QSlim.obj 12 | Generating code 13 | Finished generating code 14 | QSlimCros.vcxproj -> F:\workspacecsharp\RecentProject\SimplifiedQSlimLibrary\Release\QSlimCros.exe 15 | Manifest: 16 | C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\mt.exe /nologo /verbose /outputresource:"F:\workspacecsharp\RecentProject\SimplifiedQSlimLibrary\Release\QSlimCros.exe;#1" /manifest Release\QSlimCros.exe.intermediate.manifest 17 | FinalizeBuildStatus: 18 | Deleting file "Release\QSlimCros.unsuccessfulbuild". 19 | Touching "Release\QSlimCros.lastbuildstate". 20 | 1>Done Building Project "F:\workspacecsharp\RecentProject\SimplifiedQSlimLibrary\QSlimCros\QSlimCros.vcxproj" (build target(s)). 21 | 22 | Build succeeded. 23 | 24 | Time Elapsed 00:00:01.65 25 | -------------------------------------------------------------------------------- /QSlimCros/Release/QSlimCros.vcxprojResolveAssemblyReference.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Release/QSlimCros.vcxprojResolveAssemblyReference.cache -------------------------------------------------------------------------------- /QSlimCros/Release/QSlimCros.write.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Release/QSlimCros.write.1.tlog -------------------------------------------------------------------------------- /QSlimCros/Release/cl.command.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Release/cl.command.1.tlog -------------------------------------------------------------------------------- /QSlimCros/Release/link.command.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Release/link.command.1.tlog -------------------------------------------------------------------------------- /QSlimCros/Release/link.read.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Release/link.read.1.tlog -------------------------------------------------------------------------------- /QSlimCros/Release/link.write.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Release/link.write.1.tlog -------------------------------------------------------------------------------- /QSlimCros/Release/main.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Release/main.obj -------------------------------------------------------------------------------- /QSlimCros/Release/mt.command.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Release/mt.command.1.tlog -------------------------------------------------------------------------------- /QSlimCros/Release/mt.read.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Release/mt.read.1.tlog -------------------------------------------------------------------------------- /QSlimCros/Release/mt.write.1.tlog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Release/mt.write.1.tlog -------------------------------------------------------------------------------- /QSlimCros/Release/vc100.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/QSlimCros/Release/vc100.pdb -------------------------------------------------------------------------------- /QSlimCros/main.cpp: -------------------------------------------------------------------------------- 1 | #include "Mesh.h" 2 | #include "QSlim.h" 3 | 4 | static void qslim_init() 5 | { 6 | int i; 7 | cerr << "Reading input ..." << endl; 8 | cerr << "Cleaning up initial input ..." << endl; 9 | int initialVertCount = M0.vertCount(); 10 | int initialEdgeCount = M0.edgeCount(); 11 | int initialFaceCount = M0.faceCount(); 12 | for(i=0; iplane().isValid() ) 14 | M0.killFace(M0.face(i)); 15 | M0.removeDegeneracy(M0.allFaces()); 16 | for(i=0; iedgeUses().length() == 0 ) 19 | M0.vertex(i)->kill(); 20 | } 21 | cerr << "Input model summary:" << endl; 22 | cerr << " Vertices : " << initialVertCount << endl; 23 | cerr << " Edges : " << initialEdgeCount << endl; 24 | int man=0, non=0, bndry=0, bogus=0; 25 | for(i=0; ifaceUses().length() ) 27 | { 28 | case 0: 29 | bogus++; 30 | break; 31 | case 1: 32 | bndry++; 33 | break; 34 | case 2: 35 | man++; 36 | break; 37 | default: 38 | non++; 39 | break; 40 | } 41 | if( bogus ) 42 | cerr << " Bogus : " << bogus << endl; 43 | cerr << " Boundary : " << bndry << endl; 44 | cerr << " Manifold : " << man << endl; 45 | cerr << " Nonmanifold : " << non << endl; 46 | 47 | cerr << " Faces : " << initialFaceCount << endl; 48 | } 49 | static void qslim_run() 50 | { 51 | decimate_init(M0, pair_selection_tolerance); 52 | while( M0.validFaceCount > face_target&& decimate_min_error() < error_tolerance ) 53 | decimate_contract(M0); 54 | } 55 | static void InitM0(Mesh& m) 56 | { 57 | for(size_t i=0;i()); 72 | m.Faces.swap(std::vector()); 73 | m.Vertices.reserve(M0.vertCount()); 74 | m.Faces.reserve(M0.faceCount()); 75 | int* map=new int[M0.vertCount()]; 76 | for(int i=0;iisValid()) 81 | { 82 | real* data=M0.vertex(i)->raw(); 83 | Point3d p((float)data[0],(float)data[1],(float)data[2]); 84 | map[i]=m.AddVertex(p); 85 | } 86 | } 87 | for(int i=0;iisValid()) 90 | { 91 | Vertex* v0= M0.face(i)->vertex(0); 92 | Vertex* v1= M0.face(i)->vertex(1); 93 | Vertex* v2= M0.face(i)->vertex(2); 94 | Triangle t(map[v0->uniqID],map[v1->uniqID],map[v2->uniqID]); 95 | m.AddFace(t); 96 | } 97 | } 98 | delete[] map; 99 | } 100 | 101 | int main() 102 | { 103 | Mesh m; 104 | PlyManager::ReadFile(m,"D:\\VTKproj\\sample.ply"); 105 | InitM0(m); 106 | qslim_init(); 107 | face_target = 2*m.Faces.size()/3; 108 | error_tolerance = HUGE; 109 | will_use_plane_constraint = true; 110 | will_use_vertex_constraint = false; 111 | will_preserve_boundaries = true; 112 | will_preserve_mesh_quality = true; 113 | will_constrain_boundaries = true; 114 | boundary_constraint_weight = 1.0; 115 | will_weight_by_area = false; 116 | placement_policy = 1; 117 | pair_selection_tolerance = 0.0; 118 | qslim_run(); 119 | ReplaceM(m); 120 | PlyManager::Output(m,"D:\\VTKproj\\sample_deci.ply"); 121 | 122 | return 0; 123 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SimplifiedQSlimLibrary 2 | ====================== 3 | 4 | Simplified QSlim Library Code Blocks (QSlim库简化版本,兼容了标准Mesh定义,剥离了冗余代码) 5 | -------------------------------------------------------------------------------- /Release/QSlimCros.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/Release/QSlimCros.exe -------------------------------------------------------------------------------- /Release/QSlimCros.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/Release/QSlimCros.pdb -------------------------------------------------------------------------------- /ipch/qslimcros-8cef9581/qslimcros-3f8e8143.ipch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chnhideyoshi/SimplifiedQSlimLibrary/a982f7ea23b1097b4182d434295a178d2b2dd9fe/ipch/qslimcros-8cef9581/qslimcros-3f8e8143.ipch --------------------------------------------------------------------------------