How to set a location of point using Point class? - java

I am trying to set a location of geometric figure that appears in JFrame window. For example if it's a rectangle so i need to move it's left upper point 10 pixels right, and left lower point 10 pixels down.
I was trying to do like this but it didn't work:
public void relocate(ArrayList<MyShape> newShape){
int x1, x2, y1 , y2;
for(int i = 0; i < newShape.size(); i++){
x1 = (int)newShape.get(i).p1.getX();
y1 = (int)newShape.get(i).p1.getY();
x2 = (int)newShape.get(i).p2.getX();
y2 = (int)newShape.get(i).p2.getY();
newShape.get(i).setLocation(x1 + 10, y1);
newShape.get(i).setP1(newShape.get(i).getP1());
newShape.get(i).setLocation(x2, y2 + 10);
newShape.get(i).setP2(newShape.get(i).getP2());
if(newShape.get(i).getCol() != null){
newShape.get(i).setCol(Color.BLUE);
}
}
repaint();
}

Your code should work - in a sense that it changes the location of the objects on the screen. So, what's going on here? What's wrong with your solution?
I can give you a few hints though:
You can check if any other part of the code is messing with the location setting. It's possible that they override your settings.
Maybe this code runs outside of the AWT Thread. You can check it with SwingUtilities.isEventDispatchThread().
You can reuse the Point-s in Swing. Points are mutable object. This leads to not so clean code, but performance is important in this case:
MyShape shape = newShape.get(i);
Point p = shape.getP1();
p.setLocation(p.x, p.y + 10);
Maybe a revalidate() call can help too:
public void relocate(ArrayList<MyShape> newShape) {
// some code changing locations
revalidate(); // this is it
repatint();
}

The following analysis is based on assumptions about how MyShape works since you've declined to provide those details when asked for them.
Look at your algorithm. For each shape:
1) You're capturing the original values of P1 and P2. So far so good.
2) You're calling the shape's setLocation() method with an adjusted value for P1. Now, what does setLocation() do? Understanding that is part of why you were asked about the MyShape class, and saying it's a superclass for all shapes doesn't help.
3) You tell the shape to set its P1 to whatever value you get by querying its P1. If the getters and setters do anything reasonable, this won't do anything.
4) You then call setLocation() again, this time with an adjusted value for P2. Again, what does this do? It probably undoes whatever you accomplished in step 2.
5) You tell the shape to set its P2 to whatever value you get by querying its P2. Again, this probably doesn't do anything.
What you want to do, I assume, is set P1 based on the adjusted values you calculated in step 2; and set P2 based on the adjusted values in step 4. But that's not what your code says unless secLocation, getP1, and getP2 are all doing very ununtuitive things.

Not sure what MyShape does, but it seems that newShape.get(i).setP1 just overrides newShape.get(i).setLocation right before it. Try adjusting your code like this:
//Change this
newShape.get(i).setLocation(x1 + 10, y1);
newShape.get(i).setP1(newShape.get(i).getP1());
newShape.get(i).setLocation(x2, y2 + 10);
newShape.get(i).setP2(newShape.get(i).getP2());
//To this
newShape.get(i).getP1().setLocation(x1 + 10, y1);
newShape.get(i).getP2().setLocation(x2, y2 + 10);
I hope this helps.

Related

Java/libgdx 3D model rotation error

Problem: my player model is supposed to turn into the direction of the last mouse click but instead of turning slowly it spins in all possible ways(Game has an isometric view, the model is supposed to rotate only around the Y-axis but it rotates around the X- and Z-axis too).
Following method(called in render()) is responsible for the turning behavior of the model:
public static void turnUnit(){
if(Gdx.input.isButtonPressed(Input.Buttons.LEFT)){
mX = Gdx.input.getX();
mY = Gdx.input.getY();
angle = (float) (180+Math.atan2(mX-Gdx.graphics.getWidth()/2, mY-Gdx.graphics.getHeight()/2)*(180/Math.PI));
newAngle = ((((currentAngle - angle) % 360) + 540) % 360) - 180;
turning = newAngle/60*turnRate;
currentAngle = currentAngle-turning;
}
TestGround.player.transform.setToRotation(Vector3.Y, currentAngle).setTranslation(posX,0,posZ);
}
And the movement-method(also called in render()):
public static void movement(){
if(northM==true){
TestGround.player.transform.trn(0,0,-1f);
}
if(southM==true){
TestGround.player.transform.trn(0,0,1f);
}
if(westM==true){
TestGround.player.transform.trn(-1f,0,0);
}
if(eastM==true){
TestGround.player.transform.trn(1f,0,0);
}
posX = TestGround.player.transform.getTranslation(Vector3.X).x;
posY = TestGround.player.transform.getTranslation(Vector3.Y).y;
posZ = TestGround.player.transform.getTranslation(Vector3.Z).z;
}
Tried to use "rotate" in the last line but then it just spins faster.
Also, even though this makes no sense to me but after some testing it seems the movement-method somehow interferes with the turn-method(moving in a certain direction will rotate the model in a certain way).
Am I doing something fundamentally wrong here?
Additional Info:
originally I used simple polling to get all keyboard and mouse input
calculated movement/rotation in one big method and everything worked
fine
decided to use the inputprocessor of libgdx to make the code more readable and open-ended
The Matrix4#getTranslation(Vector3) method will set the specified vector to the translation component of the matrix and return it for chaining. What this means is that the vector you supply as argument to the TestGround.player.transform.getTranslation(vector) method, will be set (read: overwritten) to the translation (position) of the model instance.
So, in the case of the call to:
TestGround.player.transform.getTranslation(Vector3.Y)
This will practically modify the Vector3.Y variable from the default [x:0, y:1, z:0], to whatever the translation component of the matrix is set to. This will result in any other call that uses the Vector3.Y variable (like your call to setToRotation) to behave differently.
To fix that you can modify the last few lines to:
Vector3 pos = new Vector3();
TestGround.player.transform.getTranslation(pos);
posX = pos.x;
posY = pos.y;
posZ = pos.z;
Note that you should move the creation of the Vector3 out of the method and therefor might as well remove the posX, posY and posZ members in favor of the pos member.
So, you might be wondering two questions:
Why does the getTranslation method modify its arguments? This is because libGDX is designed to avoid creating garbage, because that will create hick-ups on some platforms, like Android. So instead of creating a new Vector3 every time the method is called, it allows you to specify an instance of that class which you want to reuse. You will see this pattern throughout the lib at multiple places because of this reason.
Why is it even possible to modify Vector3.Y, making it useless and cause all kind of problems? This is because the Vector3 class is mutable and does not encapsulate its members. So practically it allows you to do vector.x += 3; instead of forcing you to call vector.setX(vector.getX() + 3);. This is both for readability and performance reasons (although the latter might vary on your target platform). Also, java does not support something comparable to const.

Rectangle intersection shared edge

I'm trying to determine whether two rectangles border each other. If they share an edge or part of an edge, then I want to include them, if they only share a vertice then I don't.
I've tried using android android.graphics.Rect, I was hoping that the intersect method would return true giving me a rectangle, with 0 width but the points of the intersecting edge. I'm using andEngine and also tried the collideswith method of org.andengine.entity.primitive.Rectangle however that returns true, even if the rectangle only share one corner vertice.
Is there a nice way of doing this? The only other way I can think of is to try and create a collection of all the edges then see if they're equal or are in someway partly equal.
Here's an image to demonstrate what I want. If I click on rect 1 then I want to return rects 2,3 and 4, but not 5.
"Map":
It sounds like you need a new class to do this. I would take the coordinates of each corner of the rectangles. Then, when you are selecting a rectangle, you can get those adjacent to it by finding them one side at a time. Starting with the top for an example, you check which other rectangles have corners at the same height. From that list, you check to see which ones exist on at least one point between the two top corners. So, if top left is 0,3 and top right is 4,3 then you would look for the list of corners at y=3. From that list you find all corners where 0<=x<=4 and anything that fits will be adjacent. You then do the same thing for each additional side. It should be an easy class to make, but I am not going to write any code as I do not know anything about how you stored your data or how you would reference this in your code. If you need help with that, write a comment.
Write a function to find which rectangles share edges with rectangles within all considered rectangles.
Then, map these rectangles which share edges to one another. An Adjacency List is just a way of representing a graph in code.
Sometimes code is easier to understand, so here's code. I have not tested this, but it should get you most the way there.
Also, I'm not sure what you're end goal is here but here's a question I answered that deals with rectangular compression.
List<Rectangle> allRectangles;
public boolean shareAnEdge(Rectangle r1, Rectangle r2){
int y1 = r1.y + r1.height;
int y2 = r2.y+r2.height;
int x1 = r1.x+r1.width;
int x2 = r2.x+r2.width;
boolean topShared = (y1 == r2.y && r2.x == r1.x);
boolean bottomShared = (y2 == r2.y && r2.x==r1.x);
boolean rightShared = (x1 == r2.x && r2.y==r1.y);
boolean leftShared = (x2 == r1.x && r2.y==r1.y);
if (topShared || bottomShared || rightShared || leftShared) {
return true;
}
return false;
}
public List<Rectangle> findSharedEdgesFor(Rectangle input){
List<Rectangle> output = new List<Rectangle>();
for(Rectangle r : allRectangles){
if(r!=input && shareAnEdge(r, input)){
output.add(r);
}
}
}
public AdjacencyList createGraph(List<Rectangle> rectangles){
AdjacencyList graph = new AdjacencyList();
for(Rectangle r : rectangles){
List<Rectangle> sharedEdges = findSharedEdgesFor(r);
for(Rectangle shared : sharedEdges){
graph.createEdgeBetween(r, shared);
}
}
}

How to get a number from a changing variable?

I'm currently trying to make something like a trail that follows an object. Well, basically I just create a "trail object" every second at X,Y of the main object. However, I can't make it work.
This the movement code for the main object.
dx = ((Math.sin(speed)*20);
speed = speed + 0.09;
x = x + dx;
My idea was that for making a trail I just need to subtract dx from x, so it would look like that
tick = tick + gameTimer.getDelay();
for(int i = 0; i < 100; i++)
{
if (tick > 1000*i)
{
g2d.drawOval(x-dx, y, 50, 50);
}
}
but apparently my theory is wrong and therefore I ask for your help people.
P.S. There is no code for "y" because I don't need it yet.
P.S.S I know that I'm missing a lot of details, so if you need some more info let me know and I'll paste some more code

Draw a curved path on Canvas?

How could I draw a quadratic curve or a trigonometric curve (such as sin(x)) on a Canvas?
Like you, I needed to draw a curved line from point(x1, y1) to point (x2, y2). I did some searching around which lead me to the Path class (android.graphics.Path). Path has numerous methods for drawing lines. Once you have created a path you use a draw method to make the actual line. The paths can be rotated, transformed, saved, and added to. There are arcs, circles, and rectangles that be drawn with this class too.
http://developer.android.com/reference/android/graphics/Path.html
Set start point of path → mPath.moveTo(x1, y1);
Set constant and end points → mPath.quadTo(cx, cy, x2, y2);
Convert path to line → canvas.drawPath(mPath, mPaint);
Here is a drawEquation() method I wrote for a Graph class - I think it may help. The basic idea to create a method that accepts an equation (which is basically just a function) like
function(x) = Math.sin(x);
and then loop through the bounds of the graph and draws small segments connecting each point. The transformContext() just inverts the canvas context so that increasing values of y go upwards and not downwards:
Graph.prototype.transformContext = function(){
var canvas = this.canvas;
var context = this.context;
// move context to center of canvas
this.context.translate(this.centerX, this.centerY);
// stretch grid to fit the canvas window, and
// invert the y scale so that that increments
// as you move upwards
context.scale(this.scaleX, -this.scaleY);
};
Graph.prototype.drawEquation = function(equation, color, thickness){
var canvas = this.canvas;
var context = this.context;
context.save();
this.transformContext();
context.beginPath();
context.moveTo(this.minX, equation(this.minX));
for (var x = this.minX + this.iteration; x <= this.maxX; x += this.iteration) {
context.lineTo(x, equation(x));
}
context.restore();
context.lineJoin = "round";
context.lineWidth = thickness;
context.strokeStyle = color;
context.stroke();
};
Most drawing APIs dont provide such functions, you will have to calculate the pixels of your desired curve in pixels and draw piece by piece on the canvas using one or more calls to the canvas API.
Use Canvas.drawPath and Path.quadTo.
I'm going to assume that you are familiar with drawing basic lines on a canvas, if not then respond back and we can delve further back. However, as far as just drawing a sine function there is a function within the Math class that has just what you need.
http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Math.html#sin%28double%29
From there you just need to pass your x variable(in radians) into the function and save it's output as a y variable. This represent a point on your graph. Now increment the x1 variable by a small amount (perhaps 1/100 of your graph, though you will need to adjust this to taste), run it through the function again and save those variables(x2 and y2) as your second point. Draw a line between these two points. Save your x2,y2 variables as x1, y1 and increment your x value again to find the third point, so on and so forth. This is not a "true" curve as it is really just a series of lines which approximate the function, a calculus approach if you will.
So:
x1 = x; // where x is some point on the x axis which you would like to start graphing at.
y1 = sin(x);
x2 = x1 + increment;
y2 = sin(x2);
//Draw a line here
x1 = x2;
y1 = y2;
//return to top, this code would obviously be in a loop in which uses increment as it's own increment with the initial value being equal to the amount you want to increment each time(let's say....5) and the "next" statement being increment = increment + 5.
There is also a GraphCanvas class which I am unfamiliar with which appears to take those same points and draw the curve between them, though I am unsure what sort of transform is being used to draw the curve and how accurate that is. Here is the Class:
http://www.java2s.com/Code/Java/Swing-Components/GraphCanvas.htm

Animating a line between two Point objects

What's the simplest way to draw a line between two Point objects in a way
that will look like I am drawing that line in real time by hand?
For example:
Point a = new Point(5,20);
Point b = new Point(15,20);
How do I connect these points with a "moving" line?
In other words I want to make the user feel "motion" of some sort. Is there a simple way to do that?
Given two points, you can determine the equation of the line connecting them. The equation of a line is of the form y = mx + c, where m is the slope, and c is the y intercept.
So, given your two points (5,20) and (15,20), we first determine m.
m = (y2-y1)/(x2-x1)
= (20-20)/(15-5)
= (0)/10
= 0
Substituting into the equation for a straight line, we get y = 0x + c or y = c. Now that we know this, we simply need to know the points where y = c and 5<=x<=15. Simply draw each of these points in the normal way (look at this for the exact method) with a Thread.sleep() call in between drawing each point. In this case, you have only 11 points to draw, so it would make sense to draw 1 point every 100 ms. For details on Thread.sleep() see here.
EDIT: Since Thread.sleep() won't work on the EDT, look at javax.swing.Timer instead, as Uhlen suggested.
Following the answer by Chinmay Kanchi, you need to create a feeling of animation. As mentioned above in comments by Uhlen you should use Swing's Timer when working on EDT. To give you example of how to use Timer. Lets assume we have a panel and we want it to slide open on e.g. a button click, thus we need to animate it sliding open by increasing its size. Below is an example showing pretty much how you would use Timer to do the operations.
this.extendingTimer = new Timer(0, new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//assume sliding is vertical
int value = maximumHeight;
//make sure the size will not be bigger then allowed maximum
if(currentExtensionSize + extensionRate >= value)
{
currentExtensionSize = value;
stopExtending();
}
else
currentExtensionSize += extensionRate;
setSize(new Dimension(maximumWidth, currentExtensionSize));
}
});
extendingTimer.setInitialDelay(0);
extendingTimer.setDelay(100);
extendingTimer.setRepeats(true);
int lineCount = 0; //global
// timer calls the below
xLocation = (*a)[a->size()-1] * timeSoFar / duration ;
if(xLocation > (*a)[lineCount+1]){
lineCount++;
}
double m = ((*b)[lineCount+1] - (*b)[lineCount])/((*a)[lineCount+1]-(*a)[lineCount]);
double yIntercept = (*b)[lineCount]-m*(*a)[lineCount];
yLocation = m * xLocation + yIntercept;
xLocation = (yLocation - yIntercept) / m;
this is in c++ and using vectors but its the theory we want. This allows for multiple lines not just one.

Categories