JUNG2: How to draw a circle? - java

I need to draw a circle around a vertex in JUNG. The circle is defined by the vertex as center and a given radius r.

Something like this, I guess. This will give you points for circle with given radius. To adjust resolution of points change x+=0.01 to a bigger/smaller value as needed. To move circle centre to an arbitrary point (p,q), just add it to (x,y), that is plot(x+p,y+q);.
double radius = 3;
for (double x = -radius; x <= radius; x += 0.01) {
double y = Math.sqrt(radius * radius - x * x);
plot(x, y);//top half of the circle
plot(x, -y);//bottom half of the circle
}
EDIT: It appears that JUNG is not really an XY-plot but a network/graph framework. So all you need is to layout your points in a circle using one of provided layouts. CircleLayout and KKLayout seem to do the trick, though CircleLayout gives strange results for when there are many nodes. Here's complete sample code:
//Graph holder
Graph<Integer, String> graph = new SparseMultigraph<Integer, String>();
//Create graph with this many nodes and edges
int nodes = 30;
for (int i = 1; i <= nodes; i++) {
graph.addVertex(i);
//connect this vertext to vertex+1 to create an edge between them.
//Last vertex is connected to the first one, hence the i%nodes
graph.addEdge("Edge-" + i, i, (i % nodes) + 1);
}
//This will automatically layout nodes into a circle.
//You can also try CircleLayout class
Layout<Integer, String> layout = new KKLayout<Integer, String>(graph);
layout.setSize(new Dimension(300, 300));
//Thing that draws the graph onto JFrame
BasicVisualizationServer<Integer, String> vv = new BasicVisualizationServer<Integer, String>(layout);
vv.setPreferredSize(new Dimension(350, 350)); // Set graph dimensions
JFrame frame = new JFrame("Circle Graph");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(vv);
frame.pack();
frame.setVisible(true);
I have picked SparseMultiGraph because that's what was in JUNG tutorial. There are other types of graphs, but I am not sure what the difference is.
You could also use a StaticLayout that can take (x,y) vertices, then use my original code to plot the points, but that would not be as elegant for JUNG framework. Depends on what your requirements are, however.

Related

Java Graphics 2d avoid Polyline distorted corners

i'm working on a graphic interface for drawing subway maps. A line is represented with station as circles and a polyline to link them.You can move the stations with a mouseDrag and of course it updates the displaying map in real time. My problem is when stations comes to a certain angle, there is a polyline distortion and the corner created by the 2 lines is out of the station circle display, i'd like to know if there is a way to avoid this.
screenshots of the app with the polyline issue
here's my code for the polyline's draw
//x and y point array creation
xPoints = new int[this.stationViews.size()];
yPoints = new int[this.stationViews.size()];
for (int i=0;i<this.stationViews.size();i++) {
//fill arrays with the center point of circles representing stations
xPoints[i] = this.stationViews.get(i).getStation().getPosX()-this.stationViews.size()/2;
yPoints[i] = this.stationViews.get(i).getStation().getPosY()-this.stationViews.size();
}
//setting color
g2D.setColor(this.line.getColor());
//set stroke width relative to the zoom level
int strokeWidth=5;
if(!this.stationViews.isEmpty()) {
if (this.stationViews.get(0).getStationSize()>14) {
strokeWidth = this.stationViews.get(0).getStationSize()-13;
}else {
strokeWidth = 3;
}
}
g2D.setStroke(new BasicStroke(strokeWidth));
//draw the polyline
if (this.stationViews.size() >1) {
g2D.drawPolyline(xPoints, yPoints, this.stationViews.size());
}
//draw the station (g2D.drawCircle)
for (StationView stationView : stationViews) {
stationView.affiche(g2D,this.line.getColor());
}
thank you for your help
That is called the miter. You seem to be per default using JOIN_MITER, sharp joining of extended lines at the end, which can point far out of the join for small angles.
g2d.setStroke(new BasicStroke(strokeWidth,
BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND, 5));
miter a surface forming the beveled end or edge of a piece where a joint is made by cutting two pieces at an angle and fitting them together.
It is also a bishop's cap with a pointy top, hence the name.

mapping two points on image to another one

I am trying to map two points on one image to two points on the original image so i divided the work into three main actions first scaling the n rotation then translation after everything but cant position them correctly the scaling works fine and the translation also the rotation works perfectly if i didn't scale the images only way the rotation work perfectly when i rotate around custom point but the image get distorted
Rotate rotation = new Rotate();
rotation.setPivotX(proj.s2[0]);
rotation.setPivotY(proj.s2[1]);
MainView1.getTransforms().add(rotation);
MainView1.setManaged(false);
rotation.setAngle(Angle);
here is the code without custom rotation
guidebutton.setOnMouseClicked(event->{
if (!first_rot) {
proj.f2[0]=Lball.getCenterX();
proj.f2[1]= Lball.getCenterY();
proj.f1[0]=Rball.getCenterX();
proj.f1[1]= Rball.getCenterY();
MainView.setStyle("-fx-opacity : 0.0;");
guidetext.setText("now position them on the second image and click done");
first_rot=true;
}else {
proj.s2[0]=Lball.getCenterX();
proj.s2[1]= Lball.getCenterY();
proj.s1[0]=Rball.getCenterX();
proj.s1[1]= Rball.getCenterY();
//fixing the image first then fixing the points
// fixing the image
//adjusting the scale
double f[]=tranformations.dis_vec_d(proj.f1, proj.f2);//get the distance between the two points on the first image
double s[]=tranformations.dis_vec_d(proj.s1, proj.s2);//get the distance between the two points on the secondimage
double facx=f[0]/s[0];//factor of scale in x direction
double facy=f[1]/s[1];//factor of scale in y direction
//getting the position of second image inside the window
Bounds bounds = MainView1.getBoundsInLocal();
Bounds screenBounds = MainView1.localToScreen(bounds);
double x = screenBounds.getMinX();
double y = screenBounds.getMinY();
MainView1.setScaleX(facx);
// get the new position of image after scaling to adjust the position
bounds = MainView1.getBoundsInLocal();
screenBounds = MainView1.localToScreen(bounds);
double nx = screenBounds.getMinX();
double ny = screenBounds.getMinY();
double nmx = screenBounds.getMaxX()-nx;
double nmy = screenBounds.getMaxY()-ny;
MainView1.setTranslateX(x-nx);
MainView1.setTranslateY(y-ny);
double[]orig={nmx/2,nmy/2};
//adjusting rotation
//calculating the angle between the two line to adjust the rotation
double Angle=tranformations.angle_d(proj.s1, proj.s2);
Angle-=tranformations.angle_d(proj.f1, proj.f2);
//Add the Rotate to the ImageView's Transforms
MainView1.setRotate(Angle);
MainView1.setTranslateX(MainView.getTranslateX()+proj.f2[0]-proj.s2[0]);
MainView1.setTranslateY(MainView.getTranslateY()+proj.f2[1]-proj.s2[1]);
}
});
both views and points in unmanaged group "draw" when i get every thing work it get down when i use zooming when positioning points on the second image
i use this code for zooming using mouse wheel
final double SCALE_DELTA = 1.1;
draw.setOnScroll(event->{
event.consume();
if (event.getDeltaY() == 0) {
return;
}
double scaleFactor =(event.getDeltaY() > 0)? SCALE_DELTA: 1/SCALE_DELTA;
draw.setScaleX(draw.getScaleX() * scaleFactor);
draw.setScaleY(draw.getScaleY() * scaleFactor);
});
edit to explain the question more i have these two separate images and i use the two red points on lights as to correctly position them over each other to so they can form the new image complete image
First align one of the points using a translation then scale using the aligned point's coordinates as pivot and finally use the same pivot point to perform a rotation aligning the other points.
The following example uses groups containing 2 circles each, but it should be simple enough to replace centerX/centerY with the image coordinates of the points:
#Override
public void start(Stage primaryStage) throws Exception {
// create group containing scene that remains in place
Circle target1 = new Circle(100, 200, 20, Color.RED);
Circle target2 = new Circle(150, 100, 20, Color.RED);
Group targetGroup = new Group(target1, target2);
// create group that will be transformed
Circle c1 = new Circle(30, 30, 20, Color.BLUE);
Circle c2 = new Circle(400, 400, 20, Color.BLUE);
Group g = new Group(c1, c2);
Scene scene = new Scene(new Pane(targetGroup, g), 500, 500);
// register handler for swapping between transformed/untransformed scene on button click
scene.setOnMouseClicked(new EventHandler<MouseEvent>() {
boolean transformed;
final Translate translate = new Translate();
final Scale scale = new Scale();
final Rotate rotate = new Rotate();
{
// add transforms to transformation target
g.getTransforms().addAll(rotate, scale, translate);
}
#Override
public void handle(MouseEvent event) {
if (transformed) {
// reset transforms to identity
translate.setX(0);
translate.setY(0);
scale.setX(1);
scale.setY(1);
rotate.setAngle(0);
} else {
// align c1 and target1
translate.setX(target1.getCenterX() - c1.getCenterX());
translate.setY(target1.getCenterY() - c1.getCenterY());
// scale
double scaleFactor = Math.hypot(target1.getCenterX() - target2.getCenterX(), target1.getCenterY() - target2.getCenterY())
/ Math.hypot(c1.getCenterX() - c2.getCenterX(), c1.getCenterY() - c2.getCenterY());
scale.setPivotX(target1.getCenterX());
scale.setPivotY(target1.getCenterY());
scale.setX(scaleFactor);
scale.setY(scaleFactor);
// rotate
rotate.setPivotX(target1.getCenterX());
rotate.setPivotY(target1.getCenterY());
rotate.setAngle(Math.toDegrees(Math.atan2(target2.getCenterY() - target1.getCenterY(), target2.getCenterX() - target1.getCenterX())
- Math.atan2(c2.getCenterY() - c1.getCenterY(), c2.getCenterX() - c1.getCenterX())));
}
transformed = !transformed;
}
});
primaryStage.setScene(scene);
primaryStage.show();
}
This is particularly simple using complex numbers.
An arbitrary similarity transform can be written
Z = a.z + b
where the modulus of a is the scaling factor, the argument of a is the rotation angle and b is the translation.
These coefficients are readily obtained from the known pairs of points by the usual two-points interpolation formula
Z = Z0 + (z - z0).(Z1 - Z0)/(z1 - z0)
or
a = (Z1 - Z0)/(z1 - z0)
b = Z0 - a.z0
You have the option of using a complex data type, or to retranscript the formulas in terms of real/imaginary parts.
If the square isn't rotated, then yeah, pick x and y independently.
If the square is rotated, the math gets a little trickier. Let's let the two end points of the diagonal be X and Y, represented as complex numbers.
Then look at the equation:
(Y - X)/(1 + i) x + X
When x = 0, this returns X. When x = 1 + i, it returns Y. In fact, this equation maps the unit rectangle onto the square whose diagonal's endpoints are X and Y.
So pick two random numbers 0 ≤ a, b ≤ 1, turn it into a random point a + bi on the unit rectangle, and then use the above equation to map into into a random point in the square.

Possible to Drag Shapes Within a GridPane with JavaFX

Am I correct in thinking it is not possible to drag Shapes within a GridPane? Here's a link to some code that allows the user to drag shapes around the screen: Drag and Drop Shapes
I want my shapes to have the same behavior as above, but I want them in a GridPane (eventually I'd like their movement to be locked to the X or Y axis to be moved on to adjacent shapes).
I added the below code to the "start" method. It creates circles using the same method as the example code but instead adds them to a grid. Surprisingly, this removed the ability for them to be dragged around.
GridPane grid = new GridPane();
grid.setLayoutX(300);
grid.setLayoutY(100);
int n = 3;
int m = 3;
for (int r = 0; r < n; r++) {
for (int c = 0; c < m; c++) {
Circle circle = createCircle(100, 50, 30, Color.BLACK);
grid.add(circle, c, r);
}
}
root.getChildren().add(grid);
If you want to test this just add the above code to the "start" method of the example code, just above these lines:
primaryStage.setScene(scene);
primaryStage.show();
My theory is the GridPane, because it locks the circles to certain positions, doesn't allow this dragging behavior.
Any input on how I can achieve movement of the circles along the X and Y axis when dragged?
In general, layout panes such as GridPane manage the placement of their content. Changing the layout coordinates will not affect nodes that are placed in these panes. You may find it better to use a plain Pane and manage the layout yourself for functionality such as this.
If you do want to use a GridPane, transformations (such as translations, etc) are applied after layout coordinates are computed, so you can use a translation (e.g. the one built-in with the translateX and translateY properties) to manage dragging in a layout pane.
So you can do:
circle.setOnMouseDragged((t) -> {
double offsetX = t.getSceneX() - orgSceneX;
double offsetY = t.getSceneY() - orgSceneY;
// No idea why they are doing this. c is just circle
Circle c = (Circle) (t.getSource());
c.setTranslateX(c.getTranslateX() + offsetX);
c.setTranslateY(c.getTranslateY() + offsetY);
orgSceneX = t.getSceneX();
orgSceneY = t.getSceneY();
});

Drawing a convex/concave quadrilateral in Java

I have four randomly sorted points, and I can't seem to draw a convex/concave Polygon with these points. This is the code I am using:
int xPoly[] = new int[4];
int yPoly[] = new int[4];
for(int i = 0; i < quad.size(); i++){
g2d.fill(quad.get(i));
xPoly[i] = (int) (quad.get(i).getX());
yPoly[i] = (int) (quad.get(i).getY());
}
Polygon poly = new Poylgon(xPoly, yPoly, xPoly.length);
g2d.draw(poly);
Where quad is defined as ArrayList<Point> quad = new ArrayList();. Point is a simple class I wrote which is self explanatory. However, my solution keeps producing polygons like this:
The black points are part of quad. My desired result is a normal looking polygon, not an irregular one.
An example for the quad ArrayList:
(0,0), (5,3) (9,10), (6, 7)
There is no specified order for these points, so xPoly and yPoly aren't necessarily ordered either.
Switched to an answer:
You must order the points in a Polygon yourself - the points in a Polygon describe a fixed order in which it will be drawn. It won't interpolate what type of shape you want.

Jung : Fixing distance between vertices

I am using Jung to draw a graph. In my case, a node can have both multiple parents and multiple child.
Since, a node can have multiple parents, I can not use a Tree layout to get my graph drawn as a Tree.
Thus, I am using a DAGLayout. However, in DAGLayout, the plotting is bottom-up.
To resolve this, I have rotated the graph 180 degrees to plot it from top to bottom.
Here is the code:
// generate layout
Layout<SimpleTaskDomain, Integer> layout = new DAGLayout<SimpleTaskDomain, Integer>(g);
// fix layout size
layout.setSize(new Dimension(700, 700));
VisualizationViewer<SimpleTaskDomain, Integer> vv = new VisualizationViewer<SimpleTaskDomain, Integer>(layout);
vv.setBackground(Color.white);
vv.setPreferredSize(new Dimension(800, 800));
vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller<SimpleTaskDomain>());
Dimension d = layout.getSize();
Point2D center = new Point2D.Double(d.width / 2, d.height / 2);
vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT).rotate(Math.PI, center);
vv.setVertexToolTipTransformer(vv.getRenderContext().getVertexLabelTransformer());
// vv.getRenderContext().setEdgeShapeTransformer(new
// EdgeShape.Orthogonal<SimpleTaskDomain, Integer>());
vv.getRenderContext().setEdgeShapeTransformer(new EdgeShape.Line<SimpleTaskDomain, Integer>());
VertexFontTransformer<SimpleTaskDomain> vff = new VertexFontTransformer<SimpleTaskDomain>();
vff.setBold(true);
vv.getRenderContext().setVertexFontTransformer(vff);
Transformer<SimpleTaskDomain, Paint> vertexPaint = new Transformer<SimpleTaskDomain, Paint>() {
public Paint transform(final SimpleTaskDomain i) {
return Color.GREEN;
}
};
vv.getRenderContext().setVertexFillPaintTransformer(vertexPaint);
Transformer<SimpleTaskDomain, Shape> vertexSize = new Transformer<SimpleTaskDomain, Shape>() {
public Shape transform(final SimpleTaskDomain i) {
Rectangle2D.Double rectangle = new Rectangle2D.Double(-40, -20, 80, 40);
return AffineTransform.getScaleInstance(2, 2).createTransformedShape(rectangle);
}
};
vv.getRenderContext().setVertexShapeTransformer(vertexSize);
vv.getRenderer().getVertexLabelRenderer().setPosition(Position.CNTR);
I am changing shape of the vertices to a rectangle instead of default circle.
However, in the output graph, the vertices are overlapping.
How can I control the distance between vertices such that the overlap does not happen.
I want a tree like structure with proper distance between the vertices.
Thanks for reading!
Your question says "DagLayout", but your code sample says "FRLayout".
In any event, DagLayout doesn't let you specify node distance.
I suggest you follow the general outline in MinimumSpanningTreeDemo:
(1) Extract the appropriate spanning tree from your graph.
(2) Lay out the spanning tree using TreeLayout (which allows you to specify spacing).
(3) Use the layout positions from the Tree Layout to create a new StaticLayout instance for your original graph, and visualize using that layout.

Categories