at the moment, I'm trying to change the color of a specific vertex in JUNG.
I know i can use the following function to change the color of all nodes.
Is it possible to substitute v from the following line with a specific node.
vv.getRenderContext().setVertexFillPaintFunction(v -> Color.blue);
Or should i use transformer classes?
You can certainly supply a more complex Function than v -> Color.blue if you like; for instance:
vv.getRenderContext().setVertexFillPaintFunction(
v -> v.equals(specialNode) ? Color.red : Color.blue);
For more information on specifying Functions (using lambda expressions or not), see https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html.
Related
I am creating an Android app that draws to the canvas. For this, I have defined rectangular screenareas that I want to draw to the canvas. As I am always drawing a fixed set of screenareas, I was thinking of using Enum (as Enum is designed for fixed sets).
Here is my enum:
public enum LayoutEnum {
FULLSCREEN(
new ScreenArea(
new Rect(
0,
0,
MainActivity.getDevice().getWidth(),
MainActivity.getDevice().getHeight()),
Attributes.BG_PAINT)),
LOGO_AREA(
new ScreenArea (
new Rect(
(int) (0.3 * FULLSCREEN.getScreenArea().getArea().width()),
(int) (0.3 * FULLSCREEN.getScreenArea().getArea().width()),
(int) (FULLSCREEN.getScreenArea().getArea().width() - 0.3 * FULLSCREEN.getScreenArea().getArea().width()),
(int) (0.7 * FULLSCREEN.getScreenArea().getArea().width())),
Attributes.BG_PAINT)
);
private ScreenArea screenArea;
LayoutEnum(ScreenArea screenArea) {
this.screenArea = screenArea;
}
public ScreenArea getScreenArea() {
return screenArea;
}
}
ScreenArea is a simple class that holds a Rect and a Paint and contains a draw method (and some getters and setters).
The question I have, is: is this a good approach?
On one hand I am working with a fixed set of variables. On the other hand, these variables are mutable and I can change their attributes (e.g., using the getters and setters). For example, I can call FULLSCREEN.getScreenArea().getPaint().setColor(Color.BLUE)
When you look at Enum it says it is
a special data type that enables for a variable to be a set of
predefined constant
So I do have a fixed set, it is predefined, but not necessarily constant.
My original approach was to define a class called Layout which contained a HashMap of Screenarea's. In that case, I was using e.g., Layout.get("fullscreen").draw(canvas) to draw the screenarea to the canvas. In this new approach I am using e.g., FULLSCREEN.getScreenArea().draw(canvas).
One of the reasons I would like to switch is to introduce a typesafe solution. Of course, it would also be possible to switch from a HashMap to an EnumMap and store the names of my screenareas in an Enum.
Hope you can point me in the right direction: a direction that not only works (the above is already working) but is also acceptable and doesn't smell.
I started to use the Jung library for my visualization of a graph. Main problem currently is that I don't know how to set labels/metadata for my vertices. Depending on a specific attribute of a vertex, I would like to color the vertices differently. The object of class Node contains an additional Integer-value, I would like to add as an additional attribute (by getGroup()) for the vertices. The following code only visualizes the getId()-String of each node.
Any recommendation?
This is my following code in the main class:
Graph<String,Double> g = new SparseGraph<String,Double>();
List<Link> linkList = new ArrayList<Link>();
List<Node> nodeList = new ArrayList<Node>();
linkList = f.getLinks();
nodeList = f.getNodes();
for(Node nodeElement:nodeList){
g.addVertex(nodeElement.getId());
}
for(Link linkElement:linkList){
g.addEdge(linkElement.getValue(), linkElement.getSource(), linkElement.getTarget());
}
VisualizationImageServer vs =
new VisualizationImageServer(
new SpringLayout(g), new Dimension(500, 500));
vs.getRenderContext().setVertexLabelTransformer(new ToStringLabeller() {
public String transform(Object v) {
return Integer.toString(((Node)v).getGroup());
}
});
JFrame frame = new JFrame("");
frame.getContentPane().add(vs);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
You didn't specify which version of JUNG you're using, but you've got the right general idea: call setVertexLabelTransformer() with a function that converts nodes to the string that you want to render.
That said, there are a few issues with your code as written and I'm not sure I understand how you're getting the reported behavior with the code as quoted above.
(0) I don't understand why you're adding the node ID as the vertex, rather than just the Node. Are the endpoints of your Links node IDs or Nodes?
In any event, if you don't add the Node, then it's not clear from your code as written how you expect the vertex Group to be available.
(1) The vertices of the graph are node IDs, not Nodes, but you're casting the vertex object passed to transform() to a Node. I would expect this to throw a ClassCastException.
(2) Even supposing that your vertices were actually Node objects,
I'm surprised that you're reporting that the vertex ID (rather than the Group) is what's showing up on the label, because the only thing that you're asking for in the vertex label is the Group; I wouldn't expect the ID to be showing up at all.
That said, if the vertices are Node objects, and you want multiple elements to show up, it's pretty easy; just provide a function that does what you want on the Node object.
* If that function is toString(), then you can use ToStringLabeller (and that should actually be the default, so you shouldn't even need to specify it); more on that below.
* If that function is (say) getLabel(), then this should work (in Java 8):
// either of these should work
setVertexLabelTransformer(Node::getLabel())
setVertexLabelTransformer(v -> v.getLabel())
or you can do the anonymous inner class thing if you're not using Java 8.
If you don't want your vertices to be Node objects, then you'll need to provide a way of mapping vertex objects (node IDs) to nodes, such as a Map<String, Node>, and then supply that map to the function that converts vertices to labels:
setVertexLabelTransformer(v -> labelToNode.get(v).getLabel())
Note: ToStringLabeller() shouldn't generally have its transform() method overridden; it just specifies that you want to use the toString() of the object itself as the label.
// These two are equivalent
setVertexLabelTransformer(v -> v.toString())
setVertexLabelTransformer(new ToStringLabeller())
(Needless to say, ToStringLabeller() predates Java 8. :) )
Is there a way to set the T.label after the vertex has been created. I have tried the following:
Vertex v = graph.addVertex();
v.property(T.label.name(), "test");
But when I try the following traversal:
graph.traversal().V().hasLabel("test").next
I get
org.apache.tinkerpop.gremlin.process.traversal.util.FastNoSuchElementException
Is there something special about T.label that limits it to being set at the step of constructing the vertex ?
No, labels cannot be changed. If you need this type of functionality, you should use a vertex property instead.
From the TinkerPop documentation: "NOTE: In TinkerPop3, vertices are allowed a single immutable string label (similar to an edge label). This functionality did not exist in TinkerPop2. Likewise, element id’s are immutable as they were in TinkerPop2."
I would like to know how to apply a type filter in a Gremlin 3.x GraphTraversal. For example, let's consider the Graph of the Gods as an example graph.
Here, we can do the following:
Set<Element> set = graph.V().has("name", "jupiter").toSet()
... and get a Set<Element>. What I would like to have is an Iterable<Vertex> instead (or a subclass of Iterable). From the traversal declaration, the result can only consist of vertices, because of the .V() operator. Due to the Java type system, it is needlessly generalized to Element. Is there a way to type filter this? What I would like to do is something along these lines...
Set<Vertex> vertices = graph.V().has("name", "jupiter").cast(Vertex.class).toSet();
... but there is no cast operator. Ultimately, the reason why I want to do this is because I need to iterate over the resulting vertices in a foreach-loop, and having to down-cast the loop variable as the first statement in the loop is annoying.
I'm open for alternatives, I'm still new to Gremlin 3 and there may be many things I'm not aware of yet.
Against Tinkerpop3 M6/ titan0.9 M1, the following should work:
Set<Vertex> vertices = graph.V().<Vertex>has("name", "jupiter").toSet();
Most of the M6 type issues can be resolved in a similar manner (parameterizing the method that produces the element by the expected type).
I'm creating a 2D game in Java using the Java2D library for drawing, and I really need a float-precision Polygon object that I can use both to draw game objects and to do collision detection on them. Unfortunately, Java's Polygon object comes in int precision only, and there is no equivalent Polygon2D like there is with Rectangle and Rectangle2D. I've already done enough research to see that I have a few options, but none of them seem very good.
Use Path2D. According to a Java developer posting in this forum, the lack of Polygon2D was an oversight, but its suggested replacement is Path2D. Unfortunately, Path2D doesn't provide a way to access its individual vertices or edges, which I need in order to do collision detection (specifically I need to get a vector orthogonal to each edge).
Implement my own Polygon2D that implements the Shape interface so that I can still pass it to Graphics2D.draw(Shape). This looks like it would be pretty difficult. The Shape interface requires tricky-to-implement methods like contains(Rectangle2D) and getPathIterator(AffineTransform). For getPathIterator in particular, it seems that in order to implement it I'd need to return an object of type PathIterator, but there are no concrete implementations of the PathIterator interface available in the public AWT packages.
Wrap Path2D in an object that "remembers" the individual vertices and provides them to the client. This worked for me when I needed an Area that remembered its component shapes: I wrapped it in a CompoundShape class that implemented the Shape interface and forwarded all the Shape methods to Area's implementation of them, while keeping track of each Shape that was added to the Area in an ArrayList. The problem with this is that if I keep track of the individual vertices in two arrays of floats, there is no way to expose them to the user without the possibility of the user changing the vertices - and since that would happen by direct array access, the internal Path2D wouldn't get notified of the changes.
Copy Polygon.java. The actual source code of Java's Polygon class is available on grepcode.com, and I could simply replace the vertex-related ints with floats throughout to get a Polygon2D. Unfortunately, when I tried this, the line import sun.awt.geom.Crossings; threw a compiler error saying "The type Crossings is not accessible due to restriction on required library C:\Program Files\Java\jre7\lib\rt.jar." According to this question that happens because Sun's license agreement prevents you from replacing core Java classes with your own, but Polygon doesn't try to do that - it simply creates an object of type sun.awt.geom.Crossings, no replacing or extending happens, and I made sure to put my copy of Polygon in a package not called "java".
What's the best way to proceed with this? I'd appreciate either suggestions for how make one of these options work or an idea for another option that doesn't have the problems these encounter.
I would also recommend Path2D. GeneralPath is a legacy class; don't use it.
Path2D does provide access to the vertex values, albeit it a roundabout fashion. You need to use a PathIterator:
PathIterator pi = path.getPathIterator(null);
float[] value = new float[6];
float x = 0, y = 0;
while (!pi.isDone()) {
int type = pi.currentSegment(values);
if (type == PathIterator.SEG_LINETO) {
x = values[0];
y = values[1];
}
else if (type == PathIterator.SEG_CLOSE) {
x = 0;
y = 0;
}
else {
// SEG_MOVETO, SEG_QUADTO, SEG_CUBICTO
}
pi.next();
}
When you're ready to get fancy, you can expand that else to support the quadratic and cubic curves.
I assume you don't need those at this time as you're talking about polygons.
Also, Path2D has some handy static methods for testing whether the path intersects a rectangle and whether the path contains a rectangle or point. Sadly, there are no methods for testing for a path intersecting or containing another path.
Perhaps have the internals of the polygon at a different scale?
Multiply by a large number and typecast to int when writing to it, divide by the same large number when reading?
Can you use a 3rd party library? If so, might I suggest to use the Slick 2D Polygon class. What I would do is internally, use this class for your actual Polygon to check intersection with contains and then when you need to draw, just cast the float values to int and draw the Java2D Polygon.
I know this might not be the optimal solution, but it might work for what you're doing.