Merge remote-tracking branch 'github/jarvis'

This commit is contained in:
Adam
2017-08-13 20:04:44 -04:00
11 changed files with 434 additions and 20 deletions

View File

@@ -24,6 +24,12 @@
*/
package net.runelite.api;
import java.awt.Polygon;
import java.util.ArrayList;
import java.util.List;
import net.runelite.api.model.Jarvis;
import net.runelite.api.model.Vertex;
/**
*
* @author Adam
@@ -55,4 +61,82 @@ public class GameObject extends TileObject
{
return gameObject.getY();
}
public Renderable getRenderable()
{
return Renderable.of(gameObject.getRenderable());
}
public Polygon getConvexHull()
{
Renderable renderable = getRenderable();
if (renderable == null)
{
return null;
}
Model model;
if (renderable instanceof Model)
{
model = (Model) renderable;
}
else
{
model = renderable.getModel();
}
if (model == null)
{
return null;
}
int localX = gameObject.getX();
int localY = gameObject.getY();
// models are orientated north (1024) and there are 2048 angles total
int orientation = (gameObject.getOrientation() + 1024) % 2048;
List<Vertex> verticies = model.getVertices();
if (orientation != 0)
{
// rotate verticies
for (int i = 0; i < verticies.size(); ++i)
{
Vertex v = verticies.get(i);
verticies.set(i, v.rotate(orientation));
}
}
List<Point> points = new ArrayList<>();
for (Vertex v : verticies)
{
// Compute canvas location of vertex
Point p = Perspective.worldToCanvas(client,
localX - v.getX(),
localY - v.getZ(),
-v.getY());
if (p != null)
{
points.add(p);
}
}
// Run Jarvis march algorithm
points = Jarvis.convexHull(points);
if (points == null)
{
return null;
}
// Convert to a polygon
Polygon p = new Polygon();
for (Point point : points)
{
p.addPoint(point.getX(), point.getY());
}
return p;
}
}

View File

@@ -29,12 +29,13 @@ import java.util.List;
import net.runelite.api.model.Triangle;
import net.runelite.api.model.Vertex;
public class Model
public class Model extends Renderable
{
private final net.runelite.rs.api.Model model;
public Model(net.runelite.rs.api.Model model)
{
super(model);
this.model = model;
}

View File

@@ -68,7 +68,7 @@ public class Node
if (node instanceof net.runelite.rs.api.Renderable)
{
return new Renderable((net.runelite.rs.api.Renderable) node);
return Renderable.of((net.runelite.rs.api.Renderable) node);
}
if (node instanceof net.runelite.rs.api.WidgetNode)

View File

@@ -128,24 +128,12 @@ public class Player extends Actor
Vertex c = triangle.getC();
Triangle rotatedTriangle = new Triangle(
rotate(a, orientation),
rotate(b, orientation),
rotate(c, orientation)
a.rotate(orientation),
b.rotate(orientation),
c.rotate(orientation)
);
rotatedTriangles.add(rotatedTriangle);
}
return rotatedTriangles;
}
private Vertex rotate(Vertex vertex, int orientation)
{
int sin = Perspective.SINE[orientation];
int cos = Perspective.COSINE[orientation];
return new Vertex(
vertex.getX() * cos + vertex.getZ() * sin >> 16,
vertex.getY(),
vertex.getZ() * cos - vertex.getX() * sin >> 16
);
}
}

View File

@@ -36,11 +36,22 @@ public class Renderable extends Node
public Model getModel()
{
return new Model(renderable.getModel());
net.runelite.rs.api.Model model = renderable.getModel();
return model != null ? new Model(model) : null;
}
public static Renderable of(net.runelite.rs.api.Renderable renderable)
{
return (Renderable) Node.of(renderable);
if (renderable == null)
{
return null;
}
if (renderable instanceof net.runelite.rs.api.Model)
{
return new Model((net.runelite.rs.api.Model) renderable);
}
return new Renderable(renderable);
}
}

View File

@@ -0,0 +1,117 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.api.model;
import java.util.ArrayList;
import java.util.List;
import net.runelite.api.Point;
/**
* Implementation of the Jarvis march algorithm
* https://en.wikipedia.org/wiki/Gift_wrapping_algorithm
* @author adam
*/
public class Jarvis
{
/**
* compute the convex hull of a given set of points
*
* @param points
* @return
*/
public static List<Point> convexHull(List<Point> points)
{
if (points.size() < 3)
{
return null;
}
List<Point> ch = new ArrayList<>();
// find the left most point
Point left = findLeftMost(points);
// current point we are on
Point current = left;
do
{
ch.add(current);
// the next point - all points are to the right of the
// line between current and next
Point next = null;
for (Point p : points)
{
if (next == null)
{
next = p;
continue;
}
int cp = crossProduct(current, p, next);
if (cp > 0 || (cp == 0 && current.distanceTo(p) > current.distanceTo(next)))
{
next = p;
}
}
assert next != null;
assert ch.size() <= points.size() : "hull has more points than graph";
current = next;
}
while (current != left);
return ch;
}
private static Point findLeftMost(List<Point> points)
{
Point left = null;
for (Point p : points)
{
if (left == null || p.getX() < left.getX())
{
left = p;
}
else if (p.getX() == left.getX() && p.getY() < left.getY())
{
left = p;
}
}
return left;
}
private static int crossProduct(Point p, Point q, Point r)
{
int val = (q.getY() - p.getY()) * (r.getX() - q.getX())
- (q.getX() - p.getX()) * (r.getY() - q.getY());
return val;
}
}

View File

@@ -24,6 +24,8 @@
*/
package net.runelite.api.model;
import java.util.Objects;
public class Triangle
{
private final Vertex a;
@@ -43,6 +45,43 @@ public class Triangle
return "Triangle{" + "a=" + a + ", b=" + b + ", c=" + c + '}';
}
@Override
public int hashCode()
{
int hash = 7;
hash = 13 * hash + Objects.hashCode(this.a);
hash = 13 * hash + Objects.hashCode(this.b);
hash = 13 * hash + Objects.hashCode(this.c);
return hash;
}
@Override
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
final Triangle other = (Triangle) obj;
if (!Objects.equals(this.a, other.a))
{
return false;
}
if (!Objects.equals(this.b, other.b))
{
return false;
}
if (!Objects.equals(this.c, other.c))
{
return false;
}
return true;
}
public Vertex getA()
{
return a;

View File

@@ -24,6 +24,8 @@
*/
package net.runelite.api.model;
import net.runelite.api.Perspective;
public class Vertex
{
private final int x;
@@ -43,6 +45,43 @@ public class Vertex
return "Vertex{" + "x=" + x + ", y=" + y + ", z=" + z + '}';
}
@Override
public int hashCode()
{
int hash = 7;
hash = 67 * hash + this.x;
hash = 67 * hash + this.y;
hash = 67 * hash + this.z;
return hash;
}
@Override
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
final Vertex other = (Vertex) obj;
if (this.x != other.x)
{
return false;
}
if (this.y != other.y)
{
return false;
}
if (this.z != other.z)
{
return false;
}
return true;
}
public int getX()
{
return x;
@@ -57,4 +96,21 @@ public class Vertex
{
return z;
}
/**
* Rotate the vertex by the given orientation
* @param orientation
* @return the newly rotated vertex
*/
public Vertex rotate(int orientation)
{
int sin = Perspective.SINE[orientation];
int cos = Perspective.COSINE[orientation];
return new Vertex(
x * cos + z * sin >> 16,
y,
z * cos - x * sin >> 16
);
}
}

View File

@@ -0,0 +1,110 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.api.model;
import java.util.Arrays;
import java.util.List;
import net.runelite.api.Point;
import org.junit.Assert;
import org.junit.Test;
public class JarvisTest
{
@Test
public void test()
{
Point[] points =
{
new Point(0, 3),
new Point(1, 1),
new Point(2, 2),
new Point(4, 4),
new Point(0, 0),
new Point(1, 2),
new Point(3, 1),
new Point(3, 3)
};
List<Point> result = Jarvis.convexHull(Arrays.asList(points));
Assert.assertEquals(4, result.size());
Assert.assertEquals(new Point(0, 0), result.get(0));
Assert.assertEquals(new Point(0, 3), result.get(1));
Assert.assertEquals(new Point(4, 4), result.get(2));
Assert.assertEquals(new Point(3, 1), result.get(3));
}
@Test
public void test2()
{
Point[] points =
{
new Point(0, 3),
new Point(4, 2),
new Point(3, 5),
new Point(5, 3),
new Point(3, 0),
new Point(1, 1),
new Point(1, 2),
new Point(2, 2)
};
List<Point> result = Jarvis.convexHull(Arrays.asList(points));
Assert.assertEquals(5, result.size());
Assert.assertEquals(new Point(0, 3), result.get(0));
Assert.assertEquals(new Point(3, 5), result.get(1));
Assert.assertEquals(new Point(5, 3), result.get(2));
Assert.assertEquals(new Point(3, 0), result.get(3));
Assert.assertEquals(new Point(1, 1), result.get(4));
}
@Test
public void testCollinear()
{
Point[] points = new Point[]
{
new Point(604, 76),
new Point(609, 81),
new Point(606, 78),
new Point(602, 74),
new Point(610, 74),
new Point(609, 77),
new Point(602, 72),
new Point(606, 77),
new Point(611, 77),
new Point(607, 72),
new Point(616, 74),
new Point(611, 70),
new Point(611, 71),
new Point(610, 73),
new Point(614, 82),
new Point(615, 79),
new Point(615, 77),
new Point(615, 76),
new Point(634, 71),
new Point(604, 76)
};
Jarvis.convexHull(Arrays.asList(points));
}
}

View File

@@ -252,6 +252,14 @@ public class DevToolsOverlay extends Overlay
{
OverlayUtil.renderTileOverlay(graphics, gameObject, "ID: " + gameObject.getId(), GREEN);
}
// Draw a polygon around the convex hull
// of the model vertices
Polygon p = gameObject.getConvexHull();
if (p != null)
{
graphics.drawPolygon(p);
}
}
}
}

View File

@@ -27,7 +27,7 @@ package net.runelite.rs.api;
import net.runelite.mapping.Import;
public interface Model
public interface Model extends Renderable
{
@Import("verticesX")
int[] getVerticesX();