Is there a way to point the camera in the direction of a specific vector in Javafx8? - javafx-8

I've looked around for awhile and I can't seem to find a way to point a camera in a direction say [1, 2, 3] without calculating the angles between everything. I'm actually new to 3d graphics in general so I don't know if I'm missing something simple.

I have edited my answer to provide an example of how to manipulate the Affine transform
relative to current position in scene. Which is a very useful Transform for 3D space.
I will cover the basics with code, I do suggest you read up on Transformation Matrices.
This is a good Tutorial and cover everything in "layman's" terms.
So first define a few Callbacks for getting both rows and cols from the affine matrix:
public Affine affine = new Affine();
//Points: fwd, right, up Point3D: pos
//Forward / look direction
Callback<Transform, Point3D> forwardColCallback = (a) -> {
return new Point3D(a.getMzx(), a.getMzy(), a.getMzz());
};
Callback<Transform, Point3D> forwardRowCallback = (a) -> {
return new Point3D(a.getMxz(), a.getMyz(), a.getMzz());
};
// up direction
Callback<Transform, Point3D> upColCallback = (a) -> {
return new Point3D(a.getMyx(), a.getMyy(), a.getMyz());
};
Callback<Transform, Point3D> upRowCallback = (a) -> {
return new Point3D(a.getMxy(), a.getMyy(), a.getMzy());
};
// right direction
Callback<Transform, Point3D> rightColCallback = (a) -> {
return new Point3D(a.getMxx(), a.getMxy(), a.getMxz());
};
Callback<Transform, Point3D> rightRowCallback = (a) -> {
return new Point3D(a.getMxx(), a.getMyx(), a.getMzx());
};
//position
Callback<Transform, Point3D> positionCallback = (a) ->{
return new Point3D(a.getTx(), a.getTy(), a.getTz());
};
Point3D getForwardCol(){
return forwardColCallback.call(getTransformableNode().getLocalToSceneTransform());
}
Point3D getForwardRow(){
return forwardRowCallback.call(getTransformableNode().getLocalToSceneTransform());
}
Point3D getRightDirection(){
return rightDirCallback.call(getTransformableNode().getLocalToSceneTransform());
}
Point3D getRightRow(){
return rightRowCallback.call(getTransformableNode().getLocalToSceneTransform());
}
Point3D getUpCol(){
return upColCallback.call(getTransformableNode().getLocalToSceneTransform());
}
Point3D getUpRow(){
return upRowCallback.call(getTransformableNode().getLocalToSceneTransform());
}
Point3D getPosition(){
return positionCallback.call(getTransformableNode().getLocalToSceneTransform());
}
Ok, Now lets build some methods to use those.
Translations:
private void moveForward() {
affine.setTx(getPosition().getX() + speed * getForwardRow().x);
affine.setTy(getPosition().getY() + speed * getForwardRow().y);
affine.setTz(getPosition().getZ() + speed * getForwardRow().z);
}
private void strafeLeft() {
affine.setTx(getPosition().getX() + speed * -getRightRow().x);
affine.setTy(getPosition().getY() + speed * -getRightRow().y);
affine.setTz(getPosition().getZ() + speed * -getRightRow().z);
}
private void strafeRight() {
affine.setTx(getPosition().getX() + speed * getRightRow().x);
affine.setTy(getPosition().getY() + speed * getRightRow().y);
affine.setTz(getPosition().getZ() + speed * getRightRow().z);
}
private void moveBack() {
affine.setTx(getPosition().getX() + speed * -getForwardRow().x);
affine.setTy(getPosition().getY() + speed * -getForwardRow().y);
affine.setTz(getPosition().getZ() + speed * -getForwardRow().z);
}
private void moveUp() {
affine.setTx(getPosition().getX() + speed * -getUpRow().x);
affine.setTy(getPosition().getY() + speed * -getUpRow().y);
affine.setTz(getPosition().getZ() + speed * -getUpRow().z);
}
private void moveDown() {
affine.setTx(getPosition().getX() + speed * getUpRow().x);
affine.setTy(getPosition().getY() + speed * getUpRow().y);
affine.setTz(getPosition().getZ() + speed * getUpRow().z);
}
For Rotations you could do something like this by adding a Translate and the 3 respective Rotate transforms:
// mouse coordinates not implemented in this example
// You would need to define them
scene.setOnMousePressed(me->{
t.setX(getPosition().getX());
t.setY(getPosition().getY());
t.setZ(getPosition().getZ());
affine.setToIdentity();
rotateY.setAngle(
MathUtils.clamp(((rotateY.getAngle() + moveDelta.getX() * (speed * 0.05)) % 360 + 540) % 360 - 180, -360, 360)
); // horizontal
rotateX.setAngle(
MathUtils.clamp(((rotateX.getAngle() - moveDelta.getY() * (speed * 0.05)) % 360 + 540) % 360 - 180, -90, 90)
); // vertical
affine.prepend(t.createConcatenation(rotateY.createConcatenation(rotateX)));
}
);

Related

How to prevent automatic moving of an object when touched by other object

I have a car in my project, when I hit other objects by it, it goes to it's opposite axis, but when I use cube to hit other objects, it works correctly. Here is the code for moving the car:
// Update is called once per frame
void Update()
{
if (Input.GetButton("Vertical"))
{
VerticalMove = Input.GetAxis("Vertical") * Time.deltaTime * 10;
transform.Translate(0, 0, VerticalMove);
if (Input.GetButton("Horizontal"))
{
if (Input.GetAxis("Vertical") > 0)
{
HorizontalMove = Input.GetAxis("Horizontal") * Time.deltaTime * 50;
transform.Rotate(0, HorizontalMove, 0);
}
else
{
float x = Input.GetAxis("Horizontal");
if (x > 0) {
x -= (x*2);
} else {
x = x * (-2) / 2;
}
HorizontalMove = x * Time.deltaTime * 50;
transform.Rotate(0, HorizontalMove, 0);
}
}
}
and the car is downloaded form asset store named "ARCADE Free Racing Car"

How to limit player's velocity only when it is accelerating?

I have a 2.5D space shooter game in progress that uses Unity's built-in physics. Everything happens in 2D space but all the models are 3D.
The player (a space ship) can rotate using a controller axis and can accelerate when a button is held down (e.g. xbox controller's A button).
There is a limit on how fast the player can move (maxEngineSpeed) and I clamp the magnitude of the RigidBody's velocity in FixedUpdate as follows:
if (rb.velocity.magnitude > maxEngineSpeed)
{
rb.velocity = Vector2.ClampMagnitude(rb.velocity, maxEngineSpeed);
}
Now the problem is that this prevents the veclocity from ever reaching a value higher than maxEngineSpeed .
I want a behaviour that only limits the velocity when the player is accelerating. If the player somehow gains more speed from a coillision or from a bullet hit, then the velocity should not be limited. We can think it like the space ship not having enough power in its engines to go any faster. It's like linear drag but only when accelerating (when not accelerating, the ship doesn't decelerate at all). I have power-ups that grant the player more maximum speed, so it's important.
How would this be implemented? I've tried to only limit the velocity when the player is accelerating, but then it clamps it immediately to specified value and it looks unnatural. Would a couroutine work that would slowly reduce the magnitude when accelerating? But then it would have to take account the direction of the player and current velocity?
EDIT: Clarification: in practise what I would like to have is to ask a RigidBody "if I apply this force to you while you're moving faster than maxEngineSpeed, would it increase your speed? If it would, don't apply the force, if it would decrease your speed, then apply it".
EDIT: changed the maxSpeed variable name to maxEngineSpeed for more clarity.
Remove the clamping in FixedUpdate. Instead, add a check where you add Velocity (where you detect Xbox Controllers 'A' is pressed).
Something like:
if(Input.GetButton("Xbox-A"))
{
if(rb.velocity.magnitude < scaledMaxSpeed)
{
rb.addForce(...);
}
}
So if you are faster than your max-speed, the ship cannot accelerate more (by own power).
Pull down & Drag
There are so many ways to achieve what you want. Below I show two possible methods with a working demo to allow you to get a bit of a feel for how the perform and differ. Also link at bottom to another demo.
Pull down
You can pull down the velocity by defining a max over speed and a over speed drag coefficient
The pull down method
Define settings
float pullDown = 0.1f; // dimensionless > 0, < 1
float maxOverSpeed = 5.0f;
float maxSpeed = 4.0f
float acceleration = 0.1f;
Per frame
if (accelerate && speed < maxSpeed) { speed += acceleration }
// clamp max over speed
speed = speed > maxOverSpeed ? maxOverSpeed : speed;
float speedAdjust = speed - maxSpeed;
// pull speed down if needed
speed -= speedAdjust > 0.0f ? speedAdjust * pullDown : 0.0f;
// set the velocity magnitude to the new speed
Personally I don't like this method as it is a coasting model, ship gets to speed an holds it, there is no deceleration, but it does give finer control over velocity.
Drag
My preferred method is to use a simple drag coefficient. Slight modification to add extra draw when over speed
However this makes is difficult to know what the max speed will be given some acceleration. There is a formula that will give you a drag coefficient to match a max speed for acceleration, or acceleration to match a max speed for a drag coefficient, but off the top of my head I can not remember it as its been years since I found I needed to use it.
I wing it and define an approximation, test it, and refine till I get what feels right. In reality if ask what is the max speed of the player? All i know is not too fast and not too slow. :P
The drag method
Define
float acceleration = 0.1f;
float drag = 1.0f - 0.021f;
float overSpeedDrag = 1.0f - 0.026f;
float maxSpeed = 4;
Per frame
// apply drag depending on speed
speed *= speed > maxSpeed ? overSpeedDrag : drag;
if (accelerate) { speed += acceleration }
// set the velocity magnitude to the new current speed
Example
These methods as code do not give much of a feel for the actual results so the following snippet implements both methods so you can see and feel how they work.
The code is at the top (in JavaScript) the two different methods are flagged PULL_DOWN, DRAG in the function update() {
Ship speeds are in pixels per second (Pps)
Both ships have same acceleration constant, however ship B (drag method) does not accelerate at a constant rate.
Ship A will coast, ship B will always come to a stop.
Click bump to kick the ship's velocity.
const accelFunction = {
get vel() { return new Vec2(0, 0) },
speed: 0,
acceleration: 0.1,
maxSpeed: 4,
// drag constants
drag: 1 - 0.0241,
overSpeedDrag: 1 - 0.0291,
// pulldown constants;
overSpeed: 5,
pullDown: 0.1,
update() {
if (this.method === DRAG) { // Drag method
this.speed *= this.speed > this.maxSpeed ? this.overSpeedDrag: this.drag;
if (this.accelerate) { this.speed += this.acceleration }
} else { // Pull down method
if (this.accelerate && this.speed < this.maxSpeed) { this.speed += this.acceleration }
this.speed = this.speed > this.maxOverSpeed ? this.maxOverSpeed : this.speed;
var speedAdjust = this.speed - this.maxSpeed;
this.speed -= speedAdjust > 0 ? speedAdjust * this.pullDown : 0;
}
// move ship
this.vel.length = this.speed;
this.pos.add(this.vel);
},
}
/* rest of code unrelated to anwser */
requestAnimationFrame(start);
const ctx = canvas.getContext("2d");
const PULL_DOWN = 0;
const DRAG = 1;
var shipA, shipB;
var bgPos;
function Ship(method, control, controlBump) { // creates a Player ship
control.addEventListener("mousedown",() => API.go());
control.addEventListener("mouseup",() => API.coast());
control.addEventListener("mouseout",() => API.coast());
controlBump.addEventListener("click",() => API.bump());
const API = {
...accelFunction,
pos: new Vec2(100, 50 + method * 50),
method, // 0 drag method, 1 pulldown
draw() {
ctx.setTransform(1,0,0,1,this.pos.x - bgPos.x, this.pos.y)
ctx.strokeStyle = "#FFF";
ctx.lineWidth = 2;
ctx.beginPath();
ctx.lineTo(20, 0);
ctx.lineTo(-20, -20);
ctx.lineTo(-20, 20);
ctx.closePath();
ctx.stroke();
ctx.fillText(this.method ? "B" : "A", -11, 3);
ctx.fillText((this.speed * 60 | 0) + "Pps", 80, 3);
if (this.accelerate) {
ctx.strokeStyle = "#FF0";
ctx.beginPath();
ctx.lineTo(-20, -10);
ctx.lineTo(-30 - Math.rand(0,10), 0);
ctx.lineTo(-20, 10);
ctx.stroke();
}
},
focus: false,
reset() {
this.focus = false;
this.vel.zero();
this.pos.init(100, 50 + this.method * 50);
this.speed = 0;
this.accelerate = false;
},
go() {
this.accelerate = true;
this.focus = true;
if (this.method === 1) { shipA.reset() }
else { shipB.reset() }
},
coast() {
this.accelerate = false;
},
bump() {
this.speed += 1;
},
};
return API;
}
function start() {
init();
requestAnimationFrame(mainLoop);
}
function mainLoop() {
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0,0,500,170);
shipA.update();
shipB.update();
bgPos.x = shipA.focus ? shipA.pos.x - 50 : shipB.pos.x - 50 ;
drawBG(bgPos);
shipA.draw();
shipB.draw();
requestAnimationFrame(mainLoop);
}
function drawBG(bgPos) {
ctx.fillStyle = "#FFF";
ctx.beginPath();
const bgX = -bgPos.x + 100000;
for (const p of background) {
x = (p.x + bgX) % 504 - 2;
ctx.rect(x, p.y, 2, 2);
}
ctx.fill();
}
const BG_COUNT = 200;
const background = [];
function init() {
ctx.font = "16px arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
bgPos = new Vec2();
shipA = Ship(PULL_DOWN, goA, bumpA);
shipB = Ship(DRAG, goB, bumpB);
var i = BG_COUNT;
while (i--) {
background.push(new Vec2(Math.rand(0, 10000), Math.rand(-1, 170)));
}
}
/* Math LIB Vec2 and math extensions */
Math.rand = (m, M) => Math.random() * (M - m) + m;
function Vec2(x = 0, y = (temp = x, x === 0 ? (x = 0 , 0) : (x = x.x, temp.y))) { this.x = x; this.y = y }
Vec2.prototype = {
init(x, y = (temp = x, x = x.x, temp.y)) { this.x = x; this.y = y; return this },
zero() { this.x = this.y = 0; return this },
add(v, res = this) { res.x = this.x + v.x; res.y = this.y + v.y; return res },
scale(val, res = this) { res.x = this.x * val; res.y = this.y * val; return res },
get length() { return this.lengthSqr ** 0.5 },
set length(l) {
const len = this.lengthSqr;
len > 0 ? this.scale(l / len ** 0.5) : (this.x = l);
},
get lengthSqr() { return this.x * this.x + this.y * this.y },
};
canvas {background: #347;}
div {
position: absolute;
top: 150px;
left: 20px;
}
span { color: white; font-family: arial }
<canvas id="canvas" width="500" height="170"></canvas>
<div>
<button id="goA">Go A</button>
<button id="bumpA">Bump A</button>
<button id="goB">Go B</button>
<button id="bumpB">Bump B</button>
<span> Methods: A = Pull down B = Drag </span>
</div>
No limit
There are many variations on these methods, and the are many example on SO (I have written many answers in the subject. eg See demo snippet (bottom of answer) for example of drag method modification) .
Which method you use is very dependent on how you want the interaction to feel, there is no right or wrong method as game physics will is very different than real physics.
Knowing that acceleration (a) is the change in velocity (Δv) over the change in time (Δt), I'll check that.
Maybe with something like (pseudo):
float lastVelocity = 0;
bool isAccelerating = false;
Update()
{
float currentVelocity = rb.velocity;
if(currentVelocity > lastVelocity)
{
isAccelerating = true;
lastVelocity = currentVelocity;
}
else
{
isAccelerating = false;
}
}
Now you know when your "ship" is speedingUp, the only way to decrease the speed is caused by external forces (like gravity, or friction), depending of your setup, I'll deactivate those forces, or change the physicalMaterial that is causing the friction.

Is it possible to turn gps ground speed and vehical heading to acceleration and yaw angle in NED [duplicate]

I am developing an android application to calculate position based on Sensor's Data
Accelerometer --> Calculate Linear Acceleration
Magnetometer + Accelerometer --> Direction of movement
The initial position will be taken from GPS (Latitude + Longitude).
Now based on Sensor's Readings i need to calculate the new position of the Smartphone:
My Algorithm is following - (But is not calculating Accurate Position): Please help me improve it.
Note: My algorithm Code is in C# (I am sending Sensor Data to Server - Where Data is stored in the Database. I am calculating the position on Server)
All DateTime Objects have been calculated using TimeStamps - From 01-01-1970
var prevLocation = ServerHandler.getLatestPosition(IMEI);
var newLocation = new ReceivedDataDTO()
{
LocationDataDto = new LocationDataDTO(),
UsersDto = new UsersDTO(),
DeviceDto = new DeviceDTO(),
SensorDataDto = new SensorDataDTO()
};
//First Reading
if (prevLocation.Latitude == null)
{
//Save GPS Readings
newLocation.LocationDataDto.DeviceId = ServerHandler.GetDeviceIdByIMEI(IMEI);
newLocation.LocationDataDto.Latitude = Latitude;
newLocation.LocationDataDto.Longitude = Longitude;
newLocation.LocationDataDto.Acceleration = float.Parse(currentAcceleration);
newLocation.LocationDataDto.Direction = float.Parse(currentDirection);
newLocation.LocationDataDto.Speed = (float) 0.0;
newLocation.LocationDataDto.ReadingDateTime = date;
newLocation.DeviceDto.IMEI = IMEI;
// saving to database
ServerHandler.SaveReceivedData(newLocation);
return;
}
//If Previous Position not NULL --> Calculate New Position
**//Algorithm Starts HERE**
var oldLatitude = Double.Parse(prevLocation.Latitude);
var oldLongitude = Double.Parse(prevLocation.Longitude);
var direction = Double.Parse(currentDirection);
Double initialVelocity = prevLocation.Speed;
//Get Current Time to calculate time Travelling - In seconds
var secondsTravelling = date - tripStartTime;
var t = secondsTravelling.TotalSeconds;
//Calculate Distance using physice formula, s= Vi * t + 0.5 * a * t^2
// distanceTravelled = initialVelocity * timeTravelling + 0.5 * currentAcceleration * timeTravelling * timeTravelling;
var distanceTravelled = initialVelocity * t + 0.5 * Double.Parse(currentAcceleration) * t * t;
//Calculate the Final Velocity/ Speed of the device.
// this Final Velocity is the Initil Velocity of the next reading
//Physics Formula: Vf = Vi + a * t
var finalvelocity = initialVelocity + Double.Parse(currentAcceleration) * t;
//Convert from Degree to Radians (For Formula)
oldLatitude = Math.PI * oldLatitude / 180;
oldLongitude = Math.PI * oldLongitude / 180;
direction = Math.PI * direction / 180.0;
//Calculate the New Longitude and Latitude
var newLatitude = Math.Asin(Math.Sin(oldLatitude) * Math.Cos(distanceTravelled / earthRadius) + Math.Cos(oldLatitude) * Math.Sin(distanceTravelled / earthRadius) * Math.Cos(direction));
var newLongitude = oldLongitude + Math.Atan2(Math.Sin(direction) * Math.Sin(distanceTravelled / earthRadius) * Math.Cos(oldLatitude), Math.Cos(distanceTravelled / earthRadius) - Math.Sin(oldLatitude) * Math.Sin(newLatitude));
//Convert From Radian to degree/Decimal
newLatitude = 180 * newLatitude / Math.PI;
newLongitude = 180 * newLongitude / Math.PI;
This is the Result I get --> Phone was not moving. As you can see speed is 27.3263111114502 So there is something wrong in calculating Speed but I don't know what
ANSWER:
I found a solution to calculate position based on Sensor: I have posted an Answer below.
If you need any help, please leave a comment
this is The results compared to GPS (Note: GPS is in Red)
As some of you mentioned you got the equations wrong but that is just a part of the error.
Newton - D'Alembert physics for non relativistic speeds dictates this:
// init values
double ax=0.0,ay=0.0,az=0.0; // acceleration [m/s^2]
double vx=0.0,vy=0.0,vz=0.0; // velocity [m/s]
double x=0.0, y=0.0, z=0.0; // position [m]
// iteration inside some timer (dt [seconds] period) ...
ax,ay,az = accelerometer values
vx+=ax*dt; // update speed via integration of acceleration
vy+=ay*dt;
vz+=az*dt;
x+=vx*dt; // update position via integration of velocity
y+=vy*dt;
z+=vz*dt;
the sensor can rotate so the direction must be applied:
// init values
double gx=0.0,gy=-9.81,gz=0.0; // [edit1] background gravity in map coordinate system [m/s^2]
double ax=0.0,ay=0.0,az=0.0; // acceleration [m/s^2]
double vx=0.0,vy=0.0,vz=0.0; // velocity [m/s]
double x=0.0, y=0.0, z=0.0; // position [m]
double dev[9]; // actual device transform matrix ... local coordinate system
(x,y,z) <- GPS position;
// iteration inside some timer (dt [seconds] period) ...
dev <- compass direction
ax,ay,az = accelerometer values (measured in device space)
(ax,ay,az) = dev*(ax,ay,az); // transform acceleration from device space to global map space without any translation to preserve vector magnitude
ax-=gx; // [edit1] remove background gravity (in map coordinate system)
ay-=gy;
az-=gz;
vx+=ax*dt; // update speed (in map coordinate system)
vy+=ay*dt;
vz+=az*dt;
x+=vx*dt; // update position (in map coordinate system)
y+=vy*dt;
z+=vz*dt;
gx,gy,gz is the global gravity vector (~9.81 m/s^2 on Earth)
in code my global Y axis points up so the gy=-9.81 and the rest are 0.0
measure timings are critical
Accelerometer must be checked as often as possible (second is a very long time). I recommend not to use timer period bigger than 10 ms to preserve accuracy also time to time you should override calculated position with GPS value. Compass direction can be checked less often but with proper filtration
compass is not correct all the time
Compass values should be filtered for some peak values. Sometimes it read bad values and also can be off by electro-magnetic polution or metal enviroment. In that case the direction can be checked by GPS during movement and some corrections can be made. For example chech GPS every minute and compare GPS direction with compass and if it is constantly of by some angle then add it or substract it.
why do simple computations on server ???
Hate on-line waste of traffic. Yes you can log data on server (but still i think file on device will be better) but why to heck limit position functionality by internet connection ??? not to mention the delays ...
[Edit 1] additional notes
Edited the code above a little. The orientation must be as precise as it can be to minimize cumulative errors.
Gyros would be better than compass (or even better use them both). Acceleration should be filtered. Some low pass filtering should be OK. After gravity removal I would limit ax,ay,az to usable values and throw away too small values. If near low speed also do full stop (if it is not a train or motion in vacuum). That should lower the drift but increase other errors so an compromise has to be found between them.
Add calibration on the fly. When filtered acceleration = 9.81 or very close to it then the device is probably stand still (unless its a flying machine). Orientation/direction can be corrected by actual gravity direction.
Acceleration sensors and gyros are not suited for position calculation.
After some seconds the errors become incredible high. (I hardly remember that the double integration is the problem).
Look at this Google tech talk video about sensor fusioning,
he explains in very detail why this is not possible.
After solving the position I calculated using Sensors I would like to post my code here in case anyone needs in future:
Note: This was only checked on Samsung Galaxy S2 phone and only when person was walking with the phone, it has not been tested when moving in car or on bike
This is the result I got when compared when compared with GPS, (Red Line GPS, Blue is Position calculated with Sensor)
The code is not very efficient, but I hope my sharing this code will help someone and point them in the right direction.
I had two seperate classes:
CalculatePosition
CustomSensorService
public class CalculatePosition {
static Double earthRadius = 6378D;
static Double oldLatitude,oldLongitude;
static Boolean IsFirst = true;
static Double sensorLatitude, sensorLongitude;
static Date CollaborationWithGPSTime;
public static float[] results;
public static void calculateNewPosition(Context applicationContext,
Float currentAcceleration, Float currentSpeed,
Float currentDistanceTravelled, Float currentDirection, Float TotalDistance) {
results = new float[3];
if(IsFirst){
CollaborationWithGPSTime = new Date();
Toast.makeText(applicationContext, "First", Toast.LENGTH_LONG).show();
oldLatitude = CustomLocationListener.mLatitude;
oldLongitude = CustomLocationListener.mLongitude;
sensorLatitude = oldLatitude;
sensorLongitude = oldLongitude;
LivePositionActivity.PlotNewPosition(oldLongitude,oldLatitude,currentDistanceTravelled * 1000, currentAcceleration, currentSpeed, currentDirection, "GPSSensor",0.0F,TotalDistance);
IsFirst = false;
return;
}
Date CurrentDateTime = new Date();
if(CurrentDateTime.getTime() - CollaborationWithGPSTime.getTime() > 900000){
//This IF Statement is to Collaborate with GPS position --> For accuracy --> 900,000 == 15 minutes
oldLatitude = CustomLocationListener.mLatitude;
oldLongitude = CustomLocationListener.mLongitude;
LivePositionActivity.PlotNewPosition(oldLongitude,oldLatitude,currentDistanceTravelled * 1000, currentAcceleration, currentSpeed, currentDirection, "GPSSensor", 0.0F, 0.0F);
return;
}
//Convert Variables to Radian for the Formula
oldLatitude = Math.PI * oldLatitude / 180;
oldLongitude = Math.PI * oldLongitude / 180;
currentDirection = (float) (Math.PI * currentDirection / 180.0);
//Formulae to Calculate the NewLAtitude and NewLongtiude
Double newLatitude = Math.asin(Math.sin(oldLatitude) * Math.cos(currentDistanceTravelled / earthRadius) +
Math.cos(oldLatitude) * Math.sin(currentDistanceTravelled / earthRadius) * Math.cos(currentDirection));
Double newLongitude = oldLongitude + Math.atan2(Math.sin(currentDirection) * Math.sin(currentDistanceTravelled / earthRadius)
* Math.cos(oldLatitude), Math.cos(currentDistanceTravelled / earthRadius)
- Math.sin(oldLatitude) * Math.sin(newLatitude));
//Convert Back from radians
newLatitude = 180 * newLatitude / Math.PI;
newLongitude = 180 * newLongitude / Math.PI;
currentDirection = (float) (180 * currentDirection / Math.PI);
//Update old Latitude and Longitude
oldLatitude = newLatitude;
oldLongitude = newLongitude;
sensorLatitude = oldLatitude;
sensorLongitude = oldLongitude;
IsFirst = false;
//Plot Position on Map
LivePositionActivity.PlotNewPosition(newLongitude,newLatitude,currentDistanceTravelled * 1000, currentAcceleration, currentSpeed, currentDirection, "Sensor", results[0],TotalDistance);
}
}
public class CustomSensorService extends Service implements SensorEventListener{
static SensorManager sensorManager;
static Sensor mAccelerometer;
private Sensor mMagnetometer;
private Sensor mLinearAccelertion;
static Context mContext;
private static float[] AccelerometerValue;
private static float[] MagnetometerValue;
public static Float currentAcceleration = 0.0F;
public static Float currentDirection = 0.0F;
public static Float CurrentSpeed = 0.0F;
public static Float CurrentDistanceTravelled = 0.0F;
/*---------------------------------------------*/
float[] prevValues,speed;
float[] currentValues;
float prevTime, currentTime, changeTime,distanceY,distanceX,distanceZ;
float[] currentVelocity;
public static CalculatePosition CalcPosition;
/*-----FILTER VARIABLES-------------------------*-/
*
*
*/
public static Float prevAcceleration = 0.0F;
public static Float prevSpeed = 0.0F;
public static Float prevDistance = 0.0F;
public static Float totalDistance;
TextView tv;
Boolean First,FirstSensor = true;
#Override
public void onCreate(){
super.onCreate();
mContext = getApplicationContext();
CalcPosition = new CalculatePosition();
First = FirstSensor = true;
currentValues = new float[3];
prevValues = new float[3];
currentVelocity = new float[3];
speed = new float[3];
totalDistance = 0.0F;
Toast.makeText(getApplicationContext(),"Service Created",Toast.LENGTH_SHORT).show();
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mAccelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mMagnetometer = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
//mGyro = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
mLinearAccelertion = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
sensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
sensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_NORMAL);
//sensorManager.registerListener(this, mGyro, SensorManager.SENSOR_DELAY_NORMAL);
sensorManager.registerListener(this, mLinearAccelertion, SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
public void onDestroy(){
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_SHORT).show();
sensorManager.unregisterListener(this);
//sensorManager = null;
super.onDestroy();
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
#Override
public void onSensorChanged(SensorEvent event) {
float[] values = event.values;
Sensor mSensor = event.sensor;
if(mSensor.getType() == Sensor.TYPE_ACCELEROMETER){
AccelerometerValue = values;
}
if(mSensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION){
if(First){
prevValues = values;
prevTime = event.timestamp / 1000000000;
First = false;
currentVelocity[0] = currentVelocity[1] = currentVelocity[2] = 0;
distanceX = distanceY= distanceZ = 0;
}
else{
currentTime = event.timestamp / 1000000000.0f;
changeTime = currentTime - prevTime;
prevTime = currentTime;
calculateDistance(event.values, changeTime);
currentAcceleration = (float) Math.sqrt(event.values[0] * event.values[0] + event.values[1] * event.values[1] + event.values[2] * event.values[2]);
CurrentSpeed = (float) Math.sqrt(speed[0] * speed[0] + speed[1] * speed[1] + speed[2] * speed[2]);
CurrentDistanceTravelled = (float) Math.sqrt(distanceX * distanceX + distanceY * distanceY + distanceZ * distanceZ);
CurrentDistanceTravelled = CurrentDistanceTravelled / 1000;
if(FirstSensor){
prevAcceleration = currentAcceleration;
prevDistance = CurrentDistanceTravelled;
prevSpeed = CurrentSpeed;
FirstSensor = false;
}
prevValues = values;
}
}
if(mSensor.getType() == Sensor.TYPE_MAGNETIC_FIELD){
MagnetometerValue = values;
}
if(currentAcceleration != prevAcceleration || CurrentSpeed != prevSpeed || prevDistance != CurrentDistanceTravelled){
if(!FirstSensor)
totalDistance = totalDistance + CurrentDistanceTravelled * 1000;
if (AccelerometerValue != null && MagnetometerValue != null && currentAcceleration != null) {
//Direction
float RT[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(RT, I, AccelerometerValue,
MagnetometerValue);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(RT, orientation);
float azimut = (float) Math.round(Math.toDegrees(orientation[0]));
currentDirection =(azimut+ 360) % 360;
if( CurrentSpeed > 0.2){
CalculatePosition.calculateNewPosition(getApplicationContext(),currentAcceleration,CurrentSpeed,CurrentDistanceTravelled,currentDirection,totalDistance);
}
}
prevAcceleration = currentAcceleration;
prevSpeed = CurrentSpeed;
prevDistance = CurrentDistanceTravelled;
}
}
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
public void calculateDistance (float[] acceleration, float deltaTime) {
float[] distance = new float[acceleration.length];
for (int i = 0; i < acceleration.length; i++) {
speed[i] = acceleration[i] * deltaTime;
distance[i] = speed[i] * deltaTime + acceleration[i] * deltaTime * deltaTime / 2;
}
distanceX = distance[0];
distanceY = distance[1];
distanceZ = distance[2];
}
}
EDIT:
public static void PlotNewPosition(Double newLatitude, Double newLongitude, Float currentDistance,
Float currentAcceleration, Float currentSpeed, Float currentDirection, String dataType) {
LatLng newPosition = new LatLng(newLongitude,newLatitude);
if(dataType == "Sensor"){
tvAcceleration.setText("Speed: " + currentSpeed + " Acceleration: " + currentAcceleration + " Distance: " + currentDistance +" Direction: " + currentDirection + " \n");
map.addMarker(new MarkerOptions()
.position(newPosition)
.title("Position")
.snippet("Sensor Position")
.icon(BitmapDescriptorFactory
.fromResource(R.drawable.line)));
}else if(dataType == "GPSSensor"){
map.addMarker(new MarkerOptions()
.position(newPosition)
.title("PositionCollaborated")
.snippet("GPS Position"));
}
else{
map.addMarker(new MarkerOptions()
.position(newPosition)
.title("Position")
.snippet("New Position")
.icon(BitmapDescriptorFactory
.fromResource(R.drawable.linered)));
}
map.moveCamera(CameraUpdateFactory.newLatLngZoom(newPosition, 18));
}
As per our discussion, since your acceleration is continuously changing, the equations of motion that you have applied shall not give you an accurate answer.
You may have to keep updating your position and velocities as and when you get a new reading for acceleration.
Since this would be highly inefficient, my suggestion would be to call the update function every few seconds and use the average value of acceleration during that period to get the new velocity and position.
I am not quite sure, but my best guess would be around this part:
Double initialVelocity = prevLocation.Speed;
var t = secondsTravelling.TotalSeconds;
var finalvelocity = initialVelocity + Double.Parse(currentAcceleration) * t;
if lets say at the prevLocation the speed was: 27.326... and t==0 and currentAcceleration ==0 (as you said you were idle) the finalvelocity would come down to
var finalvelocity = 27.326 + 0*0;
var finalvelocity == 27.326
If the finalvelocity becomes the speed of the currentlocation, so that previouslocation = currentlocation. This would mean that your finalvelocity might not go down. But then again, there's quite a bit of assumptions here.
Seems like you are making it hard on yourself. You should be able to simply use the Google Play Service Location API and easily access location, direction, speed, etc. accurately.
I would look into using that instead of doing work server side for it.

unity moving an object to right/left side

I am new to unity and I am trying to make a simple task: touch an object and then release your touch. when you release, I want to check in which side of the screen you released your touch and then move the object to that side of the screen.
So if I am pressing on my object, then swiping my finger to thr giht side, the object will move left and same for the right side...
This is my code, attached to the game object, and for some reason the object is just going to the right side of the screen. and it do it immidietly even though I used Lerp.
void OnMouseUp()
{
Vector3 pos = Input.mousePosition;
Debug.Log("press off");
if (pos.x < Screen.width / 2)
{
transform.position = Vector3.Lerp(transform.position, new Vector3(0,0,0), 2f * Time.deltaTime);
}
else
{
transform.position = Vector3.Lerp(transform.position, new Vector3(Screen.width, 0, 0), 2f * Time.deltaTime);
}
}
thank you!
So After a lot of trying this worked out for me:
public float smoothing = 7f;
IEnumerator MoveCoroutine(Vector3 target)
{
while (Vector3.Distance(transform.position, target) > 0.05f)
{
transform.position = Vector3.Lerp(transform.position, target, smoothing * Time.deltaTime);
yield return null;
}
}
void OnMouseUp()
{
Plane p = new Plane(Camera.main.transform.forward, transform.position);
Ray r = Camera.main.ScreenPointToRay(Input.mousePosition);
float d;
if (p.Raycast(r, out d))
{
Vector3 target = r.GetPoint(d);
if (target.x > 0)
{
Debug.Log("right:" + target.x + " total: " + Screen.width);
target.x = 5;
target.y = 0;
}
else
{
Debug.Log("left:" + target.x + " total: " + Screen.width);
target.x = -5;
target.y = 0;
}
StartCoroutine(MoveCoroutine(target));
}
}
not sure what the Ray casting does, I would be glad if someone can explain.
You code is almost right. You just need to define target positions and have Lerp called each time in update function.
A simple solution is to define two empty objects as position targets and pass them as parameters to the function.
using UnityEngine;
using System.Collections;
public class ClickTest : MonoBehaviour {
public Transform posLeft;
public Transform posRight;
private Vector3 destPos;
void Setup()
{
// default target is init position
destPos = transform.position;
}
// Update is called once per frame
void Update () {
// Define target position
if (Input.GetMouseButtonUp (0)) {
Vector3 pos = Input.mousePosition;
Debug.Log("press off : "+pos+ " scren : "+Screen.width);
if (pos.x < Screen.width / 2)
{
Debug.Log("left");
destPos = posLeft.position;
}
else
{
Debug.Log("right");
destPos = posRight.position;
}
}
// update position to target
transform.position = Vector3.Lerp(transform.position, destPos, 2f * Time.deltaTime);
}
}
Screenshot with empty objects as parameters

How to make script only translate on one axis?

I would like my sprite to move only on axis, so I took out the x-axis from the code. However, when I try to compile it in Unity, it returns with this error:
Assets/Scripts/TongueMove.js(19,83): BCE0024: The type 'UnityEngine.Vector2' does not have a visible constructor that matches the argument list '(float)'.
Furthermore, what would I add so that it only lasts a certain time, before returning to its original position?
#pragma strict
function Start() {
transform.position.z = -0.5;
}
function Update () {
if (Input.GetKeyDown ("space"))
{
moveTo(transform.position.y + 11.8, 20); //transform.position.y + how much I want to move, speed
}
transform.position.z = -0.5;
}
function moveTo (posY : float, speed : float)
{
while (transform.position.y != posY)
{
transform.position = Vector2.MoveTowards (transform.position, new Vector2(posY), speed * Time.deltaTime);
yield;
}
}
Your problem is when you create the new Vector2() into the while loop. Vector2 needs 2 parameters.
If you don't like to modify X axis try this:
while (transform.position.y != posY)
{
transform.position = Vector2.MoveTowards (transform.position, new Vector2(transform.position.X, posY), speed * Time.deltaTime);
yield;
http://docs.unity3d.com/ScriptReference/Vector2.html