forked from LeonGiering/gp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
halfedge.ts
146 lines (133 loc) · 5.09 KB
/
halfedge.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// Copyright (c) 2021 LMU Munich Geometry Processing Authors. All rights reserved.
// Created by Changkun Ou <https://changkun.de>.
//
// Use of this source code is governed by a GNU GPLv3 license that can be found
// in the LICENSE file.
// API Usage about @penrose/linear-algebra:
//
// - There are two types of matrices: SparseMatrix and DenseMatrix
// - SparseMatrix.identity(n, n) gives you a identity matrix with
// n x n dimension
// - Triplet represents a small structure to hold non-zero entries in
// SparseMatrix, each entry is (x, i, j). To construct a SparseMatrix,
// here is an example:
//
// let A = new Triplet(2, 2) // Triplet for 2x2 SparseMatrix
// A.addEntry(1, 0, 0) // A(0, 0) += 1
// A.addEntry(2, 1, 1) // A(1, 1) += 2
// return SparseMatrix.fromTriplet(T) // Construct SparseMatrix
//
// - A.timesSparse(B) returns A*B where A and B are SparseMatrix.
// - A.plus(B) returns A+B where A and B are SparseMatrix.
// - A.timesReal(s) returns sA where A is SparseMatrix and s is a real number.
// - A.chol() returns a sparse Cholesky decomposition.
// - A.solvePositiveDefinite(b) solves linear equation Ax=b where
// A is a Cholesky decomposition, and b is a DenseMatrix, and x is the solution.
// - For a DenseMatrix A, one can use A.set(x, i, j) for A(i,j)=x,
// and A.get(i, j) returns A(i,j).
//
// Further APIs regarding @penrose/linear-algebra can be found
// in node_modules/@penrose/linear-algebra/docs/*.html, but the above
// information are all the APIs you need for this project.
import {SparseMatrix, DenseMatrix, Triplet} from '@penrose/linear-algebra';
import {Vertex, Edge, Face, Halfedge} from './primitive';
import {Vector} from '../linalg/vec';
export enum WeightType {
Uniform = 'Uniform',
Cotan = 'Cotan',
}
export class HalfedgeMesh {
color: Vector;
wireframe: Vector;
// The following four fields are the key fields to represent half-edge based
// meshes.
vertsOrig: Vertex[]; // The original copy of all vertex positions
verts: Vertex[]; // The current vertex that are updated after smooth for actual rendering
edges: Edge[]; // a list of edges
faces: Face[]; // a list of faces
halfedges: Halfedge[]; // a list of halfedges
/**
* constructor constructs the halfedge-based mesh representation.
*
* @param {string} data is a text string from an .obj file
*/
constructor(data: string) {
this.color = new Vector(0, 128, 255, 1);
this.wireframe = new Vector(125, 125, 125, 1);
// load .obj file
const indices: number[] = [];
const positions: Vector[] = [];
const lines = data.split('\n');
for (let line of lines) {
line = line.trim();
const tokens = line.split(' ');
switch (tokens[0].trim()) {
case 'v':
positions.push(
new Vector(
parseFloat(tokens[1]),
parseFloat(tokens[2]),
parseFloat(tokens[3]),
1
)
);
break;
case 'f':
// only load indices of vertices
for (let i = 1; i < tokens.length; i++) {
const vv = tokens[i].split('/');
indices.push(parseInt(vv[0]) - 1);
}
break;
}
}
this.vertsOrig = [];
this.verts = [];
this.edges = [];
this.faces = [];
this.halfedges = [];
this.buildMesh(indices, positions);
}
/**
* buildMesh builds half-edge based connectivity for the given vertex index buffer
* and vertex position buffer.
*
* @param indices is the vertex index buffer that contains all vertex indices.
* @param positions is the vertex buffer that contains all vertex positions.
*/
buildMesh(indices: number[], positions: Vector[]) {
// TODO: use the halfedge structrue implementation from Homework 1.
// We assume the input mesh is a manifold mesh.
}
/**
* smooth performs the Laplacian smoothing algorithm.
* @param weightType indicates the type of the weight for
* constructing the Laplace matrix. Possible value could be: 'uniform',
* 'cotan'.
* @param timeStep the time step in Laplacian Smoothing algorithm
* @param smoothStep the smooth step in Laplacian Smoothing algorithm
*/
smooth(weightType: WeightType, timeStep: number, smoothStep: number) {
// TODO: implmeent the Laplacian smoothing algorithm.
//
// Hint:
//
// 1. Build f(t)
// 2. Build the mass matrix `M`
// 3. Build the Laplace weight matrix `W` for the given `weightType` in laplaceWeightMatrix
// 4. Solve linear system (M - tλW)f' = Mf using a Cholesky solver.
// 5. Update the position of mesh vertices based on the solution f'.
//
}
/**
* laplaceWeightMatrix returns the Laplace weight matrix for a given laplaceType
* @param weightType indicates the type of the weight for
* constructing the Laplace matrix.
*/
laplaceWeightMatrix(weightType: WeightType) {
// TODO: implement laplacian matrix for a given weight type.
//
// Hint: To avoid numeric issue when solving linear equation,
// add 1e-8 to all elements.
}
}