Skip to content

Commit

Permalink
Drawing Improvements (#3)
Browse files Browse the repository at this point in the history
* added facial culling  using the shoelace formula
https://www.cs.uic.edu/~jbell/CourseNotes/ComputerGraphics/VisibleSurfaces.html

https://en.wikipedia.org/wiki/Back-face_culling

https://en.wikipedia.org/wiki/Shoelace_formula

* only perform measure operations when necessary

* better to remove items than to ignore drawing them

if an item is ignored, it still goes through sorting. If the item is removed all together, don't need to worry about if the item is drawn or not later in processing

* dont consider item if it is out of bounds

* add user settable variable for bounds checking of items.
  • Loading branch information
Cameron White authored and FabianTerhorst committed Oct 21, 2018
1 parent 32fcf92 commit f9595f0
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 8 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ isometricView.add(new Path(new Point[]{
# Include in your project
## Using JCenter
```groovy
compile 'io.fabianterhorst:Isometric:0.0.6.5'
compile 'io.fabianterhorst:Isometric:0.0.7'
```

### Available Shapes
Expand Down
6 changes: 3 additions & 3 deletions lib/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ android {
defaultConfig {
minSdkVersion 14
targetSdkVersion 27
versionCode 6
versionName "0.0.6"
versionCode 7
versionName "0.0.7"
testInstrumentationRunner 'io.fabianterhorst.isometric.screenshot.IsometricTestRunner'
}
buildTypes {
Expand All @@ -37,7 +37,7 @@ android {
def siteUrl = 'https://github.com/FabianTerhorst/Isometric'
def gitUrl = 'https://github.com/FabianTerhorst/Isometric.git'

version = "0.0.6.5"
version = "0.0.7"
group = "io.fabianterhorst"

install {
Expand Down
65 changes: 63 additions & 2 deletions lib/src/main/java/io/fabianterhorst/isometric/Isometric.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ public class Isometric {

private final Color lightColor;

private int currentWidth, currentHeight;

private boolean itemsChanged;

public Isometric() {
this.angle = Math.PI / 6;
this.scale = 70;
Expand All @@ -43,6 +47,9 @@ public Isometric() {
this.lightAngle = lightPosition.normalize();
this.colorDifference = 0.20;
this.lightColor = new Color(255, 255, 255);
this.currentWidth = -1;
this.currentHeight = -1;
this.itemsChanged = true;

}

Expand Down Expand Up @@ -76,10 +83,12 @@ public void add(Shape shape, Color color) {
}

public void clear() {
this.itemsChanged = true;
items.clear();
}

private void addPath(Path path, Color color) {
this.itemsChanged = true;
this.items.add(new Item(path, transformColor(path, color)));
}

Expand All @@ -105,11 +114,24 @@ private Color transformColor(Path path, Color color) {
return color.lighten(brightness * this.colorDifference, this.lightColor);
}

public void measure(int width, int height, boolean sort) {
public void measure(int width, int height, boolean sort, boolean cull, boolean boundsCheck) {

//only perform measure operation:
//if the bounds have changed
//OR if the items have changed
if (this.currentWidth == width && this.currentHeight == height && !this.itemsChanged)
return;

this.currentWidth = width;
this.currentHeight = height;
this.itemsChanged = false;

this.originX = width / 2;
this.originY = height * 0.9;

for (Item item : items) {
int itemIndex = 0, itemSize = items.size();
while (itemIndex < itemSize) {
Item item = items.get(itemIndex);

item.transformedPoints = new Point[item.path.points.length];

Expand All @@ -123,6 +145,19 @@ public void measure(int width, int height, boolean sort) {
item.transformedPoints[i] = translatePoint(point);
}

//remove item if not in view
//the if conditions here are ordered carefully to save computation, fail fast approach
if ((cull && cullPath(item)) || (boundsCheck && !this.itemInDrawingBounds(item))) {
//the path is invisible. It does not need to be considered any more
this.items.remove(itemIndex);
itemSize--;
continue;
}
else
{
itemIndex++;
}

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

for (int i = 1, length = item.transformedPoints.length; i < length; i++) {
Expand All @@ -137,6 +172,32 @@ public void measure(int width, int height, boolean sort) {
}
}

private boolean cullPath(Item item) {
double a = item.transformedPoints[0].getX() * item.transformedPoints[1].getY();
double b = item.transformedPoints[1].getX() * item.transformedPoints[2].getY();
double c = item.transformedPoints[2].getX() * item.transformedPoints[0].getY();

double d = item.transformedPoints[1].getX() * item.transformedPoints[0].getY();
double e = item.transformedPoints[2].getX() * item.transformedPoints[1].getY();
double f = item.transformedPoints[0].getX() * item.transformedPoints[2].getY();

double z = a + b + c - d - e - f;
return z > 0;
}

private boolean itemInDrawingBounds(Item item) {
for (int i = 0, len = item.transformedPoints.length; i< len; i++)
{
//if any point is in bounds, the item is worth drawing
if (item.transformedPoints[i].getX() >= 0 &&
item.transformedPoints[i].getX() <= this.currentWidth &&
item.transformedPoints[i].getY() >= 0 &&
item.transformedPoints[i].getY() <= this.currentHeight)
return true;
}
return false;
}

private List<Item> sortPaths() {
ArrayList<Item> sortedItems = new ArrayList<>();
Point observer = new Point(-10, -10, 20);
Expand Down
19 changes: 17 additions & 2 deletions lib/src/main/java/io/fabianterhorst/isometric/IsometricView.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public interface OnItemClickListener {

private OnItemClickListener listener;

private boolean sort = true;
private boolean sort = true, cull = false, boundsCheck = false;

public IsometricView(Context context) {
super(context);
Expand All @@ -32,6 +32,21 @@ public void setSort(boolean sort) {
this.sort = sort;
}

/**
* This greatly improves drawing speed
* Paths must be defined in a counter-clockwise rotation order
*/
public void setCull(boolean cull) {
this.cull = cull;
}

/**
* This improves drawing speed by not considering items that are outside of view bounds
*/
public void setBoundsCheck(boolean boundsCheck) {
this.boundsCheck = boundsCheck;
}

public void setClickListener(OnItemClickListener listener) {
this.listener = listener;
}
Expand Down Expand Up @@ -64,7 +79,7 @@ public IsometricView(Context context, AttributeSet attrs, int defStyleAttr, int
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
isometric.measure(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec), sort);
isometric.measure(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec), sort, cull, boundsCheck);
}

@Override
Expand Down

0 comments on commit f9595f0

Please sign in to comment.