I have the following code:
private _x,_y,_w,_h;
protected void paintComponent( Graphics g_ ) {
g_.setStroke( new BasicStroke(2) );
g_.drawLine(_x, _y, _x+_w, _y+_h);
g_.drawLine(_x, _y+_h, _x+_w, _y);
}
In my case I'm drawing the diagonals of a square so: _w==_h.
My problem the two line don't have the same apparent thikness: the first line look thicker than the second. When checking the actual pixels drawn here's the difference of rendering:
I don't really care which one should be considered "correct" (though I'd like to understand the reasons of this result), but I'd like some coherence here, that both lines have the same rendering: how can I do that?
(when I use a 1px stroke, there's no difference between the two lines).
Followup to Olavi's ansewer:
Using an odd number of pixel for the stroke doesn't solve the problem:
Enabling anti-aliasing leads to another problem: the stroke of the square in which the cross is drawn gets blurred:
Basically you have two options:
Use an odd-number thickness
Use antialiasing
Personally I prefer antialiasing, because it's pretty and I like pretty things. However to explain why a stroke width of 2 behaves like that: Java does not know whether or not draw the line with the first way or the second way (I can't really explain exactly why it does what it does, but this is what I see). To further elaborate this answer, try starting the other line one pixel to the left or to the right: this should result in two lines with the same thickness.
To use antialiasing, do the following (untested code!). Code picked up from here:
Graphics2D graphics2D = (Graphics2D) g_;
graphics2D.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
graphics2D.drawLine(_x, _y, _x+_w, _y+_h);
graphics2D.drawLine(_x, _y+_h, _x+_w, _y);
Related
I am currently trying to draw and fill a Polygon which has a hole in it in Java. Normally this would not be a big problem, since I would draw the exterior ring and then draw the interior ring with the color of the background.
But the problem is, that the polygon is displayed above a image which should be "seen" through the hole.
I am writing the code in Java and am using JTS Topology Suite for my geometry data.
This is my current code, which just paints the border and fills the polygon with a color.
private void drawPolygon(com.vividsolutions.jts.geom.Polygon gpoly, Color color, Graphics2D g2d){
java.awt.Polygon poly = (java.awt.Polygon)gpoly;
for(Coordinate co : gpoly.getExteriorRing().getCoordinates() {
poly.addPoint(co.x, co.y);
}
g2d.setColor(col);
g2d.fill(poly);
g2d.setColor(Color.BLACK);
g2d.draw(poly);
}
Sadly java.awt.Polygon does not support Polygons with holes.
Use the Polygon as the basis for an Area (e.g. called polygonShape).
Create an Ellipse2D for the 'hole', then establish an Area for it (ellipseShape).
Use Area.subtract(Area) something like:
Area polygonWithHole = polygonShape.subtract(ellipseShape);
There are some ways to draw shapes or areas that are more complex than a simple polygon (another answer already mentioned Area).
Besides those, you could try to tessellate your final polygon. There are lots of algorithms to do this. For more complex shapes, the algorithms get a bit more complex as well. Basically, you're dividing your final shape into little polygons (usually triangles, but it also can be something else) and then draw those polygons.
You can take a look at your possibilities by searching for "Tessellation Algorithm", there are also some already implemented libraries for Java.
You can use java.awt.geom.Path2D to render a "compound shape" with a hole in it:
If you have java.awt.Shape objects defining the outside & inside edges of the shape, use append(shape, false) to add each shape.
If you have a set of path points for the outside edge and a set of path points for the inside edge, use lineTo() to add the first set of points - creating a closed loop by either ending with the same point you started with, or calling closePath() to automatically close the loop. Then use moveTo() to create a break before adding the inner set of points via more lineTo() calls.
In either case, you must create the path passing Path.WIND_NON_ZERO to the constructor - otherwise the hole won't be left unfilled.
See How to create shape with a hole? for a longer code example.
You could fill the polygon first, and then draw the holes on top, giving the illusion that it filled everything but the holes.
I was wondering why displaying text in my frame has to be so blury, and i came across this piece of code, which is working by the way
public void paint(Graphics graphicsObject){
if(graphicsObject instanceof Graphics2D){
Graphics2D g2D = (Graphics2D) graphicsObject;
g2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
}
graphicsObject.drawString("not blurry text display", 200, 200);
}
having dificulties trying to understand how this work out.
how come g2D.setRenderingHint is fixing my blurry problem, but i dont use it to paint my string?
First, what this fixed was not blurring. It was aliasing.
Aliasing occurs when drawing functions try to create curvy shapes using a raster image - a matrix of pixels, which are squares. If the lines are not vertical or horizontal, you end up with "stairs" - edges that are jaggy.
Antialiasing is a way to make this effect less visible to the eye, by using additional pixels around the drawn line, which are painted in different tones between the foreground and the background. This cheats our eyes to see the line as "smooth". If you zoom an image drawn with antialiasing, you may notice those pixels around the actual line.
So, actually, antialiasing blurs the line, and this makes it seem smoother to our eyes.
As to your actual question - you are using the graphics object to draw the line. You set the hint in the graphics object by accessing the object in its form as a Graphics2D. Even though you then go on and use the graphicsObject using its regular Graphics reference, the method drawString() is overridden. This means that it will be activated in the concrete object that implements it, which sees - and uses - the RenderingHint hash map where your hint is stored.
but i dont use it to paint my string?
Why do you think so? Because, you are actually using it.
Nowadays, Graphics is always a Graphics2D object, so your if-statement will be executed.
g2D and graphicsObject both point to the same object. For the compiler they are two variables of different types, allowing different methods to be called, but at execution time, these two variables actually point to the same object.
So by setting the rendering hint on g2D, and this being the same object as graphicsObject, drawing the string respects that hint and fixes the blurryness by using anti-aliasing as specified in the hint.
I'm developing a JApplet in which the user can draw some lines over an image.
Lines can be red or green, but I need to highlight them because I don't know the background color.
So I thought that I can draw a white "border" to the line, and I tried to do this creating other two white lines to the left and to the rigth of the original one. But the result is poor.
Is there a better way to accomplish this goal?
As mentioned by #Jesper, draw the line first using a thicker Stroke (as seen in this answer).
The black outline on the letters has width 2.
g.setStroke(new BasicStroke(2f));
When you use Graphics2D.scale(); and draw a shape, the outline thickness is also scaled.
Is there a way to draw it without the line thickness being scaled? Perhaps there's another efficient way to scale it other than using the above function?
This question is similar. It looks like you have to mess around with a Stroke object to set the right line width.
You're going to have to save your drawing as a list of line vectors, and scale and render the drawing at various sizes to maintain the line thickness you want.
I've just found a solution to my own question. I've no idea how efficient it is but it works as intended:
Area area = new Area(myShape); //myShape is the shape I want to scale
AffineTransform at = new AffineTransform();
at.scale(2,2);
area = area.createTransformedArea(at);
graphics2d.draw(area); //graphics2d is the Graphics2D instance to do the drawing
Perhaps someone could enlighten me as to whether or not this is a good approach to take?
This is not really important, but it was bothering me for a little while.
Problem description:
Given: a line (Line2D)
Wanted: drawing the line as a wedge (Filled GeneralPath)
Surely this can be done by creating the wedge as General Path and then filling it by the Graphics (my solution).
My first approach would have been a wedge-stroked line, because I didn't want to change the line object for some reason, also I just wanted to draw the line object and not think about it any more.
Creating the wedge-stroke was no problem (Some calculations and then creating the General Path) - but I was not able to fill it (easily)
Apparently it seems the fill of Graphics2D only fills the shape it gets - and does not handle the filling of the stroke (that behavior makes sense if one thinks about it).
Question: Is there any way to fill a shape of a Stroke (filling a shape - more specifically: a GeneralPath - somehow before drawing it)?
May be BasicStroke.public Shape createStrokedShape(Shape s) can help if you pass the Line2D there?
Once you use createStrokedShape(), note that draw() "strokes the outline of a Shape," while fill() "fills the interior of a Shape."
import java.awt.*;
public static Shape strokeToShape(Shape path, float strokeWidth)
return new BasicStroke(strokeWidth).createStrokedShape(path);
}
You may also specify cap and join parameters of BasicStroke