Find connected rectangles from a HashSet using java - java

I have a HashSet filled with custom rectangle object("name",center_X,center_Y, width, height). i wrote a method to find if two rectangles are connected(touch/intersect). But i want to get all the rectangles that are a group. For example: if rectA is connected with rectB, RectC is connected with rectB but not rectA directly they all are connected because rectB is common.
I can find the shapes that have direct connection. But I want to get the group where shapes with secondary connection is also included. I'd assume recursion is useful in this case but can't solve it yet. Any solution/suggestion?
public static void canItbeGroup(HashSet<RECTANGLE> ipRectangles)
{
Deque<RECTANGLE> ipDeque = new ArrayDeque<>(ipRectangles);
for (RECTANGLE currRectangle : ipDeque)
{
Set<String> tempGrpMbrShapeID = new HashSet<>();
RECTANGLE tempRect = ipDeque.pop();
for (RECTANGLE r : ipDeque)
{
if (tempRect.areShapesFriend(r))
{
tempGrpMbrShapeID.add(r.shapeID);
tempGrpMbrShapeID.add(tempRect.shapeID);
}
}
if (tempGrpMbrShapeID.size() > 1)
{
System.out.println(tempGrpMbrShapeID);
}
}
}
public static void main(String[] args)
{
HashSet<RECTANGLE> rectHS = new HashSet<>();
RECTANGLE aRect = new RECTANGLE("a", 3, 2, 2, 2);
RECTANGLE aInnerRect = new RECTANGLE("aIn", 3, 2, 1, 1);
RECTANGLE bRect = new RECTANGLE("b", 5, 3, 2, 2);
RECTANGLE cRect = new RECTANGLE("c", 7, 3, 2, 2);
RECTANGLE dRect = new RECTANGLE("d", 4, 5, 4, 2);
RECTANGLE eRect = new RECTANGLE("e", 11, 3, 2, 2);
RECTANGLE fRect = new RECTANGLE("f", 11, 6, 2, 2);
RECTANGLE gRect = new RECTANGLE("g", 13, 3, 2, 2);
RECTANGLE hRect = new RECTANGLE("h", 4, 8, 2, 2);
RECTANGLE iRect = new RECTANGLE("i", 14, 1, 2, 2);
RECTANGLE jRect = new RECTANGLE("j", 16, 7, 2, 2);
RECTANGLE kRect = new RECTANGLE("k", 15, 6, 2, 2);
RECTANGLE lRect = new RECTANGLE("l", 8, 8, 2, 2);
RECTANGLE mRect = new RECTANGLE("m", 5, 10, 2, 2);
rectHS.add(aRect);
rectHS.add(bRect);
rectHS.add(cRect);
rectHS.add(eRect);
rectHS.add(dRect);
rectHS.add(fRect);
rectHS.add(gRect);
rectHS.add(aInnerRect);
rectHS.add(hRect);
rectHS.add(iRect);
rectHS.add(jRect);
rectHS.add(kRect);
rectHS.add(lRect);
rectDQ.add(aRect);
rectDQ.add(bRect);
rectDQ.add(cRect);
rectDQ.add(dRect);
rectDQ.add(eRect);
canItbeGroup(rectHS);
}
output i get:
[a, b, aIn],[b, c, d],[g, i],[e, g],[j, k],[c, d]
I'll need the group as
[a,b,aIn,c,d], [e,g,i], [j,k]

I won't solve the problem for you, but I will give you a general approach.
Generate an initial Collection<Set<String>>. This is effectively what you've already done, but you'll need to store them so that you can merge the sets, rather than printing the group as soon as your find them
Iterate over all groups (i), and compare each group to every other group (j)
If the i contains any item of j then merge the sets (put all items of j into i, and remove all items from j)
Go back to 2 and repeat until you perform 1 full iteration where no merges occur.
Iterate again and remove any empty sets.

Related

Java algorithm for finding faces in a graph

I have a planar graph which I am creating myself. I want to find the faces of this graph but I can't find a working algorithm for doing so. What I've done so far is using an algorithm to find all the cycles in the graph but this gives me all possible cycles and I've tried but not found a way to only sort the faces out. One of my ideas was to use Path2Ds contains method to see if another shape was overlapping but since the faces share nodes, that doesn't work. The picture below demonstrates what I want and the code after shows my reproductionable example.
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
public class PolygonFinder {
// Graph modeled as list of edges
static int[][] graph
= {
{1, 2}, {1, 6}, {1, 5}, {2, 6},
{2, 3}, {3, 7}, {7, 4}, {3, 4},
{5, 4}, {6, 5}
};
static List<int[]> cycles = new ArrayList<>();
/**
* #param args
*/
public static void main(String[] args) {
for (int[] graph1 : graph) {
for (int j = 0; j < graph1.length; j++) {
findNewCycles(new int[]{graph1[j]});
}
}
cycles.stream().map(cy -> {
String s = "" + cy[0];
for (int i = 1; i < cy.length; i++) {
s += "," + cy[i];
}
return s;
}).forEachOrdered(s -> {
System.out.println(s);
});
}
static void findNewCycles(int[] path) {
int n = path[0];
int x;
int[] sub = new int[path.length + 1];
for (int[] graph1 : graph) {
for (int y = 0; y <= 1; y++) {
if (graph1[y] == n) {
x = graph1[(y + 1) % 2];
if (!visited(x, path)) // neighbor node not on path yet
{
sub[0] = x;
System.arraycopy(path, 0, sub, 1, path.length);
// explore extended path
findNewCycles(sub);
} else if ((path.length > 2) && (x == path[path.length - 1])) // cycle found
{
int[] p = normalize(path);
int[] inv = invert(p);
if (isNew(p) && isNew(inv)) {
cycles.add(p);
}
}
}
}
}
}
// check of both arrays have same lengths and contents
static Boolean equals(int[] a, int[] b) {
Boolean ret = (a[0] == b[0]) && (a.length == b.length);
for (int i = 1; ret && (i < a.length); i++) {
if (a[i] != b[i]) {
ret = false;
}
}
return ret;
}
// create a path array with reversed order
static int[] invert(int[] path) {
int[] p = new int[path.length];
for (int i = 0; i < path.length; i++) {
p[i] = path[path.length - 1 - i];
}
return normalize(p);
}
// rotate cycle path such that it begins with the smallest node
static int[] normalize(int[] path) {
int[] p = new int[path.length];
int x = smallest(path);
int n;
System.arraycopy(path, 0, p, 0, path.length);
while (p[0] != x) {
n = p[0];
System.arraycopy(p, 1, p, 0, p.length - 1);
p[p.length - 1] = n;
}
return p;
}
// compare path against known cycles
// return true, iff path is not a known cycle
static Boolean isNew(int[] path) {
Boolean ret = true;
for (int[] p : cycles) {
if (equals(p, path)) {
ret = false;
break;
}
}
return ret;
}
// return the int of the array which is the smallest
static int smallest(int[] path) {
int min = path[0];
for (int p : path) {
if (p < min) {
min = p;
}
}
return min;
}
// check if vertex n is contained in path
static Boolean visited(int n, int[] path) {
Boolean ret = false;
for (int p : path) {
if (p == n) {
ret = true;
break;
}
}
return ret;
}
}
The result after running the above code is:
1,6,2
1,5,6,2
1,5,4,7,3,2
1,6,5,4,7,3,2
1,5,4,3,2
1,6,5,4,3,2
1,5,4,7,3,2,6
1,5,4,3,2,6
1,5,6
2,3,7,4,5,6
2,3,4,5,6
3,4,7
One of my best attempts at solving this is with the following code. The coordinates comes from the picture at the top.
List<Polygon> polys = new LinkedList<>();
Polygon p1 = new Polygon();
p1.addPoint(new Point2D.Double(-4, 4));
p1.addPoint(new Point2D.Double(-1, 3));
p1.addPoint(new Point2D.Double(-1, 5));
Polygon p2 = new Polygon();
p2.addPoint(new Point2D.Double(-4, 4));
p2.addPoint(new Point2D.Double(0, -2));
p2.addPoint(new Point2D.Double(-1, 3));
p2.addPoint(new Point2D.Double(-1, 5));
Polygon p3 = new Polygon();
p3.addPoint(new Point2D.Double(-4, 4));
p3.addPoint(new Point2D.Double(0, -2));
p3.addPoint(new Point2D.Double(4, 1));
p3.addPoint(new Point2D.Double(2, 2));
p3.addPoint(new Point2D.Double(3, 4));
p3.addPoint(new Point2D.Double(-1, 5));
Polygon p4 = new Polygon();
p4.addPoint(new Point2D.Double(-4, 4));
p4.addPoint(new Point2D.Double(-1, 3));
p4.addPoint(new Point2D.Double(0, -2));
p4.addPoint(new Point2D.Double(4, 1));
p4.addPoint(new Point2D.Double(2, 2));
p4.addPoint(new Point2D.Double(3, 4));
p4.addPoint(new Point2D.Double(-1, 5));
Polygon p5 = new Polygon();
p5.addPoint(new Point2D.Double(-4, 4));
p5.addPoint(new Point2D.Double(0, -2));
p5.addPoint(new Point2D.Double(4, 1));
p5.addPoint(new Point2D.Double(3, 4));
p5.addPoint(new Point2D.Double(-1, 5));
Polygon p6 = new Polygon();
p6.addPoint(new Point2D.Double(-4, 4));
p6.addPoint(new Point2D.Double(-1, 3));
p6.addPoint(new Point2D.Double(0, -2));
p6.addPoint(new Point2D.Double(4, 1));
p6.addPoint(new Point2D.Double(3, 4));
p6.addPoint(new Point2D.Double(-1, 5));
Polygon p7 = new Polygon();
p7.addPoint(new Point2D.Double(-4, 4));
p7.addPoint(new Point2D.Double(0, -2));
p7.addPoint(new Point2D.Double(4, 1));
p7.addPoint(new Point2D.Double(2, 2));
p7.addPoint(new Point2D.Double(3, 4));
p7.addPoint(new Point2D.Double(-1, 5));
p7.addPoint(new Point2D.Double(-1, 3));
Polygon p8 = new Polygon();
p8.addPoint(new Point2D.Double(-4, 4));
p8.addPoint(new Point2D.Double(0, -2));
p8.addPoint(new Point2D.Double(4, 1));
p8.addPoint(new Point2D.Double(3, 4));
p8.addPoint(new Point2D.Double(-1, 5));
p8.addPoint(new Point2D.Double(-1, 3));
Polygon p9 = new Polygon();
p9.addPoint(new Point2D.Double(-4, 4));
p9.addPoint(new Point2D.Double(0, -2));
p9.addPoint(new Point2D.Double(-1, 3));
Polygon p10 = new Polygon();
p10.addPoint(new Point2D.Double(-1, 5));
p10.addPoint(new Point2D.Double(3, 4));
p10.addPoint(new Point2D.Double(2, 2));
p10.addPoint(new Point2D.Double(4, 1));
p10.addPoint(new Point2D.Double(0, -2));
p10.addPoint(new Point2D.Double(-1, 3));
Polygon p11 = new Polygon();
p11.addPoint(new Point2D.Double(-1, 5));
p11.addPoint(new Point2D.Double(3, 4));
p11.addPoint(new Point2D.Double(4, 1));
p11.addPoint(new Point2D.Double(0, -2));
p11.addPoint(new Point2D.Double(-1, 3));
Polygon p12 = new Polygon();
p12.addPoint(new Point2D.Double(3, 4));
p12.addPoint(new Point2D.Double(4, 1));
p12.addPoint(new Point2D.Double(2, 2));
polys.add(p1);
polys.add(p2);
polys.add(p3);
polys.add(p4);
polys.add(p5);
polys.add(p6);
polys.add(p7);
polys.add(p8);
polys.add(p9);
polys.add(p10);
polys.add(p11);
polys.add(p12);
Set<Integer> toRemove = new HashSet<>();
for (Polygon polyI : polys) {
for (Polygon polyJ : polys) {
if (polyI.equals(polyJ)) {
continue;
}
if (polyI.contains(polyJ)) {
toRemove.add(polys.indexOf(polyI));
}
}
}
List<Integer> list = new LinkedList<>(toRemove);
Collections.sort(list);
Collections.reverse(list);
list.forEach((t) -> {
polys.remove(t.intValue());
});
System.out.println("");
polys.forEach((t) -> {
System.out.println(t.getPoints());
});
Polygons methods used is listed here.
#Override
public boolean contains(Point2D point) {
return getPath().contains(point);
}
#Override
public boolean contains(IPolygon polygon) {
List<Point2D> p2Points = polygon.getPoints();
for (Point2D point : p2Points) {
if (getPath().contains(point)) {
if (!points.contains(point)) {
return true;
}
}
}
return false;
}
private Path2D getPath() {
Path2D path = new Path2D.Double();
path.moveTo(points.get(0).getX(), points.get(0).getY());
for (int i = 1; i < points.size(); i++) {
path.lineTo(points.get(i).getX(), points.get(i).getY());
}
path.closePath();
return path;
}
This code gives me the result below and the 2nd-4th is not wanted.
[Point2D.Double[-4.0, 4.0], Point2D.Double[-1.0, 3.0], Point2D.Double[-1.0, 5.0]]
[Point2D.Double[-4.0, 4.0], Point2D.Double[0.0, -2.0], Point2D.Double[-1.0, 3.0], Point2D.Double[-1.0, 5.0]]
[Point2D.Double[-4.0, 4.0], Point2D.Double[-1.0, 3.0], Point2D.Double[0.0, -2.0], Point2D.Double[4.0, 1.0], Point2D.Double[2.0, 2.0], Point2D.Double[3.0, 4.0], Point2D.Double[-1.0, 5.0]]
[Point2D.Double[-4.0, 4.0], Point2D.Double[0.0, -2.0], Point2D.Double[4.0, 1.0], Point2D.Double[2.0, 2.0], Point2D.Double[3.0, 4.0], Point2D.Double[-1.0, 5.0], Point2D.Double[-1.0, 3.0]]
[Point2D.Double[-4.0, 4.0], Point2D.Double[0.0, -2.0], Point2D.Double[-1.0, 3.0]]
[Point2D.Double[-1.0, 5.0], Point2D.Double[3.0, 4.0], Point2D.Double[2.0, 2.0], Point2D.Double[4.0, 1.0], Point2D.Double[0.0, -2.0], Point2D.Double[-1.0, 3.0]]
[Point2D.Double[3.0, 4.0], Point2D.Double[4.0, 1.0], Point2D.Double[2.0, 2.0]]
Here's an option for identifying the faces that's based on the idea of half-edges. At a high level, the approach looks like this:
Replace each edge linking two points u and v with the directed edges (u, v) and (v, u). These are called half-edges.
Chain the half-edges together so that a single chain of half edges perfectly traces out one of the faces of the plane graph.
Walk those chains to identify all of the faces of the plane graph.
Visually, that will look something like this. We'll begin with the graph looking like this:
and end with the graph looking like this:
Once we have that second graph, walking the colored chains will identify all the faces.
The question, then, is how exactly to determine how to chain the half-edges together. The basic idea is the following: we want to chain the edges together so that
all internal faces have the half-edges winding around counterclockwise (or anticlockwise, or widdershins, depending on which side of the pond you're from),
the external face has its half-edges winding around clockwise.
Provided we can come up with a convenient strategy that will chain things like this, we can easily glue the half-edges together to get our desired property. There are many ways to do this, but the one I'd like to focus on works by looking locally at each node.
Imagine you have some node X whose neighbors are A, B, C, and D, as shown below.
Here, I've marked half-edges leaving X in solid blue, and half-edges entering X in dotted orange.
Now, focus on the outgoing half-edge (X, A) in this diagram. When we've wired everything together, some other half-edge (_, X) needs to chain into (X, A). Which edge is it? From the picture, we can see it's the half-edge (B, X), forming the partial chain (B, X), (X, A).
Similarly, focus on the half-edge (X, B) in this diagram. As before, when we've wired all the half-edges into chains, we'd need some way of determining which half-edge (_, X) should come before it. And by inspection, we can see that it would be (C, X).
More generally, notice that
The half-edge before (X, A) is (B, X).
The half-edge before (X, B) is (C, X).
The half-edge before (X, C) is (D, X).
The half-edge before (X, D) is (A, X).
See the pattern? If we order the neighbors around this node counterclockwise (anticlockwise), then the half-edge that comes before an edge (X, Y) can be found as follows: assuming Z is the next neighbor counterclockwise around the node, then the half-edge that comes before (X, Y) is the half-edge (Z, X).
This gives us a very nice strategy for wiring the edges into chains while meeting our above requirements. Here's some pseudocode:
For each node v:
Get v's neighbors sorted anticlockwise as u_1, u_2, u_3, ..., u_n
For each half-edge (v, u_i):
Update half-edge (u_{i+1 mod n}, v) to chain to (v, u_i)
At this point, we've wired everything into chains, and we're done!
There are a few technical details here I've glossed over that would need to be resolved before you code this up. For example:
How do you sort the neighbors of a node v counterclockwise? That can be done by computing the angle each neighbor of v makes with v using Math.atan2(dy, dx) and sorting based on those values.
How do you keep track of what chains into what? If all you're doing is identifying the faces, you could make a Map<HalfEdge, HalfEdge> associating each half-edge with the next half-edge after it. If you're planning on keeping the chains around for the future, you might want to make each HalfEdge part of a linked list that has a reference to the next half-edge in the sequence.
How do you map from a pair of nodes to a half-edge running between them? This could be done with something like a Map from pairs of nodes to half-edges. You could also construct the half-edges and have each half-edge store a pointer to the half-edge running in the other direction.
Attribution: I first learned this algorithm from this related question on the Computer Science Stack Exchange that asks how to build a doubly-connected edge list (DECL) from a collection of line segments. My contributions are in simplifying the algorithm to only give back the chains needed to identify the faces and in adding some visuals to better motivate the concepts.
For each edge, take the co-ordinates within your embedding of the edge's vertices and use them to calculate the angle of the edge using trigonometry.
For example, the angle from (x1, y1) to (x2, y2) measured anti-clockwise from the positive x-axis is given by Math.atan2(y2-y1,x2-x1).
For each vertex, create a cyclic edge ordering by sorting the edges by their angle. This could be stored as an array or you could use a cyclic list data structure.
Pick an edge, follow it to an adjacent vertex and then follow the next adjacent clockwise edge and repeat following edges to the next vertex and then the next clockwise edge until you get back to the starting edge; then you have found a face of the graph.
Repeat step 3 picking an unvisited edge or a visited edge in the opposite direction to previous and follow it in that same clockwise direction to find the next face. Repeat this until all the edges have been visited twice (once in each direction) and then you have found all the faces.
In Java, that would be:
import java.awt.geom.Point2D;
import java.awt.Polygon;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.stream.Collectors;
import java.text.MessageFormat;
public class GraphFaces
{
static class Vertex
{
final int index;
final Point2D point;
final ArrayList<Edge> outboundEdges = new ArrayList<>();
public Vertex( final int index, final Point2D point )
{
this.index = index;
this.point = point;
}
public void addEdge( final Edge edge )
{
this.outboundEdges.add( edge );
}
public void sortEdges()
{
this.outboundEdges.sort((e1,e2)->Double.compare(e1.angle,e2.angle));
Edge prev = this.outboundEdges.get(this.outboundEdges.size() - 1);
for ( final Edge edge: this.outboundEdges )
{
edge.setNextEdge( prev );
prev = edge;
}
}
#Override
public String toString()
{
return Integer.toString(this.index);
// return MessageFormat.format("({0},{1})",this.point.getX(),this.point.getY());
}
}
static class Edge
{
final Vertex from;
final Vertex to;
final double angle;
boolean visited = false;
Edge next = null;
Edge reverse = null;
public Edge( final Vertex from, final Vertex to )
{
this.from = from;
this.to = to;
this.angle = Math.atan2(to.point.getY() - from.point.getY(), to.point.getX() - from.point.getX());
from.addEdge( this );
}
public Vertex getFrom()
{
return this.from;
}
public Vertex getTo()
{
return this.to;
}
public void setNextEdge( final Edge edge )
{
this.next = edge;
}
public void setReverseEdge( final Edge edge )
{
this.reverse = edge;
}
#Override
public String toString()
{
return MessageFormat.format("{0} -> {1}", this.from, this.to);
}
}
public static void main(final String[] args)
{
final Vertex[] vertices = {
new Vertex( 1, new Point2D.Double(-4,+4) ),
new Vertex( 2, new Point2D.Double(-1,+5) ),
new Vertex( 3, new Point2D.Double(+3,+4) ),
new Vertex( 4, new Point2D.Double(+4,+1) ),
new Vertex( 5, new Point2D.Double(+0,-2) ),
new Vertex( 6, new Point2D.Double(-1,+3) ),
new Vertex( 7, new Point2D.Double(+2,+2) )
};
final int[][] graph = {
{1, 2}, {1, 6}, {1, 5}, {2, 6}, {2, 3}, {3, 7}, {7, 4}, {3, 4}, {5, 4}, {6, 5}
};
final Edge[] edges = new Edge[2 * graph.length];
for ( int i = 0; i < graph.length; i++ )
{
final Vertex from = vertices[graph[i][0]-1];
final Vertex to = vertices[graph[i][1]-1];
edges[2*i] = new Edge( from, to );
edges[2*i+1] = new Edge( to, from );
edges[2*i].setReverseEdge(edges[2*i+1]);
edges[2*i+1].setReverseEdge(edges[2*i]);
}
for ( final Vertex vertex: vertices )
{
vertex.sortEdges();
}
final ArrayList<ArrayList<Edge>> faces = new ArrayList<>();
for ( final Edge edge: edges )
{
if ( edge.visited )
{
continue;
}
final ArrayList<Edge> face = new ArrayList<>();
faces.add( face );
Edge e = edge;
do
{
face.add(e);
e.visited = true;
e = e.reverse.next;
}
while (e != edge);
System.out.println( face.stream().map(Edge::getFrom).collect(Collectors.toList()) );
}
}
}
Which outputs:
[1, 2, 3, 4, 5]
[2, 1, 6]
[6, 1, 5]
[2, 6, 5, 4, 7, 3]
[3, 7, 4]
Note: this includes the exterior face of the graph.
Alternatively, if you want to: test your graph for planarity; generate all possible embeddings of a (biconnected) graph; and generate a cyclic edge ordering for one (or more) of those embeddings then you can use the PhD thesis Planarity Testing by Path Addition, which includes complete Java source code in the appendices.
In a planar embedding consisting only of straight lines, the edges of a face meeting in a vertex must be adjacent among all edges of that node.
Therefore, if we are given such an embedding, and sort the edges of each vertex according to their direction, we can easily walk the perimeter of a face by leaving each vertex on the edge immediately to the right of the edge we arrived through.
As a data structure, I'd probably choose something like this:
class Vertex {
Edge edges;
}
class Edge {
Vertex source;
Vertex target;
Edge reverse; // the same edge, seen from the other end
Edge next; // forms a circular linked list, sorted in order of direction
}
Then we can iterate the perimeter of a face like this:
Edge startingEdge = ...;
Edge currentEdge = startingEdge;
do {
currentEdge = currentEdge.reverse.next;
} while (currentEdge != startingEdge);
To sort edges by direction, we can use the fact that a x b is negative if a is to the left of b (as seen from the origin of the coordinate system).
boolean left(Point2D.Double a, Point2D.Double b) {
return a.x * b.y - a.y * b.x < 0;
}
We can the use a simple insertion sort to sort edges by direction (which will be fast enough since planar graphs have a bounded average node degree, so the edge lists will be short).

javafx shape3d texturing: Don't strectch the image

I'm working now with javafx to build a maze and I want the walls to be textured with some seamless texture (that can be repeated). The maze is randomly generated so I don't know the size of any walls. I started by using a PhongMaterial with the desired texture, but it expand the image to fill the whole wall (a Box), so my texture is totally stretched. Is there any way to force the Material to replicate the texture as needed ?
The code is like:
Image img = new Image(new FileInputStream("img.jpg"), 400, 400, true, false);
Material mat = new PhongMaterial(Color.WHITE, img, null, null, null);
Box w = new Box(100,10,10);
w.setMaterial(mat);
Something like an ImagePattern seems a good idea, but there is no Material that accept it.
Thanks in advance for any help
As #fabian mentioned, Box is not suitable for customizing the texture. By default the image you set as diffuse map will be applied for each of its six faces, and, as you already discovered, this means that it will stretch the image to accommodate the different sides.
Using the FXyz library, we can easily try the Carbon-Kevlar pattern. But obviously we have to select a size for it. Like 100 x 30.
#Override
public void start(Stage primaryStage) {
Box box = new Box(100, 30, 50);
PhongMaterial material = new PhongMaterial();
Patterns pattern = new Patterns(100, 30);
material.setDiffuseMap(pattern.createPattern(Patterns.CarbonPatterns.CARBON_KEVLAR, false));
box.setMaterial(material);
Scene scene = new Scene(new Group(box), 500, 400, true, SceneAntialiasing.BALANCED);
primaryStage.setScene(scene);
primaryStage.show();
}
While the texture fits perfectly fine the front face with dimensions 100x30, this image is distorted to fit in the same way the other faces 50x50 and 100x50.
Solution 1
We can try to generate our own Box, so we can decide how to apply the diffuse map.
Creating a TriangleMesh for a cuboid is easy in terms of vertices and faces or normals.
The tricky part is setting the texture coordinates. In the following snippet I set them based on one of the different possible 2D net images of the 3D cuboid:
public MeshView createCuboid(float w, float h, float d) {
float hw = w / 2f;
float hh = h / 2f;
float hd = d / 2f;
float points[] = {
hw, hh, hd,
hw, hh, -hd,
hw, -hh, hd,
hw, -hh, -hd,
-hw, hh, hd,
-hw, hh, -hd,
-hw, -hh, hd,
-hw, -hh, -hd};
float L = 2 * w + 2 * d;
float H = h + 2 * d;
float tex[] = {
d / L, 0f,
(d + w) / L, 0f,
0f, d / H,
d / L, d / H,
(d + w) / L, d / H,
(2 * d + w) / L, d / H,
1f, d / H,
0f, (d + h) / H,
d / L, (d + h) / H,
(d + w) / L, (d + h) / H,
(2 *d + w) / L, (d + h) / H,
1f, (d + h) / H,
d / L, 1f,
(d + w) / L, 1f};
float normals[] = {
1f, 0f, 0f,
-1f, 0f, 0f,
0f, 1f, 0f,
0f, -1f, 0f,
0f, 0f, 1f,
0f, 0f, -1f,
};
int faces[] = {
0, 0, 10, 2, 0, 5, 1, 0, 9,
2, 0, 5, 3, 0, 4, 1, 0, 9,
4, 1, 7, 5, 1, 8, 6, 1, 2,
6, 1, 2, 5, 1, 8, 7, 1, 3,
0, 2, 13, 1, 2, 9, 4, 2, 12,
4, 2, 12, 1, 2, 9, 5, 2, 8,
2, 3, 1, 6, 3, 0, 3, 3, 4,
3, 3, 4, 6, 3, 0, 7, 3, 3,
0, 4, 10, 4, 4, 11, 2, 4, 5,
2, 4, 5, 4, 4, 11, 6, 4, 6,
1, 5, 9, 3, 5, 4, 5, 5, 8,
5, 5, 8, 3, 5, 4, 7, 5, 3};
TriangleMesh mesh = new TriangleMesh();
mesh.setVertexFormat(VertexFormat.POINT_NORMAL_TEXCOORD);
mesh.getPoints().addAll(points);
mesh.getTexCoords().addAll(tex);
mesh.getNormals().addAll(normals);
mesh.getFaces().addAll(faces);
return new MeshView(mesh);
}
Now we can generate the image, but using the net dimensions:
#Override
public void start(Stage primaryStage) {
MeshView box = createCuboid(100, 30, 50);
PhongMaterial material = new PhongMaterial();
Patterns pattern = new Patterns(300, 160);
material.setDiffuseMap(pattern.createPattern(Patterns.CarbonPatterns.CARBON_KEVLAR, false));
box.setMaterial(material);
box.getTransforms().addAll(rotateX, rotateY);
Scene scene = new Scene(new Group(box), 500, 400, true, SceneAntialiasing.BALANCED);
primaryStage.setScene(scene);
primaryStage.show();
}
Note that the image is not distorted anymore.
You can play with its size to get a more fine or dense pattern (with a bigger image pattern).
Note that you can find this Cuboid primitive in the FXyz library, among many other 3D primitives.
Also you can find different texture modes (density maps, images, patterns...)

How to multiply a RealVector by a RealMatrix?

How can I multiply a given RealVector by a RealMatrix? I can't find any "multiply" method on both classes, only preMultiply but it seems not work:
// point to translate
final RealVector p = MatrixUtils.createRealVector(new double[] {
3, 4, 5, 1
});
// translation matrix (6, 7, 8)
final RealMatrix m = MatrixUtils.createRealMatrix(new double[][] {
{1, 0, 0, 6},
{0, 1, 0, 7},
{0, 0, 1, 8},
{0, 0, 0, 1}
});
// p2 = m x p
final RealVector p2 = m.preMultiply(p);
// prints {3; 4; 5; 87}
// expected {9; 11; 13; 1}
System.out.println(p2);
Please compare the actual result with the expected result.
Is there also a way for multiplying a Vector3D by a 4x4 RealMatrix where the w component is throw away? (I'm looking not for custom implementation but an already existing method in the library).
preMultiply does not give you m x p but p x m. This would be suitable for your question but not for your comment // p2 = m x p.
To get the result you want you have two options:
Use RealMatrix#operate(RealVector) which produces m x p:
RealVector mxp = m.operate(p);
System.out.println(mxp);
Transpose the matrix before pre-multiplying:
RealVector pxm_t = m.transpose().preMultiply(p);
System.out.println(pxm_t);
Result:
{9; 11; 13; 1}

Calculate average top third of the population

Could you guys help me which apache-commons-math classes can I use to calculate the average of the top third of the population.
To calculate the average I know can use org.apache.commons.math3.stat.descriptive.DescriptiveStatistics.
How to get the top third of the population?
Example
Population: 0, 0, 0, 0, 0, 1, 2, 2, 3, 5,14
Top third: 2, 3, 5, 14
Average = 24/4= 6.0
First of all what do you call top third of population?
If set is divides by 3 and remainder is 0, then its is simple, but in your case 11%3 = 2.
So You should know how to get top third when remainder is not equal 0.
I would suggest You to use Arrays procedures, to get Top third of set. If You still want to use DescriptiveStatistics you can invoke it.
double[] set = {0, 0, 0, 0, 0, 1, 2, 2, 3,4,5};
Arrays.sort(set);
int from = 0;
if (set.length % 3==0){
from = set.length/3*2 ;
}
if (set.length % 3 != 0){
from = Math.round(set.length/3*2) + 1;
}
double [] topThirdSet = Arrays.copyOfRange(set,from , set.length);
DescriptiveStatistics ds = new DescriptiveStatistics(topThirdSet);
System.out.println(ds.getMean());

Eclipse reporting errors on arrays for Android

I'm trying to get a 3D array initialized for a game I'm working on, after multiple syntax changes I couldn't figure out how to get it to work! What I started with was:
public class AnimationView extends SurfaceView implements SurfaceHolder.Callback {//Create bitmaps.
Bitmap bitmapGoal = BitmapFactory.decodeResource(this.getResources(), R.drawable.goal);
Bitmap bitmapOrig = BitmapFactory.decodeResource(this.getResources(), R.drawable.ball);
Bitmap bitmap = Bitmap.createScaledBitmap(bitmapOrig, 150, 150, true);
//initialize the canvas.
private Canvas c;
private int score[] = {0, 0, 0, 0};
public int numBalls = 1;
//we support up to 4 balls. thus each array is 4 bit.
private int ballX[] = {0, 200, 400, 600};
private double ballY[] = {0, 0, 0, 0};
private double dirV[] = {0, 0, 0, 0};
private int dirH[] = {30, 30, 30, 30};
private static final int SCALE = 10;
private double elasticity = .6;
private int rotationNow[] = {5, 5, 5, 5};
private int rotationDraw[] = {0, 0, 0, 0};
class AnimationThread extends Thread {
//Are we running currently?
private boolean mRun;
//layer 1 is how many balls, 4 layers deep.
//layer 2 is which ball we're talking about, either 1, 2, 3, or 4 layers deep, depending on layer 1.
//layer 3 is the bounds of the ball, dependent on how many there are total.
//layer 3 is formatted x-min, x-max, y-min, y-max
int[][][] bounds = new int[][][] {
{ {0, c.getWidth() - bitmap.getWidth(), 0, c.getHeight() - bitmap.getHeight()}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0} },
//end first layer
{ {0, c.getWidth() / 2 - bitmap.getWidth(), 0, c.getHeight() - bitmap.getHeight()}, {c.getWidth() / 2, c.getWidth() - bitmap.getWidth(), 0, c.getHeight() - bitmap.getHeight()}, {0, 0, 0, 0}, {0, 0, 0, 0} },
//end second layer
{ {0, c.getWidth() / 3 - bitmap.getWidth(), 0, c.getHeight() - bitmap.getHeight()}, {c.getWidth() / 3, c.getWidth() * 2 / 3 - bitmap.getWidth(), 0, c.getHeight() - bitmap.getHeight()}, {c.getWidth() * 2 / 3, c.getWidth() - bitmap.getWidth(), 0, c.getHeight() - bitmap.getHeight()}, {0, 0, 0, 0} },
//end third layer
{ {0, c.getWidth() / 2, 0, c.getHeight() / 2}, {c.getWidth() / 2, c.getWidth(), 0, c.getHeight() / 2}, {0, c.getWidth() / 2, c.getHeight() / 2, c.getHeight()}, {c.getWidth() / 2, c.getWidth(), c.getHeight() / 2, c.getHeight()} }
//end fourth, and final layer!
};
Sorry about the weird formatting error. I know this doesn't help anything. There is a new line between ymax and int[][][].
You don't exactly need to look through it and understand, but this compiled and then errored out during execution. So then I tried to make a simple 3D array, I started with:
int[][][] bounds = new int[1][1][1];
bounds[0][0][0] = 0;
Eclipse had it's red squiggly under the semi-colon on the first line. Saying
'Syntax error on token ";", { expected after this token'
This is where it gets frustrating. Because that exact same code copy/pasted into a regular Java program works fine, but I can NOT get it to work inside an Android project. I then simplified some stuff, to this:
int[] bounds = new int[1];
bounds[0] = 0;
Exact same error, exact same place! Why Eclipse?? I also tried it with "int bounds[][][]" as opposed to "int[][][] bounds" but no difference, still same error.
I've rebooted my computer, cleaned my project multiple times, restarted Eclipse. I'm out of ideas. Do you have any??
Well, seems like the problem is not before, but after the code you pasted.
this assignment - bounds[0][0][0] = 0; is probably not in any method and this is illegal. When Eclipse sees an expression that need to be inside a method, it expects the line above to be the method declaration, so it expects '{' as a beginning of a method block, and not ';'
Ok, I feel ridiculous. After being very, very confused at why the variable couldn't initialize and why the very simple code then wouldn't compile. It turns out, though the canvas and bitmaps were available, it was infact them returning null values into the array.
So I got it working now.
Also, for my first question here, I was extremely impressed with the speediness of the solutions. Thanks a ton!
int[][][] bounds = new int[1][1][1];
bounds[0][0][0] = 0;
I copied these two lines and seem to be compiling fine.
I think you might have forgot to comment the earlier declaration of bounds . (or) you might be missing braces or something like that

Categories

Resources