Essentially what I'm trying to do is moving a point relative to two different scales. The reason is to edit values in a database of a 3d party application.

So basically I want to relocate the red point, relative to the red scale to the blue scale and end up with the blue point.
Unfortunately my math knowledge is seriously lacking in this case and I cannot seem to find anything similar by searching for hours and hours. And even if I do find something that might be related I'm having a hard time understanding if what I'm looking at is even related.
The scale I'm working on is very zoomed in. Maybe a couple of square kilometers. So I thought I'd be fine using 2D methods.
Moving the point and scaling it wasn't an issue creating by myself, but the rotation part is seriously wrong.

The green point is the one that has been moved (but not rotated yet) using 2D calculations, completely fine. The blue point is where it's supposed to end up after rotating it around the center point. The red point is where it actually ends up. The grey points are just extra references so I could understand what was going on.
I think the elliptical path is because I'm basically plotting on a 3D surface based on a 2D equation. The coordinates are in Stockholm, Sweden. Let's say N59.327 E18.055 So a bit north. I tried moving all the points near the equator and then it produces a better circle which seems correct.
I also assume that the moving is fine because it doesn't know that it's on a globe on such a small scale area. But the circular calculations have to account for the whole circle/sphere? I don't know.
Any help would be greatly appreciated since I'm obviously in the deep end of my knowledge.
I'm sorry I can't produce runnable code.
If you recommend switching to something like DbGeography, that's fine.
internal class DoublePoint
{
internal double Latitude;
internal double Longitude;
internal DoublePoint()
{
Latitude = 0.0;
Longitude = 0.0;
}
internal DoublePoint(double longitude, double latitude)
{
Latitude = latitude;
Longitude = longitude;
}
public override string ToString()
{
return Longitude.ToString().Replace(",", ".") + ", " + Latitude.ToString().Replace(",", ".");
}
}
internal class DoubleVector
{
internal DoublePoint A;
internal DoublePoint B;
internal DoubleVector(DoublePoint a, DoublePoint b)
{
{
A = a;
B = b;
}
}
}
public static DoublePoint RelativeMove(DoublePoint what, DoubleVector vecFrom, DoubleVector vecTo, double angle = 0.0, bool skipRotate = false)
{
double scale = Scale(vecFrom, vecTo);
DoublePoint p = new DoublePoint();
p.Latitude = vecTo.A.Latitude + ((what.Latitude - vecFrom.A.Latitude) * scale);
p.Longitude = vecTo.A.Longitude + ((what.Longitude - vecFrom.A.Longitude) * scale);
// Fine until this point.
return RotateAroundPoint(p, vecTo.A, RelativeAngle(vecFrom, vecTo));
}
public static DoublePoint RotateAroundPoint2(DoublePoint pointToRotate, DoublePoint centerDoublePoint, double angleInDegrees)
{
double angleInRadians = angleInDegrees * (Math.PI / 180.0);
double cosTheta = Math.Cos(angleInRadians);
double sinTheta = Math.Sin(angleInRadians);
DoublePoint temp = new DoublePoint(
(cosTheta * (pointToRotate.Longitude - centerDoublePoint.Longitude) -
sinTheta * (pointToRotate.Latitude - centerDoublePoint.Latitude) + centerDoublePoint.Longitude),
(sinTheta * (pointToRotate.Longitude - centerDoublePoint.Longitude) +
cosTheta * (pointToRotate.Latitude - centerDoublePoint.Latitude) + centerDoublePoint.Latitude)
);
return temp;
}
public static double RelativeAngle(DoubleVector src, DoubleVector dst)
{
return Angle(dst) - Angle(src);
}
public static double Angle(DoubleVector vec)
{
double longDiff = vec.B.Longitude - vec.A.Longitude;
double latDiff = vec.B.Latitude - vec.A.Latitude;
return Math.Atan2(latDiff, longDiff) * (180.0 / Math.PI);
}
public static double Scale(DoubleVector src, DoubleVector dst)
{
return Distance(dst) / Distance(src);
}
public static double Distance(DoubleVector vec)
{
var sCoord = new GeoCoordinate(vec.A.Latitude, vec.A.Longitude);
var eCoord = new GeoCoordinate(vec.B.Latitude, vec.B.Longitude);
return sCoord.GetDistanceTo(eCoord) * 1.2;
}
UPDATE:
Here's a very crude example on a sphere of the movement and rotation that I'm trying to achieve using the same colors as the example below.
The known coordinates I have is the ends of the blue and red line and the green point. The rotation I want to do is MUCH smaller. At most about 100m point to point.
I think this is what I need. It seems to create a 2D plane to make a rotation based on a point that is lowered from the surface to match the diameter surface. I just don't understand how to get there.
I created an example in WinForms using 2D
What I want to do is move (Yellow) the original point (Lime) to the destination point (Pink)
The logic was:
This seems to work fine with 2D. But when I use it on a sphere (the earth) the circle around the destination base becomes elliptical which I assume is because of the curvature of the sphere.
Here's the example in WinForms:
using System;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
namespace Example1
{
public partial class Form1 : Form
{
Pen Red = new Pen(Color.Red, 5);
Pen Blue = new Pen(Color.Blue, 5);
Pen Green = new Pen(Color.Green, 10);
Pen Cyan = new Pen(Color.Cyan, 10);
Pen Magenta = new Pen(Color.Magenta, 10);
Pen Lime = new Pen(Color.Lime, 10);
Pen Pink = new Pen(Color.Pink, 10);
Pen Black = new Pen(Color.Black, 2);
Pen Purple = new Pen(Color.Purple, 2);
Pen Yellow = new Pen(Color.Yellow, 2);
public Form1()
{
InitializeComponent();
this.Size = new System.Drawing.Size(800, 800);
PictureBox pictureBox1 = new PictureBox();
pictureBox1.Width = 800;
pictureBox1.Height = 800;
this.Controls.Add(pictureBox1);
Bitmap bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);
Vector src = new Vector(new Point(500, 500), new Point(700, 500));
Vector dst = new Vector(new Point(150, 600), new Point(700, 50));
Point pointToMove = new Point(525, 525);
Point resultNoRotate = RelativeMove(pointToMove, src, dst, false);
Point result = RelativeMove(pointToMove, src, dst);
using (Graphics g = Graphics.FromImage(bmp))
{
// Draw source line with A as anchor point
g.DrawLine(Blue, src.A, src.B);
g.DrawEllipse(Cyan, src.A.X - 5, src.A.Y - 5, 10, 10);
// Draw destination line with A as anchor point
g.DrawLine(Red, dst.A, dst.B);
g.DrawEllipse(Magenta, dst.A.X - 5, dst.A.Y - 5, 10, 10);
// Draw original point relative to source
g.DrawEllipse(Lime, pointToMove.X - 5, pointToMove.Y - 5, 10, 10);
// Draw point that has been moved (src.A to dst.A) and scaled(length of destination / length of source) but not rotated
g.DrawEllipse(Green, resultNoRotate.X - 5, resultNoRotate.Y - 5, 10, 10);
// Draw point that has been moved, scaled and rotated into the position I want
g.DrawEllipse(Pink, result.X - 5, result.Y - 5, 10, 10);
// Move calulation representation
g.DrawLine(Black, src.A, dst.A);
// Rotation around axis dst.A. I tried making an arc but failed.
double dist = Distance(new Vector(dst.A, resultNoRotate));
g.DrawEllipse(Purple, (float)(dst.A.X-dist), (float)(dst.A.Y - dist), (float)(dist * 2), (float)(dist * 2));
// Starting point to finished point
g.DrawLine(Yellow, pointToMove, result);
}
pictureBox1.Image = bmp;
}
public static Point RelativeMove(Point what, Vector vecFrom, Vector vecTo, bool rotate = true)
{
double scale = Scale(vecFrom, vecTo);
Debug.Print(scale.ToString());
Point p = new Point();
p.X = (int)((double)vecTo.A.X + ((what.X - vecFrom.A.X) * scale));
p.Y = (int)((double)vecTo.A.Y + ((what.Y - vecFrom.A.Y) * scale));
Console.WriteLine("This: " + (int)((double)vecTo.A.Y + ((what.Y - vecFrom.A.Y) * scale)));
Console.WriteLine("p.Y: " + p.Y);
if (!rotate)
return p;
return RotateAroundPoint(p, vecTo.A, RelativeAngle(vecFrom, vecTo));
}
public static Point RotateAroundPoint(Point pointToRotate, Point centerPoint, double angleInDegrees)
{
double angleInRadians = angleInDegrees * (Math.PI / 180.0);
double cosTheta = Math.Cos(angleInRadians);
double sinTheta = Math.Sin(angleInRadians);
Point temp = new Point(
(int)
(cosTheta * (pointToRotate.X - centerPoint.X) -
sinTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.X),
(int)
(sinTheta * (pointToRotate.X - centerPoint.X) +
cosTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.Y)
);
return temp;
}
public static double Scale(Vector src, Vector dst)
{
return Distance(dst) / Distance(src);
}
public static double Distance(Vector vec)
{
Point diff = new Point();
diff.X = Math.Abs(vec.A.X - vec.B.X);
diff.Y = Math.Abs(vec.A.Y - vec.B.Y);
return Math.Sqrt(diff.X * diff.X + diff.Y * diff.Y);
}
public static double RelativeAngle(Vector src, Vector dst)
{
Console.WriteLine((Angle(dst) - Angle(src)));
return Angle(dst) - Angle(src);
}
public static double Angle(Vector vec)
{
double diffX = vec.B.X - vec.A.X;
double diffY = vec.B.Y - vec.A.Y;
return Math.Atan2(diffY, diffX) * (180.0 / Math.PI);
}
public class Vector
{
public Point A;
public Point B;
public Vector(Point a, Point b)
{
A = a;
B = b;
}
}
}
}
UPDATE 1: Removed unused code. Some values as references:
Source A: 59.3239685738673 17.9978501743896
Source B: 59.3239832772412 17.9999819777391
Destination A: 59.3250343436533 17.9958144704476
Destination B: 59.3261225537402 17.9957850937422
Point to move: 59.3237129908632 17.9987727886078
Expectation: 59.3255056697155 17.9963157189239
Please note that the expected value is not calculated but placed on a map. I would say that +/-0,000010 0,000005 would be correct but other parts of my calculations might shift that number a bit higher.
UPDATE 2:
Trying to explain further because I feel I'm contributing to the XY-problem (which I absolutely don't want to do).
I have this 3d party software that uses earth as canvas and everything is coordinated in latitude/longitude. I am using pictures to add buildings to the map projected on this surface. I want to move a whole building and I want to move points from the old building to the new.
Keeping the colors I have the scale red/blue with the base coordinates (cyan/magenta) as the centers of the crosshairs and I want to move the lime point to the pink point.
In this specific example the point is at .8 relative to it's scale (every line is .1), the rotation is 90 degrees and the map is 2 times the original size.
I am coming at this from a math/physics angle rather than programming, so forgive me if I am focusing on the wrong thing, but I need some clarification on what exactly you are trying to transform here. Are you trying to preserve the ratio of the scale length to the point-scale distance?
By point-scale distance, I mean the length of the perpendicular line/arc from the point to the closest point on the scale. My understanding is that you are trying to satisfy:

It's known from differential geometry (see Theorema Egregium) that you cannot project from a sphere to a plane while preserving both shapes (or angles) and areas, which I suspect is very likely to be the root cause of your problems. I am not really sure if what you are trying to achieve can be done by only preserving one or the other or if you're trying to do something impossible, but it's probably worthwhile to actually carry out the math in 3D rather than a 2D projection. The (two ends of the) scale and the point together form a triangle on the Earth's surface, so you're really trying to transform (rotate, scale, translate) a spherical triangle, which I am not sure would work. Spherical trigonometry might help you here.
The transformations you're composing are:
translation (cyan -> magenta)
scaling (ends up in green point)
rotation (takes the point in question from green point to pink point)
Using regular 2D/3D cartesian coordinates, these operations do not commute. Chiefly, the reason for this is that translation is not a linear transformation in Cartesian coordinates (Tiny proof sketch: The 0 vector does not map back to 0 under a translation). In other words, you'll get a different result if you change the order. In general, you'll apparently need to use homogenous coordinates, under which translation is linear, to avoid this problem; however, you might end up working with points/lines/areas off the surface of the Earth if you directly convert Cartesian coordinates to homogenous coordinates in this case. I cannot guess offhand if the approximation would work better with homogenous coordinates or not.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With