using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using WaveLineTextDemo;
namespace waveLine
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private Point? _startPoint = null;
private void ContainerCanvas_OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var position = e.GetPosition(ContainerCanvas);
if (_startPoint == null)
{
_startPoint = position;
}
else
{
//Delete preview
if (_previewLineElement != null)
{
ContainerCanvas.Children.Remove(_previewLineElement);
_previewLineElement = null;
_lastMovedPoint = null;
}
//Determine the end point and draw a wavy line
var myLineElement = new MyLineElement();
myLineElement.DrawLine((Point)_startPoint, position);
ContainerCanvas.Children.Add(myLineElement);
_startPoint = null;
}
}
private MyLineElement _previewLineElement = null;
private Point? _lastMovedPoint = null;
private void ContainerCanvas_OnMouseMove(object sender, MouseEventArgs e)
{
var position = e.GetPosition(ContainerCanvas);
if (_startPoint != null && (_lastMovedPoint == null || _lastMovedPoint != null & (position - (Point)_lastMovedPoint).Length >= 2))
{
_lastMovedPoint = position;
if (_previewLineElement != null)
{
ContainerCanvas.Children.Remove(_previewLineElement);
}
var myLineElement = new MyLineElement();
myLineElement.DrawLine((Point)_startPoint, position);
ContainerCanvas.Children.Add(myLineElement);
_previewLineElement = myLineElement;
}
}
}
}
<Window x:Class="waveLine.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:waveLine"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Canvas x:Name="ContainerCanvas" PreviewMouseLeftButtonDown="ContainerCanvas_OnPreviewMouseLeftButtonDown"
MouseMove="ContainerCanvas_OnMouseMove"
Background="LightGray"></Canvas>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
namespace WaveLineTextDemo
{
class MyLineElement : FrameworkElement
{
public MyLineElement()
{
_visualShape = new VisualCollection(this);
}
internal void DrawLine(Point startPoint, Point endPoint)
{
List<Point> points = ForgePoints(startPoint, endPoint);
DrawLine(points);
}
private const int SeparatorPiexl = 4;
private const int AbundancePiexl = 3;
private List<Point> ForgePoints(Point startPoint, Point endPoint)
{
var points = new List<Point>();
var lineVector = endPoint - startPoint;
var lineDistance = lineVector.Length;
var lineAngle = Math.Atan2(-(endPoint.Y - startPoint.Y), endPoint.X - startPoint.X);
points.Add(startPoint);
int index = 0;
bool isAbundanceUpward = true;
while (index * SeparatorPiexl < lineDistance)
{
index++;
//Calculate the interval length (simulation point to starting point)
var separatorDistance = index * SeparatorPiexl;
var abundancePiexl = AbundancePiexl;
var distanceToStartPoint = Math.Sqrt(Math.Pow(separatorDistance, 2) + Math.Pow(abundancePiexl, 2));
//Calculate the simulation point, starting point, and the angle to the straight line
var separatorAngle = Math.Atan2(AbundancePiexl, separatorDistance);
separatorAngle = isAbundanceUpward ? separatorAngle : -separatorAngle;
isAbundanceUpward = !isAbundanceUpward;
//Get the horizontal angle of the simulated point
var mockPointAngle = lineAngle + separatorAngle;
//Calculate the simulation point coordinates
var verticalDistance = distanceToStartPoint * Math.Sin(mockPointAngle);
var horizontalDistance = distanceToStartPoint * Math.Cos(mockPointAngle);
var mockPoint = new Point(startPoint.X + horizontalDistance, startPoint.Y - verticalDistance);
points.Add(mockPoint);
}
points.Add(endPoint);
return points;
}
private void DrawLine(List<Point> points)
{
_visualShape.Clear();
var geometryTest = new StreamGeometry();
using (var ctx = geometryTest.Open())
{
ctx.BeginFigure(points[0], true, false);
if (points.Count % 2 == 0)
{
//Draw the second-order Bessel function, need to ensure that it is an even point
ctx.PolyQuadraticBezierTo(points, true, true);
}
else
{
//Draw the second-order Bessel function, need to ensure that it is an even point
points.Insert(0, points[0]);
ctx.PolyQuadraticBezierTo(points, true, true);
}
ctx.Close();
}
var visual = new DrawingVisual();
using (var context = visual.RenderOpen())
{
context.DrawGeometry(FillBrush, StrokePen, geometryTest);
}
_visualShape.Add(visual);
}
#region InternalMethod
[Obsolete]
protected override void OnRender(DrawingContext drawingContext)
{
//Deprecated, changed to _visualShape filling implementation
//drawingContext.DrawGeometry(FillBrush, StrokePen, BaseGeometry);
}
protected override int VisualChildrenCount => _visualShape.Count;
protected override Visual GetVisualChild(int index)
{
if (index < 0 || index >= _visualShape.Count)
{
throw new ArgumentOutOfRangeException();
}
return _visualShape[index];
}
#endregion
#region CurveAttributes
private readonly VisualCollection _visualShape;
protected Brush FillBrush { get; set; } = Brushes.Transparent;
public Brush LineBrush { get; set; } = Brushes.DarkSeaGreen;
protected double BorderThickness { get; set; } = 1.0;
private Pen _defaultPen = null;
protected Pen StrokePen
{
get
{
if (_defaultPen == null)
{
_defaultPen = new Pen(LineBrush, BorderThickness);
}
return _defaultPen;
}
set => _defaultPen = value;
}
#endregion}
}
}
No comments:
Post a Comment