Rotating a PictureBox is cropping the Image - c#

I have problem that image is getting cropped when I execute a function there are images which rotation do and my code:
I copied this code from StackOverflow and searched for this quite a long time, so some help would be good I don't know why is cutting the image at every rotation.
public static Bitmap RotateImage(Image image, float rotateAtX, float rotateAtY, float angle, bool bNoClip)
{
int W, H, X, Y;
if (bNoClip)
{
double dW = (double)image.Width;
double dH = (double)image.Height;
double degrees = Math.Abs(angle);
if (degrees <= 90)
{
double radians = 0.0174532925 * degrees;
double dSin = Math.Sin(radians);
double dCos = Math.Cos(radians);
W = (int)(dH * dSin + dW * dCos);
H = (int)(dW * dSin + dH * dCos);
X = (W - image.Width) / 2;
Y = (H - image.Height) / 2;
}
else
{
degrees -= 90;
double radians = 0.0174532925 * degrees;
double dSin = Math.Sin(radians);
double dCos = Math.Cos(radians);
W = (int)(dW * dSin + dH * dCos);
H = (int)(dH * dSin + dW * dCos);
X = (W - image.Width) / 2;
Y = (H - image.Height) / 2;
}
}
else
{
W = image.Width;
H = image.Height;
X = 0;
Y = 0;
}
//create a new empty bitmap to hold rotated image
Bitmap bmpRet = new Bitmap(W, H);
bmpRet.SetResolution(image.HorizontalResolution, image.VerticalResolution);
//make a graphics object from the empty bitmap
Graphics g = Graphics.FromImage(bmpRet);
//Put the rotation point in the "center" of the image
g.TranslateTransform(rotateAtX + X, rotateAtY + Y);
//rotate the image
g.RotateTransform(angle);
//move the image back
g.TranslateTransform(-rotateAtX - X, -rotateAtY - Y);
//draw passed in image onto graphics object
g.DrawImage(image, new PointF(0 + X, 0 + Y));
return bmpRet;
}
public static Bitmap RotateImage(Image image, float angle)
{
// center of the image
float rotateAtX = image.Width / 2;
float rotateAtY = image.Height / 2;
bool bNoClip = false;
return RotateImage(image, rotateAtX, rotateAtY, angle, bNoClip);
}
public static Bitmap RotateImage(Image image, float angle, bool bNoClip)
{
// center of the image
float rotateAtX = image.Width / 2;
float rotateAtY = image.Height / 2;
return RotateImage(image, rotateAtX, rotateAtY, angle, bNoClip);
}
private void DOWN_Click(object sender, EventArgs e)
{
locomotive.Image = RotateImage(locomotive.Image, 35);
}

Related

Finding the new coordinate of a pixel in an image rotated by center

I have an image on which I choose a random point. The image is rotated by any degree the user wishes. The goal here is to find the new coordinate of the pixel. I have tried it this way with the function RotatePoint where the original position of the pixel was (100, 370) and the image gets rotated by 270 degrees, but the new coordinate is not correct. How would I be able to get the correct new coordinate?
static public void RotatePoint(float angle)
{
var a = angle * System.Math.PI / 180.0;
float cosa = (float)Math.Cos(a), sina = (float)Math.Sin(a);
float x = 100 * cosa - 370 * sina;
float y = 100 * sina + 370 * cosa;
Console.WriteLine(x);
Console.WriteLine(y);
}
private static Bitmap RotateImage(Bitmap bmp, float angle)
{
Bitmap rotatedImage = new Bitmap(bmp.Width, bmp.Height);
rotatedImage.SetResolution(bmp.HorizontalResolution, bmp.VerticalResolution);
using (Graphics g = Graphics.FromImage(rotatedImage))
{
// Set the rotation point to the center in the matrix
g.TranslateTransform(bmp.Width / 2, bmp.Height / 2);
// Rotate
g.RotateTransform(angle);
// Restore rotation point in the matrix
g.TranslateTransform(-bmp.Width / 2, -bmp.Height / 2);
// Draw the image on the bitmap
g.DrawImage(bmp, new Point(0, 0));
}
return rotatedImage;
}
You perform 2 translation transformations on your image that you don't take into account into your coordinate calculations:
// Set the rotation point to the center in the matrix
g.TranslateTransform(bmp.Width / 2, bmp.Height / 2);
and
// Restore rotation point in the matrix
g.TranslateTransform(-bmp.Width / 2, -bmp.Height / 2);
Here is a fix, with both translations taken into account, where xRotationCenter and yRotationCenter should be your bitmap width and height:
public static void RotatePoint(float x = 100, float y = 377, float xRotationCenter, float yRotationCenter, float angleInDegree)
{
var angleInRadiant = (angleInDegree / 180.0) * Math.PI;
var cosa = (float)Math.Cos(angleInRadiant);
var sina = (float)Math.Sin(angleInRadiant);
// First translation
float t1x = x - xRotationCenter;
float t1y = y - yRotationCenter;
// Rotation
float rx = t1x * cosa - t1y * sina;
float ry = t1x * sina + t1y * cosa;
// seconde translation
float x = rx + xRotationCenter;
float y = ry + yRotationCenter;
Console.WriteLine(x);
Console.WriteLine(y);
}

Drawing y = sin(θ) * cos(θ) in C# with a Pen

I want to draw sin(θ)*cos(θ), but it doesn't work.
I can draw sin or cos,
but I want to draw sin(θ)*cos(θ) together.
Here is my code
private void button1_Click(object sender, EventArgs e)
{
Graphics drw = this.CreateGraphics();
Pen pen = new Pen(Brushes.Black, 7.0f);
float x1 = 0;
float y1 = 0;
float xoy = 200;
float ef = 20;
for (double i=0;i<40;i+=1)
{
double radi = (float)(i * 180 / Math.PI);
float temp = (float)Math.Cos(radi)*(float)Math.Sin(radi);
drw.DrawLine(pen, x1 * ef, y1 * ef + xoy, ef * (float)i, temp * ef + xoy);
x1 = (float)i;
y1 = temp;
}
}
And I want this result:
You may find it easier to look at the corresponding Parametric Equations.
private void Form1_Paint(object sender, PaintEventArgs e)
{
var g = e.Graphics;
double pi = Math.PI;
int n = 100;
var t = Enumerable.Range(0, n).Select(p => p * 2 * pi / n).ToArray();
var x = t.Select(p => Math.Sin(2 * p) * Math.Cos(p)).ToArray();
var y = t.Select(p => Math.Sin(2 * p) * Math.Sin(p)).ToArray();
Pen pen = new Pen(Brushes.Black, 3);
int scale = 100;
int shift = 100;
for (int i = 0; i < n - 1; i++)
{
g.DrawLine(pen, scale*(float)x[i] + shift,
scale*(float)y[i] + shift,
scale*(float)x[i + 1] + shift,
scale*(float)y[i + 1] + shift);
}
}
Actually, the real function you are looking for is a little bit different... see an example here. Looking at this article about polar flowers, I'm sure it will get pointed to the right direction, and it also contains a full working source code.
Just an example, supposing you use a panel in your form on which to draw the polar flower:
panel.OnPaint += Panel_Paint;
private void Panel_Paint(Object sender, PaintEventArgs e)
{
Double scale = ((Panel)sender).Width / 2.0d;
Double repetitions = Math.Round(scale, 0);
Double basis = (2.0d * Math.PI) / scale;
Double petals = 2.0d;
using (Graphics g = e.Graphics)
{
using (Pen pen = new Pen(Brushes.Red, 2.0f))
{
for (Double i = 0.0f; i < (repetitions - 1); ++i)
{
Double t0 = i*basis;
Double t1 = (i + 1)*basis;
Double x0 = Math.Sin(petals * t0) * Math.Cos(t0);
Double x1 = Math.Sin(petals * t1) * Math.Cos(t1);
Double y0 = Math.Sin(petals * t0) * Math.Sin(t0);
Double y1 = Math.Sin(petals * t1) * Math.Sin(t1);
g.DrawLine
(
pen,
(Single) ((scale*x0) + scale),
(Single) ((scale*y0) + scale),
(Single) ((scale*x1) + scale),
(Single) ((scale*y1) + scale)
);
}
}
}
}
The basic formulation states that if the petals variable value is:
even, then it represents half the amount of petals of the polar flower
odd, then it represents the amount of petals of the polar flower
so if you define Double petals = 2.0d;, you will obtain 4 petals... and if you define Double petals = 5.0d;, you will obtain 5 petals.

Going from a cube to a pyramid in visual studio using C#?

Hey everyone im trying to figure out how to make a 3D pyramid out of existing code that is already a 3D cube in visual studio by changing some of the code. I've been messing around with the verts as my friend suggested but I am still unsuccessful. Here is the code..
// ================================================
// | Downloaded From |
// | Visual C# Kicks - http://www.vcskicks.com/ |
// ================================================
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
namespace EulerRotation
{
public partial class Form1 : Form
{
Cube cube;
public Form1()
{
InitializeComponent();
}
private void btnReset_Click(object sender, EventArgs e)
{
tX.Value = 0;
tY.Value = 0;
tZ.Value = 0;
render();
}
private void Form1_Load(object sender, EventArgs e)
{
cube = new Cube(100);
render();
}
private void render()
{
//Set the rotation values
cube.RotateX = tX.Value;
cube.RotateY = tY.Value;
cube.RotateZ = tZ.Value;
//Cube is positioned based on center
Point origin = new Point(picCube.Width / 2, picCube.Height / 2);
picCube.Image = cube.drawCube(origin);
}
private void tX_Scroll(object sender, EventArgs e)
{
render();
}
private void tY_Scroll(object sender, EventArgs e)
{
render();
}
private void tZ_Scroll(object sender, EventArgs e)
{
render();
}
}
internal class Math3D
{
public class Point3D
{
//The Point3D class is rather simple, just keeps track of X Y and Z values,
//and being a class it can be adjusted to be comparable
public double X;
public double Y;
public double Z;
public Point3D(int x, int y, int z)
{
X = x;
Y = y;
Z = z;
}
public Point3D(float x, float y, float z)
{
X = (double)x;
Y = (double)y;
Z = (double)z;
}
public Point3D(double x, double y, double z)
{
X = x;
Y = y;
Z = z;
}
public Point3D()
{
}
public override string ToString()
{
return "(" + X.ToString() + ", " + Y.ToString() + ", " + Z.ToString() + ")";
}
}
public class Camera
{
//For 3D drawing we need a point of perspective, thus the Camera
public Point3D Position = new Point3D();
}
public static Point3D RotateX(Point3D point3D, double degrees)
{
//Here we use Euler's matrix formula for rotating a 3D point x degrees around the x-axis
//[ a b c ] [ x ] [ x*a + y*b + z*c ]
//[ d e f ] [ y ] = [ x*d + y*e + z*f ]
//[ g h i ] [ z ] [ x*g + y*h + z*i ]
//[ 1 0 0 ]
//[ 0 cos(x) sin(x)]
//[ 0 -sin(x) cos(x)]
double cDegrees = (Math.PI * degrees) / 180.0f; //Convert degrees to radian for .Net Cos/Sin functions
double cosDegrees = Math.Cos(cDegrees);
double sinDegrees = Math.Sin(cDegrees);
double y = (point3D.Y * cosDegrees) + (point3D.Z * sinDegrees);
double z = (point3D.Y * -sinDegrees) + (point3D.Z * cosDegrees);
return new Point3D(point3D.X, y, z);
}
public static Point3D RotateY(Point3D point3D, double degrees)
{
//Y-axis
//[ cos(x) 0 sin(x)]
//[ 0 1 0 ]
//[-sin(x) 0 cos(x)]
double cDegrees = (Math.PI * degrees) / 180.0; //Radians
double cosDegrees = Math.Cos(cDegrees);
double sinDegrees = Math.Sin(cDegrees);
double x = (point3D.X * cosDegrees) + (point3D.Z * sinDegrees);
double z = (point3D.X * -sinDegrees) + (point3D.Z * cosDegrees);
return new Point3D(x, point3D.Y, z);
}
public static Point3D RotateZ(Point3D point3D, double degrees)
{
//Z-axis
//[ cos(x) sin(x) 0]
//[ -sin(x) cos(x) 0]
//[ 0 0 1]
double cDegrees = (Math.PI * degrees) / 180.0; //Radians
double cosDegrees = Math.Cos(cDegrees);
double sinDegrees = Math.Sin(cDegrees);
double x = (point3D.X * cosDegrees) + (point3D.Y * sinDegrees);
double y = (point3D.X * -sinDegrees) + (point3D.Y * cosDegrees);
return new Point3D(x, y, point3D.Z);
}
public static Point3D Translate(Point3D points3D, Point3D oldOrigin, Point3D newOrigin)
{
//Moves a 3D point based on a moved reference point
Point3D difference = new Point3D(newOrigin.X - oldOrigin.X, newOrigin.Y - oldOrigin.Y, newOrigin.Z - oldOrigin.Z);
points3D.X += difference.X;
points3D.Y += difference.Y;
points3D.Z += difference.Z;
return points3D;
}
//These are to make the above functions workable with arrays of 3D points
public static Point3D[] RotateX(Point3D[] points3D, double degrees)
{
for (int i = 0; i < points3D.Length; i++)
{
points3D[i] = RotateX(points3D[i], degrees);
}
return points3D;
}
public static Point3D[] RotateY(Point3D[] points3D, double degrees)
{
for (int i = 0; i < points3D.Length; i++)
{
points3D[i] = RotateY(points3D[i], degrees);
}
return points3D;
}
public static Point3D[] RotateZ(Point3D[] points3D, double degrees)
{
for (int i = 0; i < points3D.Length; i++)
{
points3D[i] = RotateZ(points3D[i], degrees);
}
return points3D;
}
public static Point3D[] Translate(Point3D[] points3D, Point3D oldOrigin, Point3D newOrigin)
{
for (int i = 0; i < points3D.Length; i++)
{
points3D[i] = Translate(points3D[i], oldOrigin, newOrigin);
}
return points3D;
}
}
internal class Cube
{
//Example cube class to demonstrate the use of 3D points and 3D rotation
public int width = 0;
public int height = 0;
public int depth = 0;
double xRotation = 0.0;
double yRotation = 0.0;
double zRotation = 0.0;
Math3D.Camera camera1 = new Math3D.Camera();
Math3D.Point3D cubeOrigin;
public double RotateX
{
get { return xRotation; }
set { xRotation = value; }
}
public double RotateY
{
get { return yRotation; }
set { yRotation = value; }
}
public double RotateZ
{
get { return zRotation; }
set { zRotation = value; }
}
public Cube(int side)
{
width = side;
height = side;
depth = side;
cubeOrigin = new Math3D.Point3D(width / 2, height / 2, depth / 2);
}
public Cube(int side, Math3D.Point3D origin)
{
width = side;
height = side;
depth = side;
cubeOrigin = origin;
}
public Cube(int Width, int Height, int Depth)
{
width = Width;
height = Height;
depth = Depth;
cubeOrigin = new Math3D.Point3D(width / 2, height / 2, depth / 2);
}
public Cube(int Width, int Height, int Depth, Math3D.Point3D origin)
{
width = Width;
height = Height;
depth = Depth;
cubeOrigin = origin;
}
//Finds the othermost points. Used so when the cube is drawn on a bitmap,
//the bitmap will be the correct size
public static Rectangle getBounds(PointF[] points)
{
double left = points[0].X;
double right = points[0].X;
double top = points[0].Y;
double bottom = points[0].Y;
for (int i = 1; i < points.Length; i++)
{
if (points[i].X < left)
left = points[i].X;
if (points[i].X > right)
right = points[i].X;
if (points[i].Y < top)
top = points[i].Y;
if (points[i].Y > bottom)
bottom = points[i].Y;
}
return new Rectangle(0, 0, (int)Math.Round(right - left), (int)Math.Round(bottom - top));
}
public Bitmap drawCube(Point drawOrigin)
{
//FRONT FACE
//Top Left - 7
//Top Right - 4
//Bottom Left - 6
//Bottom Right - 5
//Vars
PointF[] point3D = new PointF[24]; //Will be actual 2D drawing points
Point tmpOrigin = new Point(0, 0);
Math3D.Point3D point0 = new Math3D.Point3D(0, 0, 0); //Used for reference
//Zoom factor is set with the monitor width to keep the cube from being distorted
double zoom = (double)Screen.PrimaryScreen.Bounds.Width / 1.5;
//Set up the cube
Math3D.Point3D[] cubePoints = fillCubeVertices(width, height, depth);
//Calculate the camera Z position to stay constant despite rotation
Math3D.Point3D anchorPoint = (Math3D.Point3D)cubePoints[4]; //anchor point
double cameraZ = -(((anchorPoint.X - cubeOrigin.X) * zoom) / cubeOrigin.X) + anchorPoint.Z;
camera1.Position = new Math3D.Point3D(cubeOrigin.X, cubeOrigin.Y, cameraZ);
//Apply Rotations, moving the cube to a corner then back to middle
cubePoints = Math3D.Translate(cubePoints, cubeOrigin, point0);
cubePoints = Math3D.RotateX(cubePoints, xRotation); //The order of these
cubePoints = Math3D.RotateY(cubePoints, yRotation); //rotations is the source
cubePoints = Math3D.RotateZ(cubePoints, zRotation); //of Gimbal Lock
cubePoints = Math3D.Translate(cubePoints, point0, cubeOrigin);
//Convert 3D Points to 2D
Math3D.Point3D vec;
for (int i = 0; i < point3D.Length; i++)
{
vec = cubePoints[i];
if (vec.Z - camera1.Position.Z >= 0)
{
point3D[i].X = (int)((double)-(vec.X - camera1.Position.X) / (-0.1f) * zoom) + drawOrigin.X;
point3D[i].Y = (int)((double)(vec.Y - camera1.Position.Y) / (-0.1f) * zoom) + drawOrigin.Y;
}
else
{
tmpOrigin.X = (int)((double)(cubeOrigin.X - camera1.Position.X) / (double)(cubeOrigin.Z - camera1.Position.Z) * zoom) + drawOrigin.X;
tmpOrigin.Y = (int)((double)-(cubeOrigin.Y - camera1.Position.Y) / (double)(cubeOrigin.Z - camera1.Position.Z) * zoom) + drawOrigin.Y;
point3D[i].X = (float)((vec.X - camera1.Position.X) / (vec.Z - camera1.Position.Z) * zoom + drawOrigin.X);
point3D[i].Y = (float)(-(vec.Y - camera1.Position.Y) / (vec.Z - camera1.Position.Z) * zoom + drawOrigin.Y);
point3D[i].X = (int)point3D[i].X;
point3D[i].Y = (int)point3D[i].Y;
}
}
//Now to plot out the points
Rectangle bounds = getBounds(point3D);
bounds.Width += drawOrigin.X;
bounds.Height += drawOrigin.Y;
Bitmap tmpBmp = new Bitmap(bounds.Width, bounds.Height);
Graphics g = Graphics.FromImage(tmpBmp);
//Back Face
g.DrawLine(Pens.Black, point3D[0], point3D[1]);
g.DrawLine(Pens.Black, point3D[1], point3D[2]);
g.DrawLine(Pens.Black, point3D[2], point3D[3]);
g.DrawLine(Pens.Black, point3D[3], point3D[0]);
//Front Face
g.DrawLine(Pens.Black, point3D[4], point3D[5]);
g.DrawLine(Pens.Black, point3D[5], point3D[6]);
g.DrawLine(Pens.Black, point3D[6], point3D[7]);
g.DrawLine(Pens.Black, point3D[7], point3D[4]);
//Right Face
g.DrawLine(Pens.Black, point3D[8], point3D[9]);
g.DrawLine(Pens.Black, point3D[9], point3D[10]);
g.DrawLine(Pens.Black, point3D[10], point3D[11]);
g.DrawLine(Pens.Black, point3D[11], point3D[8]);
//Left Face
g.DrawLine(Pens.Black, point3D[12], point3D[13]);
g.DrawLine(Pens.Black, point3D[13], point3D[14]);
g.DrawLine(Pens.Black, point3D[14], point3D[15]);
g.DrawLine(Pens.Black, point3D[15], point3D[12]);
//Bottom Face
g.DrawLine(Pens.Black, point3D[16], point3D[17]);
g.DrawLine(Pens.Black, point3D[17], point3D[18]);
g.DrawLine(Pens.Black, point3D[18], point3D[19]);
g.DrawLine(Pens.Black, point3D[19], point3D[16]);
//Top Face
g.DrawLine(Pens.Black, point3D[20], point3D[21]);
g.DrawLine(Pens.Black, point3D[21], point3D[22]);
g.DrawLine(Pens.Black, point3D[22], point3D[23]);
g.DrawLine(Pens.Black, point3D[23], point3D[20]);
g.Dispose(); //Clean-up
return tmpBmp;
}
public static Math3D.Point3D[] fillCubeVertices(int width, int height, int depth)
{
Math3D.Point3D[] verts = new Math3D.Point3D[24];
//front face
verts[0] = new Math3D.Point3D(0, 0, 0);
verts[1] = new Math3D.Point3D(0, height, 0);
verts[2] = new Math3D.Point3D(width, height, 0);
verts[3] = new Math3D.Point3D(width, 0, 0);
//back face
verts[4] = new Math3D.Point3D(0, 0, depth);
verts[5] = new Math3D.Point3D(0, height, depth);
verts[6] = new Math3D.Point3D(width, height, depth);
verts[7] = new Math3D.Point3D(width, 0, depth);
//left face
verts[8] = new Math3D.Point3D(0, 0, 0);
verts[9] = new Math3D.Point3D(0, 0, depth);
verts[10] = new Math3D.Point3D(0, height, depth);
verts[11] = new Math3D.Point3D(0, height, 0);
//right face
verts[12] = new Math3D.Point3D(width, 0, 0);
verts[13] = new Math3D.Point3D(width, 0, depth);
verts[14] = new Math3D.Point3D(width, height, depth);
verts[15] = new Math3D.Point3D(width, height, 0);
//top face
verts[16] = new Math3D.Point3D(0, height, 0);
verts[17] = new Math3D.Point3D(0, height, depth);
verts[18] = new Math3D.Point3D(width, height, depth);
verts[19] = new Math3D.Point3D(width, height, 0);
//bottom face
verts[20] = new Math3D.Point3D(0, 0, 0);
verts[21] = new Math3D.Point3D(0, 0, depth);
verts[22] = new Math3D.Point3D(width, 0, depth);
verts[23] = new Math3D.Point3D(width, 0, 0);
return verts;
}
}
}
Right now when I run this code in visual studio 2015 it creates a 3D cube but how do i modify it to where I can get a pyramid?

Display GPS coordinates in a canvas

I'm trying to display GPS coordinates in a canvas.
I have 400 towns in France + USA. I just want to display them in a canvas.
For each town I have its latitude and longitude (taken with google api : https://developers.google.com/maps/documentation/geocoding/ ).
I've managed to have a first result using this thread : Converting from longitude\latitude to Cartesian coordinates
Here is my result :
My code is the following (assuming "_liste" contains a list of Towns) :
private void Button_visualise_Click(object sender, RoutedEventArgs e)
{
System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
watch.Start();
List<Town> _list = LibDAO.Towns_DAO.GetAllTown().Where(u=>u.IdPays == 2 || u.IdPays == 1).ToList<Town>();
this.my_canvas.Children.Clear();
double min_x = 0;
double max_x = 0;
double min_y = 0;
double max_y = 0;
for (int i = 0; i < _list .Count; i++)
{
Ellipse ell = new Ellipse() { Width = 30, Height = 30, Fill = Brushes.Blue };
Point p = ToCanvas(_list [i].Latitude, _list [i].Longitude);
Canvas.SetLeft(ell, p.X);
Canvas.SetTop(ell, p.Y);
if (p.X < min_x) min_x = p.X;
if (p.X > max_x) max_x = p.X;
if (p.Y < min_y) min_y = p.Y;
if (p.Y > max_y) max_y = p.Y;
this.my_canvas.Children.Add(ell);
}
SetCoordinateSystem(this.my_canvas, min_x, max_x, min_y, max_y);
watch.Stop();
}
public static Canvas SetCoordinateSystem(Canvas canvas, Double xMin, Double xMax, Double yMin, Double yMax)
{
var width = xMax - xMin;
var height = yMax - yMin;
var translateX = -xMin;
var translateY = height + yMin;
var group = new TransformGroup();
group.Children.Add(new TranslateTransform(translateX, -translateY));
group.Children.Add(new ScaleTransform(canvas.ActualWidth / width, canvas.ActualHeight / -height));
canvas.RenderTransform = group;
return canvas;
}
private const int earthRadius = 6367;
private Point ToCanvas(double lat, double lon)
{
lon = ConvertToRadians(lon);
lat = ConvertToRadians(lat);
double x = earthRadius * Math.Cos(lat) * Math.Cos(lon); //((lon * my_canvas.ActualWidth) / 360.0) - 180.0; ;// //
double y = earthRadius * Math.Cos(lat) * Math.Sin(lon);// ((lat * my_canvas.ActualHeight) / 180.0) - 90.0;
return new Point(x, y);
}
public double ConvertToRadians(double angle)
{
return (Math.PI / 180) * angle;
}
As you can see in my result it's almost perfect, we can recognize the 2 countries but why are they in the wrong place ? (I would like to have them like this : http://geology.com/world/world-map.gif
Am I missing something ?
Based on this link, my result may be displayed with "Azimuthal (projections onto a plane)" while I would prefer this : http://en.wikipedia.org/wiki/Equirectangular_projection
So I'm thinking of changing my function "ToCanvas" but I don't know the component "the standard parallels (north and south of the equator) where the scale of the projection is true;"
Bonus question : What's the best way to get the border from a country in GPS coordinates ? I would like to draw the border of USA for example, so I guessed I could just get coordinates of borders to draw the country.
I've tried several websites, managed to get a .shp file from there : http://www.naturalearthdata.com/downloads/110m-cultural-vectors/, but I didn't manage to retrieve borders coordinates from there.
Thank you
EDIT Seems better with this code :
private Point ToCanvas(double lat, double lon)
{
// Equirectangular projection
double x1 = lon * Math.Cos(ConvertToRadians(lat));
double y1 = lat;
//lon = ConvertToRadians(lon);
//lat = ConvertToRadians(lat);
//double x = earthRadius * Math.Cos(lat) * Math.Cos(lon); //((lon * my_canvas.ActualWidth) / 360.0) - 180.0; ;// //
//double y = earthRadius * Math.Cos(lat) * Math.Sin(lon);// ((lat * my_canvas.ActualHeight) / 180.0) - 90.0;
return new Point(x1 * 10, y1 * 10);
}

Defining Regions for Venn Diagram using Graphics Regions

I have created a Venn diagram using simple Graphics functions provided by WinForm in the onPaint event. Here is my code for creating the Venn.
using (Brush brushLeft = new SolidBrush(LeftVennColor))
{
leftvennPath.AddEllipse(leftVenn);
leftOnlyRegion = new Region(leftVenn);
e.Graphics.FillEllipse(brushLeft, leftVenn);
e.Graphics.DrawEllipse(pen, leftVenn);
}
using (Brush brushRight = new SolidBrush(RightVennColor))
{
rightvennPath.AddEllipse(rightVenn);
rightOnlyRegion = new Region(rightVenn);
e.Graphics.FillEllipse(brushRight, rightVenn);
e.Graphics.DrawEllipse(pen, rightVenn);
}
using (GraphicsPath circle_path = new GraphicsPath())
{
circle_path.AddEllipse(leftVenn);
commonRegion.Intersect(circle_path);
}
using (GraphicsPath circle_path = new GraphicsPath())
{
circle_path.AddEllipse(rightVenn);
commonRegion.Intersect(circle_path);
}
The Venn diagram is created, but with this code my common region is the intersection of both left and right ellipses. I want to have two separate regions out of that common area, which is separated by a line. Here is the image for that,
So basically, I need all these four regions separated and clickable ( different colors for each region ).. I use Region.IsVisible(e.location) in the mouse click event to handle the click event. Could someone please help?
Final solution:
cx0, cy0, radius0 center and radius of left circle
cx1, cy1, radius1 center and radius of right circle
The function takes the regions by ref.
private void FindRegions(int cx0, int cx1, int cy0, int cy1, int radius0, int radius1, ref Region rgnLeft, ref Region rgnRight)
{
//Left circle
GraphicsPath gpL = new GraphicsPath();
//Right circle
GraphicsPath gpR = new GraphicsPath();
//The right small region (yellow color)
GraphicsPath gp = new GraphicsPath();
//Points of intersection
PointF pnt1 = new PointF();
PointF pnt2 = new PointF();
Graphics g = this.CreateGraphics();
gpL.AddEllipse(new Rectangle(cx0 - radius0, cy0 - radius0, 2 * radius0, 2 * radius0));
gpR.AddEllipse(new Rectangle(cx1 - radius0, cy1 - radius1, 2 * radius1, 2 * radius1));
g.DrawPath(Pens.Red, gpL);
g.DrawPath(Pens.Blue, gpR);
int numPoints = FindCircleCircleIntersections((single)cx0, (single)cx1, (single)cy0, (single)cy1, (single)radius0, (single)radius1, ref pnt1, ref pnt2);
if (numPoints != 2)
{
//No regions
return;
}
Double theta, fe;
Double dx = (double)pnt1.X - (double)pnt2.X;
Double dy = (double)pnt1.Y - (double)pnt2.Y;
Double dist = Math.Sqrt(dx * dx + dy * dy);
PointF minPoint, maxPoint;
if (pnt2.Y < pnt1.Y)
{
minPoint = pnt2;
maxPoint = pnt1;
}
else
{
minPoint = pnt1;
maxPoint = pnt2;
}
//theta is the angle between the three points pnt1, pnt2 and left center
theta = Math.Acos((dist / 2D) / 100D);
theta = (theta * 180D) / Math.PI;
theta = 90D - theta;
theta *= 2D;
//fe is the starting angle of the point(between pnt1 and pnt2) with
//the smaller y coordinate. The angle is measured from x axis and clockwise
fe = Math.Asin( Math .Abs ( (-(Double)minPoint.Y + (double)cy0) )/ (double)radius0);
fe = (fe * 180D) / Math.PI;
if (minPoint.X > cx0 && minPoint.Y >= cy0)
{
//fe = (90 - fe) + 270;
}
else if (minPoint.X > cx0 && minPoint.Y < cy0)
{
fe = (90D - fe) + 270D;
}
else if (minPoint.X == cx0 && minPoint.Y < cy0)
{
fe = 270D;
}
else
{
fe += 180D;
}
gp.AddArc(new Rectangle(cx0 - radius0, cy0 - radius0, 2 * radius0, 2 * radius0), (float)fe, (float)theta);
gp.AddLine(maxPoint, minPoint);
gp.CloseFigure();
g.DrawPath(Pens.Green, gp);
Region rgnL = new Region(gpL);
Region rgnR = new Region(gpR);
Region rgnInt = new Region(gpL);
Region rgn = new Region(gp); //right small
rgnInt.Intersect(rgnR);
rgnInt.Exclude(rgn); //left small
g.FillRegion(Brushes.DarkGreen, rgnInt);
g.FillRegion(Brushes.DarkGray, rgn);
rgnLeft = rgnInt.Clone();
rgnRight = rgn.Clone();
g.Dispose();
rgnL.Dispose();
rgnR.Dispose();
rgnInt.Dispose();
rgn.Dispose();
gpL.Dispose();
gpR.Dispose();
gp.Dispose();
}
private int FindCircleCircleIntersections(Single cx0, Single cx1, Single cy0, Single cy1, Single radius0, Single radius1,
ref PointF intersection1, ref PointF intersection2)
{
// Find the distance between the centers.
Single dx = cx0 - cx1;
Single dy = cy0 - cy1;
Double dist = Math.Sqrt(dx * dx + dy * dy);
// See how many solutions there are.
if (dist > radius0 + radius1)
{
//No solutions, the circles are too far apart.
intersection1 = new PointF(Single.NaN, Single.NaN);
intersection2 = new PointF(Single.NaN, Single.NaN);
return 0;
}
else if (dist < Math.Abs(radius0 - radius1))
{
// No solutions, one circle contains the other.
intersection1 = new PointF(Single.NaN, Single.NaN);
intersection2 = new PointF(Single.NaN, Single.NaN);
return 0;
}
else if ((dist == 0) && (radius0 == radius1))
{
// No solutions, the circles coincide.
intersection1 = new PointF(Single.NaN, Single.NaN);
intersection2 = new PointF(Single.NaN, Single.NaN);
return 0;
}
else
{
// Find a and h.
Double a = (radius0 * radius0 - radius1 * radius1 + dist * dist) / (2 * dist);
Double h = Math.Sqrt(radius0 * radius0 - a * a);
// Find P2.
Double cx2 = cx0 + a * (cx1 - cx0) / dist;
Double cy2 = cy0 + a * (cy1 - cy0) / dist;
// Get the points P3.
intersection1 = new PointF( (Single)(cx2 + h * (cy1 - cy0) / dist), (Single)(cy2 - h * (cx1 - cx0) / dist));
intersection2 = new PointF( (Single)(cx2 - h * (cy1 - cy0) / dist), (Single)(cy2 + h * (cx1 - cx0) / dist));
// See if we have 1 or 2 solutions.
if (dist == radius0 + radius1) return 1;
return 2;
}
}
EDIT
Region has only a Fill method and no Draw one. So you cant do it with regions. GraphicPath
however HAS both Fill and Draw.
You said that you need to validate if a point is inside the region BUT you can do the same with GraphicPath
myGraphicPath.IsVisible();
So, dont use regions but paths. It is better for another reason. GraphicPath can draw AntiAlias but regions dont. Set
g.SmoothingMode = SmoothingMode.AntiAlias;
To enable AntiAlias. All goodies with paths!
Change the function name from FindRegions to FindPaths and send paths as refference:
private void FindPaths(int cx0, int cx1, int cy0, int cy1, int radius0, int radius1, ref GraphicsPath gpLeft, ref GraphicsPath gpRight)
The code is exactly the same, but add in the and:
private void FindPaths(int cx0, int cx1, int cy0, int cy1, int radius0, int radius1, ref GraphicsPath gpLeft, ref GraphicsPath gpRight)
{
...
...
//Above code exactly the same
//replace these
//rgnLeft = rgnInt.Clone();
//rgnRight = rgn.Clone();
//with these
GraphicsPath gpLeftSmall = (GraphicsPath)gp.Clone();
Matrix matrix = new Matrix();
PointF pntf = new PointF();
pntf.X = (float)(Math.Min((double)pnt1.X, (double)pnt2.X) + Math.Abs((double)(pnt1.X - pnt2.X) / 2D));
pntf.Y = (float)(Math.Min((double)pnt1.Y, (double)pnt2.Y) + Math.Abs((double)(pnt1.Y - pnt2.Y) / 2D));
matrix.RotateAt(180, pntf);
gpLeftSmall.Transform(matrix);
g.DrawPath(Pens.Black, gpLeftSmall); //If you want to draw it
//passed by refference
gpLeft = gpLeftSmall.Clone();
gpRight = gp.Clone();
g.Dispose();
rgnL.Dispose();
rgnR.Dispose();
rgnInt.Dispose();
rgn.Dispose();
gpL.Dispose();
gpR.Dispose();
gp.Dispose();
gpLeftSmall.Dispose();
matrix.Dispose();
}
Reference:
Determine where two circles intersect

Categories