I'm working on a code that should allow me to draw an AC "Animated electricity" signal, and the time interval should be accurate in this case.
My question is; What is the measuring unit of the Point2D specifically, Is't pixels, milliseconds, or any unit else?
I'm trying to draw a Line2D, which should be drawn between two points!
I'd tried to take the '1' value as milliseconds and it's kind of worked, later on I discovered that the graphics elements is measured by pixels, I tried to convert millisecond to pixels with multiplying by pixel value, but it didn't give me the expected results.
My code as following expecting '1' value is Millie
<i>
for(i=0;i<20000;i++)
{
//System.out.println(volts[i]);
if(i!=0)
g2d.draw(new Line2D.Double(time-(timeScale/y),-(((voltScale/x)*50*volts[i-1])-300),time,-(((voltScale/x)*50*volts[i])-300)));
time+=(timeScale/y);
}
</i>
The Graphics2D class description gives a fairly good description of the units (in the "Coordinate Spaces" section:
https://docs.oracle.com/javase/8/docs/api/java/awt/Graphics2D.html
Generally speaking, a unit in "User Space" (the Java2D coordinate system) will correspond to 1/72 inch on physical devices (such as your monitor or your printer).
Well, sense no one answered, I think in the Graphics2D object case, It won't take it as pixels, maybe the pixels can't be cut into fractions, and Graphics2D is able to use fractions. Unfortunately seems like that the developers whose worked on the Graphics2D class doesn't give any clear description about it.
Related
I am looking for the simplest (and still non-problematic) way to resize a BufferedImage in Java.
In some answer to a question, the user coobird suggested the following solution, in his words (very slightly changed by me):
**
The Graphics object has a method to draw an Image while also performing a resize operation:
Graphics.drawImage(Image, int, int, int, int, ImageObserver)
method can be used to specify the location along with the size of the image when drawing.
So, we could use a piece of code like this:
BufferedImage originalImage = // .. created somehow
BufferedImage newImage = new BufferedImage(SMALL_SIZE, SMALL_SIZE, BufferedImage.TYPE_INT_RGB);
Graphics g = newImage.createGraphics();
g.drawImage(originalImage, 0, 0, SMALL_SIZE, SMALL_SIZE, null);
g.dispose();
This will take originalImage and draw it on the newImage with the width and height of SMALL_SIZE.
**
This solution seems rather simple. I have two questions about it:
Will it also work (using the exact same code), if I want to resize an image to a larger size, not only a smaller one?
Are there any problems with this solution?
If there is a better way to do this, please suggest it.
Thanks
The major problem with single step scaling is they don't generally produce quality output, as they focus on taking the original and squeezing into a smaller space, usually by dropping out a lot of pixel information (different algorithms do different things, so I'm generalizing)
Will drawGraphics scale up and down, yes, will it do it efficiently or produce a quality output? These will come down to implementation, generally speaking, most of the scaling algorithms used by default are focused on speed. You can effect these in a little way, but generally, unless you're scaling over a small range, the quality generally suffers (from my experience).
You can take a look at The Perils of Image.getScaledInstance() for more details and discussions on the topic.
Generally, what is generally recommend is to either use a dedicated library, like imgscalr, which, from the ten minutes I've played with it, does a pretty good job or perform a stepped scale.
A stepped scale basically steps the image up or down by the power of 2 until it reaches it's desired size. Remember, scaling up is nothing more then taking a pixel and enlarging it a little, so quality will always be an issue if you scale up to a very large size.
For example...
Quality of Image after resize very low -- Java
Scale the ImageIcon automatically to label size
Java: JPanel background not scaling
Remember, any scaling is generally an expensive operation (based on the original and target size of the image), so it is generally best to try and do those operations out side of the paint process and in the background where possible.
There is also the question whether you want to maintain the aspect ratio of the image? Based on you example, the image would be scaled in a square manner (stretched to meet to the requirements of the target size), this is generally not desired. You can pass -1 to either the width or height parameter and the underlying algorithm will maintain the aspect ratio of the original image or you could simply take control and make more determinations over whether you want to fill or fit the image to a target area, for example...
Java: maintaining aspect ratio of JPanel background image
In general, I avoid using drawImage or getScaledInstance most of the time (if your scaling only over a small range or want to do a low quality, fast scale, these can work) and rely more on things like fit/fill a target area and stepped scaling. The reason for using my own methods simply comes down to not always being allowed to use outside libraries. Nice not to have to re-invent the wheel where you can
It will enlarge the original if you set the parameters so. But: you should use some smart algorithm which preserves edges because simply enlarging an image will make it blurry and will result in worse perceived quality.
No problems. Theoretically this can even be hardware-accelerated on certain platforms.
I was wondering if there is a way to plot a point using a double value in the built in java graphics utility. I am making a simple clock but I want it to be as precise as possible. The method drawLine(int, int, int, int) in Graphics obviously won't take a double as a parameter. Is there a work-around to this?
P.S. The doubles in question are the change in x and y for each hand on the clock as 1 second passes.
Graphics2D has an internal AffineTransform Matrix that you can alter. I have not tested the following code, but i think this or a variant might get close to what you want (Although really, the pixels are all at integer positions...)
Graphics2D g; // get a Graphics2D from somewhere
g.rotate(Math.PI/4);
g.drawLine(0,0,1,0); //draw a line at 45°
// now you should probably rotate back...
Pixels only exist at integer positions. think of it like a chess board, each square is only one colour and it means nothing to say half a square.
There are some things you can do (bi linear interpolation for example) to draw in between pixels but all they do is modify all the pixels around the point according to a suitable algorithm and the position you select.
If you want higher resolution then the simplest thing is just to increase the resolution of the image you are using. More pixels gives more possible precision, until you reach the limits of your display device...
Could anybody explain it to me?
You can't draw between pixels so why should I use float or double measuring when drawing? In Oracle's docs is written something about printer device, but it also can't paint between the smallest points. I don't understand it.
Let's say a simple line. This line has set width 1.3f. What is going on with it when it's drawn on:
display in windows (I believe it has 96 DPI)?
printer with 300 DPI?
AFAIK Java uses 72 DPI internally. So how is the math?
Several use cases come to mind.
Your graphics device might be scaled. For example I know of several applications which draw a window-filling image of the unit circle, i.e. a circle of radius 1, using an appropiate scaling of the graphics context.
You might be producing output for a vector-oriented target, like a PDF file. In that case, users might zoom in arbitrarily, and might expect a fair amount or precision even at high resolutions.
Printers, like you mention, might print at a resolution much higher than the screen, which is accomplished by a built-in zoom factor that maps default coordinate units to several times the device pixel size.
Anti-aliasing suggest sub-pixel resolution. The amount of color applied to a given pixel at the boundary of a geometric object will depend on the sub-pixel coordinates of said object.
None of the above would readily rule out using single precision floats, and in fact most G2D operations are available using floats as well. Using doubles is only important for really large zooms, really strong demands in terms of precision, and similar applications. But on the other hand, most computations are performed on doubles in any case, and the overhead of carrying these as far through the graphics pipeline as possible is often negligible. So when you ask me why to use double instead of float, I ask you “why not?”
I am using a BufferedImage to hold a 10 by 10 sample of an image. With this Image I would like to find an approximate average color (as a Color object) that represents this image. Currently I have two ideas on how to implement this feature:
Make a scaled instance of the image into a 1 by 1 size image and find the color of the newly created image as the average color
Use two for loops. The inner-most is used to average each line, the secondary for-loop is used to average each line pixel by pixel.
I really like the idea of the first solution, however I am not sure how accurate it would be. The second solution would be as accurate as they come, however it seems incredibly tedious. I also believe the getColor command is processor intensive on a large scale such as this (I am performing this averaging roughly at 640 to 1920 times a second), please correct me if I am wrong. Since this method will be very CPU intensive, I would like to use a fairly efficient algorithm.
It depends what you mean by average. If you have half the pixels red and half the pixels blue, would the average be purple? In that case I think you can try adding all the values up and dividing it by how many pixels you have.
However, I suspect that rather than the average, you want the dominant colour?
In that case one alternative could be to discretise the colours into 'buckets' (say at intervals of 100, or even more sparser in the extreme case just 3, one for Red, one for Green and one for Blue), and create a histogram (a simple array with counts). You would then take the bucket which has the most count.
Be careful with idea 1. Remember that scaling often takes place by sampling. Since you have a very small image, you have already lost a lot of information. Scaling down further will probably just sample a few pixels and not really average all of them. Better check what algorithm your scaling process is using.
I have been using Affine Transform to rotate a String in my java project, and I am not an experienced programmer yet, so it has taking me a long time to do a seemingly small task.. To rotate a string.
Now I have finally gotten it to work more or less as I had hoped, except it is not as precisely done as I want... yet.
Since it took a lot of trial and error and reading the description of the affine transform I am still not quite sure what it really does. What I think I know at the moment, is that I take a string, and define the center of the string (or the point which I want to rotate around), but where does matrices come into this? (Apparently I do not know that hehe)
Could anyone try and explain to me how affine transform works, in other words than the java doc? Maybe it can help me tweak my implementation and also, I just would really like to know :)
Thanks in advance.
To understand what is affine transform and how it works see the wikipedia article.
In general, it is a linear transformation (like scaling or reflecting) which can be implemented as a multiplication by specific matrix, and then followed by translation (moving) which is done by adding a vector. So to calculate for each pixel [x,y] its new location you need to multiply it by specific matrix (do the linear transform) and then add then add a specific vector (do the translation).
In addition to the other answers, a higher level view:
Points on the screen have a x and a y coordinate, i.e. can be written as a vector (x,y). More complex geometric objects can be thought of being described by a collection of points.
Vectors (point) can be multiplied by a matrix and the result is another vector (point).
There are special (ie cleverly constructed) matrices that when multiplied with a vector have the effect that the resulting vector is equivalent to a rotation, scaling, skewing or with a bit of trickery translation of the input point.
That's all there is to it, basically. There are a few more fancy features of this approach:
If you multiply 2 matrices you get a matrix again (at least in this case; stop nit-picking ;-) ).
If you multiply 2 matrices that are equivalent to 2 geometric transformations, the resulting matrix is equivalent to doing the 2 geometric transformations one after the other (the order matters btw).
This means you can encode an arbitrary chain of these geometric transformations in a single matrix. And you can create this matrix by multiplying the individual matrices.
Btw this also works in 3D.
For more details see the other answers.
Apart from the answers already given by other I want to show a practical tip namely a pattern I usually apply when rotating strings or other objects:
move the point of rotation (x,y) to the origin of space by applying translate(-x,-y).
do the rotation rotate(angle) (possible also scaling will be done here)
move everything back to the original point by translate(x,y).
Remember that you have to apply these steps in reverse order (see answer of trashgod).
For strings with the first translation I normally move the center of the bounding box to the origin and with the last translate move the string to the actual point on screen where the center should appear. Then I can simply draw the string at whatever position I like.
Rectangle2D r = g.getFontMetrics().getStringBounds(text, g);
g.translate(final_x, final_y);
g.rotate(-angle);
g.translate(-r.getCenterX(), -r.getCenterY());
g.drawString(text, 0, 0);
or alternatively
Rectangle2D r = g.getFontMetrics().getStringBounds(text, g);
AffineTransform trans = AffineTransform.getTranslateInstance(final_x, final_y);
trans.concatenate(AffineTransform.getRotateInstance(-angle));
trans.concatenate(AffineTransform.getTranslateInstance(-r.getCenterX(), -r.getCenterY()));
g.setTransform(trans);
g.drawString(text, 0, 0);
As a practical matter, I found two things helpful in understanding AffineTransform:
You can transform either a graphics context, Graphics2D, or any class that implements the Shape interface, as discussed here.
Concatenated transformations have an apparent last-specified-first-applied order, also mentioned here.
Here is purely mathematical video guide how to design a transformation matrix for your needs http://www.khanacademy.org/video/linear-transformation-examples--scaling-and-reflections?topic=linear-algebra
You will probably have to watch previous videos to understand how and why this matrices work though. Anyhow, it's a good resource to learn linear algebra if you have enough patience.