I am currently working on an arrow, containing a text (here 'Test'), that shows an offset.
My code is:
Width = 200;
Length = 1000;
double arrowHeadWidth = Width;
double arrowHeadLength = Width / 2;
double arrowWidth = Width - arrowHeadWidth / 2;
double arrowLength = Length;
double centerY = Width / 2.0;
var figure = new PathFigure
{
IsClosed = true,
StartPoint = new Point(0, centerY - arrowWidth / 2.0)
};
figure.Segments.Add(new LineSegment(new Point(arrowLength - arrowHeadLength, centerY - arrowWidth / 2.0), true));
figure.Segments.Add(new LineSegment(new Point(arrowLength - arrowHeadLength, centerY - arrowHeadWidth / 2.0), true));
figure.Segments.Add(new LineSegment(new Point(arrowLength, centerY), true));
figure.Segments.Add(new LineSegment(new Point(arrowLength - arrowHeadLength, centerY + arrowHeadWidth / 2.0), true));
figure.Segments.Add(new LineSegment(new Point(arrowLength - arrowHeadLength, centerY + arrowWidth / 2.0), true));
figure.Segments.Add(new LineSegment(new Point(0, centerY + arrowWidth / 2.0), true));
var geometry = new PathGeometry();
geometry.Figures.Add(figure);
var borderPen = new Pen(Brushes.White, 10)
{
LineJoin = PenLineJoin.Round
};
var arrowDrawing = new GeometryDrawing(Brushes.Transparent, borderPen, geometry);
FormattedText formattedText = new FormattedText(
"Test",
System.Globalization.CultureInfo.CurrentUICulture,
FlowDirection.LeftToRight,
new Typeface("Tahoma"),
12,
Brushes.Black);
formattedText.MaxTextWidth = arrowLength - 40;
formattedText.MaxTextHeight = arrowWidth - 10;
Geometry textGeometry = formattedText.BuildGeometry(new System.Windows.Point(20, 5));
GeometryDrawing textDrawing = new GeometryDrawing(Brushes.Red, new Pen(Brushes.Red, 1), textGeometry);
var drawingGroup = new DrawingGroup();
drawingGroup.Children.Add(arrowDrawing);
drawingGroup.Children.Add(textDrawing);
var brush = new DrawingBrush(drawingGroup);
But I only get the arrow shown. What am I doing wrong?
If I comment out the line drawingGroup.Children.Add(arrowDrawing); I get the text displayed.
Any suggestions would help. Thanks in advance,
Benny
Edit:
Creation of arrow added
Related
I have this little code to use AddArc() method in a label, but when I execute the code the label disappears. I believe it is the numbers I have used, I followed instructions from the Windows documentation and it had these parameters there too.
GraphicsPath gp = new GraphicsPath();
Rectangle rec = new Rectangle(20, 20, 50, 100);
gp.AddArc(rec, 0 , 180);
label2.Region = new Region(gp);
label2.Invalidate();
I used another code to make the correct way or curve in a text
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
var center = new Point(Width / 2, Height / 2);
var radius = Math.Min(Width, Height) / 3;
var text = "Hello";//txtUp.Text;
var font = new Font(FontFamily.GenericSansSerif, 24, FontStyle.Bold);
for (var i = 0; i < text.Length; ++i)
{
var c = new String(text[i], 1);
var size = e.Graphics.MeasureString(c, font);
var charRadius = radius + size.Height;
var angle = (((float)i / text.Length) - 2);
var x = (int)(center.X + Math.Cos(angle) * charRadius);
var y = (int)(center.Y + Math.Sin(angle) * charRadius);
e.Graphics.TranslateTransform(x, y);
e.Graphics.RotateTransform((float)(90 + 360 * angle / (2 * Math.PI)));
e.Graphics.DrawString(c, font, Brushes.Red, 0, 0);
e.Graphics.ResetTransform();
e.Graphics.DrawArc(new Pen(Brushes.Transparent, 2.0f), center.X - radius, center.Y - radius, radius * 2, radius * 2, 0, 360);
}
}
but it wont show in front of a panel is it possible.
This is what it looks like:
Is it possible to move that text in front of the green circle?
I want to draw ellipse excluding cross inside of it. I have a suspision that I need to use opacity mask. Here is how I am trying to do it.
Color grey = Color.FromArgb(128, Colors.Gray.R, Colors.Gray.G, Colors.Gray.B);
double radius = Math.Min(ActualWidth, ActualHeight) / 2;
Brush ellipse_brush = new SolidColorBrush(grey);
CombinedGeometry cg = new CombinedGeometry();
Drawing maskDrawing = new GeometryDrawing(Brushes.Lime, null, cg);
DrawingBrush mask = new DrawingBrush(maskDrawing);
dc.PushOpacityMask(mask);
dc.DrawEllipse(ellipse_brush, new Pen(ellipse_brush, 0), new Point(radius, radius), radius, radius);
dc.Pop();
Thing is that I don't understand how to create CombinedGeometry for ellipse and two lines. Or maybe I am on the wrong path?
You do not need an opacity mask in conjunction with a CombinedGeometry.
Create the cross outline geometry from a GeometryGroup with two lines and an appropriate Pen, then combine it Xor with an EllipseGeometry and draw the result:
var radius = Math.Min(ActualWidth, ActualHeight) / 2;
var crossSize = 0.8 * radius;
var crossThickness = 0.3 * radius;
var centerPoint = new Point(radius, radius);
var ellipseGeometry = new EllipseGeometry(centerPoint, radius, radius);
var crossGeometry = new GeometryGroup();
crossGeometry.Children.Add(new LineGeometry(
new Point(centerPoint.X - crossSize / 2, centerPoint.Y - crossSize / 2),
new Point(centerPoint.X + crossSize / 2, centerPoint.Y + crossSize / 2)));
crossGeometry.Children.Add(new LineGeometry(
new Point(centerPoint.X - crossSize / 2, centerPoint.Y + crossSize / 2),
new Point(centerPoint.X + crossSize / 2, centerPoint.Y - crossSize / 2)));
var crossPen = new Pen
{
Thickness = crossThickness,
StartLineCap = PenLineCap.Round,
EndLineCap = PenLineCap.Round
};
var crossOutlineGeometry = crossGeometry.GetWidenedPathGeometry(crossPen);
var combinedGeometry = new CombinedGeometry(GeometryCombineMode.Xor,
ellipseGeometry, crossOutlineGeometry);
dc.DrawGeometry(Brushes.Gray, null, combinedGeometry);
I have UserControl of Size 300*200.
and rectangle of size 300*200.
graphics.DrawRectangle(Pens.Black, 0, 0, 300, 200);
When I rotate rectangle in userControl by 30 degree, I get rotated rectangle but it is outsized.
PointF center = new PointF(150,100);
graphics.FillRectangle(Brushes.Black, center.X, center.Y, 2, 2); // draw center point.
using (Matrix matrix = new Matrix())
{
matrix.RotateAt(30, center);
graphics.Transform = matrix;
graphics.DrawRectangle(Pens.Black, 0, 0, 300, 200);
graphics.ResetTransform();
}
I want to fit rectangle like actual result.Check Image here
Can anyone have solution about this.
Thanks.
It's more of a math question than programming one.
Calculate bouning box of any rectangle rotated by any angle in radians.
var newWidth= Math.Abs(height*Math.Sin(angle)) + Math.Abs(width*Math.Cos(angle))
var newHeight= Math.Abs(width*Math.Sin(angle)) + Math.Abs(height*Math.Cos(angle))
Calculate scale for x and y:
scaleX = width/newWidth;
scaleY = height/newHeight;
Apply it to your rectangle.
EDIT:
Applied to your example:
PointF center = new PointF(150, 100);
graphics.FillRectangle(Brushes.Black, center.X, center.Y, 2, 2); // draw center point.
var height = 200;
var width = 300;
var angle = 30;
var radians = angle * Math.PI / 180;
var boundingWidth = Math.Abs(height * Math.Sin(radians)) + Math.Abs(width * Math.Cos(radians));
var boundingHeight = Math.Abs(width * Math.Sin(radians)) + Math.Abs(height * Math.Cos(radians));
var scaleX = (float)(width / boundingWidth);
var scaleY = (float)(height / boundingHeight);
using (Matrix matrix = new Matrix())
{
matrix.Scale(scaleX, scaleY, MatrixOrder.Append);
matrix.Translate(((float)boundingWidth - width) / 2, ((float)boundingHeight - height) / 2);
matrix.RotateAt(angle, center);
graphics.Transform = matrix;
graphics.DrawRectangle(Pens.Black, 0, 0, width, height);
graphics.ResetTransform();
}
I am trying to build an app that loads n number of images and transform them radially around a center and show the result in image control. I am able to load two image by defining each of their locations and transform them by using this code:
private void button1_Click(object sender, RoutedEventArgs e)
{
BitmapImage src = new BitmapImage();
src.BeginInit();
src.UriSource = new Uri(#"Location\Car\Car89.png", UriKind.Absolute);
src.CacheOption = BitmapCacheOption.OnLoad;
src.EndInit();
double deg = 90;
double rad = deg / 180.0 * Math.PI;
//get the bounds of the rotated image
double w = Math.Abs(Math.Cos(-rad) * src.PixelWidth) + Math.Abs(Math.Sin(-rad) * src.PixelHeight);
double h = Math.Abs(Math.Sin(-rad) * src.PixelWidth) + Math.Abs(Math.Cos(-rad) * src.PixelHeight);
BitmapImage src2 = new BitmapImage();
src2.BeginInit();
src2.UriSource = new Uri(#"Location\Car\Car269.png", UriKind.Absolute);
src2.CacheOption = BitmapCacheOption.OnLoad;
src2.EndInit();
double w2 = Math.Abs(Math.Cos(rad) * src2.PixelWidth) + Math.Abs(Math.Sin(rad) * src2.PixelHeight);
double h2 = Math.Abs(Math.Sin(rad) * src2.PixelWidth) + Math.Abs(Math.Cos(rad) * src2.PixelHeight);
Double radius = 50;
//Size sz = new Size(w + w2 + radius * 2, h + h2 + radius * 2);
double c1X = Math.Abs(Math.Sin(rad)) * (radius + src.PixelHeight / 2.0);
double c1Y = Math.Abs(Math.Cos(rad)) * (radius + src.PixelHeight / 2.0);
Size sz = new Size((w / 2 + c1X) * 2.0, (h / 2 + c1Y) * 2.0);
DrawingVisual dv = new DrawingVisual();
RenderOptions.SetBitmapScalingMode(dv, BitmapScalingMode.Fant);
RenderTargetBitmap rtb = null;
using (DrawingContext dc = dv.RenderOpen())
{
dc.DrawRectangle(Brushes.Black, null, new Rect(0, 0, (int)sz.Width, (int)sz.Height));
dc.DrawEllipse(Brushes.White, null, new Point(sz.Width / 2.0, sz.Height / 2.0), radius, radius);
//translate to first center
dc.PushTransform(new TranslateTransform(sz.Width / 2.0 - c1X, sz.Height / 2.0 - c1Y));
//rotate
dc.PushTransform(new RotateTransform(-deg));
//draw
dc.DrawImage(src, new Rect(-src.PixelWidth / 2.0, -src.PixelHeight / 2.0, src.PixelWidth, src.PixelHeight));
dc.Pop();
dc.Pop();
dc.PushTransform(new TranslateTransform(sz.Width / 2.0 + c1X, sz.Height / 2.0 - c1Y));
dc.PushTransform(new RotateTransform(deg));
dc.DrawImage(src2, new Rect(-src2.PixelWidth / 2.0, -src2.PixelHeight / 2.0, src2.PixelWidth, src2.PixelHeight));
dc.Pop();
dc.Pop();
}
rtb = new RenderTargetBitmap((int)sz.Width, (int)sz.Height, 96, 96, PixelFormats.Pbgra32);
RenderOptions.SetBitmapScalingMode(rtb, BitmapScalingMode.Fant);
rtb.Render(dv);
this.image1.Source = rtb;
}
But I wasn't able to make it load n number of images automatically named for example Car0.png, Car1.png,..., CarN.png
How can I achieve this?
Sincerely,
Samuel Farid
How can we animate an arc segment in WPF. Below is the code attached.
PathGeometry pg = new PathGeometry();
PathFigure pf = new PathFigure();
LineSegment ls1 = new LineSegment();
LineSegment ls2 = new LineSegment();
ArcSegment arc = new ArcSegment();
double xc = canvas.Width / 2 - 50 + dx;
double yc = canvas.Height / 2 + dy;
double r = 0.7 * xc; // To control the Explosion generally for all the slices
pf.IsClosed = true;
pf.StartPoint = new Point(xc, yc);
pf.Segments.Add(ls1);
pf.Segments.Add(arc);
pf.Segments.Add(ls2);
pg.Figures.Add(pf);
path.Data = pg;
arc.IsLargeArc = isLargArc;
ls1.Point = new Point(xc + r * Math.Cos(startAngle), yc + r * Math.Sin(startAngle));
arc.SweepDirection = SweepDirection.Clockwise;
arc.Point = new Point(xc + r * Math.Cos(endAngle), yc + r * Math.Sin(endAngle));
arc.Size = new Size(r, r);
ls2.Point = new Point(xc + r * Math.Cos(endAngle), yc + r * Math.Sin(endAngle));
Duration duration = new Duration(TimeSpan.FromSeconds(5));
pau = new PointAnimationUsingPath();
pau.PathGeometry = pg;
pau.FillBehavior = FillBehavior.Stop;
pau.Duration = new Duration(TimeSpan.FromSeconds(5));
I am trying to get the arc segment to animate as in figure from one position to another. There are a list of arc segments which animate one after the other.
You can use Storyboard class to animate. You can for example animate position and RenderTransform it should work