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;
Related
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.
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;
}
I am trying to estimate the length of a printed string.
Font newFont = new Font("Arial", 12, FontStyle.Bold, GraphicsUnit.Point);
label1.Font = newFont;
labe1.Text = "300028";
Graphics g = Graphics.FromHwnd(label1.Handle);
SizeF txtSize = g.MeasureString(label1.Text, label1.Font);
txtSize is {Width=60.3177, Height=19.875} points.
The actual width should be 60.3177 * 0.353 = 21.29 mm
where (1 point = 1/72 inch = 0.353 mm)
On paper (printed with Word) the width is about 13.5 mm
Why do we get such a big difference between the value computed with MeasureString (21.29 mm) and the real one (13.5 mm)?
I am aware of the limitations of the MeasureString method but I do not think this cannot justify such a big difference.
What I am missing?
Because you initialize your Graphics object wrong. You are using a display handle, not a print handle.
According to this post your Graphics object should be obtained using the PrinterSettings.CreateMeasurementGraphics method on a PrintDocument:
Graphics g = pd.PrinterSettings.CreateMeasurementGraphics();
Printing units are by default in hundredths of an inch, not 72ths of an inch.
As the other answer mentions, you need to use PrinterSettings.CreateMeasurementGraphics to get a graphics object that will be configured the right way to measure text for printing.
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);
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());
}