Skip to content

Commit

Permalink
Update layer display
Browse files Browse the repository at this point in the history
  • Loading branch information
David Jourdan committed Oct 17, 2024
2 parents d284fbd + ffcbfe7 commit 08e1c9c
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 107 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ list(APPEND CMAKE_MODULE_PATH "${SHRINK_MORPH_ROOT}/cmake")

add_subdirectory(lib)

option(PYTHON_APP ON)
option(PYTHON_BINDINGS ON)

if(${PYTHON_BINDINGS})
add_subdirectory(python)
Expand Down
151 changes: 79 additions & 72 deletions lib/path_extraction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,91 +181,98 @@ void writePaths(const std::string& filename, const std::vector<std::vector<Vecto
}
}

std::vector<std::vector<std::vector<geometrycentral::Vector3>>> generatePaths(EmbeddedGeometryInterface& geometry,
const Eigen::VectorXd& theta1,
const Eigen::VectorXd& theta2,
double layerHeight,
int nLayers,
double spacing)
std::vector<std::vector<geometrycentral::Vector3>> generateOneLayer(EmbeddedGeometryInterface& geometry,
const Eigen::VectorXd& theta1,
const Eigen::VectorXd& theta2,
const Eigen::SparseMatrix<double> &massMatrix,
Eigen::VectorXd& u,
LDLTSolver &solver,
int i,
int nLayers,
double layerHeight,
double spacing)
{
std::vector<std::vector<std::vector<Vector3>>> paths;

LDLTSolver solver;

SparseMatrix<double> massMatrix = computeRealVertexMassMatrix(geometry);
geometry.requireVertexTangentBasis();
SurfaceMesh& mesh = geometry.mesh;
VertexData<double> frequencies(mesh, 1.0 / spacing);

Vector<double> u = Vector<double>::Random(mesh.nVertices() * 2);
for(int i = 0; i < nLayers / 2; ++i)
// compute direction field
VertexData<Vector2> directionField(mesh);
for(size_t j = 0; j < mesh.nVertices(); ++j)
{
Timer timer("Layers " + std::to_string(2 * i) + " and " + std::to_string(2 * i + 1));
geometry.requireVertexTangentBasis();

// compute direction field
VertexData<Vector2> directionField(mesh);
for(size_t j = 0; j < mesh.nVertices(); ++j)
{
// interpolate orientations w.r.t layer
directionField[j] = Vector2::fromAngle(2 * (theta1(j) + (i / (nLayers / 2 - 1.) - 1 / 2.) * theta2(j)));
// express vectors in their respective vertex local bases (the stripes algorithm expects that)
auto basisVector = geometry.vertexTangentBasis[j][0];
Vector2 base{basisVector.x, basisVector.y};
directionField[j] = -directionField[j] / base.pow(2);
}
// interpolate orientations w.r.t layer
directionField[j] = Vector2::fromAngle(2 * (theta1(j) + (i / (nLayers - 1.) - 1 / 2.) * theta2(j)));
// express vectors in their respective vertex local bases (the stripes algorithm expects that)
auto basisVector = geometry.vertexTangentBasis[j][0];
Vector2 base{basisVector.x, basisVector.y};
directionField[j] = -directionField[j] / base.pow(2);
}

// build matrices and factorize solver
FaceData<int> fieldIndices = computeFaceIndex(geometry, directionField, 2);
SparseMatrix<double> energyMatrix =
buildVertexEnergyMatrix(geometry, directionField, fieldIndices, 2 * PI * frequencies);
if(i == 0)
solver.compute(energyMatrix);
else
solver.factorize(energyMatrix);
// build matrices and factorize solver
FaceData<int> fieldIndices = computeFaceIndex(geometry, directionField, 2);
SparseMatrix<double> energyMatrix =
buildVertexEnergyMatrix(geometry, directionField, fieldIndices, 2 * PI * frequencies);
if(i == 0)
solver.compute(energyMatrix);
else
solver.factorize(energyMatrix);

// solve the eigenvalue problem
Vector<double> x = u;
double residual = eigenvectorResidual(energyMatrix, massMatrix, x);
const double tol = 1e-5;
while(residual > tol)
{
// Solve
Vector<double> rhs = massMatrix * u;
x = solver.solve(rhs);
// solve the eigenvalue problem
Vector<double> x;
double residual = eigenvectorResidual(energyMatrix, massMatrix, u);
const double tol = 1e-5;
while(residual > tol)
{
// Solve
Vector<double> rhs = massMatrix * u;
x = solver.solve(rhs);

// Re-normalize
double scale = std::sqrt(std::abs(x.dot(massMatrix * x)));
x /= scale;
// Re-normalize
double scale = std::sqrt(std::abs(x.dot(massMatrix * x)));
x /= scale;

// Update
u = x;
residual = eigenvectorResidual(energyMatrix, massMatrix, x);
}
// Update
u = x;
residual = eigenvectorResidual(energyMatrix, massMatrix, x);
}

// Copy the result to a VertexData vector
VertexData<Vector2> parameterization(mesh);
for(size_t j = 0; j < mesh.nVertices(); ++j)
{
parameterization[j].x = u(2 * j);
parameterization[j].y = u(2 * j + 1);
}
// Copy the result to a VertexData vector
VertexData<Vector2> parameterization(mesh);
for(size_t j = 0; j < mesh.nVertices(); ++j)
{
parameterization[j].x = u(2 * j);
parameterization[j].y = u(2 * j + 1);
}

CornerData<double> stripeValues;
FaceData<int> stripeIndices;
std::tie(stripeValues, stripeIndices) =
computeTextureCoordinates(geometry, directionField, 2 * PI * frequencies, parameterization);
CornerData<double> stripeValues;
FaceData<int> stripeIndices;
std::tie(stripeValues, stripeIndices) =
computeTextureCoordinates(geometry, directionField, 2 * PI * frequencies, parameterization);

// extract isolines
const auto& [points, edges] =
extractPolylinesFromStripePattern(geometry, stripeValues, stripeIndices, fieldIndices, directionField);
auto polylines = edgeToPolyline(points, edges);
polylines = orderPolylines(polylines);
return simplifyPolylines(polylines, (i + 1) * layerHeight);
}

// extract isolines
for(int j = 0; j < 2; ++j)
{
const auto& [points, edges] = extractPolylinesFromStripePattern(geometry, stripeValues + j * PI, stripeIndices,
fieldIndices, directionField);
auto polylines = edgeToPolyline(points, edges);
polylines = orderPolylines(polylines);
paths.push_back(simplifyPolylines(polylines, (2 * i + j) * layerHeight));
}
std::vector<std::vector<std::vector<geometrycentral::Vector3>>> generatePaths(EmbeddedGeometryInterface& geometry,
const Eigen::VectorXd& theta1,
const Eigen::VectorXd& theta2,
double layerHeight,
int nLayers,
double spacing)
{
std::vector<std::vector<std::vector<Vector3>>> paths;
SparseMatrix<double> massMatrix = computeRealVertexMassMatrix(geometry);
LDLTSolver solver;
Vector<double> u = Vector<double>::Random(geometry.mesh.nVertices() * 2);
for(int i = 0; i < nLayers; ++i)
{
Timer timer("Layer " + std::to_string(i));
paths.push_back(generateOneLayer(geometry, theta1, theta2, massMatrix, u, solver, i, nLayers, layerHeight, spacing));
}

return paths;
}

Expand Down
11 changes: 11 additions & 0 deletions lib/path_extraction.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ generatePaths(geometrycentral::surface::EmbeddedGeometryInterface& geometry,
int nLayers,
double spacing);

std::vector<std::vector<geometrycentral::Vector3>> generateOneLayer(geometrycentral::surface::EmbeddedGeometryInterface& geometry,
const Eigen::VectorXd& theta1,
const Eigen::VectorXd& theta2,
const Eigen::SparseMatrix<double>& massMatrix,
Eigen::VectorXd& u,
LDLTSolver& solver,
int i,
int nLayers,
double layerHeight,
double spacing);

void writePaths(const std::string& filename,
const std::vector<std::vector<geometrycentral::Vector3>>& paths,
double height);
Expand Down
43 changes: 32 additions & 11 deletions python/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ def callback_optim(self):
if gui.Button("Generate trajectories"):
self.leave = False
ps.unshow()

def traj_screen(self):
# Trajectories & G-code generation
if self.resolution == "Low":
Expand All @@ -254,36 +254,44 @@ def traj_screen(self):
elif self.resolution == "High":
target_edge_length = 0.2
self.V, self.P, self.F, self.theta2 = shrink_morph_py.subdivide(self.V, self.P, self.F, self.theta2, target_edge_length)
self.trajectories = shrink_morph_py.generate_trajectories(self.V, self.P, self.F, self.theta2, self.printer.layer_height, self.printer.nozzle_width, self.n_layers)
self.theta1 = shrink_morph_py.vertex_based_stretch_angles(self.V, self.P, self.F)
self.stripe = shrink_morph_py.StripeAlgo(self.P, self.F)
self.trajectories = []
self.trajectories = self.trajectories + self.stripe.generate_one_layer(self.P, self.F, self.theta1, self.theta2, self.printer.layer_height, self.printer.nozzle_width, self.n_layers, 0)
# self.trajectories = shrink_morph_py.generate_trajectories(self.P, self.F, theta1, self.theta2, self.printer.layer_height, self.printer.nozzle_width, self.n_layers)
ps.remove_all_structures();

self.display_trajectories()
self.display_buildplate()

ps.set_user_callback(self.callback_traj)
ps.reset_camera_to_home_view()
ps.show()
ps.show()

def display_trajectories(self):
nodes = self.trajectories[0]
edges = np.empty([nodes.shape[0] - 1, 2])
edges[:, 0] = np.arange(nodes.shape[0] - 1)
edges[:, 1] = np.arange(1, nodes.shape[0])
colors = np.zeros(nodes.shape[0])
# colors = np.zeros(nodes.shape[0])
path_id = 1
self.layer_nodes = []
self.layer_edges = []

h = nodes[0,2]
k = 1
for traj in self.trajectories:
if traj[0, 2] > h:
ps_traj = ps.register_curve_network("Layer " + str(k), nodes, edges, enabled=False)
self.layer_nodes.append(nodes)
self.layer_edges.append(edges)
ps_traj.set_radius(self.printer.nozzle_width / 2, relative=False)
ps_traj.add_scalar_quantity("Ordering", colors, enabled=True, cmap="blues")
# ps_traj.add_scalar_quantity("Ordering", colors, enabled=True, cmap="blues")
nodes = traj
edges = np.empty([nodes.shape[0] - 1, 2])
edges[:, 0] = np.arange(nodes.shape[0] - 1)
edges[:, 1] = np.arange(1, nodes.shape[0])
colors = np.zeros(nodes.shape[0])
# colors = np.zeros(nodes.shape[0])

h = nodes[0,2]
path_id = 1
Expand All @@ -295,17 +303,26 @@ def display_trajectories(self):

nodes = np.vstack((nodes, traj))
edges = np.vstack((edges, new_edges))
colors = np.hstack((colors, path_id * np.ones(traj.shape[0])))
# colors = np.hstack((colors, path_id * np.ones(traj.shape[0])))
path_id += 1

self.layer_nodes.append(nodes)
self.layer_edges.append(edges)
ps_traj = ps.register_curve_network("Layer " + str(k), nodes, edges, enabled=True, radius=self.printer.nozzle_width / 2)
ps_traj.add_scalar_quantity("Ordering", colors, enabled=True, cmap="blues")
# ps_traj.add_scalar_quantity("Ordering", colors, enabled=True, cmap="blues")
ps_traj.set_radius(self.printer.nozzle_width / 2, relative=False)


layer_id = 1
progress = 1
curr_layer = 1
def callback_traj(self):
# global self.layer_id, self.V, self.P, self.F, self.theta2, self.printer_profile, self.trajectories, self.printer
if self.curr_layer < self.n_layers:
self.trajectories = self.trajectories + self.stripe.generate_one_layer(self.P, self.F, self.theta1, self.theta2, self.printer.layer_height, self.printer.nozzle_width, self.n_layers, self.curr_layer)
self.curr_layer = self.curr_layer + 1
self.display_trajectories()

gui.PushItemWidth(200)
changed = gui.BeginCombo("Select self.printer", self.printer_profile)
if changed:
Expand All @@ -322,18 +339,22 @@ def callback_traj(self):
self.V, self.P, self.F, self.theta2 = shrink_morph_py.subdivide(self.V, self.P, self.F, self.theta2)
ps.remove_all_structures();
self.trajectories = shrink_morph_py.generate_trajectories(self.V, self.P, self.F, self.theta2, self.printer.layer_height, self.printer.nozzle_width, self.n_layers)
self.display_trajectories(self.trajectories)
self.display_trajectories()
self.display_buildplate()

gui.PushItemWidth(200)
changed, self.layer_id = gui.SliderInt("Layer", self.layer_id, 1, self.n_layers)
gui.PopItemWidth()
changed, self.layer_id = gui.SliderInt("Layer", self.layer_id, 1, self.curr_layer)
if changed:
for i in range(1, self.n_layers + 1):
if i == self.layer_id:
ps.get_curve_network("Layer " + str(i)).set_enabled(True)
else:
ps.get_curve_network("Layer " + str(i)).set_enabled(False)
changed, self.progress = gui.SliderInt("Progress", self.progress, 1, self.layer_edges[self.layer_id - 1].shape[0])
gui.PopItemWidth()
if changed:
d = int(np.max(self.layer_edges[self.layer_id - 1][:self.progress, :])) + 1
ps.register_curve_network("Layer " + str(self.layer_id), self.layer_nodes[self.layer_id - 1][:d, :], self.layer_edges[self.layer_id - 1][:self.progress, :])
if gui.Button("Export to g-code"):
filename = filedialog.asksaveasfilename(defaultextension='.gcode')
self.printer.to_gcode(self.trajectories, filename)
Expand Down
Loading

0 comments on commit 08e1c9c

Please sign in to comment.