I have two fits images from the WFC3 that I am trying to combine with a C# program. When I try to combine multiple images I don't think the values I am getting for my x/y coordinates (calculated from Right Ascension/Declination) are correct. I am expecting a final image that is about the same width as the two images combined, but it turns out to be about the same width and about twice the height. I know the final image should be about double the width of a single image because I manually combined the images in photoshop and the final image was about twice as wide as either of the two original images.
NOTE: when I say "image" they are fits images, so they are just a bunch of single values in a file, so to combine them I create a new file and initialize the correct number of single values (width * height) to zero, and then fill in the values from the images I am using to combine. They are not jpg or tif or png.
I am using the following formula to change from world coordinate system to cartesian:
formula is (since distance is the same for everything):
x = cos(dec) * cos(ra)
y = cos(dec) * sin(ra)
I get the right ascension and declination from the header in the fits file.
For the final image dimensions, I calculate the distance between x1 and x2 and create a new image that is 1/2 image 1 width + distance + 1/2 image 2 width. For the final height I do a similar calculation with y and image heights.
The images do also have a rotational component, but I am ignoring that as both images share the same rotation. This could be part of my problem.
public const double PixelsPerArcSecond = .039; // per WFC3 spec from Nasa
public static ImageDataModel Combine(List<ImageDataModel> inputImages)
{
// Right ascension is CRVAL1
// Declination is CRVAL2
// formula is (since distance is the same for everything):
// x = cos(dec) * cos(ra)
// y = cos(dec) * sin(ra)
ImageDataModel returnImage = new ImageDataModel();
ImageDataModel bm = inputImages[0];
double x1, y1, x2, y2;
x1 = Math.Cos(bm.CRVAL2) * Math.Cos(bm.CRVAL1);
y1 = Math.Cos(bm.CRVAL2) * Math.Sin(bm.CRVAL1);
int mult = 4; // todo: set this based off of the bitpix of the incoming images.
for (int i = 1; i < inputImages.Count; i++)
{
ImageDataModel cm = inputImages[i];
x2 = Math.Cos(cm.CRVAL2) * Math.Cos(cm.CRVAL1);
y2 = Math.Cos(cm.CRVAL2) * Math.Sin(cm.CRVAL1);
double dx = x1 - x2;
double dy = y1 - y2;
int distX = (int)((dx * 3600) / PixelsPerArcSecond);
int distY = (int)((dy * 3600) / PixelsPerArcSecond);
// This is what I expect to be wider than tall, but the converse is true.
int w = Math.Abs(distX) + (bm.ImageWidth / 2) + (cm.ImageWidth / 2);
int h = Math.Abs(distY) + (bm.ImageHeight / 2) + (cm.ImageHeight / 2);
// This is where the two images are combined into the final image.
ImageDataModel imd = CombineTwoImages(bm, cm, i, w, h, mult);
bm = imd;
}
return returnImage;
}
I am expecting an image that turns out like this:
http://wierdling.net/stack-overflow-images/ManuallyCombined.png
But getting this:
http://wierdling.net/stack-overflow-images/CombinedTest.png
The stats for the first image are: Width = 4139, Height = 4535, RA = 350.1584456860353 (CRVAL1), DEC = 61.16155335032816 (CRVAL2), ORIENTAT = -125
The stats for the second image are:Width = 4139, Height = 4535, RA = 350.1159150008405 (CRVAL1), DEC = 61.19543100394401 (CRVAL2), ORIENTAT = -125
The final expected width is close to 7733 with a height near 4773.
The final actual width is 4284, and the height is 7662.
Does anyone have any insight into what I am doing wrong?
The full source code for the program can be downloaded from https://bitbucket.org/wierdling/fitscombiner/src/master/
It currently only works with WFC3 data, and the program is very much a work in progress.
I think that your image program already does the rotation and you should do it too.
If I rotate the coordinates you calculated by 125 degrees and then calculate how far away the coordinate x1 is from the left side and the same for x2 and the y coordiantes I get a width of 6725 and height of 6166.
Not perfect but I think it goes in the right direction.
Hope that helped.
public static ImageDataModel Combine(List<ImageDataModel> inputImages)
{
// Right ascension is CRVAL1
// Declination is CRVAL2
// formula is (since distance is the same for everything):
// x = cos(dec) * cos(ra)
// y = cos(dec) * sin(ra)
ImageDataModel returnImage = new ImageDataModel();
ImageDataModel bm = inputImages[0];
double x1, y1, x2, y2;
x1 = Math.Cos(bm.CRVAL2) * Math.Cos(bm.CRVAL1);
y1 = Math.Cos(bm.CRVAL2) * Math.Sin(bm.CRVAL1);
var values = Rotate(0 - bm.Orientation, x1, y1);
x1 = values.x;
y1 = values.y;
int mult = 4; // todo: set this based off of the bitpix of the incoming images.
for (int i = 1; i < inputImages.Count; i++)
{
ImageDataModel cm = inputImages[i];
x2 = Math.Cos(cm.CRVAL2) * Math.Cos(cm.CRVAL1);
y2 = Math.Cos(cm.CRVAL2) * Math.Sin(cm.CRVAL1);
var values2 = Rotate(0 - bm.Orientation, x2, y2);
x2 = values2.x;
y2 = values2.y;
double dx = x1 - x2;
double dy = y1 - y2;
int distX = (int)((dx * 3600) / PixelsPerArcSecond);
int distY = (int)((dy * 3600) / PixelsPerArcSecond);
double width = (1.0 + x1) * (bm.ImageWidth / 2) + (1.0 - x2) * (cm.ImageWidth / 2) + Math.Abs(distX);
double height = (1.0 + y1) * (bm.ImageHeight / 2) + (1.0 - y2) * (cm.ImageHeight / 2) + Math.Abs(distY);
// This is what I expect to be wider than tall, but the converse is true.
int w = Math.Abs(distX) + (bm.ImageWidth / 2) + (cm.ImageWidth / 2);
int h = Math.Abs(distY) + (bm.ImageHeight / 2) + (cm.ImageHeight / 2);
// This is where the two images are combined into the final image.
ImageDataModel imd = CombineTwoImages(bm, cm, i, w, h, mult);
bm = imd;
}
return returnImage;
}
private static (double x, double y) Rotate(int angle, double x, double y)
{
double rad = Math.PI * angle / 180.0;
return (x * Math.Cos(rad) - y * Math.Sin(rad), x * Math.Sin(rad) + y * Math.Cos(rad));
}
Related
I have managed to find code that determines if a Line intersects with a rectangle. My problem is when the Rectangle is rotated. I have looked hi and low to find code that will give me the coordinates of the corners of the rectangle after the transform is performed with no luck. My rectangle when it is rotated is rotated around CenterX and CenterY of 0,0.
I'd appreciate any code that you may have that does this.
Thanks!
More information:
I am working on a program that I want to be able to select one or more rectangles on a canvas by drawing a line. The rectangles can be rotated.
I have tried the following code. The second function works properly for non rotated rectangles but not for rotated rectangles.:
public bool AdjustedIntersects(FrameworkElement elem, Line line)
{
double x = Canvas.GetLeft(elem);
double y = Canvas.GetTop(elem);
double X = x * Math.Cos(((RotateTransform)elem.RenderTransform).Angle)
- y * Math.Sin(((RotateTransform)elem.RenderTransform).Angle);
double Y = x * Math.Sin(((RotateTransform)elem.RenderTransform).Angle)
+ y * Math.Cos(((RotateTransform)elem.RenderTransform).Angle);
x = Canvas.GetLeft(elem) + elem.Width;
y = Canvas.GetTop(elem) + elem.Height;
double X2 = x * Math.Cos(((RotateTransform)elem.RenderTransform).Angle)
- y * Math.Sin(((RotateTransform)elem.RenderTransform).Angle);
double Y2 = x * Math.Sin(((RotateTransform)elem.RenderTransform).Angle)
+ y * Math.Cos(((RotateTransform)elem.RenderTransform).Angle);
return SegmentIntersectRectangle(X, Y,X2,Y2,
line.X1, line.Y1, line.X2, line.Y2);
}
public bool SegmentIntersectRectangle(
double rectangleMinX,
double rectangleMinY,
double rectangleMaxX,
double rectangleMaxY,
double p1X,
double p1Y,
double p2X,
double p2Y)
{
// Find min and max X for the segment
double minX = p1X;
double maxX = p2X;
if (p1X > p2X)
{
minX = p2X;
maxX = p1X;
}
// Find the intersection of the segment's and rectangle's x-projections
if (maxX > rectangleMaxX)
{
maxX = rectangleMaxX;
}
if (minX < rectangleMinX)
{
minX = rectangleMinX;
}
if (minX > maxX) // If their projections do not intersect return false
{
return false;
}
// Find corresponding min and max Y for min and max X we found before
double minY = p1Y;
double maxY = p2Y;
double dx = p2X - p1X;
if (Math.Abs(dx) > 0.0000001)
{
double a = (p2Y - p1Y) / dx;
double b = p1Y - a * p1X;
minY = a * minX + b;
maxY = a * maxX + b;
}
if (minY > maxY)
{
double tmp = maxY;
maxY = minY;
minY = tmp;
}
// Find the intersection of the segment's and rectangle's y-projections
if (maxY > rectangleMaxY)
{
maxY = rectangleMaxY;
}
if (minY < rectangleMinY)
{
minY = rectangleMinY;
}
if (minY > maxY) // If Y-projections do not intersect return false
{
return false;
}
return true;
}
A polygon intersects with a line if one of lines of the poligon overlap with the line. Then try this:
Find four conners of the rectangle by the above way.
Check if one of lines make from sequence of conners overlap with the line. I have a ideal for it:
private bool IsStraightLineOverlap(System.Windows.Shapes.Line line1, Line line2)
{
var line1Min_X = Math.Min(line1.X1, line1.X2);
var line1Max_X = Math.Max(line1.X1, line1.X2);
var line1Min_Y = Math.Min(line1.Y1, line1.Y2);
var line1Max_Y = Math.Max(line1.Y1, line1.Y2);
var line2Min_X = Math.Min(line2.X1, line2.X2);
var line2Max_X = Math.Max(line2.X1, line2.X2);
var line2Min_Y = Math.Min(line2.Y1, line2.Y2);
var line2Max_Y = Math.Max(line2.Y1, line2.Y2);
var isOverlap_X = (line1Min_X <= line2Max_X && line1Max_X >= line2Min_X);
var isOverlap_Y = (line1Min_Y <= line2Max_Y && line1Max_Y >= line2Min_Y);
return isOverlap_X && isOverlap_Y;
}
In our game suite I have to find rotated points for various purposes.
Here's an extension method:
public static class PointExtension
{
public static Point GetRotatedPoint(this Point point, Point centerPoint, double angleInDegrees)
{
double angleInRadians = angleInDegrees * (Math.PI / 180.0);
double cosTheta = Math.Cos(angleInRadians);
double sinTheta = Math.Sin(angleInRadians);
return new Point
{
X =
(int)
(cosTheta * (point.X - centerPoint.X) -
sinTheta * (point.Y - centerPoint.Y) + centerPoint.X),
Y =
(int)
(sinTheta * (point.X - centerPoint.X) +
cosTheta * (point.Y - centerPoint.Y) + centerPoint.Y)
};
}
}
I also have to work out the cells on a grid that a line passes through.
To do this I use a bresenham line algorithm.
You can google this and find various implementations.
Here's mine:
public static IEnumerable<Point> GetOrderedPointsOnLine(int x0, int y0, int x1, int y1)
{
bool steep = Math.Abs(y1 - y0) > Math.Abs(x1 - x0);
if (steep)
{
Swap<int>(ref x0, ref y0);
Swap<int>(ref x1, ref y1);
}
int dx = Math.Abs(x1 - x0);
int dy = Math.Abs(y1 - y0);
int error = (dx / 2);
int ystep = (y0 < y1 ? 1 : -1);
int xstep = (x0 < x1 ? 1 : -1);
int y = y0;
for (int x = x0; x != (x1 + xstep); x += xstep)
{
yield return new Point((steep ? y : x), (steep ? x : y));
error = error - dy;
if (error < 0)
{
y += ystep;
error += dx;
}
}
yield break;
}
The outline of a rectangle is of course 4 lines.
There is an edge case where both an edge and the line can be a variation of 4 degrees and intersection exactly picks cells don't match.
To obviate that you could use a bresenham variation which picks both cells the line partially passes through.
Or you can build two geometries and see if you get anything overlaps when you use the wpf library to detect intersection.
I'm not sure what happens if you apply a transform to a geometry and then use geometry.fillcontainswithdetail
https://learn.microsoft.com/en-us/dotnet/api/system.windows.media.geometry.fillcontainswithdetail?redirectedfrom=MSDN&view=net-5.0#overloads
There's also combinedgeometry to consider.
Pick the right options and it'll only give you what overlaps between 2 geometries.
I use neither because in game has to be very fast.
For pre game calculations I render offscreen and examine the bytes of the image I get. This is the fastest simplest way I've found to see which cells (px) an irregular shape occupies.
And another way you could approach this.
Solution 1: break the problem down into something that is easier to solve:
Pick any edge on the rectangle, represented by points P1 and P2.
Translate both the points in your rectangle and the points that define your line by -P1, so that the P1 point is now at the origin.
Calculate the angle of your edge i.e. Math.Atan2(deltaY, deltaX).
Rotate the points for both the rectangle and line in the opposite direction, so that you now have an axis-aligned rectangle.
Do your line/rectangle hit test between these new primitives, using the algorithm you already have for axis-aligned rectangles.
If you need the actual point of intersection in proper world space coordinates then rotate it forward by the angle and translate by +P1.
Solution 2: test the line against each line that forms the rectangle, your problem is now 4 line-to-line intersection tests.
Disclaimer: this is not c#. I only know javascript but the math should be the same.
The way I attack this is by creating an array for my shape that I use to store each vertex. I then use those points to determine where the objects boundaries are. I am assuming that translate and rotate work the same in c# and the objects coordinate are always axis-aligned.
When I draw my rectangle I draw it with the x (left) as -width/2 and y (top) as -height/2. This is because I am going to use translate to position it where I want it and also allow it to rotate from the center.
ctx.save();
ctx.translate(this.x, this.y)
ctx.rotate(this.rotation);
ctx.fillStyle = this.color;
ctx.fillRect(-this.width/2, -this.height/2, this.width, this.height)
ctx.restore();
I don't know if c# uses save and restore but it would be the same as just translating and rotating it back after i.e.
ctx.translate(this.x, this.y);
ctx.rotate(this.rotation);
ctx.fillStyle = this.color;
ctx.fillRect(-this.width/2, -this.height/2, this.width, this.height);
ctx.rotate(-this.rotation);
ctx.translate(-this.x, -this.y)
Also you'll notice in the snippet code that I created an array to store my x and y coordinates of each vertex
this.vertices = [];
for (let i = 0; i < 4; i++) {
//initially set to (0, 0) and updated in updateVertices()
this.vertices.push({ x: 0, y: 0 });
}
This is part of my rectangle object by the array could be global also.
The part that really matters is the math associated to updating the position of the vertices. In this snippet I use a function called updateVertices(). In this function I need to first calculate the sin and cos based on the current rotation.
let cos = Math.cos(this.rotation); //passing in radians in JS
let sin = Math.sin(this.rotation); //passing in radians in JS
Once I have that I just update the array of vertices that I created
//update Top Left Corner
this.vertices[0].x =
(this.x - this.centerX) * cos -
(this.y - this.centerY) * sin +
(this.centerX - this.width / 2);
this.vertices[0].y =
(this.x - this.centerX) * sin +
(this.y - this.centerY) * cos +
(this.centerY - this.height / 2);
Do that with all four corners. The math is slightly different for each vertex.
That's it. You have an array with all 4 vertices and can use them how you want. In this example I iterate over them passing two (adjacent) at time to my intersectLines() function to see if my vector lines intersects. Since I am testing 4 edges I use a loop to test all four sides against my vector, I do this in my passToIntersectFunction() function.
In this snippet you can use the mouse to move the vector around and see how the intersect points move.
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
canvas.width = 400;
canvas.height = 400;
let ptX, ptY;
let intersectPoints = [];
let mouse = {
x: null,
y: null
};
canvas.addEventListener("mousemove", (e) => {
mouse.x = e.x - canvas.getBoundingClientRect().x;
mouse.y = e.y - canvas.getBoundingClientRect().y;
});
class Square {
constructor() {
this.x = 100;
this.y = 100;
this.width = 50;
this.height = 50;
this.centerX = this.x + this.width / 2;
this.centerY = this.y + this.height / 2;
this.color = "red";
this.angle = 0;
this.rotation = (this.angle * Math.PI) / 180; //convert to rads
//used to store all four vertices
this.vertices = [];
for (let i = 0; i < 4; i++) {
//initially set to (0, 0) and updated in updateVertices()
this.vertices.push({ x: 0, y: 0 });
}
}
draw() {
this.angle += 0.5;
this.rotation = (this.angle * Math.PI) / 180;
ctx.translate(this.x, this.y);
ctx.rotate(this.rotation);
ctx.fillStyle = this.color;
ctx.fillRect(-this.width / 2, -this.height / 2, this.width, this.height);
ctx.rotate(-this.rotation);
ctx.translate(-this.x, -this.y);
}
drawIntersectPoint() {
ctx.fillStyle = "black";
ctx.beginPath();
ctx.arc(ptX, ptY, 3, 0, Math.PI * 2);
ctx.fill();
}
drawVertices() {
ctx.fillStyle = "blue";
ctx.beginPath();
for (let i = 0; i < this.vertices.length; i++) {
ctx.arc(this.vertices[i].x, this.vertices[i].y, 3, 0, Math.PI * 2);
ctx.fill();
ctx.closePath();
}
}
updateVertices() {
let cos = Math.cos(this.rotation);
let sin = Math.sin(this.rotation);
//update Top Left Corner
this.vertices[0].x =
(this.x - this.centerX) * cos -
(this.y - this.centerY) * sin +
(this.centerX - this.width / 2);
this.vertices[0].y =
(this.x - this.centerX) * sin +
(this.y - this.centerY) * cos +
(this.centerY - this.height / 2);
//updates Top Right Corner
this.vertices[1].x =
(this.x + this.width - this.centerX) * cos -
(this.y - this.centerY) * sin +
(this.centerX - this.width / 2);
this.vertices[1].y =
(this.x + this.width - this.centerX) * sin +
(this.y - this.centerY) * cos +
(this.centerY - this.height / 2);
//updates Bottom Right Corner
this.vertices[2].x =
(this.x + this.width - this.centerX) * cos -
(this.y + this.height - this.centerY) * sin +
(this.centerX - this.width / 2);
this.vertices[2].y =
(this.x + this.width - this.centerX) * sin +
(this.y + this.height - this.centerY) * cos +
(this.centerY - this.height / 2);
//updates Bottom Left Corner
this.vertices[3].x =
(this.x - this.centerX) * cos -
(this.y + this.height - this.centerY) * sin +
(this.centerX - this.width / 2);
this.vertices[3].y =
(this.x - this.centerX) * sin +
(this.y + this.height - this.centerY) * cos +
(this.centerY - this.height / 2);
}
}
let square = new Square();
class Vector {
constructor() {
this.x1 = 200;
this.y1 = 100;
this.x2 = mouse.x;
this.y2 = mouse.y;
}
draw() {
ctx.strokeStyle = "black";
ctx.beginPath();
ctx.moveTo(this.x1, this.y1);
ctx.lineTo(this.x2, this.y2);
ctx.stroke();
}
updateVector() {
this.x2 = mouse.x;
this.y2 = mouse.y;
this.draw();
}
}
let vector = new Vector();
function intersectLines(coord1, coord2, vector) {
//this if statement just keeps the array from constantly growing
if (intersectPoints.length > 2) {
intersectPoints.shift();
}
let x1 = coord1.x;
let x2 = coord2.x;
let y1 = coord1.y;
let y2 = coord2.y;
let x3 = vector.x1;
let x4 = vector.x2;
let y3 = vector.y1;
let y4 = vector.y2;
let d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
if (d == 0) {
return;
}
let t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / d;
let u = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / d;
if (t > 0 && t < 1 && u > 0) {
intersectPoints.push({ x: x1 + t * (x2 - x1), y: y1 + t * (y2 - y1) });
}
return;
}
function passToIntersectFunction() {
for (let i = 0; i < square.vertices.length; i++) {
intersectLines(
square.vertices[i],
square.vertices[i + 1] ?? square.vertices[0],
vector
);
}
}
function drawIntersectPoints() {
for (let i = 0; i < intersectPoints.length; i++) {
ctx.fillStyle = "black";
ctx.beginPath();
ctx.arc(intersectPoints[i].x, intersectPoints[i].y, 3, 0, Math.PI * 2);
ctx.fill();
}
}
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
square.draw();
square.updateVertices();
square.drawIntersectPoint();
square.drawVertices();
vector.updateVector();
drawIntersectPoints();
passToIntersectFunction();
requestAnimationFrame(animate);
}
animate();
<canvas id="canvas"></canvas>
Sorry its not c# but maybe it can help.
i i am relative new to c# and is trying to draw a curved line in c#. I would like to ask that is there any possible way to create an X and Y axis in order to show the coordinates of each point of the curved line.
Please do help me on this matter as i am stuck on how to execute it.
protected override void OnPaint(PaintEventArgs e)
{
float a = 1, b = 5, c = 1;
double x1, x2, x3,x4,x5,x6, y1, y2, y3,y4,y5, delta;
delta = (b * b) - (4 * a * c);
x1=0;
y1 = a * (x1 * x1) + (b * (x1)) + c;
x2 = 3;
y2 = a * (x2 * x2) + (b * (x2)) + c;
x3 = - 3;
y3 = a * (x3 * x3) + (b * (x3)) + c;
x4 = 5;
y4 = a * (x4 * x4) + (b * (x4)) + c;
x5 = -10;
y5 = a * (x5 * x5) + (b * (x5)) + c;
int cx1 = Convert.ToInt32(x1);
int cx2 = Convert.ToInt32(x2);
int cx3 = Convert.ToInt32(x3);
int cy1 = Convert.ToInt32(y1);
int cy2 = Convert.ToInt32(y2);
int cy3 = Convert.ToInt32(y3);
int cx4 = Convert.ToInt32(x4);
int cy4 = Convert.ToInt32(y4);
int cx5 = Convert.ToInt32(x5);
int cy5 = Convert.ToInt32(y5);
Graphics g = e.Graphics;
int deltaX = 100;
int deltaY = 100;
g.TranslateTransform(deltaX, deltaY);
float factor = 2.5f;
Matrix m = new Matrix();
m.Scale(factor, factor);
g.MultiplyTransform(m);
Pen aPen = new Pen(Color.Blue, 1);
Point point1 = new Point(cx1, cy1);
Point point2 = new Point(cx2, cy2);
Point point3 = new Point(cx3, cy3);
Point point4 = new Point(cx4, cy4);
Point point5 = new Point(cx5, cy5);
Point[] Points = { point5, point3, point1,point2,point4 };
g.DrawCurve(aPen, Points);
Maybe I misunderstand you, but it sounds like you want to make your GDI+ graphics scale with the window size (i.e. you want to scale the X and Y axis with the size of the window), right?
This is pretty simple, you just have to decide how big of a space you want to present in the window -- i.e. if you want to make the axis go from 0,0 on the top left, to 512x512 on the bottom right, then you would just need to scale the X axis by a factor of 512/width, and the Y axis by a factor of 512/height.
So you would do that by performing a ScaleTransform on your Graphics object. You'll need to use your Form's ClientSize to get the width and height. (The regular Form's .Width, and .Height properties, include all the borders and title bars, padding pixels, etc. -- so it's no good for this calculation.)
Then you will need to force an Invalidation during the form's Resize event (it will work without this, when you make the window smaller, but when you make it bigger, this will be required, or else it will only redraw the edges).
Another thing worth considering is turning on the form's DoubleBuffered property, the redraw will be much smoother.
So, let's assume you want to work in a virtual space of 512x512 "pixels" where 0 ,0 is always the top left, and 512,512 is the bottom right. You could add this code to the top of your OnPaint event handler:
float scaleX = 512f / ((float)this.ClientSize.Width);
float scaleY = 512f / ((float)this.ClientSize.Height);
e.Graphics.ScaleTransform(scaleX, scaleY);
Then add a handler for the Form's Resize event and add something like this:
this.Invalidate(true);
That should do the trick.
This question already has answers here:
Rotating a point about another point (2D)
(6 answers)
Closed 9 years ago.
I have list of points containing x and y locations of a page. I want to apply rotation on all these points relative to any pivot point of page (currently lets assume its center).
var points = new List<Point>();
points.Add(1,1);
points.Add(15,18);
points.Add(25,2);
points.Add(160,175);
points.Add(150,97);
const int pageHeight = 300;
const int pageWidth = 400;
var pivotPoint = new Point(200, 150); //Center
var angle = 45; // its in degree.
// Apply rotation.
Do I need some formula here?
public static Point Rotate(Point point, Point pivot, double angleDegree)
{
double angle = angleDegree * Math.PI / 180;
double cos = Math.Cos(angle);
double sin = Math.Sin(angle);
int dx = point.X - pivot.X;
int dy = point.Y - pivot.Y;
double x = cos * dx - sin * dy + pivot.X;
double y = sin * dx + cos * dy + pivot.X;
Point rotated = new Point((int)Math.Round(x), (int)Math.Round(y));
return rotated;
}
static void Main(string[] args)
{
Console.WriteLine(Rotate(new Point(1, 1), new Point(0, 0), 45));
}
If you have a large number of points to rotate, you might want to precompute the rotation matrix…
[C -S U]
[S C V]
[0 0 1]
…where…
C = cos(θ)
S = sin(θ)
U = (1 - C) * pivot.x + S * pivot.y
V = (1 - C) * pivot.y - S * pivot.x
You then rotate each point as follows:
rotated.x = C * original.x - S * original.y + U;
rotated.x = S * original.x + C * original.y + V;
The above formula is the result of combining three transforms…
rotated = translate(pivot) * rotate(θ) * translate(-pivot) * original
…where…
translate([x y]) = [1 0 x]
[0 1 y]
[0 0 1]
rotate(θ) = [cos(θ) -sin(θ) 0]
[sin(θ) cos(θ) 0]
[ 0 0 1]
if u rotate a point(x,y) around point (x1,y1) by an angle some a then you need a formula...
x2 = cos(a) * (x-x1) - sin(a) * (y-y1) + x1
y2 = sin(a) * (x-x1) + cos(a) * (y-y1) + y1
Point newRotatedPoint = new Point(x2,y2)
I need to make circle with bar.
Here is my image when someone will still not understand:
Does any existing control work? Or should I create a new control somehow? I used a new control with circle filled with gradient but it isn't the same effect :(
I also tried to draw a circle but when I do in my math cycle with sin and cos it does something what I do not want.
double slice = 2 * Math.PI / 360;
for (int i = 0; i < 360; i++)
{
double angle = slice * i;
int x = (int)(0 + 300 * Math.Cos(angle)); // start x + radius * ...
int y = (int)(0 + 300 * Math.Sin(angle));
Line line = new Line()
{
X1 = 0,
Y1 = 0,
X2 = x,
Y2 = y,
Stroke = new SolidColorBrush(Colors.Red),
StrokeThickness = 1.0
};
canvas.Children.Add(line);
}
EDIT: Metro = Xaml!!!
I have this formula for simple circle collision detection:
private bool CircleCollision(Rectangle Circle1, Rectangle Circle2)
{
int X1 = Circle1.Left;
int Y1 = Circle1.Top;
int X2 = Circle2.Left;
int Y2 = Circle2.Top;
int R1 = Circle1.Width / 2;
int R2 = Circle2.Width / 2;
int Radius = R1 + R2;
int dX = X2 - X1;
int dY = Y2 - Y1;
if (Math.Sqrt((dX * dX) + (dY * dY)) <= Math.Sqrt(Radius * Radius))
return true;
else
return false;
}
But it just expose detection whenever the two circles have same radius. What am I doing wrong?
Solved
int X1 = Circle1.Left + (Circle1.Width / 2);
int Y1 = Circle1.Top + (Circle1.Height / 2);
int X2 = Circle2.Left + (Circle2.Width / 2);
int Y2 = Circle2.Top + (Circle2.Height / 2);
To check if two circles overlap you can do:
var radius=circle1.Radius+circle2.Radius;
var deltaX=circle1.CenterX-circle2.CenterX;
var deltaY=circle1.CenterY-circle2.CenterY;
return deltaX*deltaX + deltaY*deltaY <= radius*radius;
Note that I'm calculating the distance of the centers, not of the top left corners. I'm also comparing with the squared radius so I don't need to use the expensive Math.Sqrt function, but that doesn't affect correctness.
Your code doesn't work because you use Left and Top instead of the position of the center. The difference between the top-left corners is the same as the difference between the centers if the radius is the same. This explains why your code only works in that special case.
Not sure why you use a rectangle to represent a circle. You can calculate the center as centerX = 0.5*(Left+Right). You should also add a check that Width==Height, else you might get an ellipse as parameter, and then this algorithm won't work.