diff --git a/SubdivisionSurfaces/.gitignore b/SubdivisionSurfaces/.gitignore
new file mode 100644
index 0000000..fa96b5b
--- /dev/null
+++ b/SubdivisionSurfaces/.gitignore
@@ -0,0 +1,29 @@
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+# Eclipse
+.classpath
+.project
+.settings/
+/target/
diff --git a/SubdivisionSurfaces/src/typescript b/SubdivisionSurfaces/bin/typescript
similarity index 100%
rename from SubdivisionSurfaces/src/typescript
rename to SubdivisionSurfaces/bin/typescript
diff --git a/SubdivisionSurfaces/pom.xml b/SubdivisionSurfaces/pom.xml
new file mode 100644
index 0000000..829602f
--- /dev/null
+++ b/SubdivisionSurfaces/pom.xml
@@ -0,0 +1,60 @@
+
+ 4.0.0
+ com.sweta
+ subdivisionsurfaces
+ 1.0.0
+ Subdivision Surfaces
+ Implementations of subdivision surfaces using Catmull-Clark, Doo-Sabin, Loop, Root 3 and Midpoint subdivision schemes
+
+ src
+
+
+ src
+
+ **/*.java
+
+
+
+
+
+ maven-compiler-plugin
+ 3.8.1
+
+ 8
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 3.2.1
+
+
+ attach-sources
+ deploy
+
+ jar-no-fork
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 3.5.0
+
+ false
+
+
+
+ attach-javadocs
+
+ jar
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SubdivisionSurfaces/script b/SubdivisionSurfaces/script
deleted file mode 100644
index 2233d35..0000000
--- a/SubdivisionSurfaces/script
+++ /dev/null
@@ -1,80 +0,0 @@
-cd ./output
-rm -r *
-mkdir catmull
-mkdir doo
-mkdir midpoint
-mkdir loop
-mkdir root
-cd ../bin
-
-echo "Catmull"
-java SubD "../input/cube.s3d" "../output/catmull/cube.C1.s3d" C 1
-java SubD "../input/cube.s3d" "../output/catmull/cube.C2.s3d" C 2
-java SubD "../input/cube.s3d" "../output/catmull/cube.C3.s3d" C 3
-java SubD "../input/cube.s3d" "../output/catmull/cube.C4.s3d" C 4
-java SubD "../input/icosa.s3d" "../output/catmull/icosa.C1.s3d" C 1
-java SubD "../input/icosa.s3d" "../output/catmull/icosa.C2.s3d" C 2
-java SubD "../input/icosa.s3d" "../output/catmull/icosa.C3.s3d" C 3
-java SubD "../input/icosa.s3d" "../output/catmull/icosa.C4.s3d" C 4
-java SubD "../input/cube_hole.s3d" "../output/catmull/cube_hole.C1.s3d" C 1
-java SubD "../input/cube_hole.s3d" "../output/catmull/cube_hole.C2.s3d" C 2
-java SubD "../input/cube_hole.s3d" "../output/catmull/cube_hole.C3.s3d" C 3
-java SubD "../input/cube_hole.s3d" "../output/catmull/cube_hole.C4.s3d" C 4
-java SubD "../input/torii.s3d" "../output/catmull/torii.C1.s3d" C 1
-java SubD "../input/torii.s3d" "../output/catmull/torii.C2.s3d" C 2
-java SubD "../input/torii.s3d" "../output/catmull/torii.C3.s3d" C 3
-java SubD "../input/torii.s3d" "../output/catmull/torii.C4.s3d" C 4
-
-echo "Doo"
-java SubD "../input/cube.s3d" "../output/doo/cube.D1.s3d" D 1
-java SubD "../input/cube.s3d" "../output/doo/cube.D2.s3d" D 2
-java SubD "../input/cube.s3d" "../output/doo/cube.D3.s3d" D 3
-java SubD "../input/cube.s3d" "../output/doo/cube.D4.s3d" D 4
-
-echo "Midpoint"
-java SubD "../input/cube.s3d" "../output/midpoint/cube.M1.s3d" M 1
-java SubD "../input/cube.s3d" "../output/midpoint/cube.M2.s3d" M 2
-java SubD "../input/cube.s3d" "../output/midpoint/cube.M3.s3d" M 3
-java SubD "../input/cube.s3d" "../output/midpoint/cube.M4.s3d" M 4
-
-echo "Loop"
-java SubD "../input/cube.s3d" "../output/loop/cube.L1.s3d" L 1
-java SubD "../input/cube.s3d" "../output/loop/cube.L2.s3d" L 2
-java SubD "../input/cube.s3d" "../output/loop/cube.L3.s3d" L 3
-java SubD "../input/cube.s3d" "../output/loop/cube.L4.s3d" L 4
-java SubD "../input/icosa.s3d" "../output/loop/icosa.L1.s3d" L 1
-java SubD "../input/icosa.s3d" "../output/loop/icosa.L2.s3d" L 2
-java SubD "../input/icosa.s3d" "../output/loop/icosa.L3.s3d" L 3
-java SubD "../input/icosa.s3d" "../output/loop/icosa.L4.s3d" L 4
-
-echo "Root"
-java SubD "../input/cube.s3d" "../output/root/cube.R1.s3d" R 1
-java SubD "../input/cube.s3d" "../output/root/cube.R2.s3d" R 2
-java SubD "../input/cube.s3d" "../output/root/cube.R3.s3d" R 3
-java SubD "../input/cube.s3d" "../output/root/cube.R4.s3d" R 4
-java SubD "../input/icosa.s3d" "../output/root/icosa.R1.s3d" R 1
-java SubD "../input/icosa.s3d" "../output/root/icosa.R2.s3d" R 2
-java SubD "../input/icosa.s3d" "../output/root/icosa.R3.s3d" R 3
-java SubD "../input/icosa.s3d" "../output/root/icosa.R4.s3d" R 4
-
-echo "Venus"
-java SubD "../input/venus.s3d" "../output/catmull/venus.C1.s3d" C 1
-java SubD "../input/venus.s3d" "../output/loop/venus.L1.s3d" L 1
-java SubD "../input/venus.s3d" "../output/root/venus.R1.s3d" R 1
-java SubD "../input/venus.s3d" "../output/catmull/venus.C2.s3d" C 2
-java SubD "../input/venus.s3d" "../output/loop/venus.L2.s3d" L 2
-java SubD "../input/venus.s3d" "../output/root/venus.R2.s3d" R 2
-java SubD "../input/venus.s3d" "../output/catmull/venus.C3.s3d" C 3
-java SubD "../input/venus.s3d" "../output/loop/venus.L3.s3d" L 3
-java SubD "../input/venus.s3d" "../output/root/venus.R3.s3d" R 3
-
-echo "Teddy"
-java SubD "../input/teddy.s3d" "../output/catmull/teddy.C1.s3d" C 1
-java SubD "../input/teddy.s3d" "../output/loop/teddy.L1.s3d" L 1
-java SubD "../input/teddy.s3d" "../output/root/teddy.R1.s3d" R 1
-java SubD "../input/teddy.s3d" "../output/catmull/teddy.C2.s3d" C 2
-java SubD "../input/teddy.s3d" "../output/loop/teddy.L2.s3d" L 2
-java SubD "../input/teddy.s3d" "../output/root/teddy.R2.s3d" R 2
-java SubD "../input/teddy.s3d" "../output/catmull/teddy.C3.s3d" C 3
-java SubD "../input/teddy.s3d" "../output/loop/teddy.L3.s3d" L 3
-java SubD "../input/teddy.s3d" "../output/root/teddy.R3.s3d" R 3
diff --git a/SubdivisionSurfaces/site.zip b/SubdivisionSurfaces/site.zip
deleted file mode 100644
index 8b765ff..0000000
Binary files a/SubdivisionSurfaces/site.zip and /dev/null differ
diff --git a/SubdivisionSurfaces/src/SubD.java b/SubdivisionSurfaces/src/SubD.java
deleted file mode 100644
index 7396f15..0000000
--- a/SubdivisionSurfaces/src/SubD.java
+++ /dev/null
@@ -1,127 +0,0 @@
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.text.ParseException;
-
-import com.sweta.basic.InputFile;
-import com.sweta.basic.MyHashSet;
-import com.sweta.basic.Polygon;
-import com.sweta.basic.PolygonMesh;
-import com.sweta.basic.algo.AbstractSubdivisionAlgorithm;
-import com.sweta.basic.algo.CatmullClarkAlgorithm;
-import com.sweta.basic.algo.DooSabinAlgorithm;
-import com.sweta.basic.algo.LoopAlgorithm;
-import com.sweta.basic.algo.MidpointAlgorithm;
-import com.sweta.basic.algo.Root3Algorithm;
-import com.sweta.basic.algo.TriangulateAlgorithm;
-
-public class SubD {
-
- private enum Algos {
- TRIANGULATE("Triangulate"), //
- CATMULL_CLARK("Catmull-Clark"), //
- DOO_SABIN("Doo-Sabin"), //
- MIDPOINT("Midpoint"), //
- LOOP("Loop"), //
- ROOT3("√3"); //
-
- final String name;
-
- Algos(final String name) {
- this.name = name;
- }
-
- }
-
- public static void main(final String[] args) {
- final Algos algo;
-
- if (args.length != 4) {
- System.out.println("4 args expected!\n");
- return;
- }
-
- final String algoString = args[2];
- if (algoString.equalsIgnoreCase("T"))
- algo = Algos.TRIANGULATE;
- else if (algoString.equalsIgnoreCase("C"))
- algo = Algos.CATMULL_CLARK;
- else if (algoString.equalsIgnoreCase("D"))
- algo = Algos.DOO_SABIN;
- else if (algoString.equalsIgnoreCase("M"))
- algo = Algos.MIDPOINT;
- else if (algoString.equalsIgnoreCase("L"))
- algo = Algos.LOOP;
- else if (algoString.equalsIgnoreCase("R"))
- algo = Algos.ROOT3;
- else {
- System.out.println("Invalid algorithm selection!");
- return;
- }
-
- final String inputFilePath = args[0];
- System.out.println("\nReading input file '" + inputFilePath + "' ...");
- InputFile inFile = null;
- try {
- inFile = new InputFile(inputFilePath);
- } catch (final ParseException | IOException e) {
- e.printStackTrace();
- return;
- }
- final int n = inFile.polygons.size();
- System.out.println("Input file has " + n + " polygons.");
-
- System.out.println("Using " + algo.name + " subdivision algorithm.");
-
- final int level = Integer.parseInt(args[3]);
- System.out.println("Using subdivision level = " + level);
-
- final String outputFilePath = args[1];
- System.out.println("Writing to output file '" + outputFilePath
- + "' ...\n");
- final File outFile = new File(outputFilePath);
-
- try {
- final BufferedWriter bw = new BufferedWriter(
- new FileWriter(outFile));
-
- MyHashSet polySet = new MyHashSet();
- polySet.addAll(inFile.polygons);
-
- for (int i = 1; i <= level; i++) {
- System.out.println("\tRunning subdivision level " + i);
- final PolygonMesh mesh = new PolygonMesh(polySet);
-
- AbstractSubdivisionAlgorithm algorithm = null;
- if (algo == Algos.TRIANGULATE)
- algorithm = new TriangulateAlgorithm(mesh);
- else if (algo == Algos.CATMULL_CLARK)
- algorithm = new CatmullClarkAlgorithm(mesh);
- else if (algo == Algos.DOO_SABIN)
- algorithm = new DooSabinAlgorithm(mesh);
- else if (algo == Algos.MIDPOINT)
- algorithm = new MidpointAlgorithm(mesh);
- else if (algo == Algos.LOOP)
- algorithm = new LoopAlgorithm(mesh);
- else if (algo == Algos.ROOT3)
- algorithm = new Root3Algorithm(mesh);
-
- polySet = algorithm.run();
- }
-
- for (final Polygon poly : polySet) {
- bw.append(poly.toString());
- bw.append("\n");
- }
-
- bw.close();
- System.out.println("Done.\n");
-
- } catch (final IOException e) {
- e.printStackTrace();
- return;
- }
-
- }
-}
diff --git a/SubdivisionSurfaces/src/com/sweta/basic/PolygonMesh.java b/SubdivisionSurfaces/src/com/sweta/basic/PolygonMesh.java
deleted file mode 100644
index dc6771e..0000000
--- a/SubdivisionSurfaces/src/com/sweta/basic/PolygonMesh.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package com.sweta.basic;
-
-import java.util.HashMap;
-
-import com.sweta.basic.Polygon.Edge;
-
-public class PolygonMesh {
-
- public final MyHashSet faces = new MyHashSet();
-
- public final MyHashSet edges = new MyHashSet();
-
- public final MyHashSet points = new MyHashSet();
-
- public final HashMap> pointFaces = new HashMap>();
-
- public final HashMap> edgeFaces = new HashMap>();
-
- public final HashMap> pointEdges = new HashMap>();
-
- public PolygonMesh(final MyHashSet polySet) {
- for (final Polygon poly : polySet) {
- this.faces.add(poly);
- this.edges.addAll(poly.getEdges());
- this.points.addAll(poly.getPoints());
- }
-
- for (final Point p : this.points) {
- final MyHashSet set = new MyHashSet();
- for (final Polygon poly : this.faces)
- if (poly.isVertex(p))
- set.add(poly);
- this.pointFaces.put(p, set);
- }
-
- for (final Edge e : this.edges) {
- final MyHashSet set = new MyHashSet();
- for (final Polygon poly : this.faces)
- if (poly.isEdge(e))
- set.add(poly);
- this.edgeFaces.put(e, set);
- }
-
- for (final Point p : this.points) {
- final MyHashSet set = new MyHashSet();
- for (final Polygon.Edge edge : this.edges)
- if (edge.isEnd(p))
- set.add(edge);
- this.pointEdges.put(p, set);
- }
- }
-
- public String describe() {
- return this.faces.size() + " faces, " + this.edges.size() + " edges, "
- + this.points.size() + " points.";
- }
-
- public boolean isEdgeOnHole(final Edge e) {
- if (!this.edges.contains(e))
- throw new IllegalArgumentException("Edge not in mesh!");
- return this.edgeFaces.get(e) != null
- && this.edgeFaces.get(e).size() == 1;
- }
-
- public boolean isPointOnHole(final Point p) {
- if (!this.points.contains(p))
- throw new IllegalArgumentException("Point not in mesh!");
- return this.pointFaces.get(p) != null
- && this.pointEdges.get(p) != null
- && this.pointFaces.get(p).size() != this.pointEdges.get(p)
- .size();
- }
-
- public boolean hasOnlyTriangles() {
- for (final Polygon face : this.faces)
- if (face.getPoints().size() != 3)
- return false;
- return true;
- }
-
- public boolean hasOnlyTrianglesAndQuads() {
- for (final Polygon face : this.faces)
- if (face.getPoints().size() != 3 && face.getPoints().size() != 4)
- return false;
- return true;
- }
-
- public PolygonMesh triangulate() {
- final MyHashSet newFaces = new MyHashSet();
- for (final Polygon face : this.faces)
- newFaces.addAll(face.triangulateCentroid());
- return new PolygonMesh(newFaces);
- }
-
-}
diff --git a/SubdivisionSurfaces/src/com/sweta/basic/algo/AbstractSubdivisionAlgorithm.java b/SubdivisionSurfaces/src/com/sweta/basic/algo/AbstractSubdivisionAlgorithm.java
deleted file mode 100644
index 2474363..0000000
--- a/SubdivisionSurfaces/src/com/sweta/basic/algo/AbstractSubdivisionAlgorithm.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.sweta.basic.algo;
-
-import com.sweta.basic.MyHashSet;
-import com.sweta.basic.Polygon;
-import com.sweta.basic.PolygonMesh;
-
-public abstract class AbstractSubdivisionAlgorithm {
-
- protected PolygonMesh mesh;
-
- public AbstractSubdivisionAlgorithm(final PolygonMesh mesh) {
- this.mesh = mesh;
- }
-
- public abstract MyHashSet run();
-}
diff --git a/SubdivisionSurfaces/src/com/sweta/basic/algo/TriangulateAlgorithm.java b/SubdivisionSurfaces/src/com/sweta/basic/algo/TriangulateAlgorithm.java
deleted file mode 100644
index 5e11176..0000000
--- a/SubdivisionSurfaces/src/com/sweta/basic/algo/TriangulateAlgorithm.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.sweta.basic.algo;
-
-import com.sweta.basic.MyHashSet;
-import com.sweta.basic.Polygon;
-import com.sweta.basic.PolygonMesh;
-
-public class TriangulateAlgorithm extends AbstractSubdivisionAlgorithm {
-
- public TriangulateAlgorithm(final PolygonMesh mesh) {
- super(mesh);
- }
-
- @Override
- public MyHashSet run() {
- System.out.println("\tInput mesh has " + this.mesh.describe());
- final MyHashSet set = new MyHashSet();
- for (final Polygon face : this.mesh.faces)
- set.addAll(face.triangulateCentroid());
- System.out.println("\tOutput set has " + set.size() + " faces.\n");
- return set;
- }
-}
diff --git a/SubdivisionSurfaces/src/com/sweta/basic/Color.java b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/Color.java
similarity index 90%
rename from SubdivisionSurfaces/src/com/sweta/basic/Color.java
rename to SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/Color.java
index 44f2072..6d974ba 100644
--- a/SubdivisionSurfaces/src/com/sweta/basic/Color.java
+++ b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/Color.java
@@ -1,4 +1,4 @@
-package com.sweta.basic;
+package com.sweta.subdivisionsurfaces;
public class Color extends Triple {
diff --git a/SubdivisionSurfaces/src/com/sweta/basic/ConvexHull.java b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/ConvexHull.java
similarity index 64%
rename from SubdivisionSurfaces/src/com/sweta/basic/ConvexHull.java
rename to SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/ConvexHull.java
index 81e44ee..9ec84b8 100644
--- a/SubdivisionSurfaces/src/com/sweta/basic/ConvexHull.java
+++ b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/ConvexHull.java
@@ -1,33 +1,31 @@
-package com.sweta.basic;
+package com.sweta.subdivisionsurfaces;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
-import com.sweta.basic.Polygon.Edge;
+import com.sweta.subdivisionsurfaces.Polygon.Edge;
public class ConvexHull {
- public static ArrayList getConvexHullOrderedPoints(
- final MyHashSet points) {
+ public static List getConvexHullOrderedPoints(final MyHashSet points) {
final int n = points.size();
- if (n == 3)
+ if (n == 3) {
return ConvexHull.getConvexHullOrderedPointsTriangle(points);
- else if (n == 4)
+ } else if (n == 4) {
return ConvexHull.getConvexHullOrderedPointsQuad(points);
- else
- throw new RuntimeException(
- "Only triangles and quads are supported!");
+ } else {
+ throw new RuntimeException("Only triangles and quads are supported!");
+ }
}
- private static ArrayList getConvexHullOrderedPointsTriangle(
- final MyHashSet points) {
- final ArrayList retVal = new ArrayList();
+ private static List getConvexHullOrderedPointsTriangle(final MyHashSet points) {
+ final List retVal = new ArrayList<>();
retVal.addAll(points);
return retVal;
}
- private static ArrayList getConvexHullOrderedPointsQuad(
- final MyHashSet points) {
+ private static List getConvexHullOrderedPointsQuad(final MyHashSet points) {
final Point[] pts = points.toArray(new Point[0]);
final Edge[] edges = new Edge[6];
@@ -45,14 +43,15 @@ private static ArrayList getConvexHullOrderedPointsQuad(
Edge diag2 = null;
for (int i = 4; i >= 0; i--) {
diag2 = edges[i];
- if (!diag1.meets(diag2))
+ if (!diag1.meets(diag2)) {
break;
+ }
}
final Point[] diag1Pts = diag1.getEnds().toArray(new Point[0]);
final Point[] diag2Pts = diag2.getEnds().toArray(new Point[0]);
- final ArrayList retVal = new ArrayList();
+ final List retVal = new ArrayList<>();
retVal.add(diag1Pts[0]);
retVal.add(diag2Pts[0]);
retVal.add(diag1Pts[1]);
@@ -60,21 +59,19 @@ private static ArrayList getConvexHullOrderedPointsQuad(
return retVal;
}
- public static MyHashSet getConvexHullEdges(
- final ArrayList points) {
+ public static MyHashSet getConvexHullEdges(final List points) {
final int n = points.size();
- if (n == 3)
+ if (n == 3) {
return ConvexHull.getConvexHullEdgesTriangle(points);
- else if (n == 4)
+ } else if (n == 4) {
return ConvexHull.getConvexHullEdgesQuad(points);
- else
- throw new RuntimeException(
- "Only triangles and quads are supported!");
+ } else {
+ throw new RuntimeException("Only triangles and quads are supported!");
+ }
}
- private static MyHashSet getConvexHullEdgesTriangle(
- final ArrayList points) {
- final MyHashSet retVal = new MyHashSet();
+ private static MyHashSet getConvexHullEdgesTriangle(final List points) {
+ final MyHashSet retVal = new MyHashSet<>();
final Point[] pts = points.toArray(new Point[0]);
retVal.add(new Edge(pts[0], pts[1]));
retVal.add(new Edge(pts[1], pts[2]));
@@ -82,8 +79,7 @@ private static MyHashSet getConvexHullEdgesTriangle(
return retVal;
}
- private static MyHashSet getConvexHullEdgesQuad(
- final ArrayList points) {
+ private static MyHashSet getConvexHullEdgesQuad(final List points) {
final Point[] pts = points.toArray(new Point[0]);
final Edge[] edges = new Edge[6];
edges[0] = new Edge(pts[0], pts[1]);
@@ -98,11 +94,12 @@ private static MyHashSet getConvexHullEdgesQuad(
Edge diag2 = null;
for (int i = 4; i >= 0; i--) {
diag2 = edges[i];
- if (!diag1.meets(diag2))
+ if (!diag1.meets(diag2)) {
break;
+ }
}
- final MyHashSet retVal = new MyHashSet();
+ final MyHashSet retVal = new MyHashSet<>();
retVal.add(edges[0]);
retVal.add(edges[1]);
retVal.add(edges[2]);
diff --git a/SubdivisionSurfaces/src/com/sweta/basic/InputFile.java b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/InputFile.java
similarity index 68%
rename from SubdivisionSurfaces/src/com/sweta/basic/InputFile.java
rename to SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/InputFile.java
index be07b85..b42470b 100644
--- a/SubdivisionSurfaces/src/com/sweta/basic/InputFile.java
+++ b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/InputFile.java
@@ -1,4 +1,4 @@
-package com.sweta.basic;
+package com.sweta.subdivisionsurfaces;
import java.io.BufferedReader;
import java.io.File;
@@ -9,28 +9,30 @@
public class InputFile {
- public MyHashSet polygons = new MyHashSet();
+ public MyHashSet polygons = new MyHashSet<>();
public InputFile(final String filePath) throws ParseException, IOException {
- final ArrayList points = new ArrayList();
+ final ArrayList points = new ArrayList<>();
// final MyHashSet points = new MyHashSet();
final File file = new File(filePath);
final BufferedReader br = new BufferedReader(new FileReader(file));
String line = null;
while ((line = br.readLine()) != null) {
final String[] tokens = line.split(" ");
- if (tokens.length != 4)
+ if (tokens.length != 4) {
continue;
+ }
final float a = Float.parseFloat(tokens[1]);
final float b = Float.parseFloat(tokens[2]);
final float c = Float.parseFloat(tokens[3]);
- if (tokens[0].equalsIgnoreCase("P"))
+ if (tokens[0].equalsIgnoreCase("P")) {
points.clear();
- else if (tokens[0].equalsIgnoreCase("v"))
+ } else if (tokens[0].equalsIgnoreCase("v")) {
points.add(new Point(a, b, c));
- else if (tokens[0].equalsIgnoreCase("E"))
+ } else if (tokens[0].equalsIgnoreCase("E")) {
this.polygons.add(PolygonFactory.fromOrderedPoints(points));
- // this.polygons.add(PolygonFactory.fromPointsConvex(points));
+ // this.polygons.add(PolygonFactory.fromPointsConvex(points));
+ }
}
br.close();
}
diff --git a/SubdivisionSurfaces/src/com/sweta/basic/MyHashSet.java b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/MyHashSet.java
similarity index 63%
rename from SubdivisionSurfaces/src/com/sweta/basic/MyHashSet.java
rename to SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/MyHashSet.java
index e3ace89..35fdf58 100644
--- a/SubdivisionSurfaces/src/com/sweta/basic/MyHashSet.java
+++ b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/MyHashSet.java
@@ -1,4 +1,4 @@
-package com.sweta.basic;
+package com.sweta.subdivisionsurfaces;
import java.util.HashSet;
import java.util.Iterator;
@@ -14,38 +14,47 @@ public String toString() {
while (iterator.hasNext()) {
final E e = iterator.next();
builder.append(e.toString());
- if (iterator.hasNext())
+ if (iterator.hasNext()) {
builder.append(", ");
+ }
}
builder.append("]");
return builder.toString();
}
public MyHashSet union(final MyHashSet s) {
- final MyHashSet retVal = new MyHashSet();
- for (final E e : this)
+ final MyHashSet retVal = new MyHashSet<>();
+ for (final E e : this) {
retVal.add(e);
- for (final E e : s)
+ }
+ for (final E e : s) {
retVal.add(e);
+ }
return retVal;
}
public MyHashSet intersection(final MyHashSet s) {
- final MyHashSet retVal = new MyHashSet();
- for (final E e : this)
- if (s.contains(e))
+ final MyHashSet retVal = new MyHashSet<>();
+ for (final E e : this) {
+ if (s.contains(e)) {
retVal.add(e);
- for (final E e : s)
- if (this.contains(e))
+ }
+ }
+ for (final E e : s) {
+ if (this.contains(e)) {
retVal.add(e);
+ }
+ }
return retVal;
}
public MyHashSet complement(final MyHashSet s) {
- final MyHashSet retVal = new MyHashSet();
- for (final E e : this)
- if (!s.contains(e))
+ final MyHashSet retVal = new MyHashSet<>();
+ for (final E e : this) {
+ if (!s.contains(e)) {
retVal.add(e);
+ }
+ }
return retVal;
}
}
diff --git a/SubdivisionSurfaces/src/com/sweta/basic/Point.java b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/Point.java
similarity index 92%
rename from SubdivisionSurfaces/src/com/sweta/basic/Point.java
rename to SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/Point.java
index 06cfd75..40c49bd 100644
--- a/SubdivisionSurfaces/src/com/sweta/basic/Point.java
+++ b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/Point.java
@@ -1,4 +1,4 @@
-package com.sweta.basic;
+package com.sweta.subdivisionsurfaces;
public class Point extends Triple {
@@ -22,8 +22,7 @@ public Point times(final float k) {
return new Point(k * this.x, k * this.y, k * this.z);
}
- public static Point linearCombination(final Point P0, final Point P1,
- final float a0) {
+ public static Point linearCombination(final Point P0, final Point P1, final float a0) {
final float x = a0 * P0.x + (1 - a0) * P1.x;
final float y = a0 * P0.y + (1 - a0) * P1.y;
final float z = a0 * P0.z + (1 - a0) * P1.z;
diff --git a/SubdivisionSurfaces/src/com/sweta/basic/Polygon.java b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/Polygon.java
similarity index 51%
rename from SubdivisionSurfaces/src/com/sweta/basic/Polygon.java
rename to SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/Polygon.java
index 40d9a4e..43144da 100644
--- a/SubdivisionSurfaces/src/com/sweta/basic/Polygon.java
+++ b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/Polygon.java
@@ -1,169 +1,110 @@
-package com.sweta.basic;
+package com.sweta.subdivisionsurfaces;
-import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
public class Polygon {
- public static class Edge implements Comparable {
-
- private final MyHashSet ends = new MyHashSet();
-
- public Edge(final Point endA, final Point endB) {
- if (endA == null || endB == null)
- throw new NullPointerException();
- if (endA.equals(endB))
- throw new IllegalArgumentException("Invalid edge! endA="
- + endA.toString() + " endB=" + endB.toString());
- this.ends.add(endA);
- this.ends.add(endB);
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result
- + (this.ends == null ? 0 : this.ends.hashCode());
- return result;
- }
-
- @Override
- public String toString() {
- return "Edge [ends=" + this.ends.toString() + "]";
- }
-
- @Override
- public boolean equals(final Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (this.getClass() != obj.getClass())
- return false;
- final Edge other = (Edge) obj;
- if (this.ends == null) {
- if (other.ends != null)
- return false;
- } else if (!this.ends.equals(other.ends))
- return false;
- return true;
- }
-
- public MyHashSet getEnds() {
- return this.ends;
- }
-
- public float length() {
- final Point[] ends = this.ends.toArray(new Point[0]);
- return new Vector(ends[0], ends[1]).length();
- }
-
- public Point midPoint() {
- final Object[] arr = this.ends.toArray();
- return Point
- .linearCombination((Point) arr[0], (Point) arr[1], 0.5f);
- }
+ private final LinkedHashSet points = new LinkedHashSet<>();
- public boolean isEnd(final Point p) {
- final Object[] arr = this.ends.toArray();
- if (p.equals(arr[0]) || p.equals(arr[1]))
- return true;
- return false;
- }
-
- @Override
- public int compareTo(final Edge o) {
- return Float.compare(this.length(), o.length());
- }
-
- public boolean meets(final Edge other) {
- return this.ends.intersection(other.ends).size() > 0;
- }
- }
-
- private final ArrayList points = new ArrayList();
-
- private final MyHashSet edges = new MyHashSet();
+ private final MyHashSet edges = new MyHashSet<>();
private final Vector normal;
private final Color color;
- public Polygon(final ArrayList argPoints,
- final MyHashSet argEdges, final Vector argNormal,
- final Color argColor) {
- if (argPoints == null || argEdges == null || argNormal == null)
- throw new NullPointerException(
- "Non-null normal and sets of points and edges required!");
+ public Polygon(final List argPoints, final MyHashSet argEdges, final Vector argNormal, final Color argColor) {
+ if (argPoints == null || argEdges == null || argNormal == null) {
+ throw new NullPointerException("Non-null normal and sets of points and edges required!");
+ }
final MyHashSet edgeEnds = Polygon.validateEdges(argEdges);
- if (edgeEnds == null)
+ if (edgeEnds == null) {
throw new IllegalArgumentException("Invalid set of edges!");
- final MyHashSet pointsSet = new MyHashSet();
+ }
+ final MyHashSet pointsSet = new MyHashSet<>();
pointsSet.addAll(argPoints);
- if (!pointsSet.equals(edgeEnds))
- throw new IllegalArgumentException(
- "Invalid set of points and edges!");
+ if (!pointsSet.equals(edgeEnds)) {
+ throw new IllegalArgumentException("Invalid set of points and edges!");
+ }
this.points.addAll(argPoints);
this.edges.addAll(argEdges);
this.normal = new Vector(argNormal).normalize();
this.color = argColor;
}
- public boolean isVertex(final Point point) {
- for (final Point p : this.getPoints())
- if (point.equals(p))
- return true;
- return false;
+ public boolean hasVertex(final Point point) {
+ return points.contains(point);
}
- public boolean isEdge(final Edge e) {
- for (final Edge edge : this.getEdges())
- if (e.equals(edge))
- return true;
- return false;
+ public boolean hasEdge(final Edge e) {
+ return this.edges.contains(e);
}
private static MyHashSet validateEdges(final MyHashSet edges) {
- if (edges.size() < 3)
+ if (edges.size() < 3) {
return null;
+ }
- final MyHashSet points = new MyHashSet();
- for (final Edge e : edges)
+ final MyHashSet points = new MyHashSet<>();
+ for (final Edge e : edges) {
points.addAll(e.ends);
- if (points.size() < 3)
+ }
+ if (points.size() < 3) {
return null;
+ }
- final HashMap pointDegrees = new HashMap();
- for (final Point p : points)
+ final HashMap pointDegrees = new HashMap<>();
+ for (final Point p : points) {
pointDegrees.put(p, 0);
- for (final Edge e : edges)
+ }
+ for (final Edge e : edges) {
for (final Point p : e.ends) {
int d = pointDegrees.get(p).intValue();
pointDegrees.put(p, ++d);
}
+ }
- final MyHashSet degreeSet = new MyHashSet();
+ final MyHashSet degreeSet = new MyHashSet<>();
degreeSet.addAll(pointDegrees.values());
final Integer[] degreeArr = degreeSet.toArray(new Integer[0]);
- if (degreeArr == null || degreeArr.length != 1)
+ if (degreeArr == null || degreeArr.length != 1) {
return null;
+ }
final int degInt = degreeArr[0].intValue();
- if (degInt != 2)
+ if (degInt != 2) {
return null;
+ }
return points;
}
+ public MyHashSet getEdges() {
+ return this.edges;
+ }
+
+ public Collection getPoints() {
+ return this.points;
+ }
+
+ public MyHashSet triangulateCentroid() {
+ return PolygonFactory.triangulateCentroid(this.points, this.color);
+ }
+
+ public MyHashSet triangulateFan() {
+ return PolygonFactory.triangulateFan(this.points, this.color);
+ }
+
@Override
public String toString() {
final Vector n = this.normal;
final StringBuilder builder = new StringBuilder();
builder.append("P " + this.points.size() + " 0 0\n");
- if (this.color != Color.DEFAULT)
- builder.append("d " + this.color.x + " " + this.color.y + " "
- + this.color.z + "\n");
+ if (this.color != Color.DEFAULT) {
+ builder.append("d " + this.color.x + " " + this.color.y + " " + this.color.z + "\n");
+ }
for (final Point p : this.points) {
builder.append("n " + n.x + " " + n.y + " " + n.z + "\n");
builder.append("v " + p.x + " " + p.y + " " + p.z + "\n");
@@ -176,49 +117,106 @@ public String toString() {
public int hashCode() {
final int prime = 31;
int result = 1;
- result = prime * result
- + (this.getPoints() == null ? 0 : this.getPoints().hashCode());
- result = prime * result
- + (this.getEdges() == null ? 0 : this.getEdges().hashCode());
+ result = prime * result + (this.getPoints() == null ? 0 : this.getPoints().hashCode());
+ result = prime * result + (this.getEdges() == null ? 0 : this.getEdges().hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
- if (this == obj)
+ if (this == obj) {
return true;
- if (obj == null)
- return false;
- if (this.getClass() != obj.getClass())
+ }
+ if ((obj == null) || (this.getClass() != obj.getClass())) {
return false;
+ }
final Polygon other = (Polygon) obj;
if (this.getEdges() == null) {
- if (other.getEdges() != null)
+ if (other.getEdges() != null) {
return false;
- } else if (!this.getEdges().equals(other.getEdges()))
+ }
+ } else if (!this.getEdges().equals(other.getEdges())) {
return false;
+ }
if (this.getPoints() == null) {
- if (other.getPoints() != null)
+ if (other.getPoints() != null) {
return false;
- } else if (!this.getPoints().equals(other.getPoints()))
+ }
+ } else if (!this.getPoints().equals(other.getPoints())) {
return false;
+ }
return true;
}
- public MyHashSet getEdges() {
- return this.edges;
- }
+ public static class Edge implements Comparable {
- public ArrayList getPoints() {
- return this.points;
- }
+ private final MyHashSet ends = new MyHashSet<>();
+ public final Point a, b;
- public MyHashSet triangulateCentroid() {
- return PolygonFactory.triangulateCentroid(this.points, this.color);
- }
+ public Edge(final Point endA, final Point endB) {
+ if (endA == null || endB == null) {
+ throw new NullPointerException();
+ }
+ if (endA.equals(endB)) {
+ throw new IllegalArgumentException("Invalid edge! endA=" + endA.toString() + " endB=" + endB.toString());
+ }
+ this.ends.add(endA);
+ this.ends.add(endB);
+ this.a = endA;
+ this.b = endB;
+ }
- public MyHashSet triangulateFan() {
- return PolygonFactory.triangulateFan(this.points, this.color);
+ public MyHashSet getEnds() {
+ return this.ends;
+ }
+
+ public float length() {
+ return new Vector(a, b).length();
+ }
+
+ public Point midPoint() {
+ return Point.linearCombination(a, b, 0.5f);
+ }
+
+ public boolean isEnd(final Point p) {
+ return (p.equals(a) || p.equals(b));
+ }
+
+ public boolean meets(final Edge other) {
+ return !this.ends.intersection(other.ends).isEmpty();
+ }
+
+ @Override
+ public int compareTo(final Edge o) {
+ return Float.compare(this.length(), o.length());
+ }
+
+ @Override
+ public int hashCode() {
+ return Float.floatToIntBits(b.y + a.y) ^ Float.floatToIntBits(b.x + a.x - 1);
+ }
+
+ @Override
+ public String toString() {
+ return "Edge [ends=" + this.ends.toString() + "]";
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if ((obj == null) || (this.getClass() != obj.getClass())) {
+ return false;
+ }
+ final Edge other = (Edge) obj;
+ if (this.ends == null) {
+ if (other.ends != null) {
+ return false;
+ }
+ }
+ return (other.a.equals(a) && other.b.equals(b)) || (other.a.equals(b) && other.b.equals(a));
+ }
}
}
\ No newline at end of file
diff --git a/SubdivisionSurfaces/src/com/sweta/basic/PolygonFactory.java b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/PolygonFactory.java
similarity index 67%
rename from SubdivisionSurfaces/src/com/sweta/basic/PolygonFactory.java
rename to SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/PolygonFactory.java
index d37d6ec..5a2af04 100644
--- a/SubdivisionSurfaces/src/com/sweta/basic/PolygonFactory.java
+++ b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/PolygonFactory.java
@@ -1,8 +1,10 @@
-package com.sweta.basic;
+package com.sweta.subdivisionsurfaces;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
-import com.sweta.basic.Polygon.Edge;
+import com.sweta.subdivisionsurfaces.Polygon.Edge;
public class PolygonFactory {
@@ -10,12 +12,11 @@ public static Polygon fromPointsConvex(final MyHashSet points) {
return PolygonFactory.fromPointsConvex(points, Color.DEFAULT);
}
- public static Polygon fromPointsConvex(final MyHashSet points,
- final Color color) {
- final ArrayList pts = ConvexHull
- .getConvexHullOrderedPoints(points);
- if (!PolygonFactory.validateInput(pts))
+ public static Polygon fromPointsConvex(final MyHashSet points, final Color color) {
+ final List pts = ConvexHull.getConvexHullOrderedPoints(points);
+ if (!PolygonFactory.validateInput(pts)) {
throw new IllegalArgumentException("Invalid set of points!");
+ }
final MyHashSet edges = ConvexHull.getConvexHullEdges(pts);
// final MyHashSet edges = new MyHashSet();
// for (int i = 0; i < pts.size() - 1; i++)
@@ -25,48 +26,49 @@ public static Polygon fromPointsConvex(final MyHashSet points,
return new Polygon(pts, edges, normal, color);
}
- public static Polygon fromOrderedPoints(final ArrayList points) {
+ public static Polygon fromOrderedPoints(final List points) {
return PolygonFactory.fromOrderedPoints(points, Color.DEFAULT);
}
- private static Polygon fromOrderedPoints(final ArrayList points,
- final Color color) {
- if (!PolygonFactory.validateInput(points))
+ private static Polygon fromOrderedPoints(final List points, final Color color) {
+ if (!PolygonFactory.validateInput(points)) {
throw new IllegalArgumentException("Invalid set of points!");
- final MyHashSet edges = new MyHashSet();
- for (int i = 0; i < points.size() - 1; i++)
+ }
+ final MyHashSet edges = new MyHashSet<>();
+ for (int i = 0; i < points.size() - 1; i++) {
edges.add(new Edge(points.get(i), points.get(i + 1)));
+ }
edges.add(new Edge(points.get(points.size() - 1), points.get(0)));
- final Vector normal = Vector.cross(points.get(0), points.get(1),
- points.get(2));
+ final Vector normal = Vector.cross(points.get(0), points.get(1), points.get(2));
return new Polygon(points, edges, normal, color);
}
- public static MyHashSet triangulateCentroid(
- final ArrayList points, final Color color) {
- if (points.size() < 3)
+ public static MyHashSet triangulateCentroid(final Collection points, final Color color) {
+ if (points.size() < 3) {
throw new IllegalArgumentException("Invalid set of points!");
- final MyHashSet triangles = new MyHashSet();
+ }
+ final MyHashSet triangles = new MyHashSet<>();
// if (points.size() == 3)
// triangles.add(PolygonFactory.createTriangle(points, color));
// else
// {
Point centroid = new Point();
- for (final Point p : points)
+ for (final Point p : points) {
centroid = centroid.add(p);
+ }
centroid = centroid.times(1.0f / points.size());
final Point[] pts = points.toArray(new Point[0]);
for (int i = 0; i < pts.length - 1; i++) {
- final ArrayList triPts = new ArrayList();
+ final List triPts = new ArrayList<>();
triPts.add(centroid);
triPts.add(pts[i]);
triPts.add(pts[i + 1]);
triangles.add(PolygonFactory.createTriangle(triPts, color));
}
{
- final ArrayList triPts = new ArrayList();
+ final List triPts = new ArrayList<>();
triPts.add(centroid);
triPts.add(pts[pts.length - 1]);
triPts.add(pts[0]);
@@ -76,14 +78,14 @@ public static MyHashSet triangulateCentroid(
return triangles;
}
- public static MyHashSet triangulateFan(
- final ArrayList points, final Color color) {
- if (points.size() < 3)
+ public static MyHashSet triangulateFan(final Collection points, final Color color) {
+ if (points.size() < 3) {
throw new IllegalArgumentException("Invalid set of points!");
- final MyHashSet triangles = new MyHashSet();
+ }
+ final MyHashSet triangles = new MyHashSet<>();
final Point[] pts = points.toArray(new Point[0]);
for (int i = 1; i < pts.length - 1; i++) {
- final ArrayList triPts = new ArrayList();
+ final List triPts = new ArrayList<>();
triPts.add(pts[0]);
triPts.add(pts[i]);
triPts.add(pts[i + 1]);
@@ -92,12 +94,12 @@ public static MyHashSet triangulateFan(
return triangles;
}
- public static Polygon createTriangle(final ArrayList points,
- final Color color) {
- if (points.size() != 3)
+ public static Polygon createTriangle(final List points, final Color color) {
+ if (points.size() != 3) {
throw new IllegalArgumentException("Invalid set of points!");
+ }
final Point[] pts = points.toArray(new Point[0]);
- final MyHashSet edges = new MyHashSet();
+ final MyHashSet edges = new MyHashSet<>();
edges.add(new Edge(pts[0], pts[1]));
edges.add(new Edge(pts[1], pts[2]));
edges.add(new Edge(pts[2], pts[0]));
@@ -108,9 +110,10 @@ public static Polygon createTriangle(final ArrayList points,
private static boolean PLANARITY_CHECKING = false;
private static float PLANARITY_CHECKING_MAX_DOT_PRODUCT_SIZE = 1e-3f;
- private static boolean validateInput(final ArrayList points) {
- if (points.size() < 3)
+ private static boolean validateInput(final List points) {
+ if (points.size() < 3) {
return false;
+ }
if (PolygonFactory.PLANARITY_CHECKING) {
final Point[] pts = points.toArray(new Point[0]);
@@ -121,8 +124,7 @@ private static boolean validateInput(final ArrayList points) {
final Vector PS = new Vector(pts[0], pts[i]);
final float dotProduct = Triple.dotProduct(PS, cross);
if (Math.abs(dotProduct) > PolygonFactory.PLANARITY_CHECKING_MAX_DOT_PRODUCT_SIZE) {
- System.out.println("Dot product = " + dotProduct
- + " is too large to continue!");
+ System.out.println("Dot product = " + dotProduct + " is too large to continue!");
System.out.println("Points are: " + points.toString());
return false;
}
diff --git a/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/PolygonMesh.java b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/PolygonMesh.java
new file mode 100644
index 0000000..89598f8
--- /dev/null
+++ b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/PolygonMesh.java
@@ -0,0 +1,81 @@
+package com.sweta.subdivisionsurfaces;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.sweta.subdivisionsurfaces.Polygon.Edge;
+
+public class PolygonMesh {
+
+ public final MyHashSet faces = new MyHashSet<>();
+ public final MyHashSet edges = new MyHashSet<>();
+ public final MyHashSet points = new MyHashSet<>();
+ public final Map> pointFaces = new HashMap<>();
+ public final Map> edgeFaces = new HashMap<>();
+ public final Map> pointEdges = new HashMap<>();
+
+ public PolygonMesh(final Collection polySet) {
+ for (final Polygon poly : polySet) {
+ this.faces.add(poly);
+ this.edges.addAll(poly.getEdges());
+ this.points.addAll(poly.getPoints());
+ }
+
+ faces.forEach(poly -> {
+ poly.getEdges().forEach(e -> {
+ this.pointFaces.computeIfAbsent(e.a, (x -> new MyHashSet<>())).add(poly);
+ this.pointFaces.computeIfAbsent(e.b, (x -> new MyHashSet<>())).add(poly);
+ this.edgeFaces.computeIfAbsent(e, (x -> new MyHashSet<>())).add(poly);
+ this.pointEdges.computeIfAbsent(e.a, (x -> new MyHashSet<>())).add(e);
+ this.pointEdges.computeIfAbsent(e.b, (x -> new MyHashSet<>())).add(e);
+ });
+ });
+ }
+
+ public String describe() {
+ return this.faces.size() + " faces, " + this.edges.size() + " edges, " + this.points.size() + " points.";
+ }
+
+ public boolean isEdgeOnHole(final Edge e) {
+ if (!this.edges.contains(e)) {
+ throw new IllegalArgumentException("Edge not in mesh!");
+ }
+ return this.edgeFaces.get(e) != null && this.edgeFaces.get(e).size() == 1;
+ }
+
+ public boolean isPointOnHole(final Point p) {
+ if (!this.points.contains(p)) {
+ throw new IllegalArgumentException("Point not in mesh!");
+ }
+ return this.pointFaces.get(p) != null && this.pointEdges.get(p) != null
+ && this.pointFaces.get(p).size() != this.pointEdges.get(p).size();
+ }
+
+ public boolean hasOnlyTriangles() {
+ for (final Polygon face : this.faces) {
+ if (face.getPoints().size() != 3) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean hasOnlyTrianglesAndQuads() {
+ for (final Polygon face : this.faces) {
+ if (face.getPoints().size() != 3 && face.getPoints().size() != 4) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public PolygonMesh triangulate() {
+ final MyHashSet newFaces = new MyHashSet<>();
+ for (final Polygon face : this.faces) {
+ newFaces.addAll(face.triangulateCentroid());
+ }
+ return new PolygonMesh(newFaces);
+ }
+
+}
diff --git a/SubdivisionSurfaces/src/com/sweta/basic/Triple.java b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/Triple.java
similarity index 67%
rename from SubdivisionSurfaces/src/com/sweta/basic/Triple.java
rename to SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/Triple.java
index a09934d..77d937c 100644
--- a/SubdivisionSurfaces/src/com/sweta/basic/Triple.java
+++ b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/Triple.java
@@ -1,4 +1,4 @@
-package com.sweta.basic;
+package com.sweta.subdivisionsurfaces;
public class Triple {
@@ -32,20 +32,14 @@ public int hashCode() {
@Override
public boolean equals(final Object obj) {
- if (this == obj)
+ if (this == obj) {
return true;
- if (obj == null)
+ }
+ if ((obj == null) || (this.getClass() != obj.getClass())) {
return false;
- if (this.getClass() != obj.getClass())
- return false;
- final Triple other = (Triple) obj;
- if (Float.floatToIntBits(this.x) != Float.floatToIntBits(other.x))
- return false;
- if (Float.floatToIntBits(this.y) != Float.floatToIntBits(other.y))
- return false;
- if (Float.floatToIntBits(this.z) != Float.floatToIntBits(other.z))
- return false;
- return true;
+ }
+ final Triple p = (Triple) obj;
+ return x == p.x && y == p.y && z == p.z;
}
public static float dotProduct(final Triple a, final Triple b) {
diff --git a/SubdivisionSurfaces/src/com/sweta/basic/Vector.java b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/Vector.java
similarity index 96%
rename from SubdivisionSurfaces/src/com/sweta/basic/Vector.java
rename to SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/Vector.java
index faa5172..f3107f5 100644
--- a/SubdivisionSurfaces/src/com/sweta/basic/Vector.java
+++ b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/Vector.java
@@ -1,4 +1,4 @@
-package com.sweta.basic;
+package com.sweta.subdivisionsurfaces;
public class Vector extends Triple {
@@ -55,8 +55,7 @@ public static Vector proj(final Vector u, final Vector v) {
public static Vector projPlane(final Vector u, final Vector n) {
final Vector proj = Vector.proj(u, n);
- final Vector retVal = new Vector(u.x - proj.x, u.y - proj.y, u.z
- - proj.z);
+ final Vector retVal = new Vector(u.x - proj.x, u.y - proj.y, u.z - proj.z);
return retVal;
}
diff --git a/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/algo/AbstractSubdivisionAlgorithm.java b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/algo/AbstractSubdivisionAlgorithm.java
new file mode 100644
index 0000000..177121a
--- /dev/null
+++ b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/algo/AbstractSubdivisionAlgorithm.java
@@ -0,0 +1,17 @@
+package com.sweta.subdivisionsurfaces.algo;
+
+import java.util.Set;
+
+import com.sweta.subdivisionsurfaces.Polygon;
+import com.sweta.subdivisionsurfaces.PolygonMesh;
+
+public abstract class AbstractSubdivisionAlgorithm {
+
+ protected PolygonMesh mesh;
+
+ public AbstractSubdivisionAlgorithm(final PolygonMesh mesh) {
+ this.mesh = mesh;
+ }
+
+ public abstract Set run();
+}
diff --git a/SubdivisionSurfaces/src/com/sweta/basic/algo/CatmullClarkAlgorithm.java b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/algo/CatmullClarkAlgorithm.java
similarity index 70%
rename from SubdivisionSurfaces/src/com/sweta/basic/algo/CatmullClarkAlgorithm.java
rename to SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/algo/CatmullClarkAlgorithm.java
index d784278..5c8bb37 100644
--- a/SubdivisionSurfaces/src/com/sweta/basic/algo/CatmullClarkAlgorithm.java
+++ b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/algo/CatmullClarkAlgorithm.java
@@ -1,22 +1,22 @@
-package com.sweta.basic.algo;
+package com.sweta.subdivisionsurfaces.algo;
import java.util.ArrayList;
import java.util.HashMap;
-import com.sweta.basic.MyHashSet;
-import com.sweta.basic.Point;
-import com.sweta.basic.Polygon;
-import com.sweta.basic.Polygon.Edge;
-import com.sweta.basic.PolygonFactory;
-import com.sweta.basic.PolygonMesh;
+import com.sweta.subdivisionsurfaces.MyHashSet;
+import com.sweta.subdivisionsurfaces.Point;
+import com.sweta.subdivisionsurfaces.Polygon;
+import com.sweta.subdivisionsurfaces.PolygonFactory;
+import com.sweta.subdivisionsurfaces.PolygonMesh;
+import com.sweta.subdivisionsurfaces.Polygon.Edge;
public class CatmullClarkAlgorithm extends AbstractSubdivisionAlgorithm {
- private final HashMap facePoints = new HashMap();
+ private final HashMap facePoints = new HashMap<>();
- private final HashMap edgePoints = new HashMap();
+ private final HashMap edgePoints = new HashMap<>();
- private final HashMap newVertices = new HashMap();
+ private final HashMap newVertices = new HashMap<>();
public CatmullClarkAlgorithm(final PolygonMesh mesh) {
super(mesh);
@@ -42,8 +42,9 @@ private Point getNewVertex(final Point p) {
private Point getAverageMidEdges(final Point p) {
final MyHashSet edges = this.mesh.pointEdges.get(p);
Point retVal = new Point();
- for (final Edge e : edges)
+ for (final Edge e : edges) {
retVal = retVal.add(e.midPoint());
+ }
retVal = retVal.times(1.0f / edges.size());
return retVal;
}
@@ -52,40 +53,45 @@ private Point getAverageMidBoundaryEdges(final Point p) {
final MyHashSet edges = this.mesh.pointEdges.get(p);
Point retVal = new Point();
int n = 0;
- for (final Edge e : edges)
+ for (final Edge e : edges) {
if (this.mesh.isEdgeOnHole(e)) {
retVal = retVal.add(e.midPoint());
n++;
}
- if (n > 0)
+ }
+ if (n > 0) {
retVal = retVal.times(1.0f / n);
+ }
return retVal;
}
private Point getAverageFacePoint(final Point p) {
final MyHashSet faces = this.mesh.pointFaces.get(p);
Point retVal = new Point();
- for (final Polygon poly : faces)
+ for (final Polygon poly : faces) {
retVal = retVal.add(this.facePoints.get(poly));
+ }
retVal = retVal.times(1.0f / faces.size());
return retVal;
}
private Point getFacePoint(final Polygon face) {
Point retVal = new Point();
- for (final Point p : face.getPoints())
+ for (final Point p : face.getPoints()) {
retVal = retVal.add(p);
+ }
return retVal.times(1.0f / face.getPoints().size());
}
private Point getEdgePoint(final Edge edge) {
- if (this.mesh.isEdgeOnHole(edge))
+ if (this.mesh.isEdgeOnHole(edge)) {
return edge.midPoint();
- else {
+ } else {
final MyHashSet faces = this.mesh.edgeFaces.get(edge);
Point retVal = new Point();
- for (final Polygon face : faces)
+ for (final Polygon face : faces) {
retVal = retVal.add(this.facePoints.get(face));
+ }
retVal = retVal.times(1.0f / faces.size());
retVal = retVal.add(edge.midPoint());
retVal = retVal.times(1.0f / 2);
@@ -95,57 +101,65 @@ private Point getEdgePoint(final Edge edge) {
@Override
public MyHashSet run() {
- System.out.println("\tInput mesh has " + this.mesh.describe());
// Filling the facepoints
- for (final Polygon face : this.mesh.faces)
+ for (final Polygon face : this.mesh.faces) {
this.facePoints.put(face, this.getFacePoint(face));
+ }
// Filling the edgepoints
- for (final Edge edge : this.mesh.edges)
+ for (final Edge edge : this.mesh.edges) {
this.edgePoints.put(edge, this.getEdgePoint(edge));
+ }
// Get the new vertices
- for (final Point p : this.mesh.points)
+ for (final Point p : this.mesh.points) {
this.newVertices.put(p, this.getNewVertex(p));
+ }
- final MyHashSet set = new MyHashSet();
- for (final Polygon face : this.mesh.faces)
+ final MyHashSet set = new MyHashSet<>();
+ for (final Polygon face : this.mesh.faces) {
set.addAll(this.getNewFaces(face));
+ }
- System.out.println("\tOutput set has " + set.size() + " faces.\n");
return set;
}
private MyHashSet getNewFaces(final Polygon face) {
- if (face.getPoints().size() < 3)
+ if (face.getPoints().size() < 3) {
throw new RuntimeException("Invalid polygon!");
+ }
final Point[] points = face.getPoints().toArray(new Point[0]);
- final MyHashSet retVal = new MyHashSet();
- for (final Point p : points)
+ final MyHashSet retVal = new MyHashSet<>();
+ for (final Point p : points) {
retVal.add(this.getNewFaceForVertex(face, p));
+ }
return retVal;
}
private Polygon getNewFaceForVertex(final Polygon face, final Point p) {
- if (!face.isVertex(p))
+ if (!face.hasVertex(p)) {
throw new RuntimeException("Invalid vertex!");
+ }
- final ArrayList incidentEdges = new ArrayList();
- for (final Edge e : face.getEdges())
- if (e.isEnd(p))
+ final ArrayList incidentEdges = new ArrayList<>();
+ for (final Edge e : face.getEdges()) {
+ if (e.isEnd(p)) {
incidentEdges.add(e);
+ }
+ }
- if (incidentEdges.size() != 2)
+ if (incidentEdges.size() != 2) {
throw new RuntimeException("Invalid vertex!");
+ }
final Point a = this.newVertices.get(p);
final Point b = this.edgePoints.get(incidentEdges.get(0));
final Point c = this.facePoints.get(face);
final Point d = this.edgePoints.get(incidentEdges.get(1));
- final ArrayList points = new ArrayList();
+ final ArrayList points = new ArrayList<>();
points.add(a);
points.add(b);
points.add(c);
diff --git a/SubdivisionSurfaces/src/com/sweta/basic/algo/DooSabinAlgorithm.java b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/algo/DooSabinAlgorithm.java
similarity index 69%
rename from SubdivisionSurfaces/src/com/sweta/basic/algo/DooSabinAlgorithm.java
rename to SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/algo/DooSabinAlgorithm.java
index 85d9f25..da2453c 100644
--- a/SubdivisionSurfaces/src/com/sweta/basic/algo/DooSabinAlgorithm.java
+++ b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/algo/DooSabinAlgorithm.java
@@ -1,14 +1,14 @@
-package com.sweta.basic.algo;
+package com.sweta.subdivisionsurfaces.algo;
import java.util.ArrayList;
import java.util.HashMap;
-import com.sweta.basic.MyHashSet;
-import com.sweta.basic.Point;
-import com.sweta.basic.Polygon;
-import com.sweta.basic.Polygon.Edge;
-import com.sweta.basic.PolygonFactory;
-import com.sweta.basic.PolygonMesh;
+import com.sweta.subdivisionsurfaces.MyHashSet;
+import com.sweta.subdivisionsurfaces.Point;
+import com.sweta.subdivisionsurfaces.Polygon;
+import com.sweta.subdivisionsurfaces.PolygonFactory;
+import com.sweta.subdivisionsurfaces.PolygonMesh;
+import com.sweta.subdivisionsurfaces.Polygon.Edge;
public class DooSabinAlgorithm extends AbstractSubdivisionAlgorithm {
@@ -26,42 +26,44 @@ public FaceVertex(final Point vertex, final Polygon face) {
public int hashCode() {
final int prime = 31;
int result = 1;
- result = prime * result
- + (this.face == null ? 0 : this.face.hashCode());
- result = prime * result
- + (this.vertex == null ? 0 : this.vertex.hashCode());
+ result = prime * result + (this.face == null ? 0 : this.face.hashCode());
+ result = prime * result + (this.vertex == null ? 0 : this.vertex.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
- if (this == obj)
+ if (this == obj) {
return true;
- if (obj == null)
- return false;
- if (this.getClass() != obj.getClass())
+ }
+ if ((obj == null) || (this.getClass() != obj.getClass())) {
return false;
+ }
final FaceVertex other = (FaceVertex) obj;
if (this.face == null) {
- if (other.face != null)
+ if (other.face != null) {
return false;
- } else if (!this.face.equals(other.face))
+ }
+ } else if (!this.face.equals(other.face)) {
return false;
+ }
if (this.vertex == null) {
- if (other.vertex != null)
+ if (other.vertex != null) {
return false;
- } else if (!this.vertex.equals(other.vertex))
+ }
+ } else if (!this.vertex.equals(other.vertex)) {
return false;
+ }
return true;
}
}
- private final HashMap facePoints = new HashMap();
+ private final HashMap facePoints = new HashMap<>();
- private final HashMap edgePoints = new HashMap();
+ private final HashMap edgePoints = new HashMap<>();
- private final HashMap newVertices = new HashMap();
+ private final HashMap newVertices = new HashMap<>();
public DooSabinAlgorithm(final PolygonMesh mesh) {
super(mesh);
@@ -71,12 +73,15 @@ public DooSabinAlgorithm(final PolygonMesh mesh) {
}
private Point getNewVertex(final Point p, final Polygon face) {
- final MyHashSet edges = new MyHashSet();
- for (final Edge e : face.getEdges())
- if (e.isEnd(p))
+ final MyHashSet edges = new MyHashSet<>();
+ for (final Edge e : face.getEdges()) {
+ if (e.isEnd(p)) {
edges.add(e);
- if (edges.size() != 2)
+ }
+ }
+ if (edges.size() != 2) {
throw new RuntimeException("edges.size() != 2");
+ }
final Edge[] edgeArr = edges.toArray(new Edge[0]);
final Point a = p;
final Point b = this.edgePoints.get(edgeArr[0]);
@@ -89,8 +94,9 @@ private Point getNewVertex(final Point p, final Polygon face) {
private Point getFacePoint(final Polygon face) {
Point retVal = new Point();
- for (final Point p : face.getPoints())
+ for (final Point p : face.getPoints()) {
retVal = retVal.add(p);
+ }
retVal = retVal.times(1.0f / face.getPoints().size());
return retVal;
}
@@ -101,41 +107,44 @@ private Point getEdgePoint(final Edge edge) {
@Override
public MyHashSet run() {
- System.out.println("\tInput mesh has " + this.mesh.describe());
-
// Filling the facepoints
- for (final Polygon face : this.mesh.faces)
+ for (final Polygon face : this.mesh.faces) {
this.facePoints.put(face, this.getFacePoint(face));
+ }
// Filling the edgepoints
- for (final Edge edge : this.mesh.edges)
+ for (final Edge edge : this.mesh.edges) {
this.edgePoints.put(edge, this.getEdgePoint(edge));
+ }
// Get the new vertices
- for (final Polygon face : this.mesh.faces)
+ for (final Polygon face : this.mesh.faces) {
for (final Point p : face.getPoints()) {
final FaceVertex fv = new FaceVertex(p, face);
final Point pt = this.getNewVertex(p, face);
this.newVertices.put(fv, pt);
}
+ }
- final MyHashSet set = new MyHashSet();
+ final MyHashSet set = new MyHashSet<>();
- for (final Polygon face : this.mesh.faces)
+ for (final Polygon face : this.mesh.faces) {
set.add(this.getNewFFace(face));
+ }
- for (final Edge edge : this.mesh.edges)
+ for (final Edge edge : this.mesh.edges) {
set.add(this.getNewEFace(edge));
+ }
- for (final Point vertex : this.mesh.points)
+ for (final Point vertex : this.mesh.points) {
set.add(this.getNewVFace(vertex));
+ }
- System.out.println("\tOutput set has " + set.size() + " faces.\n");
return set;
}
private Polygon getNewFFace(final Polygon face) {
- final MyHashSet points = new MyHashSet();
+ final MyHashSet points = new MyHashSet<>();
for (final Point p : face.getPoints()) {
final FaceVertex fv = new FaceVertex(p, face);
points.add(this.newVertices.get(fv));
@@ -153,16 +162,15 @@ private Polygon getNewFFace(final Polygon face) {
// }
private Polygon getNewEFace(final Edge edge) {
- final ArrayList points = new ArrayList();
+ final ArrayList points = new ArrayList<>();
- final MyHashSet ends = edge.getEnds();
- final Point[] endsArr = ends.toArray(new Point[0]);
- final Point end0 = endsArr[0];
- final Point end1 = endsArr[1];
+ final Point end0 = edge.a;
+ final Point end1 = edge.b;
final MyHashSet faces = this.mesh.edgeFaces.get(edge);
- if (faces.size() != 2)
+ if (faces.size() != 2) {
throw new RuntimeException("faces.size() != 2");
+ }
final Polygon[] facesArr = faces.toArray(new Polygon[0]);
final Polygon face0 = facesArr[0];
final Polygon face1 = facesArr[1];
@@ -176,7 +184,7 @@ private Polygon getNewEFace(final Edge edge) {
}
private Polygon getNewVFace(final Point vertex) {
- final MyHashSet points = new MyHashSet();
+ final MyHashSet points = new MyHashSet<>();
for (final Polygon face : this.mesh.pointFaces.get(vertex)) {
final FaceVertex fv = new FaceVertex(vertex, face);
points.add(this.newVertices.get(fv));
diff --git a/SubdivisionSurfaces/src/com/sweta/basic/algo/LoopAlgorithm.java b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/algo/LoopAlgorithm.java
similarity index 64%
rename from SubdivisionSurfaces/src/com/sweta/basic/algo/LoopAlgorithm.java
rename to SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/algo/LoopAlgorithm.java
index 2562258..c317b94 100644
--- a/SubdivisionSurfaces/src/com/sweta/basic/algo/LoopAlgorithm.java
+++ b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/algo/LoopAlgorithm.java
@@ -1,40 +1,40 @@
-package com.sweta.basic.algo;
+package com.sweta.subdivisionsurfaces.algo;
import java.util.ArrayList;
import java.util.HashMap;
-import com.sweta.basic.MyHashSet;
-import com.sweta.basic.Point;
-import com.sweta.basic.Polygon;
-import com.sweta.basic.Polygon.Edge;
-import com.sweta.basic.PolygonFactory;
-import com.sweta.basic.PolygonMesh;
+import com.sweta.subdivisionsurfaces.MyHashSet;
+import com.sweta.subdivisionsurfaces.Point;
+import com.sweta.subdivisionsurfaces.Polygon;
+import com.sweta.subdivisionsurfaces.PolygonFactory;
+import com.sweta.subdivisionsurfaces.PolygonMesh;
+import com.sweta.subdivisionsurfaces.Polygon.Edge;
public class LoopAlgorithm extends AbstractSubdivisionAlgorithm {
- private final HashMap edgePoints = new HashMap();
+ private final HashMap edgePoints = new HashMap<>();
- private final HashMap newVertices = new HashMap();
+ private final HashMap newVertices = new HashMap<>();
public LoopAlgorithm(final PolygonMesh mesh) {
super(mesh);
if (!mesh.hasOnlyTriangles()) {
- System.out
- .println("\tmesh is not composed of only triangles! Triangulating mesh.");
+ System.out.println("\tmesh is not composed of only triangles! Triangulating mesh.");
this.mesh = mesh.triangulate();
}
- if (mesh.faces.size() <= 1)
+ if (mesh.faces.size() <= 1) {
throw new RuntimeException("mesh mush have > 1 triangle!");
+ }
this.edgePoints.clear();
this.newVertices.clear();
}
private static float s(final int n) {
- if (n < 3)
+ if (n < 3) {
throw new IllegalArgumentException("n must be >= 3");
- else if (n == 3)
+ } else if (n == 3) {
return 3.0f / 16;
- else {
+ } else {
float a = (float) Math.cos(2.0f * Math.PI / n);
a = 1.0f / 4 * a + 3.0f / 8;
a = 5.0f / 8 - a * a;
@@ -45,29 +45,33 @@ else if (n == 3)
private Point getEdgePoint(final Edge edge) {
final MyHashSet polySet = this.mesh.edgeFaces.get(edge);
- final MyHashSet points = new MyHashSet();
- for (final Polygon poly : polySet)
+ final MyHashSet points = new MyHashSet<>();
+ for (final Polygon poly : polySet) {
points.addAll(poly.getPoints());
+ }
points.removeAll(edge.getEnds());
Point a = edge.midPoint();
a = a.times(3.0f / 4);
Point b = new Point();
- for (final Point p : points)
+ for (final Point p : points) {
b = b.add(p);
+ }
b = b.times(1.0f / 8);
return a.add(b);
}
private Point getNewVertex(final Point p) {
final MyHashSet edges = this.mesh.pointEdges.get(p);
- final MyHashSet