Advertisement
neonsoup

voxel triangle

Jan 29th, 2015
325
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 11.18 KB | None | 0 0
  1. package com.neonsoup.coords3i;
  2.  
  3. import java.io.IOException;
  4. import java.io.Serializable;
  5. import java.util.Iterator;
  6. import java.util.NoSuchElementException;
  7.  
  8. import com.neonsoup.coords2i.ArrayIntContainer;
  9. import com.neonsoup.coords2i.Direction;
  10. import com.neonsoup.coords2i.FilledRectangle;
  11. import com.neonsoup.coords2i.IntContainer;
  12. import com.neonsoup.coords2i.Line8Iterator;
  13.  
  14. public class Polygon26 extends AbstractShape {
  15.  
  16.     private static final int CELL_STATE_EMPTY = Integer.MAX_VALUE;
  17.     private static final int CELL_STATE_NOT_CALCULATED = Integer.MAX_VALUE - 1;
  18.  
  19.     private transient Point[] vertices;
  20.  
  21.     private transient CoordPlane projectionPlane;
  22.     private transient IntContainer projection;
  23.  
  24.  
  25.     public Polygon26(Point... vertices) {
  26.         this.vertices = new Point[vertices.length];
  27.         for (int i = 0; i < vertices.length; i++) {
  28.             this.vertices[i] = new Point(vertices[i]);
  29.         }
  30.        
  31.         generateProjection();
  32.     }
  33.  
  34.  
  35.     private void generateProjection() {
  36.         Point normal = new Point();
  37.  
  38.         {
  39.             Point p0 = new Point(vertices[0]);
  40.             p0.sub(vertices[2]);
  41.  
  42.             Point p1 = new Point(vertices[1]);
  43.             p1.sub(vertices[2]);
  44.  
  45.             normal.x = p0.y * p1.z - p0.z * p1.y;
  46.             normal.y = p0.z * p1.x - p0.x * p1.z;
  47.             normal.z = p0.x * p1.y - p0.y * p1.x;
  48.         }
  49.  
  50.         if (Math.abs(normal.z) >= Math.abs(normal.x)
  51.             && Math.abs(normal.z) >= Math.abs(normal.y)) {
  52.  
  53.             projectionPlane = CoordPlane.XY;
  54.  
  55.         } else if (Math.abs(normal.y) >= Math.abs(normal.x)
  56.                    && Math.abs(normal.y) >= Math.abs(normal.z)) {
  57.  
  58.             projectionPlane = CoordPlane.ZX;
  59.         } else {
  60.             projectionPlane = CoordPlane.YZ;
  61.         }
  62.  
  63.         FilledRectangle projectionBoundingBox = new FilledRectangle();
  64.  
  65.         for (Point p : vertices) {
  66.             projectionBoundingBox.expand(projectionPlane.getFirstCoord(p),
  67.                                          projectionPlane.getSecondCoord(p));
  68.         }
  69.  
  70.         IntContainer projectionErr = new ArrayIntContainer(projectionBoundingBox);
  71.  
  72.         projection = new ArrayIntContainer(projectionBoundingBox,
  73.                                            CELL_STATE_EMPTY);
  74.  
  75.         {
  76.             com.neonsoup.coords2i.LineIterator line = new Line8Iterator();
  77.  
  78.             com.neonsoup.coords2i.Point cursor = new com.neonsoup.coords2i.Point();
  79.  
  80.             for (int i = 0; i < vertices.length; i++) {
  81.                 Point v1 = vertices[i];
  82.                 Point v2 = vertices[(i + 1) % vertices.length];
  83.  
  84.                 cursor.set(projectionPlane.getFirstCoord(v1),
  85.                            projectionPlane.getSecondCoord(v1));
  86.  
  87.                 line.reset(cursor.x,
  88.                            cursor.y,
  89.                            projectionPlane.getFirstCoord(v2),
  90.                            projectionPlane.getSecondCoord(v2));
  91.  
  92.                 while (line.hasNext()) {
  93.                     cursor.add(line.next());
  94.                     projection.put(cursor, CELL_STATE_NOT_CALCULATED);
  95.                 }
  96.             }
  97.         }
  98.  
  99.         fillProjection();
  100.  
  101.         Point firstPoint = vertices[0];
  102.  
  103.         {
  104.             int maxCoord = projectionPlane.getPerpendicularCoord(firstPoint);
  105.             for (Point p : vertices) {
  106.                 projection.put(projectionPlane.getFirstCoord(p),
  107.                                projectionPlane.getSecondCoord(p),
  108.                                projectionPlane.getPerpendicularCoord(p));
  109.  
  110.                 int coord = projectionPlane.getPerpendicularCoord(p);
  111.                 if (coord > maxCoord) {
  112.                     maxCoord = coord;
  113.                     firstPoint = p;
  114.                 }
  115.             }
  116.         }
  117.  
  118.         {
  119.  
  120.             int dx = projectionPlane.getFirstCoord(normal);
  121.             int dy = projectionPlane.getSecondCoord(normal);
  122.             int dz = projectionPlane.getPerpendicularCoord(normal);
  123.  
  124.             com.neonsoup.coords2i.HollowRectangle waveRect;
  125.             waveRect = new com.neonsoup.coords2i.HollowRectangle();
  126.             waveRect.expand(projectionPlane.getFirstCoord(firstPoint),
  127.                             projectionPlane.getSecondCoord(firstPoint));
  128.  
  129.             boolean somethingChanged = true;
  130.  
  131.             while (somethingChanged) {
  132.                 somethingChanged = false;
  133.                 for (com.neonsoup.coords2i.Point p : waveRect) {
  134.                     int centerProjVal = projection.get(p);
  135.                     if (centerProjVal != CELL_STATE_EMPTY
  136.                         && centerProjVal != CELL_STATE_NOT_CALCULATED) {
  137.  
  138.                         int centerErr = projectionErr.get(p);
  139.  
  140.                         for (Direction dir : Direction.DIR_8) {
  141.                             int newX = p.x + dir.x;
  142.                             int newY = p.y + dir.y;
  143.  
  144.                             if (projection.get(newX, newY) != CELL_STATE_NOT_CALCULATED) {
  145.                                 continue;
  146.                             }
  147.  
  148.                             int newZ = centerProjVal;
  149.                             int newErr = centerErr;
  150.  
  151.                             newErr += dx * dir.x;
  152.                             newErr += dy * dir.y;
  153.  
  154.                             if (dz >= 0) {
  155.                                 while (2 * newErr >= dz) {
  156.                                     newZ--;
  157.                                     newErr -= dz;
  158.                                 }
  159.                                 while (2 * newErr <= -dz) {
  160.                                     newZ++;
  161.                                     newErr += dz;
  162.                                 }
  163.                             } else {
  164.                                 while (2 * newErr <= dz) {
  165.                                     newZ--;
  166.                                     newErr -= dz;
  167.                                 }
  168.                                 while (2 * newErr >= -dz) {
  169.                                     newZ++;
  170.                                     newErr += dz;
  171.                                 }
  172.                             }
  173.  
  174.                             projection.put(newX, newY, newZ);
  175.                             projectionErr.put(newX, newY, newErr);
  176.  
  177.                             somethingChanged = true;
  178.                         }
  179.                     }
  180.                 }
  181.  
  182.                 waveRect.grow();
  183.             }
  184.         }
  185.     }
  186.  
  187.  
  188.     private void fillProjection() {
  189.         FilledRectangle area = projection.getBoundingRectangle();
  190.  
  191.         for (int x = area.minX; x <= area.maxX; x++) {
  192.             int state = 0;
  193.             int startedAt = 0;
  194.  
  195.             for (int y = area.minY; y <= area.maxY; y++) {
  196.                 if (projection.get(x, y) == CELL_STATE_NOT_CALCULATED) {
  197.                     if (state == 0) {
  198.                         state = 1;
  199.                     } else if (state == 2) {
  200.                         for (int y2 = startedAt; y2 < y; y2++) {
  201.                             projection.put(x, y2, CELL_STATE_NOT_CALCULATED);
  202.                         }
  203.                         break;
  204.                     }
  205.                 } else if (state == 1) {
  206.                     startedAt = y;
  207.                     state = 2;
  208.                 }
  209.             }
  210.         }
  211.     }
  212.  
  213.  
  214.     @Override
  215.     public Iterator<Point> iterator() {
  216.         return new PointIteratorBasedShapeIterator(this);
  217.     }
  218.  
  219.  
  220.     @Override
  221.     public PointIterator pointIterator() {
  222.         return new Polygon26PointIterator();
  223.     }
  224.  
  225.  
  226.     private class Polygon26PointIterator implements
  227.                                         PointIterator,
  228.                                         Serializable {
  229.  
  230.         private static final long serialVersionUID = -8909605563473525751L;
  231.  
  232.         private Point current = new Point();
  233.         private Point next = new Point();
  234.         private com.neonsoup.coords2i.PointIterator boundingBoxIterator = projection
  235.                 .getBoundingRectangle().pointIterator();
  236.  
  237.         private boolean started = false;
  238.  
  239.  
  240.         public Polygon26PointIterator() {
  241.             findNext();
  242.         }
  243.  
  244.  
  245.         private void findNext() {
  246.             while (boundingBoxIterator.hasNext()) {
  247.                 boundingBoxIterator.next();
  248.  
  249.                 int val = projection.get(boundingBoxIterator.currentX(),
  250.                                          boundingBoxIterator.currentY());
  251.  
  252.                 if (val != CELL_STATE_EMPTY) {
  253.                     projectionPlane.setFirstCoord(next, boundingBoxIterator
  254.                             .currentX());
  255.                     projectionPlane.setSecondCoord(next, boundingBoxIterator
  256.                             .currentY());
  257.                     projectionPlane.setPerpendicularCoord(next, val);
  258.  
  259.                     return;
  260.                 }
  261.             }
  262.  
  263.             next = null;
  264.         }
  265.  
  266.  
  267.         @Override
  268.         public boolean hasNext() {
  269.             return next != null;
  270.         }
  271.  
  272.  
  273.         @Override
  274.         public void next() {
  275.             if (next == null) {
  276.                 throw new NoSuchElementException();
  277.             }
  278.  
  279.             started = true;
  280.  
  281.             current.set(next);
  282.             findNext();
  283.         }
  284.  
  285.  
  286.         @Override
  287.         public int currentX() {
  288.             if (!started) {
  289.                 throw new IllegalStateException();
  290.             }
  291.             return current.x;
  292.         }
  293.  
  294.  
  295.         @Override
  296.         public int currentY() {
  297.             if (!started) {
  298.                 throw new IllegalStateException();
  299.             }
  300.             return current.y;
  301.         }
  302.  
  303.  
  304.         @Override
  305.         public int currentZ() {
  306.             if (!started) {
  307.                 throw new IllegalStateException();
  308.             }
  309.             return current.z;
  310.         }
  311.  
  312.  
  313.         @Override
  314.         public void remove() {
  315.             throw new UnsupportedOperationException();
  316.         }
  317.  
  318.     }
  319.  
  320.  
  321.     @Override
  322.     public boolean contains(int x, int y, int z) {
  323.         return projection.get(projectionPlane.getFirstCoord(x, y, z),
  324.                               projectionPlane.getSecondCoord(x, y, z)) == projectionPlane
  325.                 .getPerpendicularCoord(x, y, z);
  326.     }
  327.  
  328.  
  329.     @Override
  330.     public void getBoundingRectangle(com.neonsoup.coords3i.Rectangle dest) {
  331.         dest.setEmpty();
  332.         for (Point p : vertices) {
  333.             dest.expand(p);
  334.         }
  335.     }
  336.  
  337.  
  338.     private void writeObject(java.io.ObjectOutputStream out)
  339.             throws IOException {
  340.  
  341.         out.defaultWriteObject();
  342.  
  343.         out.writeInt(vertices.length);
  344.         for (Point p : vertices) {
  345.             out.writeInt(p.x);
  346.             out.writeInt(p.y);
  347.             out.writeInt(p.z);
  348.         }
  349.     }
  350.  
  351.  
  352.     private void readObject(java.io.ObjectInputStream in) throws IOException,
  353.             ClassNotFoundException {
  354.  
  355.         in.defaultReadObject();
  356.  
  357.         int len = in.readInt();
  358.  
  359.         this.vertices = new Point[len];
  360.  
  361.         for (int i = 0; i < len; i++) {
  362.             int x = in.readInt();
  363.             int y = in.readInt();
  364.             int z = in.readInt();
  365.  
  366.             this.vertices[i] = new Point(x, y, z);
  367.         }
  368.  
  369.         generateProjection();
  370.     }
  371.  
  372. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement