Why do I see this jagged curves? - c#

I have a canvas and draw curve with this code:
using (Graphics g = Graphics.FromImage(canvas.BackgroundImage))
{
g.DrawCurve(pen, points);
points is array that I fill that by mouse location points.
In the result I see some jagged lines that I didn't draw.
You can see them here(in red rectangles):
What can i do about this?

What you is see is the somewhat unlucky combination of the default for Linejoin, which is Miter and the default for MiterLimit, which is 10.
Instead you have a choice of either picking one of the other LineJoin options or reducing the MiterLimit to say less than half the Pen.Width..
using (Pen myPen = new Pen(Color.Blue, 24f))
{
// either another LineJoine;
myPen.LineJoin = System.Drawing.Drawing2D.LineJoin.Round;
// or a reduced MiterLimit:
myPen.MiterLimit = 1+ myPen.Width / 5f;
}

Related

C# fonts as 2D points

I am programming in C# and I need a way to get fonts as points in 2D. I basically want fonts converted to a mesh so that I can render it in 2D/3D. Are there any ways to do that? Or is it better to just download the meshes or something and then load them into my program.
In winforms you can use a GraphicsPath from System.Drawing.Drawing2D to
either acces the Bezier curves in the PathPoints and PathTypes data
or, after Flattening the path to acces the PathPoints array that now makes up an array of line segments.
Use one of the GraphicsPath.AddString methods to create the path..!
You may also want to look into the GraphicsPathIterator class, which..
Provides the ability to iterate through subpaths in a GraphicsPath and
test the types of shapes contained in each subpath..
Here is an example of drawing the flattened segment points:
Bitmap bmp = new Bitmap(400, 400);
GraphicsPath gp = new GraphicsPath();
using (Graphics g = Graphics.FromImage(bmp))
using (Font f = new Font("Tahoma", 40f))
{
g.ScaleTransform(4,4);
gp.AddString("Y?", f.FontFamily, 0, 40f, new Point(0, 0), StringFormat.GenericDefault);
g.DrawPath(Pens.Gray, gp);
gp.Flatten(new Matrix(), 0.2f); // <<== *
g.DrawPath(Pens.DarkSlateBlue, gp);
for (int i = 0; i < gp.PathPoints.Length; i++)
{
PointF p = gp.PathPoints[i];
g.FillEllipse(Brushes.DarkOrange, p.X-1, p.Y - 1, 2, 2);
}
pictureBox1.Image = bmp;
}
Note the 2nd Flatten parameter that lets you control how tight i.e. how closely the curve is approximated by the lines. The smaller the value the more 2d points are created..
To use the unflattended path you need to combine the PathPoints with their respective PathTypes; this is basically the same as creating Bezier curves: Two control points go between each pair of points. The types tell you where a figure starts/ends and where a line starts or a curve..
You can use the GlyphTypeface.GetGlyphOutline method to return the glyphs which make up the curves of the lettering. Note this is part of WPF.
MSDN:
Returns a Geometry value describing the path for a single glyph in the font
Under the hood I suspect it is calling the native function GetGlyphOutline
...which you could p-invoke from a WinForms/XNA app.

DrawPath Points with rounded edges

I'm drawing a GraphicPant with lines that are intersecting and I'm wondering if the edges of the lines could be rounded.
The code with that I draw is:
Graphics G = e.Graphics;
GraphicsPath gp = new GraphicsPath();
gp.AddLine((float)(line.startX), (float)(line.startY), (float)(line.endX), (float)(line.endY));
gp.CloseFigure();
using (Pen pen = new Pen(Color.DarkGray, 0.0001f))
{
G.SmoothingMode = SmoothingMode.AntiAlias;
G.Clear(Color.White);
G.DrawPath(pen, gp)
}
If it could look like this:
Try:
pen.StartCap = LineCap.Round;
pen.EndCap = LineCap.Round;
Using such a tiny Pen.Width will result in a line that is only one pixel 'thick'. But pixels are always square by definition. So if you enlarge with a non-dithering or -antialising software it will look as if the ends were square.
But they really have no shape at all as they do not have a real size. Instead their width is a virtual number: The one pixel that is used is simply the default minimum used so the line doesn't disappear.
So: Yes the Pen.Width does matter.
So: Do set it to a reasonable number greater than 1 and you will see the round endpoints..
You could also scale the Graphics object by a suitable number and you would see the rounded ends as well..If you want to try that, don't forget to adapt the coodinates to the extreme scaling!
For several lines created by AddLines (or AddPolygon if you were serious about the CloseFigure) also set the LineJoin:
pen.LineJoin = LineJoin.Round;
pen.EndCap = LineCap.Round;
pen.StartCap = LineCap.Round;

C# Pen.DashPattern

I want to draw a Line between 2 rows while using drag and drop. The function of this is simply visual, so that the user knows, where he is dropping the row. The line should look like the excel onces. Here my code:
Pen _marqueePen = new Pen(Color.Gray, 2);
float[] dashValues = {1f,1f};
_marqueePen.DashPattern = dashValues;
But this looks like that
I want to look it like that:
I'm WinForms and the C1 Flexgrid control.
You can use a Custom Pen like this:
using (Pen pen = new Pen(Color.Gray, 4f) )
{
pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Custom;
pen.DashPattern = new float[] { 0.25F, 0.25F };
// now draw your stuff..
}
Note the doc on MSDN:
The elements in the dashArray array set the length of each dash
and space in the dash pattern. The first element sets the length of a dash,
the second element sets the length of a space, the third element sets
the length of a dash, and so on. Consequently, each element should be a
non-zero positive number.
The length of each dash and space in the dash pattern is the product
of the element value in the array and the width of the Pen.
You can pick any pen width and any dash&gap lengths as long as you keep their relation in mind.. So if you want the finest dashes, make sure they multiply to 1.0 pixels!
Here is the resulting line:
Some options:
You could use a PNG graphic that mimics that excel behaviour and then draw it on the control (you'll have to tile your image vertically).
Draw three lines with your code, with offset of y-axis & x-axis one pixel.
That looks to me more like a rectangle filed with HatchBrush having HatchStyle.Percent50 and height of 3.
You could try
Rectangle rect = new Rectangle(0, 0, 500, 3) //you will use the values here from your cursor but height will be 3
HatchBrush brush = new HatchBrush(HatchStyle.Percent50, Color.Black);
g.FillRectangle(brush, rect);

Create Shape from Lines 2D c#

I have a project with a graphic object called GraphicsLine. What it does is simply draw line on every mousedown and stop on every mouseup, nothing complicated. It stores coordinates for the start and the end of the line (x,y). Now what I want to know is whenever a shape is created. For example, you create 4 lines that forms a square, I want to be able to run an algorithm that can tell me that there is a square in the drawing.
Note that the shape can be anything that is "closed". Not only square, rectangle or triangle.
The goal of this is to calculate the area of the created shapes.
Is there something that already exists for doing this? I've been struggling to find something that could fit my needs.
EDIT 1:
I added some additionnal information :
Lines are either "cliped" to another line start or end point or they are not. There is no close closure, it is on the same point or not closed at all. 1 line can be used in multiple shapes.
EDIT 2 :
So basically, I want something that can give me an array of "GraphicsLine" that forms a shape. So if we have 6 lines in the drawing but 4 of them forms a square, I want something that returns those 4 lines so I can create another object from it.
Thanks in advance.
Please check this question How do I calculate the area of a 2d polygon? it is probably what you need, you just have to port it to C# :)
Edit: from #chmike answer:
Where x and y are the arrays of coordinates
var x = [10,10,20,20];
var y = [10,20,20,10];
var n = x.Length;
x[n] = x[0];
x[n+1] = x[1];
y[n] = y[0];
y[n+1] = y[1];
// compute area
int area = 0;
for(var i = 1; i <= n; ++i ) {
area += x[i]*( y[i+1] - y[i-1] );
}
Console.Write(area /= 2);
Take a look at this tutorial of AForge.NET Shape Checker
If your GraphicsLine object is drawing on a PictureBox or if you can convert that object to a bitmap, you can then run the code below.
You can easily try detection of quadrilaterals, this code here will actually highlight the detected objects, you do change the loop and make it do whatever you want instead:
// if you are using a PictureBox to draw the shapes, then convert it to a bitmap
Bitmap bitmap = new Bitmap(pictureBox1.Image)
// locate objects using blob counter
BlobCounter blobCounter = new BlobCounter( );
blobCounter.ProcessImage( bitmap );
Blob[] blobs = blobCounter.GetObjectsInformation( );
// create Graphics object to draw on the image and a pen
Graphics g = Graphics.FromImage( bitmap );
Pen bluePen = new Pen( Color.Blue, 2 );
// check each object and draw circle around objects, which are recognized as circles
for ( int i = 0, n = blobs.Length; i < n; i++ )
{
List<IntPoint> edgePoints = blobCounter.GetBlobsEdgePoints( blobs[i] );
List<IntPoint> corners = PointsCloud.FindQuadrilateralCorners( edgePoints );
g.DrawPolygon( bluePen, ToPointsArray( corners ) );
}
bluePen.Dispose( );
g.Dispose( );
I know it is 2 years + later, but I found a way with a recursive function to know when the shapes are "closed". You start from any points of the last drawed line, then you check if the other point is connected to another line. You do this until you reach the starting point. I save all the lines into another class called Polygon. This way, they keep all the lines with the start and finish that forms the polygon. Then to calculate the area, I do as Eduardo Cobuci said in his answer.
Hope this helps.

spring like drawing in c#

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());
}

Categories

Resources