Using a matrix to rotate rectangles individually - c#

Having a bit of a drawing complication you would call it. My math is a bit rusty when it comes to Matrices and drawing rotations on shapes. Here is a bit of code:
private void Form1_Paint(object sender, PaintEventArgs e)
{
g = e.Graphics;
g.SmoothingMode = SmoothingMode.HighQuality;
DoRotation(e);
g.DrawRectangle(new Pen(Color.Black), r1);
g.DrawRectangle(new Pen(Color.Black), r2);
// draw a line (PEN, CenterOfObject(X, Y), endpoint(X,Y) )
g.DrawLine(new Pen(Color.Black), new Point((r1.X + 50), (r1.Y + 75)), new Point((/*r1.X + */50), (/*r1.Y - */25)));
this.lblPoint.Text = "X-pos: " + r1.X + " Y-pos: " + r1.Y;
//this.Invalidate();
}
public void DoRotation(PaintEventArgs e)
{
// move the rotation point to the center of object
e.Graphics.TranslateTransform((r1.X + 50), (r1.Y + 75));
//rotate
e.Graphics.RotateTransform((float)rotAngle);
//move back to the top left corner of the object
e.Graphics.TranslateTransform(-(r1.X + 50), -(r1.Y + 75));
}
public void Form1_KeyDown(object sender, KeyEventArgs e)
{
case Keys.T:
rotAngle += 1.0f;
}
when I rotate (what I think should be r1) both r1 and r2 rotate. I need to be able to rotate each shape individually as I add more shapes.

I would use a function similar to this:
public void RotateRectangle(Graphics g, Rectangle r, float angle) {
using (Matrix m = new Matrix()) {
m.RotateAt(angle, new PointF(r.Left + (r.Width / 2),
r.Top + (r.Height / 2)));
g.Transform = m;
g.DrawRectangle(Pens.Black, r);
g.ResetTransform();
}
}
It uses a matrix to perform the rotation at a certain point, which should be the middle of each rectangle.
Then in your paint method, use it to draw your rectangles:
g.SmoothingMode = SmoothingMode.HighQuality;
//g.DrawRectangle(new Pen(Color.Black), r1);
//DoRotation(e);
//g.DrawRectangle(new Pen(Color.Black), r2);
RotateRectangle(g, r1, 45);
RotateRectangle(g, r2, 65);
Also, here is the line to connect the two rectangles:
g.DrawLine(Pens.Black, new Point(r1.Left + r1.Width / 2, r1.Top + r1.Height / 2),
new Point(r2.Left + r2.Width / 2, r2.Top + r2.Height / 2));
Using these settings:
private Rectangle r1 = new Rectangle(100, 60, 32, 32);
private Rectangle r2 = new Rectangle(160, 100, 32, 32);
resulted in:

Related

How to Draw these dots?

I can not find any information on how to draw a few dots (for Split separator slider) as shown in the first picture.
I am trying to draw this:
Right now, my custom control code is drawing a straight line with a shadow
public class CustomPaintSplitter : SplitContainer {
...
protected override void OnPaint(PaintEventArgs pe)
{
Graphics g = pe.Graphics;
Rectangle r = ClientRectangle;
g.FillRectangle(new SolidBrush(BackColor), r);
if (Orientation == Orientation.Horizontal)
{
SplitterWidth = 9;
int recWidth = SplitterRectangle.Width / 3;
Rectangle split_rect = new(SplitterRectangle.X + recWidth, SplitterRectangle.Y, SplitterRectangle.Width - recWidth, SplitterRectangle.Height);
int x = split_rect.X;
int y = split_rect.Y + 3;
g.DrawLine(new Pen(SystemColors.ControlLightLight), x, y, x, y + 2);
g.DrawLine(new Pen(SystemColors.ControlLightLight), x, y, x + recWidth, y);
g.DrawLine(new Pen(SystemColors.ControlDark), x, y + 2, x + recWidth, y + 2);
g.DrawLine(new Pen(SystemColors.ControlDark), x + recWidth, y, x + recWidth, y + 2);
}
// Calling the base class OnPaint
base.OnPaint(pe);
}
}
How can this be achieved? I tried different Point[] methods on the internet, but none of them draw anything near what I am trying to achieve.
Even a parameter to specify the number of "dots" drawn would be a plus.
Any help is appreciated!
I just draw it on a panel but you can use it the same way.
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
Brush b = new SolidBrush(Color.Gray);
e.Graphics.FillEllipse(b, new Rectangle(10, 5, 5, 5));
e.Graphics.FillEllipse(b, new Rectangle(20, 5, 5, 5));
e.Graphics.FillEllipse(b, new Rectangle(30, 5, 5, 5));
}

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

How to create a form in shape of rhomb?

How to create a form in shape of rhomb?
I managed to create a shape in form of ellipse with the help of this:
private void Form1_Load(object sender, EventArgs e)
{
System.Drawing.Drawing2D.GraphicsPath myPath = new System.Drawing.Drawing2D.GraphicsPath();
myPath.AddEllipse(45, 60, 200, 200);
Region myRegion = new Region(myPath);
this.Region = myRegion;
}
How can I do it but making rhomb?
Use myPath.AddLines instead of the myPath.AddEllipse:
private void Form1_Load(object sender, EventArgs e)
{
using (GraphicsPath myPath = new GraphicsPath())
{
myPath.AddLines(new[]
{
new Point(0, Height / 2),
new Point(Width / 2, 0),
new Point(Width, Height / 2),
new Point(Width / 2, Height)
});
Region = new Region(myPath);
}
}
Above answer by #Dmitry helped me a lot. However, it does not draw a complete rhombus, as claimed. The last segment is not drawn due to absent final point, which must coincide with the starting point. Line array should contain five points, not four.
I have made some corrections and come up with this function, which draws a rhombus withing a given rectangle:
private void DrawRhombus(Graphics graphics, Rectangle rectangle)
{
using (GraphicsPath myPath = new GraphicsPath())
{
myPath.AddLines(new[]
{
new Point(rectangle.X, rectangle.Y + (rectangle.Height / 2)),
new Point(rectangle.X + (rectangle.Width / 2), rectangle.Y),
new Point(rectangle.X + rectangle.Width, rectangle.Y + (rectangle.Height / 2)),
new Point(rectangle.X + (rectangle.Width / 2), rectangle.Y + rectangle.Height),
new Point(rectangle.X, rectangle.Y + (rectangle.Height / 2))
});
using (Pen pen = new Pen(Color.Black, 1))
graphics.DrawPath(pen, myPath);
}
}

need to draw an Google marker image via C# Graphics

I need to draw an Google marker image via C# Graphics
for that i;ll need the exact coordinates of Google marker
how can i do that Please help .
My Current Code is .
private void Shape8(PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
int startMarker = 0;
int MarkerDiameter = 30;
int EllipseDiameter = 15;
const int StartX = 150;
const int StartY = 350;
int X = StartX;
int Y = StartY;
GraphicsPath path = new GraphicsPath();
Rectangle ellipse = new Rectangle(X, Y, EllipseDiameter, EllipseDiameter);
path.AddEllipse(ellipse);
path.CloseFigure();
X = X + (EllipseDiameter / 2) - (MarkerDiameter / 2);
Y = Y - (EllipseDiameter * 2) - (MarkerDiameter / 2);
startMarker = StartY - 10 - (Convert.ToInt32(MarkerDiameter * 1.5));//Space Between marker and circle.
AddMarker8(ref path, X, startMarker, StartX, StartY, EllipseDiameter, MarkerDiameter, "Concept1");
e.Graphics.FillPath(Brushes.Pink, path);
e.Graphics.DrawPath(Pens.Black, path);
e.Graphics.FillEllipse(Brushes.White, ellipse);
path.CloseAllFigures();
}
private void AddMarker8(ref GraphicsPath path, int X, int Y, int StartX, int StartY, int EllipseDiameter, int MarkerDiameter, string conceptName)
{
float startAngle = 180.0F;
float sweepAngle = 180.0F;
int fontStyle = (int)FontStyle.Regular;
path.AddString(conceptName, new FontFamily("Arial"), fontStyle, 15, new Point(X + (MarkerDiameter / 2), Y - 15), lblFormat);
Rectangle rect = new Rectangle(X, Y, MarkerDiameter, MarkerDiameter);
path.AddArc(rect, startAngle, sweepAngle);
Point lastpoint = new Point(X + (MarkerDiameter / 2), (Y + (MarkerDiameter * 2)) - (MarkerDiameter / 2));
path.AddCurve(new Point[] {
new Point(X+(MarkerDiameter), Y + (MarkerDiameter / 2)), //a
new Point((X +MarkerDiameter)-(MarkerDiameter/4) ,(Y +(MarkerDiameter ))) ,//A.5
lastpoint ,//c
new Point(X +(MarkerDiameter / 4) ,(Y +(MarkerDiameter ))) ,//B.5
new Point(X, Y + (MarkerDiameter / 2))//b
}, 0.5f);
path.CloseFigure();
}
Try the following code
private void DrawMarker(int X, int Y, double Scale, Color BorderColor, Color FillColor, PaintEventArgs e, char Letter = '\0')
{
Graphics G1 = e.Graphics;
Pen Pen1 = new Pen(BorderColor, 8);
SolidBrush Brush1 = new SolidBrush(BorderColor);
SolidBrush Brush2 = new SolidBrush(FillColor);
G1.SmoothingMode = SmoothingMode.AntiAlias;
G1.ResetTransform();
G1.ScaleTransform(Convert.ToSingle(0.4 * Scale), Convert.ToSingle(0.4 * Scale));
GraphicsPath GraphicsPath1 = new GraphicsPath();
GraphicsPath1.AddBeziers(new Point(X + 51, Y + 169), new Point(X + 47, Y + 137), new Point(X + 42, Y + 107), new Point(X + 14, Y + 77));
GraphicsPath1.AddBeziers(new Point(X + 87, Y + 77), new Point(X + 62, Y + 107), new Point(X + 55, Y + 137), new Point(X + 51, Y + 169));
GraphicsPath GraphicsPath2 = new GraphicsPath();
GraphicsPath2.AddEllipse(X + 5, Y + 5, 92, 92);
G1.FillPath(Brush2, GraphicsPath2);
G1.DrawPath(Pen1, GraphicsPath2);
G1.SetClip(new Rectangle(X, Y + 85, 103, 84));
G1.FillPath(Brush2, GraphicsPath1);
G1.DrawPath(Pen1, GraphicsPath1);
G1.ResetClip();
if (Letter != '\0')
{
Font Font1 = new Font("Arial", 52, FontStyle.Bold);
StringFormat StringFormat1 = new StringFormat
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center
};
G1.DrawString(Convert.ToString(Letter), Font1, Brush1, new Rectangle(X, Y, 103, 103), StringFormat1);
Font1.Dispose();
StringFormat1.Dispose();
}
else
{
G1.FillEllipse(Brush1, new Rectangle(X + 32, Y + 32, 37, 37));
}
Pen1.Dispose();
Brush1.Dispose();
Brush2.Dispose();
GraphicsPath1.Dispose();
GraphicsPath2.Dispose();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
DrawMarker(0, 0, 0.5, Color.Black, Color.Tomato, e, Convert.ToChar("A"));
DrawMarker(80, 0, 0.8, Color.Black, Color.Red, e, Convert.ToChar("B"));
DrawMarker(160, 0, 1, Color.Black, Color.Linen, e, Convert.ToChar("C"));
DrawMarker(210, 0, 1.3, Color.Black, Color.Orange, e, Convert.ToChar("D"));
DrawMarker(260, 0, 1.6, Color.Black, Color.Green, e);
}
after running it, the result should be like this

Empty space between two shapes in GDI+

I am trying to draw a custom drop shadow in GDI+ (C#). I keep having this awkward look:
I guess I could solve it by adding a pixel to the arc's width, but then the shapes overlap.
Preview http://puu.sh/2sv2N
I have absolutely no idea what is causing this small piece of white.
Here's my code:
Rectangle drawRect = new Rectangle(10, 10, 400, 400);
radius = 10;
// TOP //
Rectangle topRect = new Rectangle(drawRect.X + radius, drawRect.Y, drawRect.Width - 2 * radius, radius);
LinearGradientBrush topBrush = new LinearGradientBrush(new Rectangle(topRect.X, topRect.Y - 1, topRect.Width,topRect.Height + 2), firstColor, secondColor, 270f);
g.FillRectangle(topBrush, topRect);
topBrush.Dispose();
// LEFT //
Rectangle leftRect = new Rectangle(drawRect.X, drawRect.Y + radius, radius, drawRect.Height - 2 * radius);
LinearGradientBrush leftBrush = new LinearGradientBrush(new Rectangle(leftRect.X - 1, leftRect.Y, leftRect.Width + 2, leftRect.Height), firstColor, secondColor, 180f);
g.FillRectangle(leftBrush, leftRect);
leftBrush.Dispose();
// TOP LEFT //
GraphicsPath topLeftPath = new GraphicsPath();
topLeftPath.StartFigure();
topLeftPath.AddArc(new Rectangle(drawRect.X, drawRect.Y, 2 * radius, 2 * radius), 180, 90);
topLeftPath.AddLine(new Point(drawRect.X + radius, drawRect.Y), new Point(drawRect.X + radius, drawRect.Y + radius));
topLeftPath.AddLine(new Point(drawRect.X + radius, drawRect.Y + radius), new Point(drawRect.X, drawRect.Y + radius + 1));
topLeftPath.CloseFigure();
PathGradientBrush topLeftBrush = new PathGradientBrush(topLeftPath);
topLeftBrush.CenterPoint = new PointF(drawRect.X + radius, drawRect.Y + radius);
topLeftBrush.CenterColor = firstColor;
topLeftBrush.SurroundColors = new Color[] { secondColor };
g.FillPath(topLeftBrush, topLeftPath);
topLeftBrush.Dispose();
topLeftPath.Dispose();
Thanks in advance
Thanks to LarsTech, I got the working solution.
e.Graphics.PixelOffsetMode = PixelOffsetMode.Half;
That did the job.
Thank you !

Categories

Resources