Find nearest point from a rectangle to array of points - math

I have a rectangle and array of points (pts). Points can be inside rectangle or not. I need to find some point P(x, y) inside the rectangle to the maximum distance between P and each point from pts will be minimum.
In other words for all space inside the rectangle i need to choose one point for which the value of the function Dist will be minimal.
float Dist(Vector2 p, Vector2[] pts)
{
float d = float.MinValue;
foreach (Vector2 point in pts)
{
float dx = point.x - p.x;
float dy = point.y - p.y;
d = Math.Max(d, Math.Sqrt(dx * dx + dy * dy));
}
return d;
}

Removing the constraint about point P lying inside a rectangle would turn this into the smallest circle problem, which has a liner worst-case solution, and a simple randomized expected linear time solution. Your problem can be reduced to the smallest circle problem and solved in linear time, too.
For each point A to the left of the left vertical side l of the rectangle, consider its mirror image A' with respect to l. If a circle with a center inside the rectangle contains point A, it must also contain A'. Let's construct the corresponding mirror images for each point to the left of the left side, to the right of the right side, above the upper side and below the lower side, and add them to the set. For "corner" points, like the point B in the picture, we also add the mirror image of their mirror image (point B''' must lie also in any circle containing B). Note how in the constructed set, each point either lies between the horizontal boundaries of the rectangle, or has a mirror image across one of the horizontal sides of the rectangle. The same is true for the vertical sides. Turns out that the smallest enclosing circle of the resulting set of points will always have its center inside the rectangle.
Indeed, consider the horizontal diameter of the smallest enclosing circle. There must be at least one point lying on the closed (i.e. including endpoints) upper half of the circle, or else the circle radius could be shrinked. But then the upper boundary of the rectangle is not allowed to lie strictly below the diameter, or else the mirror image of our point across the horizontal line would end up outside the circle. By analogous argument, the lower boundary of the rectangle may not lie above the diameter, the left boundary may not lie to the right of the vertical diameter, and the right boundary may not lie to the left of the verticle diameter. This means that the center of the circle is inside the rectangle, Q.E.D.
Vector2 Center(Rectangle rectangle, Vector2[] pts) {
extended_pts = []
foreach (Vector2 point in pts) {
extended_pts.append(point)
if (point.x < rectangle.x_min) {
extended_pts.append((2*rectangle.x_min - point.x, point.y));
if (point.y < rectangle.y_min)
extended_pts.append((2*rectangle.x_min - point.x, 2*rectangle.y_min - point.y));
if (point.y > rectangle.y_max)
extended_pts.append((2*rectangle.x_min - point.x, 2*rectangle.y_max - point.y));
}
if (point.x > rectangle.x_max)
extended_pts.append((2*rectangle.x_max - point.x, point.y));
if (point.y < rectangle.y_min)
extended_pts.append((2*rectangle.x_max - point.x, 2*rectangle.y_min - point.y));
if (point.y > rectangle.y_max)
extended_pts.append((2*rectangle.x_max - point.x, 2*rectangle.y_max - point.y));
if (point.y < rectangle.y_min)
extended_pts.append((point.x, 2*rectangle.y_min - point.y));
if (point.y > rectangle.y_max)
extended_pts.append((point.x, 2*rectangle.y_max - point.y));
}
return SmallestCircleCenter(extended_pts);
}

Related

How to determine if need to swap start and end angle when drawing an arc

I have multiple polygon maps (made up of lines and arcs). I am using turf.lineArc() to calculate points on an arc and to do this the start and end points of the arc need to be clockwise, if not they need to be swapped around.
I have the following code to swap the start and end points around (but it is not quite right)
if (endAngle < startAngle) {
endAngle = endAngle + 360;
}
if (startAngle < endAngle) {
var e = endAngle;
endAngle = startAngle;
startAngle = e;
}
while (startAngle - endAngle > 180) {
startAngle = startAngle - 360;
}
var arc = turf.lineArc(center, radius, startAngle, endAngle, options);
My problem is knowing when to swap the start and end around and when not to. In my attached picture Map1 works correctly without being swapped around but Map2 needs to have the start and end points swapped. (and they both need to use the same code). If map 2 does not have the start and end swapped around turf.lineArc draws a major arc of 353 degrees which is not what I want.
How do I fix my code so I only swap the start and end points when travelling from start to end is in an anti-clockwise direction?
Thank you :)
Edit: Arc can be < 180 or >180 and I know if it is major (>180) or minor (<180)
If your desired arc always should be < 180 degrees, then you can apply the next approach to overcome periodicity and zero-crossing pitfalls:
if Math.sin(endAngle-startAngle) < 0 then swap
I think, angles should be in radians in turfjs.
Also check - perhaps you have to change <0 to >0 to provide clockwise direction in your coordinate system.
I used this by Corrl to determine clockwise direction so then knew if to swap or not.
JavaScript - Find turn direction from two angles

Three.js - get screen position with no camera

I need to calculate screen position outside of Three, with with no camera present.
I know the object position, camera position and camera target
I've seen lots of instructions such as three.js Vector3 to 2D screen coordinate with rotated scene
vector.project(camera);
vector.x = Math.round( ( vector.x + 1 ) * w / 2 );
vector.y = Math.round( ( - vector.y + 1 ) * h / 2 );
I understand Vector.project camera takes into account the camera settings, FOV etc I'd assume?
Vector3 has projectOnVector(), does this do the same thing as vector3.project(camera) ?
Is there a way to calculate where the object would be on screen without being able to access the camera?
Yes, the Vector3.project takes into account the camera settings...
You need to calculate a projection matrix as you are trying to transform a position from world space to view space. This is a great little animation describing the journey that point will make: https://jsantell.com/model-view-projection/mvp.webm (lifted from this useful page: https://jsantell.com/model-view-projection/).
If you look in the three source code it will show you everything you need to do this. Vector3.project is just applying the two matrices from the camera:
return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix );
So how do you get these matrices? The project matrix is generated here.
You can ignore the view, skew and zoom, so you just need near, far, aspect and fov.
updateProjectionMatrix() {
const near = this.near;
let top = near * Math.tan( MathUtils.DEG2RAD * 0.5 * this.fov );
let height = 2 * top;
let width = this.aspect * height;
let left = - 0.5 * width;
this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far );
}
If you need makePerspective it is here
The matrixWorldInverse is just that... take your world matrix and inverse it. Three.js does it here.
This gives you your view matrix. So, view matrix multiplied with the projection gives you your screen space position... just like in a shader i.e:
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
I'm assuming your point is in world space so you can ignore the model part as this just takes you from model to world.

Calculating if or not a 3D eyepoint is behind a 2D plane or upwards

The setup
Draw XY-coordinate axes on a piece of paper. Write a word on it along X-axis, so that the word's centerpoint is at origo (half on positive side of X/Y, the other half on negative side of X/Y).
Now, if you flip the paper upside down you'll notice that the word is mirrored in relation to both X- and Y-axis. If you look from behind the paper, it's mirrored in relation to Y-axis. If you look at it from behind and upside down, it's mirrored in relation to X-axis.
Ok, I have points in 2D-plane (vertices) that are created in similar way at the origo and I need to apply exactly the same rule for them. To make things interesting:
The 2D plane is actually 3D, each point (vertex) being (x, y, 0). Initially the vertices are positioned to the origo and their normal is Pn(0,0,1). => Correctly seen when looked at from point Pn towards origo.
The vertex-plane has it's own rotation matrix [Rp] and position P(x,y,z) in the 3D-world. The rotation is applied before positioning.
The 3D world is "right handed". The viewer would be looking towards origo from some distance along positive Z-axis but the world is also oriented by rotation matrix [Rw]. [Rw] * (0,0,1) would point directly to the viewer's eye.
From those I need to calculate when the vertex-plane should be mirrored and by which axis. The mirroring itself can be done before applying [Rp] and P by:
Vertices vertices = Get2DPlanePoints();
int MirrorX = 1; // -1 to mirror, 1 NOT to mirror
int MirrorY = 1; // -1 to mirror, 1 NOT to mirror
Matrix WorldRotation = GetWorldRotationMatrix();
MirrorX = GetMirrorXFactor(WorldRotation);
MirrorY = GetMirrorYFactor(WorldRotation);
foreach(Vertex v in vertices)
{
v.X = v.X * MirrorX * MirrorY;
v.Y = V.Y * MirrorY;
}
// Apply rotation...
// Add position...
The question
So I need GetMirrorXFactor() & ..YFactor() -functions that return -1 if the viewer's eyepoint is at greater "X/Y"-angle than +-90 degrees in relation to the vertex-plane's normal after the rotation and world orientation. I have already solved this, but I'm looking for more "elegant" mathematics. I know that rotation matrices somehow contain info about how much is rotated by which axis and I believe that can be utilized here.
My Solution for MirrorX:
// Matrix multiplications. Vectors are vertical matrices here.
Pnr = [Rp] * Pn // Rotated vertices's normal
Pur = [Rp] * (0,1,0) // Rotated vertices's "up-vector"
Wnr = [Rw] * (0,0,1) // Rotated eye-vector with world's orientation
// = vector pointing directly at the viewer's eye
// Use rotated up-vector as a normal some new plane and project viewer's
// eye on it. dot = dot product between vectors.
Wnrx = Wnr - (Wnr dot Pur) * Pur // "X-projected" eye.
// Calculate angle between eye's X-component and plane's rotated normal.
// ||V|| = V's norm.
angle = arccos( (Wnrx dot Pnr) / ( ||Wnrx|| * ||Pnr|| ) )
if (angle > PI / 2)
MirrorX = -1; // DO mirror
else
MirrorX = 1; // DON'T mirror
Solution for mirrorY can be done in similar way using viewer's up and vertex-plane's right -vectors.
Better solution?
if (([Rp]*(1,0,0)) dot ([Rw]*(1,0,0))) < 0
MirrorX = -1; // DO mirror
else
MirrorX = 1; // DON'T mirror
if (([Rp]*(0,1,0)) dot ([Rw]*(0,1,0))) < 0
MirrorY = -1; // DO mirror
else
MirrorY = 1; // DON'T mirror
Explaining in more detail is difficult without diagrams, but if you have trouble with this solution we can work through some cases.

Rotating a D3DXVECTOR3 around a specific point

This is probably a pretty simple thing but my knowledge of direct x is just not up to par with what I'm trying to achieve.
For the moment I am trying to create a vehicle that moves around on terrain. I am attempting to make the vehicle recognize the terrain by creating a square (4 D3DXVECTOR3 points) around the vehicle who's points each detect the height of the terrain and adjust the vehicle accordingly.
The vehicle is a simple object derived from Microsoft sample code. It has a world matrix, coordinates, rotations etc.
What I am trying to achieve is to make these points move along with the vehicle, turning when it does so they can detect the difference in height. This requires me to update the points each time the vehicle moves but I cannot for the life of me figure out how to get them to rotate properly.
So In summary I am looking for a simple way to rotate a vector about an origin (my vehicles coordinates).
These points are situated near the vehicle wheels so if it worked they would stay there regardless of the vehicles y -axis rotation.
Heres What Ive tryed:
D3DXVECTOR3 vec;
D3DXVec3TransformCoord(&vectorToHoldTransformation,&SquareTopLeftPoint,&matRotationY);
SquareTopLeftPoint = vec;
This resulted in the point spinning madly out of control and leaving the map.
xRot = VehicleCoordinateX + cos(RotationY) * (SquareTopleftX - VehicleCoordinateX) - sin(RotationY) * (SquareTopleftZ - VehicleCoordinateZ);
yRot = VehicleCoordinateZ + sin(RotationY) * (SquareTopleftX - VehicleCoodinateX) + cos(RotationY) * (SquareToplefteZ - VehicleCoordinateZ);
BoxPoint refers to the vector I am attempting to rotate.
Vehicle is of course the origin of rotation
RotationY is the amount it has rotated.
This is the code for 1 of 4 vectors in this square but I assume once I get 1 write the rest are just copy-paste.
No matter what I try the point either does not move or spirals out of control under leaving the map all-together.
Here is a snippet of my object class
class Something
{
public:
float x, y, z;
float speed;
float rx, ry, rz;
float sx, sy, sz;
float width;
float length;
float frameTime;
D3DXVECTOR3 initVecDir;
D3DXVECTOR3 currentVecDir;
D3DXMATRIX matAllRotations;
D3DXMATRIX matRotateX;
D3DXMATRIX matRotateY;
D3DXMATRIX matRotateZ;
D3DXMATRIX matTranslate;
D3DXMATRIX matWorld;
D3DXMATRIX matView;
D3DXMATRIX matProjection;
D3DXMATRIX matWorldViewProjection;
//these points represent a box that is used for collision with terrain.
D3DXVECTOR3 frontLeftBoxPoint;
D3DXVECTOR3 frontRightBoxPoint;
D3DXVECTOR3 backLeftBoxPoint;
D3DXVECTOR3 backRightBoxPoint;
}
I was thinking it might be possible to do this using D3DXVec3TransformCoord
D3DXMatrixTranslation(&matTranslate, origin.x,0,origin.z);
D3DXMatrixRotationY(&matRotateY, ry);
D3DXMatrixTranslation(&matTranslate2,width,0,-length);
matAllRotations = matTranslate * matRotateY * matTranslate2;
D3DXVECTOR3 newCoords;
D3DXVECTOR3 oldCoords = D3DXVECTOR3(x,y,z);
D3DXVec3TransformCoord(&newCoords, &oldCoords, &matAllRotations);
Turns out that what I need to do was
Translate by -origin.
rotate
Translate by origin.
What I was doing was
Move to origin
Rotate
Translate by length/width
Thought it was the same.
D3DXMATRIX matTranslate2;
D3DXMatrixTranslation(&matTranslate,-origin.x,0,-origin.z);
D3DXMatrixRotationY(&matRotateY,ry);
D3DXMatrixTranslation(&matTranslate2,origin.x,0,origin.z);
//D3DXMatrixRotationAxis(&matRotateAxis,&origin,ry);
D3DXMATRIX matAll = matTranslate * matRotateY * matTranslate2;
D3DXVECTOR4 newCoords;
D3DXVECTOR4 oldCoords = D3DXVECTOR4(x,y,z,1);
D3DXVec4Transform(&newCoords,&oldCoords,&matAll);
//D3DXVec4TransformCoord(&newCoords, &oldCoords, &matAll);
return newCoords;
Without knowing more about your code I can't say what it does exactly, however one 'easy' way to think about this problem if you know the angle of the heading of your vehicle in world coordinates is to represent your points in a manner such that the center of the vehicle is at the origin, use a simple rotation matrix to rotate it around the vehicle according to the heading, and then add your vehicle's center to the resulting coordinates.
x = vehicle_center_x + cos(heading) * corner_x - sin(heading) * corner_y
y = vehicle_center_y - sin(heading) * corner_x + cos(heading) * corner_y
Keep in mind that corner_x and corner_y are expressed in coordinates relative to the vehicle -- NOT relative to the world.

Flipping an angle horizontally

I want to know a way to flip an angle in a horizontal axis, without having to do many operations. Say I have an angle of 0 ("pointing right" in my code's coordinate system), the flipped angle should be 180 (pointing left). If 90 (pointing up), flipped it should still be 90. 89 is 91, and so on.
I can operate on the X/Y speeds implied by the angle but that would slow things down, and I feel it's not the proper way to go.
I don't know much math so I might be calling things by the wrong name...Can anyone help?
EDIT: Sorry I took long, I had to be out of the computer for long, OK...
http://img215.imageshack.us/img215/8095/screenshot031v.jpg
This screenshot might do.The above structure are two satellites and a beam linked to the white dot in the center. The two satellites should inherit the angle of the white dot (it's visible for debug purposes), so if it's aiming at an angle, they will follow. The satellite at the left is mirrored, so I calculated it with 180-angle as suggested, although it was my first try as well. As you can see it is not mirrored but flipped. And when the white dot rotates, it rotates backwards. The other does alright.
This is the angle recalculation for something linked to something else, pid would be the parent, and id the current. pin.ang is the angle offset copied when the object is linked to another, so it keeps position when rotated:
if(object[id].mirror)
object[id].angle = 180 - (object[id].pin.ang + object[pid].angle);
else
object[id].angle = object[id].pin.ang + object[pid].angle;
And this is the specific rotation part. OpenGL. the offx/y is for things rotated off-center, like the beam about to come out there, it renders everything else right.
glTranslatef(list[index[i]].x, list[index[i]].y, 0);
glRotatef(list[index[i]].angle, 0.0, 0.0, 1.0);
glTranslatef(list[index[i]].offx, -list[index[i]].offy, 0);
The rotation also seems to miss when the rotation speed (an integer added every redraw to the current angle, positive for rotating clockwise, like in this next one:
http://img216.imageshack.us/img216/7/screenshot032ulr.jpg
So it's definitely not 180-angle, despite how obvious it'd be. The mirroring is done by just reversing the texture coordinates so it doesn't affect angle. I am afraid it might be a quirk on the GL rotation thing.
The reflected amount (just looking at the maths) would be (180 - angle)
Angle | Reflection
------+-----------
0 | 180
90 | 90
89 | 91
91 | 89
360 | -180
270 | -90
Note the negatives if you fall below the "horizontal plane" - which you could leave as they are, or handle as a special case.
Isn't it simply
result = 180-(your angle)
As already explained, you find the opposite angle by subtracting your angle from 180 degrees. Eg:
180 - yourangle
Directly manipulating the X/Y speeds would not be very cumbersome. You simply reverse the direction of the X speed, by multiplying it by minus 1, example: speedx = (-1) * speedx. This would change the left-right direction, eg: something moving to the left would start moving to the right, and vice versa, and the vertical speed would be unaffected.
If you're using sine/cosine (sin/cos) to recalculate your X/Y speed components, then the *(-1) method would probably be more efficient. Ultimately it depends on the context of your program. If you're looking for a better solution, update your question with more details.
This solution is for -Y oriented angles (like a watch)! For +X orientation (like school math) you need to swap X and Y.
public static float FlipAngleX(float angle)
{
angle = NormalizeAngle(angle);
angle = TwoPi - angle;
return angle;
}
public static float FlipAngleY(float angle)
{
angle = NormalizeAngle(angle);
if (angle < Pi)
{
angle = Pi - angle;
}
else
{
angle = TwoPi - angle + Pi;
}
return angle;
}
/// <summary>
/// Keeps angle between 0 - Two Pi
/// </summary>
public static float NormalizeAngle(float angle)
{
if (angle < 0)
{
int backRevolutions = (int)(-angle / TwoPi);
return angle + TwoPi * (backRevolutions + 1);
}
else
{
return angle % TwoPi;
}
}
Aah, seems the problem came from negative numbers after all, I ensured them being positive and now the rotation does fine, I don't even need to recalculate angle...
Thanks to everyone, I ended up figuring out due to bits of every response.
to flip counter clockwise to clockwise (270 on right -> 90 on right)
angle - 360
--
to flip vertical (180 on top -> 0/360 on top)
Math.Normalize(angle - 180)
--
both:
float flipped_vertical = angle - 360
float flipped_vertical_and_horizontal = Math.Normalize(flipped_vertical- 180)
just 360-angle will flip your angle horizontaly but not verticaly

Resources