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 points = new MyHashSet(); - for (final Edge e : edges) + final MyHashSet points = new MyHashSet<>(); + for (final Edge e : edges) { points.addAll(e.getEnds()); + } points.remove(p); final int n = points.size(); Point sumNeighbour = new Point(); - for (final Point pt : points) + for (final Point pt : points) { sumNeighbour = sumNeighbour.add(pt); + } final float s = LoopAlgorithm.s(n); Point retVal = p.times(1.0f - n * s); @@ -77,51 +81,57 @@ private Point getNewVertex(final Point p) { @Override public MyHashSet run() { - System.out.println("\tInput mesh has " + this.mesh.describe()); - // 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 MyHashSet retVal = new MyHashSet(); - for (final Point p : face.getPoints()) + } + final MyHashSet retVal = new MyHashSet<>(); + for (final Point p : face.getPoints()) { retVal.add(this.getNewFaceForVertex(face, p)); + } retVal.add(this.getNewFaceForFace(face)); 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.edgePoints.get(incidentEdges.get(1)); - final ArrayList points = new ArrayList(); + final ArrayList points = new ArrayList<>(); points.add(a); points.add(b); points.add(c); @@ -131,15 +141,16 @@ private Polygon getNewFaceForVertex(final Polygon face, final Point p) { private Polygon getNewFaceForFace(final Polygon face) { final MyHashSet edges = face.getEdges(); - if (edges.size() != 3) + if (edges.size() != 3) { throw new RuntimeException("Invalid face!"); + } final Edge[] edgeArr = edges.toArray(new Edge[0]); final Point a = this.edgePoints.get(edgeArr[0]); final Point b = this.edgePoints.get(edgeArr[1]); final Point c = this.edgePoints.get(edgeArr[2]); - 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/MidpointAlgorithm.java b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/algo/MidpointAlgorithm.java similarity index 67% rename from SubdivisionSurfaces/src/com/sweta/basic/algo/MidpointAlgorithm.java rename to SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/algo/MidpointAlgorithm.java index abc244d..5a6f543 100644 --- a/SubdivisionSurfaces/src/com/sweta/basic/algo/MidpointAlgorithm.java +++ b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/algo/MidpointAlgorithm.java @@ -1,17 +1,17 @@ -package com.sweta.basic.algo; +package com.sweta.subdivisionsurfaces.algo; 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 MidpointAlgorithm extends AbstractSubdivisionAlgorithm { - private final HashMap edgePoints = new HashMap(); + private final HashMap edgePoints = new HashMap<>(); public MidpointAlgorithm(final PolygonMesh mesh) { super(mesh); @@ -24,32 +24,34 @@ private Point getEdgePoint(final Edge edge) { @Override public MyHashSet run() { - System.out.println("\tInput mesh has " + this.mesh.describe()); - // Filling the edgepoints - for (final Edge edge : this.mesh.edges) + for (final Edge edge : this.mesh.edges) { this.edgePoints.put(edge, this.getEdgePoint(edge)); + } - 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.add(this.getNewFaceForFace(face)); + } for (final Point point : this.mesh.points) { final Polygon newFace = this.getNewFaceForVertex(point); - if (newFace != null) + if (newFace != null) { set.add(newFace); + } } - - System.out.println("\tOutput set has " + set.size() + " faces.\n"); + return set; } private Polygon getNewFaceForFace(final Polygon face) { - if (face.getPoints().size() < 3) + if (face.getPoints().size() < 3) { throw new RuntimeException("Invalid polygon!"); + } - final MyHashSet points = new MyHashSet(); - for (final Edge e : face.getEdges()) + final MyHashSet points = new MyHashSet<>(); + for (final Edge e : face.getEdges()) { points.add(this.edgePoints.get(e)); + } return PolygonFactory.fromPointsConvex(points); } @@ -64,17 +66,21 @@ private Polygon getNewFaceForFace(final Polygon face) { // } private Polygon getNewFaceForVertex(final Point p) { - if (!this.mesh.points.contains(p)) + if (!this.mesh.points.contains(p)) { throw new RuntimeException("Invalid vertex!"); + } final MyHashSet edges = this.mesh.pointEdges.get(p); - if (edges.size() < 3) + if (edges.size() < 3) { return null; + } - final MyHashSet points = new MyHashSet(); - for (final Edge e : edges) - if (e.isEnd(p)) + final MyHashSet points = new MyHashSet<>(); + for (final Edge e : edges) { + if (e.isEnd(p)) { points.add(this.edgePoints.get(e)); + } + } return PolygonFactory.fromPointsConvex(points); } diff --git a/SubdivisionSurfaces/src/com/sweta/basic/algo/Root3Algorithm.java b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/algo/Root3Algorithm.java similarity index 62% rename from SubdivisionSurfaces/src/com/sweta/basic/algo/Root3Algorithm.java rename to SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/algo/Root3Algorithm.java index 31c4745..b03f8eb 100644 --- a/SubdivisionSurfaces/src/com/sweta/basic/algo/Root3Algorithm.java +++ b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/algo/Root3Algorithm.java @@ -1,26 +1,25 @@ -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 Root3Algorithm extends AbstractSubdivisionAlgorithm { - private final HashMap facePoints = new HashMap(); + private final HashMap facePoints = new HashMap<>(); - private final HashMap newVertices = new HashMap(); + private final HashMap newVertices = new HashMap<>(); public Root3Algorithm(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(); } this.facePoints.clear(); @@ -28,9 +27,9 @@ public Root3Algorithm(final PolygonMesh mesh) { } private static float a(final int n) { - if (n <= 0) + if (n <= 0) { throw new IllegalArgumentException("n must be > 0"); - else { + } else { float a = 2.0f - (float) Math.cos(2.0f * Math.PI / n); a *= 2.0f / 9; return a; @@ -39,24 +38,28 @@ private static float a(final int n) { private Point getFacePoint(final Polygon face) { Point sum = new Point(); - for (final Point p : face.getPoints()) + for (final Point p : face.getPoints()) { sum = sum.add(p); + } sum = sum.times(1.0f / face.getPoints().size()); return sum; } private Point getNewVertex(final Point p) { - if (!this.mesh.points.contains(p)) + if (!this.mesh.points.contains(p)) { throw new RuntimeException("Invalid vertex!"); + } - final MyHashSet neighbours = new MyHashSet(); - for (final Edge e : this.mesh.pointEdges.get(p)) + final MyHashSet neighbours = new MyHashSet<>(); + for (final Edge e : this.mesh.pointEdges.get(p)) { neighbours.addAll(e.getEnds()); + } neighbours.remove(p); Point b = new Point(); - for (final Point pt : neighbours) + for (final Point pt : neighbours) { b = b.add(pt); + } final int n = neighbours.size(); final float a = Root3Algorithm.a(n); return p.times(1.0f - a).add(b.times(a / n)); @@ -64,57 +67,59 @@ private Point getNewVertex(final Point p) { @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)); + } // 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(); + final MyHashSet set = new MyHashSet<>(); for (final Polygon face : this.mesh.faces) { final MyHashSet newFaces = this.getNewFaces(face); set.addAll(newFaces); } - 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 MyHashSet retVal = new MyHashSet(); - for (final Edge edge : face.getEdges()) + final MyHashSet retVal = new MyHashSet<>(); + for (final Edge edge : face.getEdges()) { retVal.addAll(this.getNewFacesForEdge(face, edge)); + } return retVal; } - private MyHashSet getNewFacesForEdge(final Polygon face, - final Edge edge) { - if (!face.isEdge(edge)) + private MyHashSet getNewFacesForEdge(final Polygon face, final Edge edge) { + if (!face.hasEdge(edge)) { throw new RuntimeException("Invalid edge!"); + } - final MyHashSet retVal = new MyHashSet(); + final MyHashSet retVal = new MyHashSet<>(); final MyHashSet faces = this.mesh.edgeFaces.get(edge); faces.remove(face); final Point[] ends = edge.getEnds().toArray(new Point[0]); - for (final Polygon f : faces) + for (final Polygon f : faces) { for (final Point end : ends) { final Point a = this.facePoints.get(face); final Point b = this.newVertices.get(end); final Point c = this.facePoints.get(f); - final ArrayList points = new ArrayList(); + final ArrayList points = new ArrayList<>(); points.add(a); points.add(b); points.add(c); retVal.add(PolygonFactory.fromOrderedPoints(points)); } + } return retVal; } diff --git a/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/algo/TriangulateAlgorithm.java b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/algo/TriangulateAlgorithm.java new file mode 100644 index 0000000..3e494fa --- /dev/null +++ b/SubdivisionSurfaces/src/com/sweta/subdivisionsurfaces/algo/TriangulateAlgorithm.java @@ -0,0 +1,21 @@ +package com.sweta.subdivisionsurfaces.algo; + +import com.sweta.subdivisionsurfaces.MyHashSet; +import com.sweta.subdivisionsurfaces.Polygon; +import com.sweta.subdivisionsurfaces.PolygonMesh; + +public class TriangulateAlgorithm extends AbstractSubdivisionAlgorithm { + + public TriangulateAlgorithm(final PolygonMesh mesh) { + super(mesh); + } + + @Override + public MyHashSet run() { + final MyHashSet set = new MyHashSet<>(); + for (final Polygon face : this.mesh.faces) { + set.addAll(face.triangulateCentroid()); + } + return set; + } +}