Drawing lines with an arrow in the middle - c#

First of all sorry for my English...
I would like to draw lines with arrows in the middle in c#. How can i do it?
I have done this:
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
Pen p = new Pen(Color.Black, 2);
p.StartCap = LineCap.Round;
p.EndCap = LineCap.ArrowAnchor;
g.DrawLine(p, StartX, StartY, EndX, EndY);
p.Dispose();
But it's not enough... I would like to draw the arrow to the line's middle...

try this maybe it helps
AdjustableArrowCap bigArrow = new AdjustableArrowCap(5, 5);
Pen p = new Pen(Color.Blue, 1);
p.CustomEndCap = bigArrow;
e.Graphics.DrawLine(p, 20, 20, 100, 100);

Related

Is it posble create text on image with higher quality in .net

I need to create some kind of graph in .net desktop application.
I use .Net Framework 4.7.2 and System.Drawing library.
The scenario looked like this.
In the console application I create a bitmap with X and Y axes and some simple lines and some text on those lines, nothing complicated.
After creating the bitmap, I save it as .bmp file.
The problem is that the letters and numbers I create are bad and look furry, I tried with different fonts and different settings but the result was always the same.
The picture looks like this:
and under a magnifyer it looks like this:
This is my sample code:
// create new bitmap
Bitmap bitmap = new Bitmap(900, 700, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
Graphics g = Graphics.FromImage(bitmap);
g.Clear(Color.LightGray);
// set attr
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.Bicubic;
// draw X and Y axes
Pen pen = new Pen(Color.Black, 1);
g.DrawLine(pen, new Point(100, 100), new Point(100,600));
g.DrawLine(pen, new Point(100, 600), new Point(800, 600));
SolidBrush brush = new SolidBrush(Color.Black);
Font font = new Font("Lucida Console", 14, FontStyle.Bold);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.Bicubic;
// grid numbeers on x axis
for (int i = 0; i < 8; i++)
{
g.DrawString(i.ToString(), font, brush, 100 * (i+1), 620);
}
// grid numbeers on y axis
for (int i = 0; i < 6; i++)
{
g.DrawString(i.ToString(), font, brush, 70, 600 - (100 * i));
}
// label 1
font = new Font("Lucida Console", 14, FontStyle.Bold);
g.DrawString("Line - X axis", font, brush, 100, 650);
// label 2
font = new Font("Lucida Console", 32, FontStyle.Bold);
g.DrawString("PORCO El.01", font, brush, 550, 150);
// label 3
font = new Font("Lucida Console", 24, FontStyle.Regular);
g.DrawString("PORCO El.01", font, brush, 550, 200);
// save as .bmp file
bitmap.Save(Path.Combine(picturePath, "sample.bmp"));
Is it possible to get better text quality? Is there maybe another 3rd party library that can achieve better results?
Thanks in advance!

Scaling Picturebox does not change image at all

I'm using a picturebox to create a visual of an instance of my truss class. I'm creating the visual by drawing directly onto the picture box in the paint event. The method looks like this
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (isDraw)
{
//Preparing to draw
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.Bicubic;
RunEntry entry = this.passedHistory.SelectedItem as RunEntry;
AnsFile objToDraw = entry.FileRead;
Pen pen = new Pen(Color.Black);
//Getting size of bitmap
int maxWidth = 0, maxHeight = 0;
foreach (AnsJoint joint in objToDraw.AnsJoints)
{
if (joint.Location.X.Length > maxWidth)
{
maxWidth = (int)joint.Location.X.Length;
}
if (joint.Location.Y.Length > maxHeight)
{
maxHeight = (int)joint.Location.Y.Length;
}
}
//Drawing joints
foreach (AnsJoint joint in objToDraw.AnsJoints)
{
PointF jointPoint = this.ToCartesian(new PointF((float)joint.Location.X.Length - 4f, (float)joint.Location.Y.Length + 10f), maxHeight);
e.Graphics.DrawString(joint.JointID.ToString(), new Font(FontFamily.GenericMonospace, 6f, FontStyle.Regular, GraphicsUnit.Point, 1, false), Brushes.Black, jointPoint);
}
//Draw the panels and links
foreach (AnsMember member in objToDraw.AnsMembers)
{
List<AnsPanel> panels = member.Panels; //Drawing the panels
foreach (AnsPanel pan in panels)
{
pen.Color = Color.Red;
PointF p1 = this.ToCartesian(new PointF((float)pan.I.Location.X.Length, (float)pan.I.Location.Y.Length), maxHeight);
PointF p2 = this.ToCartesian(new PointF((float)pan.J.Location.X.Length, (float)pan.J.Location.Y.Length), maxHeight);
g.DrawEllipse(pen, p1.X - 2.5f, p1.Y - 2.5f, 5, 5);
g.DrawEllipse(pen, p2.X - 2.5f, p2.Y - 2.5f, 5, 5);
g.DrawEllipse(pen, p1.X - 3, p1.Y - 3.3f, 5, 5);
g.DrawEllipse(pen, p2.X - 3, p2.Y - 3.3f, 5, 5);
pen.Color = Color.Black;
g.DrawLine(pen, p1, p2);
}
List<AnsLink> links = member.Links; //Drawing the links
foreach (AnsLink link in links)
{
PointF p1 = this.ToCartesian(new PointF((float)link.I.Location.X.Length, (float)link.I.Location.Y.Length), maxHeight);
PointF p2 = this.ToCartesian(new PointF((float)link.J.Location.X.Length, (float)link.J.Location.Y.Length), maxHeight);
g.FillEllipse(Brushes.Green, p1.X - 1.5f, p1.Y - 1.5f, 3, 3);
g.FillEllipse(Brushes.Green, p2.X - 1.5f, p2.Y - 1.5f, 3, 3);
g.DrawLine(pen, p1, p2);
}
}
g.ScaleTransform(.5f, .5f);
pictureBox1.Tag = entry.FileName;
}
}
Which yields the result I'm expecting
except that I want the truss image to scale to fill the picturebox more. I added the ScaleTransform call to the end of the paint event method but that doesn't seem to have any impact as the picture is the same size with or without the call. How can I scale what I draw on the picturebox to the size of the picturebox?
Call ScaleTransform before you do your drawing. You can calculate the desired scale factor like this:
// place this code after the calculation of maxWidth and maxHeight
// but before the drawing code
PictureBox p = (PictureBox)sender;
float scaleFactor = Math.Min(
((float)p.Width) / maxWidth,
((float)p.Height) / maxHeight
);
g.ScaleTransform(scaleFactor, scaleFactor);

Drawline with same pen width, but the line widths are different in result

I draw lines with the same pen, but the line widths are different in result. Why?
Bitmap b = new Bitmap(400, 400);
Graphics g = Graphics.FromImage(b);
g.PageUnit = GraphicsUnit.Point;
g.Clear(Color.White);
Pen pen = new Pen(Color.Red, 1.2f);
for (int i = 20; i < 200; i = i + 20)
{
g.DrawLine(pen, 10, i, 190, i);
}
g.Dispose();
b.Save("d:/temp/test.png", ImageFormat.Png);
b.Dispose()
Here is the result:
MSDN for GraphicsUnit
It's because you're working with Points and not Pixels and the variation in the width of the lines is the result of a rounding errors in the placement of the line and the width of the line in relation to how it gets rendered in pixels in the final product.
If you don't care about printing the image, it might be best to stick with Pixels.
Edit: If you want to continue using points, space things relative to your pen width:
Bitmap b = new Bitmap(400, 400);
Graphics g = Graphics.FromImage(b);
g.PageUnit = GraphicsUnit.Point;
g.Clear(Color.White);
Pen pen = new Pen(Color.Red, 1.2f);
for (float i = 20f * pen.Width; i < 200f * pen.Width; i = i + 20f * pen.Width)
{
g.DrawLine(pen, 10f, i, 190f, i);
}
g.Dispose();
b.Save("c:/temp/test.png", ImageFormat.Png);
b.Dispose();

Strange DrawRectangle and DrawLine

I want to draw several figures on the PictureBox. I expected that the following code will draw a rectangle with it's full size diagonal, but it doesn't. Line do not connected with bottom-right corner of rectangle. I'm really curious what may be wrong?
private void onPaint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
Pen p = new Pen(System.Drawing.Color.Black, 2);
g.DrawRectangle(p, 50, 10, 400, 400);
g.DrawLine(p, 50, 10, 400, 400);
}
In DrawRectangle, the last two arguments are width and height. In DrawLine, the last two arguments are final x and final y.
So just add the starting x and starting y to the width and height to get your diagonal line:
g.DrawRectangle(p, 50, 10, 400, 400);
g.DrawLine(p, 50, 10, 450, 410);
Also, if you declare a Rectangle then you can change the values without needing to change the drawing code. Something like:
private void onPaint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
Rectangle rc = new Rectangle(50, 10, 400, 400);
using (Pen p = new Pen(System.Drawing.Color.Black, 2))
{
g.DrawRectangle(p, rc);
g.DrawLine(p, rc.Left, rc.Top, rc.Right, rc.Bottom);
}
}

Upscaling a bitmap with no smoothing is inaccurate somehow, how to make it right?

Bitmap outputBitmap = new Bitmap(inputBitmap.Width * 5, inputBitmap.Height * 5);
using (Graphics graphics = Graphics.FromImage(outputBitmap))
{
graphics.CompositingQuality =
System.Drawing.Drawing2D.CompositingQuality.HighQuality;
graphics.InterpolationMode =
System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
graphics.SmoothingMode =
System.Drawing.Drawing2D.SmoothingMode.HighQuality;
graphics.DrawImage(inputBitmap, 0, 0,
inputBitmap.Width * 5, inputBitmap.Height * 5);
}
The result is an upscaled image offset by a few pixels in direction of top left corner.
How do I make this right?

Categories

Resources