I have 2 OpenLayers.LonLat objects, and I want to determine the distance in pixels for the current zoom between the 2. I'm using OpenLayers.Layer.getViewPortPxFromLonLat() to determine the x and y of the points and then subtract to see the difference between the 2, but the values that I get are very small for points that are 2000km apart.
Here is my code:
var center_lonlat = new OpenLayers.LonLat(geometry.lon, geometry.lat);
var center_px = layer.getViewPortPxFromLonLat(center_lonlat);
var radius_m = parseFloat(feature.attributes["radius"]);
var radius_lonlat = OpenLayers.Util.destinationVincenty(center_lonlat, 0, radius_m);
var radius_px = layer.getViewPortPxFromLonLat(radius_lonlat);
var radius = radius_px.y - center_px.y;
I'm trying here to draw a circle, giving that I receive a center point and a radius in meters. The LonLat object seems to be ok.
Am I doing something wrong ?
I found the issue: destinationVincenty() need and returns coordinates in wgs84 where my map was using spherical mercator projection.
I hope I got correctly the answer, because projections make me dizzy and never really understood them :(. I was looking in the console to the numbers for my coordinates and the coordinates from the map.getExtent() that is used to calculate the getViewPortPxFromLonLat() and I realised they are not in the right order of magnitude, and then it hit me.
So, the code is now:
var spherical_mercator = new OpenLayers.Projection("EPSG:900913");
var wgs84 = new OpenLayers.Projection("EPSG:4326");
var map = feature.layer.map;
var geometry = feature.geometry;
var center_lonlat = new OpenLayers.LonLat(geometry.y, geometry.x);
var center_px = map.getViewPortPxFromLonLat(center_lonlat);
var radius_m = parseFloat(feature.attributes["radius"]);
var radius_lonlat = OpenLayers.Util.destinationVincenty(center_lonlat.clone().transform(spherical_mercator, wgs84), 0, radius_m).transform(wgs84, spherical_mercator);
var radius_px = map.getViewPortPxFromLonLat(radius_lonlat);
var radius = Math.abs(radius_px.y - center_px.y);
Measured the circles with the OpenLayers.Control.ScaleLine, and the size is dead on :D
You seem to be doing right. If the distance you get is too small, maybe there is a problem with OpenLayers.Util.destinationVincenty function? Have you tried to replace the bearing (0) with anything else - its value seem to be not important in your case. But frankly speaking, I wasn't able to understand how it works while browsing the source
Related
I have an image 8640x11520 pixels from a part of the map in real scale. I need convert my x, y point to coordinate, anyone has an idea to find out it??
var mapWidth = 8640;
var mapHeight = 11520;
var mapLatitudeStart = 28.349768989955244;
var mapLongitudeStart = -81.55803680419922;
var maxLatitude = 28.349806758250104;
var maxLongitude = -81.541128;
var pointNeedConversion = {'x': 4813.10 'y': 2674.84};
var pointLatitude = ??
As you are mapping to lat/long, beware, you can't do that with a linear proportion, instead you have to check what kind of projection is applied to the map, then convert coordinates accordingly.
Usually maps are WGS84 Projections so you have to apply the inverse formulas for the Mercator projection.
The task is not trivial so my advice is to rely on libraries like Proj4js
The usage of the library is simple, you provide a reference system to work on, then you can trasform coordinates on another projection.
// include the library
<script src="lib/proj4js-combined.js"></script> //adjust the path for your server
//or else use the compressed version
// creating source and destination Proj4js objects
// once initialized, these may be re-used as often as needed
var source = new Proj4js.Proj('EPSG:4326'); //source coordinates will be in Longitude/Latitude, WGS84
var dest = new Proj4js.Proj('EPSG:3785'); //destination coordinates in meters, global spherical mercators projection, see http://spatialreference.org/ref/epsg/3785/
// transforming point coordinates
var p = new Proj4js.Point(-76.0,45.0); //any object will do as long as it has 'x' and 'y' properties
Proj4js.transform(source, dest, p); //do the transformation. x and y are modified in place
//p.x and p.y are now EPSG:3785 in meters
Credit for the snippet: Convert long/lat to pixel x/y on a given picture
Working example:
var dest = new proj4.Proj('EPSG:4326'); //destination coordinates coordinates will be in Longitude/Latitude, WGS84 , global spherical mercators projection, see http://spatialreference.org/ref/epsg/3785/
var source = new proj4.Proj('EPSG:3785'); //source coordinates in meters
$("#convert").on("click", function(){
var p = new proj4.Point($("#x").val(), $("#y").val() );
proj4.transform(source, dest, p);
alert("lng : " +p.x + " \nlat : " + p.y);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.3.3/proj4.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
x : <input type="number" id="x" />
y : <input type="number" id="y" />
<button id="convert">Convert</button>
Note: it is essential to know what is the lat/lon of the corner of your map if you intend to use it to map a GPS signal.
Here a graph example that visually explains why a linear proportion is not suitable:
Take a close look to (Eg) the size of the Greenland, on mercator projection space coordinates it looks bigger than north America. Of course it is not!
There are plenty of examples on how to draw lines on canvas, in js.
But for only educational purposes i want to draw line using algorithm. basically method gets two Vector2 points, from them it finds middle point, then it continues like that recursively until minimum distance of 2 pixels is reached.
I have DrawPoint method to basically draw 1 point on canvas, and DrawLine method that does all the job.
For now I have 2 problems:
1: points are not colored red, as they should be.
2:
It doesnt look like a line.
For Vector2 i used "Victor.js" plugin, and it seems to be working well.
this is code i have:
JS:
var point2 = new Victor(100, 100);
var point3 = new Victor(150, 150);
DrawLine(point2, point3);
function DrawLine(vec0, vec1)
{
var point0 = new Victor(vec0.x, vec0.y);
var point1 = new Victor(vec1.x, vec1.y);
var dist = point1.distance(point0);
if (dist < 2)
return;
//this is how it should look like in c# var middlePoint = point0 + (point1 - point0)/2; But looks like i cant just divide by 2 using victor js because i can only divide vector by vector.
var middlePoint = point0.add(point1.subtract(point0).divide(new Victor(2,2)));
DrawPoint(middlePoint);
DrawLine(point0, middlePoint);
DrawLine(middlePoint, point1);
}
function DrawPoint(point){
var c = document.getElementById("screen");
var ctx = c.getContext("2d");
ctx.fillStyle = "FF0000";
ctx.fillRect(point.x, point.y, 3,1);
}
I really appreciate any help you can provide.
The victor.js documentation shows that most functions of Victors do not return new Victors, but operate on the current instance. In a way, v1.add(v2) is semantically more like v1 += v2 and not v1 + v2.
The problem is with calculating the midpoint. You could use the mix() method, which blends two vectors with a weight. You must clone() the Victor first, otherwise point0will be midofied:
var middlePoint = point0.clone().mix(point1, 0.5);
If you don't change the original Vectors, you don't need to create new instances of Victors from the arguments, you can use the arguments directly:
function DrawLine(point0, point1)
{
var dist = point1.distance(point0);
if (dist < 2) return;
var middlePoint = point0.clone().mix(point1, 0.5);
DrawPoint(middlePoint);
DrawLine(point0, middlePoint);
DrawLine(middlePoint, point1);
}
Finally, as Sven the Surfer has already said in a comment, "FF0000" isn't a valid colour. Use "#FF0000", note the hash mark, or one of the named web colours such as "crimson".
I am trying to rotate the camera smoothly and without altering the y-vector of the camera direction, i can use look at, and it changes the camera direction in a flash, but this is not working for me, I would like a smooth transition as the direction of the camera changes. I have been reading up, and not understanding everything, but it seems to me that quaternions are the solution to this problem.
I have this.object (my camera) moving along a set path (this.spline.points). The location of the camera at any one time is (thisx,thisy, thisz)
I have cc[i] the direction vector for the direction I would like the camera to face (formerly I was using lookat(cc[i]) which changes the direction correctly, but too quickly/instantaneously)
Using info I have read, I have tried this below, and it just resulted in the screen going black at the point when the camera is due to move.
Could anyone please explain if I am on the right track, how to correct my code.
Thanks
var thisx = this.object.matrixWorld.getPosition().x.toPrecision(3);
var thisy = this.object.matrixWorld.getPosition().y.toPrecision(3);
var thisz = this.object.matrixWorld.getPosition().z.toPrecision(3);
var i = 0;
do {
var pathx = this.spline.points[i].x.toPrecision(3);
var pathz = this.spline.points[i].z.toPrecision(3);
if (thisx == pathx && thisz == pathz){
this.object.useQuaternion = true;
this.object.quaternion = new THREE.Quaternion(thisx, thisy, thisz, 1);
var newvect;
newvect.useQuaternion = true;
newvect.quaternion = new THREE.Quaternion(thisx+cc[i].x, thisy+cc[i].y, thisz+cc[i].z, 1);
var newQuaternion = new THREE.Quaternion();
THREE.Quaternion.slerp(this.object.quaternion, newvect.quaternion, newQuaternion, 0.5);
this.object.quaternion = newQuaternion;
//this.object.lookAt( cc[i]);
i = cc.length;
} else i++;
} while(i < cc.length);
There is no need to call this.object.useQuaternion = true. That is default behavior.
Also, this.object.quaternion contains the current rotation, so no need to generate that either.
You might want to try a different approach - construct the rotation matrix from the spline position, lookAt and up vectors, creating a path of quaternions as a preprocessing step:
var eye = this.spline.points[i].clone().normalize();
var center = cc[i].normalize();
var up = this.object.up.normalize();
var rotMatrix = new THREE.Matrix4().lookAt(eye, center, up);
You could then create the quaternions from the rotation matrix:
var quaternionAtSplineCoordinates = [];
quaternionAtSplineCoordinates.push(new THREE.Quaternion().setFromRotationMatrix(rotMatrix));
Once you have that path, you could apply the quaternion to the camera in your animation loop - provided you have a large enough number of samples. Otherwise, you could consider using slerp to generate the intermediate points.
I have two squares in space which are something like front and back wall of cube one vith vertices
x=-2 y=-1138 z=-2;
x=-2 y=-1134 z=-2;
x=2 y=-1138 z=-2;
x=2 y=-1134 z=-2
second
x=-2 y=1134 z=2;
x=-2 y=1138 z=2;
x=2 y=1134 z=2;
x=2 y=1138 z=2
when I calculate distanceTo from camera like this
var point1 = this.camera.matrixWorld.getPosition().clone();
var point2 = this.mesh.cubePlane3.children[0].matrixWorld.getPosition().clone();
var distance = point1.distanceTo( point2 );
I have always the same distance for both 20,09. These squres are rotated in space, so only rotation is changed and I would need somehow find out which wall is closer to camera to be able to do something that in cube 3 walls closer to camera are not displayed and next 3 walls are displayed.
And obviously I do not understand math behind this, for example why walls which are next to each other one have positive coordinates for y and next negative + why distance is the same value, when one is closer on z axis than second. Can you pls someone help me how I can get closer walls? Thank you
Each geometry has a computeBoundingBox function. So you can do:
var bbox = geometry.computeBoundingBox();
for each geometry that you are interested in and then use the
bbox.center()
to get the center of your geometry. A much faster computation is to use the computeBoundingSphere on your geometry.
Then you just compare the relation of the centers to your camera position.
I used computeBoundingBox with this code
this.mesh[cubePlane[0]].children[0].geometry.computeBoundingBox();
var position = new THREE.Vector3();
position.sub( this.mesh[cubePlane[0]].children[0].geometry.boundingBox.max, this.mesh[cubePlane[0]].children[0].geometry.boundingBox.min );
position.multiplyScalar( 0.5 );
position.addSelf(this.mesh[cubePlane[0]].children[0].geometry.boundingBox.min );
this.mesh[cubePlane[0]].children[0].matrixWorld.multiplyVector3( position );
var point1 = this.camera.matrixWorld.getPosition().clone();
var point2 = position;
var distance = point1.distanceTo( point2 );
and it works so thank you for your advice :)
I've got a script that creates a gradient by shading cells based on their distance from a set of coordinates. What I want to do is make the gradient circular rather than the diamond shape that it currently is. You can see an en example here: http://jsbin.com/uwivev/9/edit
var row = 5, col = 5, total_rows = 20, total_cols = 20;
$('table td').each(function(index, item) {
// Current row and column
var current_row = $(item).parent().index(),
current_col = $(item).index();
// Percentage based on location, always using positive numbers
var percentage_row = Math.abs(current_row-row)/total_rows;
var percentage_col = Math.abs(current_col-col)/total_cols;
// I'm thinking this is what I need to change to achieve the curve I'm after
var percentage = (percentage_col+percentage_row)/2;
$(this).find('div').fadeTo(0,percentage*3);
});
If you can give me hand with the right maths function to get the curve I'm after that would be great! Thanks!
Darren
// Current row and column
var current_row = $(item).parent().index(),
current_col = $(item).index();
// distance away from the bright pixel
var dist = Math.sqrt(Math.pow(current_row - row, 2) + Math.pow(current_col - col, 2))
// do something with dist, you might change this
var percentage = dist / total_cols;
$(this).find('div').fadeTo(0,percentage*3);
You can use the square of the distance formula:
((current_row - row)*(current_row - row) + (current_col - col)*(current_col - col))
then multiply it by whatever scale factor you need.
Here is a circle drawing procudure I wrote many moons ago in Pascal which you can use as pseudo code to understand how to color pixels at the radius from an (X,Y) and work your way in. Multiple shrinking circles should cover the entire area you need. The code also gives you the formula for accessing the radius.
PROCEDURE DrawCircle(X,Y,Radius:Integer);
VAR A,B,Z:LongInt;
BEGIN
Z:=Round(Sqrt(Sqr(LongInt(Radius))/2));
FOR A:=Z TO Radius DO
FOR B:=0 TO Z DO
IF Radius=Round(Sqrt(A*A+B*B)) THEN
BEGIN
PutPixel(X+A,Y+B,8);
PutPixel(X+A,Y-B,9);
PutPixel(X-A,Y+B,10);
PutPixel(X-A,Y-B,11);
PutPixel(X+B,Y+A,12);
PutPixel(X+B,Y-A,13);
PutPixel(X-B,Y+A,14);
PutPixel(X-B,Y-A,15);
END;
END;
NB: "Longint()" is a compiler typecast for larger numeric computations so don't let that worry you.
NB: Inner-most brackets are executed first.