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.
Related
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;
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 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);
Consider the two images below (original and transformed respectively). The three blue squares (markers) are used for orientation.
Original Image:
We know the width, height
We know the (x,y) coordinates of all three markers.
Transformed Image:
We can detect the (x,y) coordinates of all three markers.
As a result, we can calculate the angle of rotation, the amount of (x,y) translation and the (x,y) scaling factor.
I now want to use the System.Drawing.Graphics object to perform RotateTransform, TranslateTransform and ScaleTransform. The trouble is, the resulting image is NEVER like the original.
I've been told on stack overflow that the order of applying transformations does not matter but my observation is different. Below is some code that generates an original image and attempts to draw it on a new canvas after introducing some transformations. You can change the order of the transformations to see different results.
public static void GenerateImages ()
{
int width = 200;
int height = 200;
string filename = "";
System.Drawing.Bitmap original = null; // Original image.
System.Drawing.Bitmap transformed = null; // Transformed image.
System.Drawing.Graphics graphics = null; // Drawing context.
// Generate original image.
original = new System.Drawing.Bitmap(width, height);
graphics = System.Drawing.Graphics.FromImage(original);
graphics.Clear(System.Drawing.Color.MintCream);
graphics.DrawRectangle(System.Drawing.Pens.Red, 0, 0, original.Width - 1, original.Height - 1);
graphics.FillRectangle(System.Drawing.Brushes.Blue, 10, 10, 20, 20);
graphics.FillRectangle(System.Drawing.Brushes.Blue, original.Width - 31, 10, 20, 20);
graphics.FillRectangle(System.Drawing.Brushes.Blue, original.Width - 31, original.Height - 31, 20, 20);
filename = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "Original.png");
original.Save(filename, System.Drawing.Imaging.ImageFormat.Png);
graphics.Dispose();
// Generate transformed images.
transformed = new System.Drawing.Bitmap(width, height);
graphics = System.Drawing.Graphics.FromImage(transformed);
graphics.Clear(System.Drawing.Color.LightBlue);
graphics.ScaleTransform(0.5F, 0.7F); // Add arbitrary transformation.
graphics.RotateTransform(8); // Add arbitrary transformation.
graphics.TranslateTransform(100, 50); // Add arbitrary transformation.
graphics.DrawImage(original, 0, 0);
filename = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "Transformed.png");
transformed.Save(filename, System.Drawing.Imaging.ImageFormat.Png);
graphics.Dispose();
transformed.Dispose();
original.Dispose();
System.Diagnostics.Process.Start(filename);
}
I can see two potential issues here:
Since the transformations are being applies one after another, they render the originally calculated values useless.
The graphics object applies rotation at the (0, 0) coordinate where as I should be doing something different. Not sure what.
From what I understand from here, here, and here, the Graphics.Drawing transformations are performed by multiplying matrices together in the order in which you apply the transformations.
With integers, a*b*c = b*a*c
However, with matricies, ABC almost never equals BAC.
So, it appears the order of transformations does matter, since matrix multiplication is not commutative.
Put another way, it seems that if I do the following on your picture:
case 1:
translate (100,50)
scale (0.5,0.7)
picture ends up with top-left corner at: (100,50)
and bottom-right corner at: (200,190)
case 2:
scale (0.5,0.7)
translate (100,50)
picture ends up with top-left corner at: (50,35)
and bottom-right corner at: (150,174)
This means that by scaling first, and then translating, that the scaling will also scale the amount of translation, that is why in case two the the picture ended up at (50,35) for the top left corner, half of the translated X and .7 of the translated Y.
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());
}