Skip to content

Commit ccf1856

Browse files
committed
Refactor: enhance BevelEdgesModifier with improved structure and edge
processing - Introduced `EdgeProcessor` as a dedicated utility class to manage edge mapping and processing, improving modularity and encapsulation. - Replaced redundant logic in old edge processing with a cleaner, reusable approach. - Simplified the `toReverseArray` method and corrected its behavior to properly reverse the list order. - Improved readability by adding clear method-level documentation for inset face and edge processing steps. - Optimized `createFacesVertex` with enhanced traversal logic using `EdgeProcessor`. - Streamlined vertex inset calculation to handle width types consistently, adhering to geometric principles. - Consolidated internal collections (e.g., `processed`, `oldEdgeToNewEdge`) into `EdgeProcessor` for better abstraction and easier maintenance. - Maintained functionality for inset and bevel edge creation while improving code structure, efficiency, and maintainability.
1 parent b3032df commit ccf1856

File tree

1 file changed

+149
-105
lines changed

1 file changed

+149
-105
lines changed

src/main/java/mesh/modifier/BevelEdgesModifier.java

Lines changed: 149 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,7 @@ public class BevelEdgesModifier implements IMeshModifier {
1717

1818
public enum WidthType {
1919

20-
OFFSET,
21-
22-
WIDTH,
23-
24-
DEPTH,
20+
OFFSET, WIDTH, DEPTH
2521

2622
}
2723

@@ -37,14 +33,11 @@ public enum WidthType {
3733

3834
private List<Vector3f> verticesToAdd;
3935

40-
private HashMap<Edge3D, Edge3D> oldEdgeToNewEdge;
41-
42-
private HashSet<Edge3D> processed;
36+
private EdgeProcessor edgeProcessor;
4337

4438
public BevelEdgesModifier(float amount) {
4539
setAmount(amount);
46-
processed = new HashSet<>();
47-
oldEdgeToNewEdge = new HashMap<>();
40+
edgeProcessor = new EdgeProcessor();
4841
verticesToAdd = new ArrayList<Vector3f>();
4942
facesToAdd = new ArrayList<Face3D>();
5043
}
@@ -55,81 +48,26 @@ public BevelEdgesModifier() {
5548

5649
@Override
5750
public Mesh3D modify(Mesh3D mesh) {
58-
if (amount == 0)
51+
validateMesh(mesh);
52+
if (canExitEarly(mesh)) {
5953
return mesh;
54+
}
55+
6056
setMesh(mesh);
6157
clearAll();
58+
6259
createInsetFaces();
60+
6361
createFacesForOldEdges();
6462
createFacesVertex();
63+
6564
clearOriginalFaces();
6665
clearOriginalVertices();
66+
6767
addNewVertices();
6868
addNewFaces();
69-
return mesh;
70-
}
71-
72-
private void createInsetFaces() {
73-
for (Face3D face : mesh.faces)
74-
insetFace(mesh, face);
75-
}
76-
77-
private void insetFace(Mesh3D mesh, Face3D face) {
78-
int nextVertexIndex = verticesToAdd.size();
79-
int[] indices = createIndices(face.indices.length, nextVertexIndex);
80-
List<Vector3f> vertices = new ArrayList<Vector3f>();
81-
extracted(face, vertices);
82-
extracted(vertices);
83-
mapOldEdgesToNewEdges(face, indices);
84-
addNewFace(indices);
85-
}
86-
87-
private void extracted(Face3D face, List<Vector3f> vertices) {
88-
for (int i = 0; i < face.indices.length; i++) {
89-
Vector3f from = getVertexAt(face, i);
90-
Vector3f to = getVertexAt(face, i + 1);
91-
92-
float distance = to.distance(from);
93-
float a = 1 / distance * getAmountByWidthType();
94-
95-
Vector3f v4 = to.subtract(from).mult(a).add(from);
96-
Vector3f v5 = to.add(to.subtract(from).mult(-a));
9769

98-
vertices.add(v4);
99-
vertices.add(v5);
100-
}
101-
}
102-
103-
private float getAmountByWidthType() {
104-
float a;
105-
switch (widthType) {
106-
case OFFSET:
107-
// amount is offset of new edges from original
108-
a = amount * 2;
109-
break;
110-
case WIDTH:
111-
// amount is width of new faces
112-
a = inset;
113-
break;
114-
case DEPTH:
115-
a = inset * 2;
116-
break;
117-
default:
118-
// default width type offset
119-
a = amount * 2;
120-
break;
121-
}
122-
return a;
123-
}
124-
125-
private void extracted(List<Vector3f> vertices) {
126-
for (int i = 1; i < vertices.size(); i += 2) {
127-
int a = vertices.size() - 2 + i;
128-
Vector3f v0 = vertices.get(a % vertices.size());
129-
Vector3f v1 = vertices.get((a + 1) % vertices.size());
130-
Vector3f v = v1.add(v0).mult(0.5f);
131-
verticesToAdd.add(v);
132-
}
70+
return mesh;
13371
}
13472

13573
private void createFacesVertex() {
@@ -139,7 +77,7 @@ private void createFacesVertex() {
13977
Edge3D edge = outgoingEdge;
14078
List<Integer> indices = new ArrayList<Integer>();
14179
do {
142-
Edge3D newEdge = oldEdgeToNewEdge.get(edge);
80+
Edge3D newEdge = edgeProcessor.getMappedEdge(edge);
14381
int index = newEdge.fromIndex;
14482
indices.add(index);
14583
edge = helper.getPairNext(edge.fromIndex, edge.toIndex);
@@ -155,33 +93,46 @@ private void createFacesForOldEdges() {
15593
}
15694

15795
private void createFaceForOldEdgeAt(Face3D face, int i) {
158-
Edge3D edge = getMappedEdge(createEdgeAt(face.indices, i));
159-
Edge3D pair = getMappedEdge(createEdgeAt(face.indices, i).createPair());
96+
Edge3D edge = edgeProcessor
97+
.getMappedEdge(edgeProcessor.createEdge(face.indices, i));
98+
Edge3D pair = edgeProcessor
99+
.getMappedEdge(edgeProcessor.createEdge(face.indices, i).createPair());
160100

161-
if (isProcessed(edge) || isProcessed(pair))
101+
if (edgeProcessor.isProcessed(edge) || edgeProcessor.isProcessed(pair))
162102
return;
163103

164-
addNewFace(new int[] { edge.toIndex, edge.fromIndex, pair.toIndex,
165-
pair.fromIndex });
104+
createFaceForEdge(edge, pair);
166105

167-
markAsProcessed(edge);
168-
markAsProcessed(pair);
106+
edgeProcessor.markProcessed(edge);
107+
edgeProcessor.markProcessed(pair);
169108
}
170109

171-
private void mapOldEdgesToNewEdges(Face3D face, int[] indices) {
172-
for (int i = 0; i < indices.length; i++) {
173-
Edge3D oldEdge = createEdgeAt(face.indices, i);
174-
Edge3D newEdge = createEdgeAt(indices, i);
175-
oldEdgeToNewEdge.put(oldEdge, newEdge);
176-
}
110+
private void createFaceForEdge(Edge3D edge, Edge3D pair) {
111+
addNewFace(edge.toIndex, edge.fromIndex, pair.toIndex, pair.fromIndex);
177112
}
178113

179-
private Edge3D getMappedEdge(Edge3D edge) {
180-
return oldEdgeToNewEdge.get(edge);
114+
private int[] toReverseArray(List<Integer> values) {
115+
Collections.reverse(values);
116+
return values.stream().mapToInt(x -> x).toArray();
181117
}
182118

183-
private Edge3D createEdgeAt(int[] indices, int i) {
184-
return new Edge3D(indices[i], indices[(i + 1) % indices.length]);
119+
private void clearAll() {
120+
edgeProcessor.clearAll();
121+
verticesToAdd.clear();
122+
facesToAdd.clear();
123+
}
124+
125+
private void createInsetFaces() {
126+
for (Face3D face : mesh.faces)
127+
insetFace(mesh, face);
128+
}
129+
130+
private void insetFace(Mesh3D mesh, Face3D face) {
131+
int nextVertexIndex = verticesToAdd.size();
132+
int[] indices = createIndices(face.indices.length, nextVertexIndex);
133+
createInsetVertices(processFaceEdges(face));
134+
edgeProcessor.mapOldEdgesToNewEdges(face, indices);
135+
addNewFace(indices);
185136
}
186137

187138
private int[] createIndices(int size, int nextVertexIndex) {
@@ -191,24 +142,75 @@ private int[] createIndices(int size, int nextVertexIndex) {
191142
return indices;
192143
}
193144

194-
private int[] toReverseArray(List<Integer> values) {
195-
return values.stream().sorted(Collections.reverseOrder()).mapToInt(x -> x)
196-
.toArray();
145+
/**
146+
* Processes the edges of a face to calculate the new inset vertices.
147+
*
148+
* @param face the face to process.
149+
* @return a list of inset vertices.
150+
*/
151+
private List<Vector3f> processFaceEdges(Face3D face) {
152+
List<Vector3f> vertices = new ArrayList<>();
153+
for (int i = 0; i < face.indices.length; i++) {
154+
Vector3f from = getVertexAt(face, i);
155+
Vector3f to = getVertexAt(face, i + 1);
156+
157+
float edgeLength = to.distance(from);
158+
float insetFactor = calculateInsetFactor(edgeLength);
159+
160+
Vector3f v4 = to.subtract(from).mult(insetFactor).add(from);
161+
Vector3f v5 = to.add(to.subtract(from).mult(-insetFactor));
162+
163+
vertices.add(v4);
164+
vertices.add(v5);
165+
}
166+
return vertices;
197167
}
198168

199-
private void clearAll() {
200-
processed.clear();
201-
oldEdgeToNewEdge.clear();
202-
verticesToAdd.clear();
203-
facesToAdd.clear();
169+
/**
170+
* Creates the inset vertices from the processed edge vertices.
171+
*
172+
* @param vertices the processed edge vertices.
173+
*/
174+
private void createInsetVertices(List<Vector3f> vertices) {
175+
for (int i = 1; i < vertices.size(); i += 2) {
176+
int a = vertices.size() - 2 + i;
177+
Vector3f v0 = vertices.get(a % vertices.size());
178+
Vector3f v1 = vertices.get((a + 1) % vertices.size());
179+
Vector3f v = v1.add(v0).mult(0.5f);
180+
verticesToAdd.add(v);
181+
}
204182
}
205183

206-
private void markAsProcessed(Edge3D edge) {
207-
processed.add(edge);
184+
/**
185+
* Calculates the inset factor based on the edge length and
186+
* #{@link WidthType}.
187+
*
188+
* @param edgeLength the length of the edge.
189+
* @return the inset factor.
190+
*/
191+
private float calculateInsetFactor(float edgeLength) {
192+
return edgeLength > 0 ? (1f / edgeLength) * getAmountByWidthType() : 0f;
208193
}
209194

210-
private boolean isProcessed(Edge3D edge) {
211-
return processed.contains(edge);
195+
private float getAmountByWidthType() {
196+
float amount;
197+
switch (widthType) {
198+
case OFFSET -> amount = this.amount * 2;
199+
case WIDTH -> amount = inset;
200+
case DEPTH -> amount = inset * 2;
201+
default -> amount = this.amount * 2;
202+
}
203+
return amount;
204+
}
205+
206+
private boolean canExitEarly(Mesh3D mesh) {
207+
return amount == 0 || mesh.faces.isEmpty();
208+
}
209+
210+
private void validateMesh(Mesh3D mesh) {
211+
if (mesh == null) {
212+
throw new IllegalArgumentException("Mesh cannot be null.");
213+
}
212214
}
213215

214216
private Vector3f getVertexAt(Face3D face, int index) {
@@ -231,7 +233,7 @@ private void clearOriginalFaces() {
231233
mesh.faces.clear();
232234
}
233235

234-
private void addNewFace(int[] indices) {
236+
private void addNewFace(int... indices) {
235237
facesToAdd.add(new Face3D(indices));
236238
}
237239

@@ -256,4 +258,46 @@ public void setWidthType(WidthType widthType) {
256258
this.widthType = widthType;
257259
}
258260

261+
private class EdgeProcessor {
262+
263+
private HashSet<Edge3D> processed;
264+
265+
private HashMap<Edge3D, Edge3D> edgeMapping;
266+
267+
public EdgeProcessor() {
268+
processed = new HashSet<Edge3D>();
269+
edgeMapping = new HashMap<Edge3D, Edge3D>();
270+
}
271+
272+
public void mapOldEdgesToNewEdges(Face3D face, int[] indices) {
273+
for (int i = 0; i < indices.length; i++) {
274+
Edge3D oldEdge = createEdge(face.indices, i);
275+
Edge3D newEdge = createEdge(indices, i);
276+
edgeMapping.put(oldEdge, newEdge);
277+
}
278+
}
279+
280+
public Edge3D getMappedEdge(Edge3D edge) {
281+
return edgeMapping.get(edge);
282+
}
283+
284+
public void markProcessed(Edge3D edge) {
285+
processed.add(edge);
286+
}
287+
288+
public boolean isProcessed(Edge3D edge) {
289+
return processed.contains(edge);
290+
}
291+
292+
public Edge3D createEdge(int[] indices, int i) {
293+
return new Edge3D(indices[i], indices[(i + 1) % indices.length]);
294+
}
295+
296+
public void clearAll() {
297+
processed.clear();
298+
edgeMapping.clear();
299+
}
300+
301+
}
302+
259303
}

0 commit comments

Comments
 (0)