Skip to content

Commit

Permalink
* performance update
Browse files Browse the repository at this point in the history
* paths and points inside the shapes and paths are now arrays
* optimize point rotation and scaling
* optimize prism, octahedron, stairs and pyramid
* use bubble sort to sort the inner shape paths after inserting
  • Loading branch information
FabianTerhorst committed Apr 6, 2017
1 parent 6191d05 commit 3d80c72
Show file tree
Hide file tree
Showing 9 changed files with 295 additions and 195 deletions.
66 changes: 25 additions & 41 deletions lib/src/main/java/io/fabianterhorst/isometric/Isometric.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,10 @@ public void add(List<Path> paths, Color color) {

public void add(Shape shape, Color color) {
/* Fetch paths ordered by distance to prevent overlaps */
List<Path> paths = shape.orderedPaths();
Path[] paths = shape.orderedPaths();

for (int j = 0; j < paths.size(); j++) {
addPath(paths.get(j), color);
for (Path path : paths) {
addPath(path, color);
}
}

Expand All @@ -81,8 +81,8 @@ public void clear() {

private void addPath(Path path, Color color) {
/* Compute color */
Vector v1 = Vector.fromTwoPoints(path.points.get(1), path.points.get(0));
Vector v2 = Vector.fromTwoPoints(path.points.get(2), path.points.get(1));
Vector v1 = Vector.fromTwoPoints(path.points[1], path.points[0]);
Vector v2 = Vector.fromTwoPoints(path.points[2], path.points[1]);

Vector normal = Vector.crossProduct(v1, v2).normalize();

Expand All @@ -101,22 +101,22 @@ public void measure(int width, int height, boolean sort) {

for (Item item : items) {

if (item.transformedPoints.size() > 0) {
item.transformedPoints.clear();
}
item.transformedPoints = new Point[item.path.points.length];

if (!item.drawPath.isEmpty()) {
item.drawPath.rewind();//Todo: test if .reset is not needed and rewind is enough
}

for (Point point : item.path.points) {
item.transformedPoints.add(translatePoint(point));
Point point;
for (int i = 0;i < item.path.points.length;i++) {
point = item.path.points[i];
item.transformedPoints[i] = translatePoint(point);
}

item.drawPath.moveTo((float) item.transformedPoints.get(0).x, (float) item.transformedPoints.get(0).y);
item.drawPath.moveTo((float) item.transformedPoints[0].x, (float) item.transformedPoints[0].y);

for (int i = 1, length = item.transformedPoints.size(); i < length; i++) {
item.drawPath.lineTo((float) item.transformedPoints.get(i).x, (float) item.transformedPoints.get(i).y);
for (int i = 1, length = item.transformedPoints.length; i < length; i++) {
item.drawPath.lineTo((float) item.transformedPoints[i].x, (float) item.transformedPoints[i].y);
}

item.drawPath.close();
Expand Down Expand Up @@ -284,7 +284,7 @@ static class Item {
Color baseColor;
Paint paint;
int drawn;
List<Point> transformedPoints;
Point[] transformedPoints;
android.graphics.Path drawPath;

Item(Item item) {
Expand All @@ -297,7 +297,7 @@ static class Item {
}

Item(Path path, Color baseColor) {
transformedPoints = new ArrayList<>();
//transformedPoints = new ArrayList<>();
drawPath = new android.graphics.Path();
drawn = 0;
this.paint = new Paint(Paint.ANTI_ALIAS_FLAG);
Expand Down Expand Up @@ -331,28 +331,28 @@ private boolean isPointInPoly(Point[] poly, double x, double y) {
return c;
}

private boolean hasIntersection(List<Point> pointsA, List<Point> pointsB) {
int i, j, lengthA = pointsA.size(), lengthB = pointsB.size(), lengthPolyA, lengthPolyB;
double AminX = pointsA.get(0).x;
double AminY = pointsA.get(0).y;
private boolean hasIntersection(Point[] pointsA, Point[] pointsB) {
int i, j, lengthA = pointsA.length, lengthB = pointsB.length, lengthPolyA, lengthPolyB;
double AminX = pointsA[0].x;
double AminY = pointsA[0].y;
double AmaxX = AminX;
double AmaxY = AminY;
double BminX = pointsB.get(0).x;
double BminY = pointsB.get(0).y;
double BminX = pointsB[0].x;
double BminY = pointsB[0].y;
double BmaxX = BminX;
double BmaxY = BminY;

Point point;

for (i = 0; i < lengthA; i++) {
point = pointsA.get(i);
point = pointsA[i];
AminX = Math.min(AminX, point.x);
AminY = Math.min(AminY, point.y);
AmaxX = Math.max(AmaxX, point.x);
AmaxY = Math.max(AmaxY, point.y);
}
for (i = 0; i < lengthB; i++) {
point = pointsB.get(i);
point = pointsB[i];
BminX = Math.min(BminX, point.x);
BminY = Math.min(BminY, point.y);
BmaxX = Math.max(BmaxX, point.x);
Expand All @@ -362,8 +362,8 @@ private boolean hasIntersection(List<Point> pointsA, List<Point> pointsB) {
if (((AminX <= BminX && BminX <= AmaxX) || (BminX <= AminX && AminX <= BmaxX)) &&
((AminY <= BminY && BminY <= AmaxY) || (BminY <= AminY && AminY <= BmaxY))) {
// now let's be more specific
Point[] polyA = cloneListAndInsert(pointsA, pointsA.get(0));
Point[] polyB = cloneListAndInsert(pointsB, pointsB.get(0));
Point[] polyA = Path.add(pointsA[0], pointsA);
Point[] polyB = Path.add(pointsB[0], pointsB);

// see if edges cross, or one contained in the other
lengthPolyA = polyA.length;
Expand Down Expand Up @@ -423,20 +423,4 @@ private boolean hasIntersection(List<Point> pointsA, List<Point> pointsB) {
return false;
}
}

private Point[] cloneListAndInsert(List<Point> points, Point insertPoint) {
int size = points.size();
Point[] clonedList = new Point[size + 1];
Point point, newPoint;
for (int i = 0; i < size; i++) {
point = points.get(i);
newPoint = new Point();
newPoint.x = point.x;
newPoint.y = point.y;
newPoint.z = point.z;
clonedList[i] = newPoint;
}
clonedList[size] = insertPoint;
return clonedList;
}
}
135 changes: 91 additions & 44 deletions lib/src/main/java/io/fabianterhorst/isometric/Path.java
Original file line number Diff line number Diff line change
@@ -1,111 +1,158 @@
package io.fabianterhorst.isometric;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
* Created by fabianterhorst on 31.03.17.
*/

public class Path {

//Todo: replace with Point[]
final List<Point> points;
Point[] points;

public Path() {
this.points = new ArrayList<>();
}

public Path(List<Point> points) {
public Path(Point[] points) {
this.points = points;
}

public Path(Point[] points) {
this.points = Arrays.asList(points);
public void push(Point point) {
if (points == null) {
points = new Point[0];
}
points = add(point, points);
}

public void push(Point point) {
this.points.add(point);
public void setPoints(Point[] points) {
this.points = points;
}

public List<Point> getPoints() {
public Point[] getPoints() {
return points;
}

public static Point[] add(Point point, Point[] values) {
Point[] anotherArray = new Point[values.length + 1];
System.arraycopy(values, 0, anotherArray, 0, values.length);
anotherArray[values.length] = point;
return anotherArray;
}

private static Point[] concat(Point[] a, Point[] b) {
Point[] c = new Point[a.length + b.length];
System.arraycopy(a, 0, c, 0, a.length);
System.arraycopy(b, 0, c, a.length, b.length);
return c;
}

private static Point[] reverseArray(Point[] array) {
if (array.length == 0) {
return new Point[]{};
} else if (array.length == 1) {
return array;
} else {
// recursion: concatenate the reverse of the end of the array
// to the first element (put at the end)
return concat(
reverseArray(Arrays.copyOfRange(array, 1, array.length)),
new Point[]{array[0]}
);
}
}

/**
* Returns a new path with the points in reverse order
*/
public Path reverse() {
List<Point> points = new ArrayList<>();
for (int i = this.points.size() - 1; i >= 0; i--) {
points.add(this.points.get(i));
}
return new Path(points);
return new Path(reverseArray(this.points));
}

public Path translate(double dx, double dy, double dz) {
List<Point> points = new ArrayList<>();
for (Point point : this.points) {
points.add(point.translate(dx, dy, dz));
Point[] points = new Point[this.points.length];
Point point;
for (int i = 0; i < this.points.length; i++) {
point = this.points[i];
points[i] = point.translate(dx, dy, dz);
}
return new Path(points);
}

public Path rotateX(Point origin, double angle) {
List<Point> points = new ArrayList<>();
for (Point point : this.points) {
points.add(point.rotateX(origin, angle));
Point[] points = new Point[this.points.length];
Point point;
for (int i = 0; i < this.points.length; i++) {
point = this.points[i];
points[i] = point.rotateX(origin, angle);
}
return new Path(points);
}

public Path rotateY(Point origin, double angle) {
List<Point> points = new ArrayList<>();
for (Point point : this.points) {
points.add(point.rotateY(origin, angle));
Point[] points = new Point[this.points.length];
Point point;
for (int i = 0; i < this.points.length; i++) {
point = this.points[i];
points[i] = point.rotateY(origin, angle);
}
return new Path(points);
}

public Path rotateZ(Point origin, double angle) {
List<Point> points = new ArrayList<>();
for (Point point : this.points) {
points.add(point.rotateZ(origin, angle));
Point[] points = new Point[this.points.length];
Point point;
for (int i = 0; i < this.points.length; i++) {
point = this.points[i];
points[i] = point.rotateZ(origin, angle);
}
return new Path(points);
}

public Path scale(Point origin, double dx, double dy, double dz) {
List<Point> points = new ArrayList<>();
for (Point point : this.points) {
points.add(point.scale(origin, dx, dy, dz));
Point[] points = new Point[this.points.length];
Point point;
for (int i = 0; i < this.points.length; i++) {
point = this.points[i];
points[i] = point.scale(origin, dx, dy, dz);
}
return new Path(points);
}

public Path scale(Point origin, double dx, double dy) {
List<Point> points = new ArrayList<>();
for (Point point : this.points) {
points.add(point.scale(origin, dx, dy));
Point[] points = new Point[this.points.length];
Point point;
for (int i = 0; i < this.points.length; i++) {
point = this.points[i];
points[i] = point.scale(origin, dx, dy);
}
return new Path(points);
}

public Path scale(Point origin, double dx) {
List<Point> points = new ArrayList<>();
for (Point point : this.points) {
points.add(point.scale(origin, dx));
Point[] points = new Point[this.points.length];
Point point;
for (int i = 0; i < this.points.length; i++) {
point = this.points[i];
points[i] = point.scale(origin, dx);
}
return new Path(points);
}

public Path translatePoints(double dx, double dy, double dz) {
Point point;
for (int i = 0; i < this.points.length; i++) {
point = this.points[i];
points[i] = point.translate(dx, dy, dz);
}
return this;
}

public double depth() {
int i;
double total = 0;
int length = this.points.size();
int length = this.points.length;
for (i = 0; i < length; i++) {
total += this.points.get(i).depth();
total += this.points[i].depth();
}
if (length == 0) {
length = 1;
Expand All @@ -123,11 +170,11 @@ public int closerThan(Path pathA, Point observer) {

public int countCloserThan(Path pathA, Point observer) {
// the plane containing pathA is defined by the three points A, B, C
Vector AB = Vector.fromTwoPoints(pathA.points.get(0), pathA.points.get(1));
Vector AC = Vector.fromTwoPoints(pathA.points.get(0), pathA.points.get(2));
Vector AB = Vector.fromTwoPoints(pathA.points[0], pathA.points[1]);
Vector AC = Vector.fromTwoPoints(pathA.points[0], pathA.points[2]);
Vector n = Vector.crossProduct(AB, AC);

Vector OA = Vector.fromTwoPoints(Point.ORIGIN, pathA.points.get(0));
Vector OA = Vector.fromTwoPoints(Point.ORIGIN, pathA.points[0]);
Vector OU = Vector.fromTwoPoints(Point.ORIGIN, observer); //U = user = observer

// Plane defined by pathA such as ax + by + zc = d
Expand All @@ -136,9 +183,9 @@ public int countCloserThan(Path pathA, Point observer) {
double observerPosition = Vector.dotProduct(n, OU) - d;
int result = 0;
int result0 = 0;
int length = this.points.size();
int length = this.points.length;
for (int i = 0; i < length; i++) {
Vector OP = Vector.fromTwoPoints(Point.ORIGIN, this.points.get(i));
Vector OP = Vector.fromTwoPoints(Point.ORIGIN, this.points[i]);
double pPosition = Vector.dotProduct(n, OP) - d;
if (observerPosition * pPosition >= 0.000000001) { //careful with rounding approximations
result++;
Expand Down
Loading

0 comments on commit 3d80c72

Please sign in to comment.