Changing coordinates


E

Eustace

Instead of having the x and y coordinates start at the top right corner,
I prefer them to start either at the center of the window. This I can do
with:

....
class CustomPanel extends JPanel {
public void paintComponent(Graphics painter) {
painter2D = (Graphics2D)painter;
painter2D.translate(width/2, height/2);
....

But I would also prefer the positive values across the y axis to be
positive above the base line and negative below.

I could use

painter2D.rotate(-Math.PI/2);

but then of course the x axis and the y axis replace each other, so then
I have to use, for example,

Rectangle 2D frame = new Rectangle2D.Double(y, x, h, w);

instead of

Rectangle 2D frame = new Rectangle2D.Double(x, y, w, h);

As I see it my choices are:

(a) Get used to the y axis moving downwards.

(b) Use rotation and learn to remember that y replaces x etc.

(c) Use (b) and overwrite the constructors that use x, y, w, h.

I would like to hear what the solution of experienced programmers is. I
tend to accept (a), hoping that after some time it will seem natural.
But is there a (d) option of reversing the direction of the y axis?

Thanks,

emf
 
Ad

Advertisements

L

Lew

Instead of having the x and y coordinates start at the top right corner,
I prefer them to start either at the center of the window. This I can do
with:

...
class CustomPanel extends JPanel {
public void paintComponent(Graphics painter) {
painter2D = (Graphics2D)painter;
painter2D.translate(width/2, height/2);
...

But I would also prefer the positive values across the y axis to be
positive above the base line and negative below.

I could use

painter2D.rotate(-Math.PI/2);

but then of course the x axis and the y axis replace each other, so then
I have to use, for example,

Rectangle 2D frame = new Rectangle2D.Double(y, x, h, w);

instead of

Rectangle 2D frame = new Rectangle2D.Double(x, y, w, h);

As I see it my choices are:

(a) Get used to the y axis moving downwards.

(b) Use rotation and learn to remember that y replaces x etc.

(c) Use (b) and overwrite the constructors that use x, y, w, h.

I would like to hear what the solution of experienced programmers is. I
tend to accept (a), hoping that after some time it will seem natural.
But is there a (d) option of reversing the direction of the y axis?

From time immemorial screen coordinates have been expressed from the top-left
corner. You will go through a lot of useless effort resisting this.

Take the world for what it is and don't fight to jam it into your preconceptions.
 
L

Lew

Eustace said:
From time immemorial screen coordinates have been expressed from the
top-left corner. You will go through a lot of useless effort resisting
this.
Take the world for what it is and don't fight to jam it into your
preconceptions.


I missed a few points.

What the heck do you mean by "overwrite the constructors"?

Where did you get the idea that screen coordinates start at the top right?
They don't.

Your line 'Rectangle 2D frame = ...' will not compile.
 
R

Rene' Descartes

From time immemorial screen coordinates have been expressed from the
top-left corner. You will go through a lot of useless effort
resisting this.

But even before such immemorial times, physicists and mathematicians are
used to coordinates starting in the bottom left corner.
Take the world for what it is and don't fight to jam it into your
preconceptions.

And Y-flipping is something standard in every sensible graphics package.
Usually one has some world coordinates, some "normalized device
coordinates" (NDC) and the raw device coordinates. Y-flipping is taken
care when passing from NDC to raw.
 
L

Lew

Rene' Descartes said:
But even before such immemorial times, physicists and mathematicians are
used to coordinates starting in the bottom left corner.

On computer screens? I think not.

Different domain of discourse, different rules.

My degree is in mathematics, but I don't try to fight the standard for
screen coordinates. I'm much happier that way. I recommend the same
to you.

Rene' Descartes said:
And Y-flipping is something standard in every sensible graphics package.

Circular reasoning. You're proving your point by calling the
conclusion "sensible".
Usually one has some world coordinates, some "normalized device
coordinates" (NDC) and the raw device coordinates. Y-flipping is taken
care when passing from NDC to raw.

The OP is using libraries that work in terms of screen coordinates.
Ergo, they must use screen coordinates. Y-flipping is not relevant.
 
E

Eustace

Eustace said:
[...]
I would like to hear what the solution of experienced programmers is.
I tend to accept (a), hoping that after some time it will seem
natural. But is there a (d) option of reversing the direction of the y
axis?

Yes. Use a scaling transform on the Graphics or Graphics2D instance,
just as you've already used a translation transform. Scale the X
coordinates by 1.0, and the Y coordinates by -1.0.

Don't forget to set it back to the original state when you're done drawing.

As for whether this is a good idea or not, IMHO the warnings to just
follow the existing conventions are over-cautious.

I agree that manipulating the language itself to try to make it look
like something else is a bad idea. But graphical coordinate systems are
inherently transformable, and it's actually a very good idea to do so
when the data is naturally in some coordinate system other than the
default one. It is much better to transform the coordinate system in
one place, and then just draw the data as it is, than to try to adjust
all of the data for each drawing operation explicitly.

If you are trying to do this just so that you can, for example, lay out
controls in a different coordinate system than the default, then I would
advise against it as others have (I doubt it would even work). But if
this is just about the things that you are drawing yourself, it's not
only not bad, it can actually be a good way to simplify the code.

Pete

Many thanks, Pete. I would have actually been surprised if they was not
a scale method. It works *almost* marvelously. The only thing I've found
so far is that if you try:

Arc2D.Double arc = new Arc2D.Double(0, 0, 100, 100, 0, 90, Arc2D.PIE);

the angle opens *downwards* rather than *upwards* as the angles do in
trigonometry.

Let me may clear that I am neither a programmer nor a mathematician.
15-20 years ago, when I had just learned QBasic I wrote strictly for my
own use a number of programs, the most complex of which would read the
coastline coordinates of the continents and draw globes any way I
wanted, along with doing a couple other specific things I wanted it to
do, with heavy use, of course, or spherical trigonometry. The programs
were sufficient for my needs at the time, and I postponed the
inevitable, that is learning an advanced language, until 5 years ago
when I audited 2 Java classes, working on them certainly much harder
than any of my for credit classmates. Soon, however, afterwards I lost
steam, perhaps realizing that the globe program was still far beyond my
capabilities at the time.

Then, last year my new Vista laptop finally relegated my old programs to
the programming junkyard (where of course they are only useful for still
valuable spare parts), and lately it seems I've caught once more
programming fever :) and started reworking the *easier* of my old
(graphics) programs. I am excited discovering Java's immense
capabilities (think of it: compared with QBasic!) and I enjoy the
learning that comes from hands-on experience. As for the globe program,
that will have to wait a little.

In QBasic I would always declare the screen coordinates as I wanted,
often with (0, 0) at the center of the screen that is indicated for
globes, and had never even occurred to me to opt *not* to have the y
axis *always* move upwards. I fully understand that this is a
convention, and now I soon have to decide on the issue. Your suggestion
would have settled it if only there wasn't this little thing with the
opening of the angles, and, I suspect, other repercussions coming later.

So, I am sorry to say Monsieur Descartes, however much I admire your
reasoning, I am on the brink of letting go and flow with the flow;
except if, after setting scale(1.0, -1.0), there is an easy way to set
the angles opening upwards like in trigonometry...? I doubt it, but I
have to ask before going whichever way I will go.

Eustace
 
Ad

Advertisements

J

John B. Matthews

Eustace said:
On 2010-06-16 11:21 Peter Duniho wrote: [...]
Yes. Use a scaling transform on the Graphics or Graphics2D instance,
just as you've already used a translation transform. Scale the X
coordinates by 1.0, and the Y coordinates by -1.0.
[...]
Many thanks, Pete. I would have actually been surprised if they was not
a scale method. It works *almost* marvelously. The only thing I've found
so far is that if you try:

Arc2D.Double arc = new Arc2D.Double(0, 0, 100, 100, 0, 90, Arc2D.PIE);

the angle opens *downwards* rather than *upwards* as the angles do in
trigonometry.

This may be a limitation of Arc2D itself, which specifies "that 45
degrees always falls on the line from the center of the ellipse to the
upper right corner of the framing rectangle.

15-20 years ago, when I had just learned QBasic I wrote strictly for my
own use a number of programs, the most complex of which would read the
coastline coordinates of the continents and draw globes any way I
wanted, along with doing a couple other specific things I wanted it to
do, with heavy use, of course, or spherical trigonometry.

You may enjoy Jerry Huxtable's Globe Applet and map projection library,
written in Java:

<http://www.jhlabs.com/java/maps/proj/index.html>

[...]
 
A

Arne Vajhøj

From time immemorial screen coordinates have been expressed from the
top-left corner. You will go through a lot of useless effort resisting
this.

Take the world for what it is and don't fight to jam it into your
preconceptions.

I would never assume that 0,0 is top left.

I would read the docs to see if it is top left or bottom
left or center or something else.

Top left is by far the most common - probably an inheritage
from hardcopy terminals.

But common != guaranteed.

Arne
 
A

Arne Vajhøj

The least readable piece of C code I have ever seen was written by some
programmers who preferred Pascal, and used #define to make their C code
look a bit Pascal-ish. Even for someone fluent in both C and Pascal, it
was very confusing.

You mean:

#define begin {
#define end }

?

I have seen that too !

<various nasty words censored >

Arne
 
E

Eustace

Eustace said:
On 2010-06-16 11:21 Peter Duniho wrote: [...]
Yes. Use a scaling transform on the Graphics or Graphics2D instance,
just as you've already used a translation transform. Scale the X
coordinates by 1.0, and the Y coordinates by -1.0.
[...]
Many thanks, Pete. I would have actually been surprised if they was not
a scale method. It works *almost* marvelously. The only thing I've found
so far is that if you try:

Arc2D.Double arc = new Arc2D.Double(0, 0, 100, 100, 0, 90, Arc2D.PIE);

the angle opens *downwards* rather than *upwards* as the angles do in
trigonometry.

This may be a limitation of Arc2D itself, which specifies "that 45
degrees always falls on the line from the center of the ellipse to the
upper right corner of the framing rectangle.

<http://java.sun.com/javase/6/docs/api/java/awt/geom/Arc2D.html>

Talking about conventions, the pixel by pixel way of drawing an ark does
not give the same results as the Ard2D:

....
setSize(width, height);
....
Rectangle2D.Double pixel = new Rectangle2D.Double(0, 0, 1, 1);
painter2D.translate(width/2, height/2);

painter2D.setColor(Color.red);
x = -100;
y = -100;
w = 200;
h = 200;
arc = new Arc2D.Double(x, y, w, h, 0, 90, Arc2D.Double.OPEN);
painter2D.draw(arc);

painter2D.setColor(Color.green);
x = 0;
y = 0;
double x0 = x + w/2;
double y0 = y - h/2;
double r = 100;
double q;
for (int i = 0; i < 89; i++) {
q = Math.toRadians(i);
pixel.x = Math.sin(q) * r;
pixel.y = Math.cos(q) * r;
painter2D.fill(pixel);
}

For the second method to give the same arc it has to be:

q = Math.toRadians(i + 90);

(I am using variable q instead of theta, since q is the Latin letter
representing the Greek theta in "Greeklish", that is writing Greek using
the Latin alphabet.)

So Java is following 2 contradicting conventions. I do not remember any
such problems with Basic. If it had even crossed my mind that the
setting of the axes might have been different in other languages, I
would have spent some time investigating how different languages handle
this before plunging into one, and it would have been one of the factors
in my decision.

Anyway, the decisive drawback against using

scale(1.0, -1.0)

is that if you then want to use

painter2D.draw(String, x, y)

the string appears in the right place but upside down. There may be ways
to correct this, but would make programming more complicated than
flowing with the flow, so that settles the issue.

I will be checking the projection library (as well as your website).

Thanks,

emf
 
J

John B. Matthews

Eustace said:
Eustace said:
On 2010-06-16 11:21 Peter Duniho wrote: [...]
Yes. Use a scaling transform on the Graphics or Graphics2D
instance, just as you've already used a translation transform.
Scale the X coordinates by 1.0, and the Y coordinates by -1.0.
[Thoughtful arc implementation elided.]
Anyway, the decisive drawback against using

scale(1.0, -1.0)

is that if you then want to use

painter2D.draw(String, x, y)

the string appears in the right place but upside down. There may be ways
to correct this, but would make programming more complicated than
flowing with the flow, so that settles the issue.

One can always preserve and restore the graphics transform:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;

/** @author John B. Matthews */
public class SineTest extends JPanel implements Runnable {

private static final int SIZE = 400;
private AffineTransform at;

public static void main(String[] args) {
EventQueue.invokeLater(new SineTest());
}

@Override
public void run() {
JFrame f = new JFrame("ArcTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}

public SineTest() {
this.setPreferredSize(new Dimension(640, 480));
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int w = getWidth();
int h = getHeight();
g2d.setColor(Color.gray);
g2d.drawLine(w / 2, 0, w / 2, h);
g2d.drawLine(0, h / 2, w, h / 2);

at = g2d.getTransform();
g2d.translate(w / 2, h / 2);
g2d.scale(1, -1);
g2d.setColor(Color.blue);
double r = SIZE / 2;
double q = -Math.PI / 2;
double d = Math.PI / 180d;
int x1 = (int) Math.round(q * r);
int y1 = (int) Math.round(Math.sin(q) * r);
int x2, y2;
for (int i = 0; i < 180; i++) {
q += d;
x2 = (int) Math.round(q * r);
y2 = (int) Math.round(Math.sin(q) * r);
g2d.drawLine(x1, y1, x2, y2);
x1 = x2;
y1 = y2;
}

g2d.setTransform(at);
g2d.setColor(Color.blue);
g2d.drawString("y = sin(x)", 100, 100);
}
}
I will be checking the projection library (as well as your website).

Excellent!
 
Ad

Advertisements

R

Roedy Green

(a) Get used to the y axis moving downwards.

(b) Use rotation and learn to remember that y replaces x etc.

(c) Use (b) and overwrite the constructors that use x, y, w, h.

The most important thing is, no matter what you choose, document your
convention. If you don't document this, it can confuse, or waste other
people's time trying to figure out what you used. This is especially
true if you change the convention at different stages of your
computation.
--
Roedy Green Canadian Mind Products
http://mindprod.com

There is no harm in being sometimes wrong especially if one is promptly found out.
~ John Maynard Keynes (born: 1883-06-05 died: 1946-04-21 at age: 62)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top