1
\$\begingroup\$

I'm making a game in android and I need plot a function, my algorithm is this:

    @Override
    protected void onDraw(Canvas canvas) {
        float e = 0.5f; 
        //from -x axis to +x evaluate f(x) 
        for (float x = -z(canvas.getWidth()); x < z(canvas.getWidth()); x+=e) {
                 float x1,y1;
                 x1 = x;
                 y1 = f(x);
                 canvas.drawPoint((canvas.getWidth()/2)+x1, (canvas.getHeight()/2)-y1, paintWhite);
        }   
        super.onDraw(canvas);
    }

This is how it works. If my function is, for example f(x)=x^2, then z(x) is sqrt(x). I evaluate each point between -z(x) to z(x) and then I draw them. As you can see I use the half of the size of the screen to put the function in the middle of the screen. The problem isn't that the code isn't working, actually plots the function. But if the screen is of 320*480 then this function will be really tiny like in the image below. My question is: how can I change this algorithm to scale the function?. BTW what I'm really wanting to do is trace a route to later display an animated sprite, so actually scale this image doesnt gonna help me. I need change the algorithm in order to draw the same interval but in a larger space. Any tip helps, thanks!

Current working result

enter image description here

Desired result

enter image description here

UPDATE: I will try explain more in detail what the problem is. Given this interval [-15...15] (-z(x) to z(x)) I need divide this points in a bigger interval [-320...320] (-x to x). For example, when you use some plotting software like this one. Although the div where is contain the function has 640 px of width, you dont see that the interval is from -320 to 320, you see that the interval is from -6 to 6. How can I achieve this?

\$\endgroup\$

closed as off-topic by Anko, Jari Komppa, Sean Middleditch, Vaughan Hilts, Seth Battin May 1 '14 at 3:52

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "Programming questions that aren't specific to game development are off-topic here, but can be asked on Stack Overflow. A good rule of thumb is to ask yourself "would a professional game developer give me a better/different/more specific answer to this question than other programmers?"" – Anko, Jari Komppa, Sean Middleditch, Vaughan Hilts, Seth Battin
If this question can be reworded to fit the rules in the help center, please edit the question.

1
\$\begingroup\$

Like Anastasios mentioned, you would be better off creating a "virtual coordinate space" for yourself, compute everything in this virtual space, and then when drawing, convert to pixel coordinates.

Basically, for the horizontal axis, you could create a function that converts from virtual coordinates <=> pixel coordinates. In c++ pseudo-code it would be something like this:

int virtualToScreenX(float vx) {
  return floorf(((vx - virtualMinX) / (virtualMaxX - virtualMinX)) * physicalWidth);
}

float screenToVirtualX(int sx) {
  return virtualMinX + (sx / (float)physicalWidth) * (virtualMaxX - virtualMinX);
}

You could then do the same for your Y axis, by substituting the appropriate variable names. These could be optimized by pre-computing and caching some of the terms, and converting divisions by pre-computed terms to multiplications. Be-ware that you might have to re-compute cached terms if your window changes dimensions.

You should also care about aspect ratio. To do this, you pick your "main" axis, usually Y, and then you scale your virtual ranges on the other axis by this aspect ratio.

Like so:

const float virtualMinY = -1.0f;
const float virtualMaxY = 1.0f;

const float aspect = physicalWidth / (float)physicalHeight;

const float virtualMinX = -1.0f * aspect;
const float virtualMaxX = 1.0f * aspect;

Now, your function or sprite path will always look right, no matter what the aspect ratio is.

It looks like you don't really want to zoom, but anyways, for completeness, all you need to do to implement zoom, is to scale your virtual coordinate ranges (virtualMinX, virtualMaxX, virtualMinY, virtualMaxY) by your zoom factor.

To zoom in 3x, your zoom factor is 1.0f / 3.0f. To zoom out 5x, it is 5.0f;

(remember to recompute any cached values after changing zoom levels)

\$\endgroup\$
  • \$\begingroup\$ You get what I was trying to achive, thanks. Your solution worked perfectly. \$\endgroup\$ – 4gus71n Apr 30 '14 at 15:24
0
\$\begingroup\$

Just find what the value will be when f(x) is out of your screen vertically. Then, scale the screen to that x value.

So, just start at the middle of your function and find when the f(x) value is out of your bounds of your screen and scale it to there.

\$\endgroup\$
  • \$\begingroup\$ That doesn't solve my problem, where I get the value to scale the image? and how I do it? and what operation must I do?. I'm looking for a math solution, I can't do things like stretch the image from the canvas. Maybe I didnt explain myself very well. I'm trying to display an animated sprite (a missile or a fire ball for example) and that sprite rotates and follow the path given by the function, for that reason first I need correctly plot the function. \$\endgroup\$ – 4gus71n Sep 22 '13 at 3:22
  • \$\begingroup\$ Hmmm, I'm not sure we are on the same page. Not your fault. Well, you could use the same method I described about, to find when the function would go out of bounds of your screen. Then, knowing how much space the function takes, you could scale x accordingly. If that doesn't help I'll try to completely rethink me answer :P \$\endgroup\$ – TheNickmaster21 Sep 22 '13 at 14:19
  • \$\begingroup\$ I updated my question to be more understandable. \$\endgroup\$ – 4gus71n Sep 22 '13 at 18:36
  • \$\begingroup\$ That doesn't really help me because if I do that I will plotting another function. Yeah, I could change my function x^2 by (x/2)^2 to make It look like x^2 in a really big interval, but that doesnt help me. Instead I want to know how plot it in scale. When I'm doing the (canvas.getWidth()/2)+x1 doesn't exist some operation that I can make over this in order to separate each point one from another by a R factor? \$\endgroup\$ – 4gus71n Sep 22 '13 at 18:45
  • \$\begingroup\$ To plot in scale, you just plot the modified function? You don't have to actually change the function. If that doesn't help you, I'm not quite sure how to. Sorry \$\endgroup\$ – TheNickmaster21 Sep 22 '13 at 19:49
0
\$\begingroup\$

If you want to "scale" the function you should change your input range ( or in mathematical terminology the domain of the function ). I advise you to make your domain irrelevant to the screen size. Also in order to make your display irrelevant of the the screen size you should use normalized coordinates ( e.x [-1...1] or [0...1] ). Screen coordinates normalization is very easy, you just divide your coordinates with the size of the screen.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.