I have a set of geo coordinates as latitude/longitude pairs that I wish to project onto a 2D surface. Some of the coordinates are connected by lines forming a shape/outline/polygon.
I understand how to project individual points using one of the many available map projections like Mercator and then drawing them with Graphics.DrawArc but how do I go about projecting the connecting lines between them? I can't just project the two defining coordinates of a line and draw it Graphics.DrawLine because every single point on that line has to be projected as well, right? I don't know much about these things, so I hope you understand what I mean.
Is it even possible to do what I'm trying to do using just the methods provided by the System.Drawing.Graphics class? Can I do this with a projection matrix? If anyone could explain a bit how I would go about doing this, I would greatly appreciate it. Thanks.
If your are only drawing lines it is probably easiest just to subdivide the lines into short segments, project each segment point and draw straight lines between them. This might not be the most performant or exact way to do it. But it should be fairly easy to implement.
For example:
public static void DrawSubdivided(this Graphics g, Pen pen, Vector2 p1, Vector2 p2, float subdivisionLength)
{
var d = p2 - p1;
var length = d.Length();
// Add check for zero-length lines
var dn = d / length;
var points = new List<Vector2>();
for (float l = 0; l < length; l += subdivisionLength)
{
points.Add( p1 + dn * l);
}
points.Add(p2);
// apply transformation to the points
g.DrawLines(pen, points.Select(p => new PointF(p.X, p.Y)).ToArray());
}
This uses System.Numerics.Vector2 since it has reasonable arithmetic operations defined, in contrast to PointF.
Related
I'm trying to get the corners of the following shape:
By corners I mean this (red dots):
The minimum quantity of points that can define this shape.
And I have implemented the following:
public Shape Optimize()
{
// If the vertices are null or empty this can't be executed
if (vertices.IsNullOrEmpty())
return this; // In this case, return the same instance.
if (!edges.IsNullOrEmpty())
edges = null; //Reset edges, because a recalculation was requested
// The corners available on each iteration
var corners = new Point[] { Point.upperLeft, Point.upperRight, Point.downLeft, Point.downRight };
//The idea is to know if any of the following or previous vertice is inside of the the array from upside, if it is true then we can add it.
Point[] vs = vertices.ToArray();
for (int i = 0; i < vertices.Count - 1; ++i)
{
Point backPos = i > 0 ? vs[i - 1] : vs[vertices.Count - 1],
curPos = vs[i], //Punto actual
nextPos = i < vertices.Count - 1 ? vs[i + 1] : vs[0];
// We get the difference point between the actual point and the back & next point
Point backDiff = backPos - curPos,
nextDiff = nextPos - curPos,
totalDiff = nextPos - backPos;
if (corners.Contains(backDiff) || corners.Contains(nextDiff) || corners.Contains(totalDiff))
AddEdge(curPos, center); // If any of the two points are defined in the corners of the point of before or after it means that the actual vertice is a edge/corner
}
return this;
}
This works rectangled shapes, but rotated shapes are very sharp, so, this code doesn't work well:
Blue pixels (in this photo and the following) are the vertices variable processed on Optimize method.
Green pixels are the detected corners/edges (on both photos).
But sharpness in a shape only defines the side inclination, so what can I do to improve this?
Also, I have tested Accord.NET BaseCornersDetector inherited classes, but the best result is obtained with HarrisCornersDetector, but:
Many edges/corners are innecesary, and they aren't in the needed place (see first photo).
Well, after hours of research I found a library called Simplify.NET that internally runs the Ramer–Douglas–Peucker algorithm.
Also, you maybe interested on the Bresenham algorithm, with this algorithm you can draw a line using two Points.
With this algorithm, you can check if your tolerance is too high, comparing the actual points and the points that this algorithm outputs and making some kind of percentage calculator of similarity.
Finally, is interesting to mention Concave Hull and Convex Hull algorithms.
All this is related to Unity3D.
My outputs:
And my implementation.
It's very important to say, that points needs to be sorted forcing them to be connected. If the shape is concave as you can see on the second photo maybe you need to iterate walls of the shape.
You can see an example of implementation here. Thanks to #Bunny83.
So i'm trying to write a simple 3d-application (for study only).
I want to do shading using Phong. So i'm reading this article and see
Since this can be slow, there are various ways you can speed it up if you don't mind a little loss of freedom. If you assume that the light source is at the same place as the camera, then you can ignore the V and H vectors altogether. Instead take the X and Y components of the normal vector, multiply by 128 and add 127 (assuming that is that the magnitude of the normal vector is 1).
okay, i can do it, but now, what should I do with this X and Y? I have array of triangles, each has calculated normal. I'm calculating this X and Y, but what should i do with? This code works, but not properly, because in this case light source is in 0,0,0 when i assume that it's in camera point.
Invalid code is here:
public override void Draw(Graphics graphics, VisualizableShape shape)
{
if (!shape.IsVisible)
return;
base.Draw(graphics, shape); // draw edge
int x = (int) (shape.Normal.X*128 + 127);
int y = (int) (shape.Normal.Y*128 + 127);
int z = x + y;
var color = Color.FromArgb(255, (Pen.Color.R*z)/511, ((Pen.Color.G*z)/511), (Pen.Color.B*z)/511);
graphics.FillPolygon(new SolidBrush(color), shape.Points.CastToPointF());
}
just dunno what should I do in this case...
I've loaded a 3d model using Helix toolking like this
modelGroupScull = importer.Load("C:\\Users\\Robert\\Desktop\\a.obj");
GeometryModel3D modelScull = (GeometryModel3D)modelGroupScull.Children[0];
and I also have _3DTools that can draw lines from point-to-point in 3d space. now to draw a wireframe of my GeometryModel3D I guess I have to cycle to its vertexes and add them to ScreenSpaceLines3D.
ScreenSpaceLines3D wireframe = new ScreenSpaceLines3D();
// need to cycle through all vertexes of modelScull as Points, to add them to wireframe
wireframe.Points.Add(new Point3D(1, 2, 3));
wireframe.Color = Colors.LightBlue;
wireframe.Thickness = 3;
Viewport3D1.Children.Add(wireframe);
But... how do I actually get this vertex points?
EDIT:
Thanks for the answer. It did add the points
ScreenSpaceLines3D wireframe = new ScreenSpaceLines3D();
MeshGeometry3D mg3 = (MeshGeometry3D)modelScull.Geometry;
foreach (Point3D point3D in mg3.Positions)
{
wireframe.Points.Add(point3D);
}
wireframe.Color = Colors.LightBlue;
wireframe.Thickness = 1;
Viewport3D1.Children.Add(wireframe);
but the wireframe is messed up )
(source: gyazo.com)
maybe someone knows of other ways to draw wireframes? )
Normally the trigons are drawn with index buffers (to prevent extra rotations of vertices) Take a look at the TriangleIndices:
if you do something like this: (not tested it)
MeshGeometry3D mg3 = (MeshGeometry3D)modelScull.Geometry;
for(int index=0;index<mg3.TriangleIndices.Count; index+=3)
{
ScreenSpaceLines3D wireframe = new ScreenSpaceLines3D();
wireframe.Points.Add(mg3.Positions[mg3.TriangleIndices[index]]);
wireframe.Points.Add(mg3.Positions[mg3.TriangleIndices[index+1]]);
wireframe.Points.Add(mg3.Positions[mg3.TriangleIndices[index+2]]);
wireframe.Points.Add(mg3.Positions[mg3.TriangleIndices[index]]);
wireframe.Color = Colors.LightBlue;
wireframe.Thickness = 1;
Viewport3D1.Children.Add(wireframe);
}
But, this can create some overdraw (2 lines on the same coordinates) and probably very slow.
If you put each side into a list and use something like a Distinct on it, it will be better.
The problem with the ScreenSpaceLines3D is that will continue the line, instead of create 1 line (start/end).
If you can manage a algoritm that tries to draw you model with 1 line, it will go faster.
Wireframes are very slow in WPF. (because they are created with trigons)
You should find the vertex points in MeshGeometry3D.Positions Property
foreach (var point3D in modelScull.Geometry.Positions)
I'm not really good in maths, so I'm having really hard times converting formulas into code, and I can't find anything ready-made googling around. I have a big rectangle containing a lot of small rectangles... and all what I need to do is to calculate the largest empty rectangle. Anyonne can help me?
Here is what I came up with... nothing to say, it's a big fail.
Rect result = new Rect();
for (Double l = 0; l < bigRect.Width; ++l)
{
for (Double t = 0; t < bigRect.Height; ++t)
{
Double h = 0;
Double w = 0;
while ((h <= bigRect.Width) && (w <= bigRect.Height))
{
Rect largestEmpty = new Rect(l, t, w, h);
if (smallRects.TrueForAll(smallRect => !smallRect.IntersectsWith(largestEmpty)) && ((largestEmpty.Height * largestEmpty.Width) > (result.Height * result.Width)))
result = largestEmpty;
else
break;
++h;
++w;
}
}
}
From your Perdue Docs Link it says there is a set (let's call it ASD) of points in the Big Rect and you would to have find the largest Rect containing no points of the set ASD. Looking at your code, it seems you didn't (directly) incorporate these points. I would extract the points from the smaller Rects ans create set ASD. Since your working in type double, you should have access to the points, otherwise the algorithm would have a significantly higher run time since you need to check all possible doubles in a specific range (the entire Big Rect). Using the points, I would trying find the points with the shortest distance form each other (sqrt(dx^2+ dy^2)) (shortest shouldn't contain any points) then go to the next shortest and see if any points are contained and etc. In other words, create a order list of all combinations (not permutations, (a,b) to (c, d) should be == (c, d) to (a,b)) ordered by the distance in between them. Might not be optimal, but gets the job done.
EDIT: All order pair besides the diagonals of the smaller Rects should be in the order list, since the smaller Rects should not be conatined, You can also exclude pairs with the same x or y value.
How to draw the spring like shape using c# drawing class
alt text http://img812.imageshack.us/img812/373/spring.jpg
First of all you'd need to think of a formula that would represent the spring. You could draw a circle and as you're going around it, let the X increase a bit. For instance:
for (double i = 0; i < 50; i += 0.01)
{
int x = (int)(Math.Sin(i) * 10 + i * 3);
int y =(int)(Math.Cos(i) * 10 + 50);
}
See the i variable there as time, and the result x and y the coordinates to draw; you'd traverse the path of the spring in small steps.
You could then create a new Bitmap and use the SetPixel method on those coordinates, and in the OnPaint method of your form, draw the bitmap on it.
If you're any good with math (I'm not :P) you might be able to only plot pixels inside the bitmap - the above example doesn't solve the problem of the minimum and maximum values for i.
This is more of a math problem than a C# one. What you want is to derive a Parametric equation for the curve you wish to draw.
With that go and fill an array of Point objects with values for the parametric equation on a certain interval with a certain step (the smaller the step the more the final drawing will look like the actual shape). Then you can use g.DrawLines (MSDN: DrawLines) to draw the actual curve on a surface.
You can edit the width, color and other properties of the line by modifying parameters of the Pen object.
Your actual code would look like this:
void DrawSpring (Graphics g)
{
List<Point> points = new List<Point>();
double step = 0.01;
for(double t = -2; t < 2; t += step)
{
Point p = new Point();
p.X = XPartOfTheEquation(t);
p.Y = YPartOfTheEquation(t);
points.Add(p);
}
g.DrawLines(new Pen(new SolidBrush(Color.Black), 2f), points.ToArray());
}