using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;
namespace _20181029_ベジェ曲線_直角方向線
{
public partial class MainWindow : Window
{
public enum DistanceType
{
None,
Average,
Separate,
Shorter,
FrontBack
}
private PointCollection AnchorPoints;
private Path MyBezierPath = new Path();
private Path VertexPath = new Path();
private Path ControlLinePath = new Path();
public MainWindow()
{
InitializeComponent();
this.Title = this.ToString();
ButtonA0.Click += ButtonA0_Click;
ButtonC1.Click += ButtonC1_Click;
ButtonC2.Click += ButtonC2_Click;
ButtonC3.Click += ButtonC3_Click;
ButtonC4.Click += ButtonC4_Click;
ButtonC5.Click += ButtonC5_Click;
ButtonA1.Click += ButtonA1_Click;
ButtonRandomPoint.Click += ButtonRandomPoint_Click;
ButtonVisible.Click += ButtonVisible_Click;
AnchorPoints = new PointCollection() { new Point(150, 250), new Point(100, 300), new Point(400, 400) };
InitializeBezierPath();
InitializeVertexPath();
InitializeLinePath();
MyCanvas.Children.Add(MyBezierPath);
MyCanvas.Children.Add(VertexPath);
MyCanvas.Children.Add(ControlLinePath);
}
private void ButtonC5_Click(object sender, RoutedEventArgs e)
{
ToCurveTypeC(0.5, DistanceType.Shorter);
InitializeVertexPath();
InitializeLinePath();
}
private void ButtonC4_Click(object sender, RoutedEventArgs e)
{
ToCurveTypeC(0.3, DistanceType.FrontBack);
InitializeVertexPath();
InitializeLinePath();
}
private void ButtonC3_Click(object sender, RoutedEventArgs e)
{
ToCurveTypeC(0.3, DistanceType.Shorter);
InitializeVertexPath();
InitializeLinePath();
}
private void ButtonC2_Click(object sender, RoutedEventArgs e)
{
ToCurveTypeC(0.3, DistanceType.Separate);
InitializeVertexPath();
InitializeLinePath();
}
private void ButtonC1_Click(object sender, RoutedEventArgs e)
{
ToCurveTypeC(0.3, DistanceType.Average);
InitializeVertexPath();
InitializeLinePath();
}
private void ButtonA1_Click(object sender, RoutedEventArgs e)
{
ToCurveTypeA(0.3);
InitializeVertexPath();
InitializeLinePath();
}
private void ButtonA0_Click(object sender, RoutedEventArgs e)
{
ToCurveTypeC(0.3, DistanceType.None);
InitializeVertexPath();
InitializeLinePath();
}
private void ButtonVisible_Click(object sender, RoutedEventArgs e)
{
if (VertexPath.Visibility == Visibility.Visible)
{
VertexPath.Visibility = Visibility.Hidden;
ControlLinePath.Visibility = Visibility.Hidden;
}
else
{
VertexPath.Visibility = Visibility.Visible;
ControlLinePath.Visibility = Visibility.Visible;
}
}
private void ButtonRandomPoint_Click(object sender, RoutedEventArgs e)
{
AnchorPoints = RandomPoint(6);
InitializeBezierPath();
ToCurveTypeC(0.3, DistanceType.Average);
InitializeVertexPath();
InitializeLinePath();
}
private void ToCurveTypeC(double curve, DistanceType distanceType)
{
PointCollection segPoints = GetPolyBezierSegmentPoints(MyBezierPath);
for (int i = 1; i < AnchorPoints.Count - 1; i++)
{
Point beginP = AnchorPoints[i - 1];
Point currentP = AnchorPoints[i];
Point endP = AnchorPoints[i + 1];
double beginDistance = 0, endDistance = 0;
switch (distanceType)
{
case DistanceType.None:
beginDistance = 0;
endDistance = 0;
break;
case DistanceType.Average:
(beginDistance, endDistance) = DistanceAverage(beginP, currentP, endP);
break;
case DistanceType.Separate:
(beginDistance, endDistance) = DistanceSeparate(beginP, currentP, endP);
break;
case DistanceType.Shorter:
(beginDistance, endDistance) = DistanceShorter(beginP, currentP, endP);
break;
case DistanceType.FrontBack:
(beginDistance, endDistance) = DistanceFrontAndBackAnchor(beginP, currentP, endP);
break;
default:
break;
}
(double bRadian, double eRadian) = GetRadianDirectionLine(beginP, currentP, endP);
double xDiff = Math.Cos(bRadian) * beginDistance * curve;
double yDiff = Math.Sin(bRadian) * beginDistance * curve;
segPoints[i * 3 - 2] = new Point(currentP.X + xDiff, currentP.Y + yDiff);
xDiff = Math.Cos(eRadian) * endDistance * curve;
yDiff = Math.Sin(eRadian) * endDistance * curve;
segPoints[i * 3] = new Point(currentP.X + xDiff, currentP.Y + yDiff);
}
}
private (double begin, double end) DistanceAverage(Point beginP, Point currentP, Point endP)
{
double bSide = GetDistance(currentP, beginP);
double eSide = GetDistance(currentP, endP);
double average = (bSide + eSide) / 2.0;
return (average, average);
}
private (double begin, double end) DistanceSeparate(Point beginP, Point currentP, Point endP)
{
double bSide = GetDistance(currentP, beginP);
double eSide = GetDistance(currentP, endP);
return (bSide, eSide);
}
private (double begin, double end) DistanceShorter(Point beginP, Point currentP, Point endP)
{
double bSide = GetDistance(currentP, beginP);
double eSide = GetDistance(currentP, endP);
double shorter = (bSide > eSide) ? eSide : bSide;
return (shorter, shorter);
}
private (double begin, double end) DistanceFrontAndBackAnchor(Point beginP, Point currentP, Point endP)
{
double distance = GetDistance(beginP, endP);
return (distance, distance);
}
<summary>
</summary>
<param name="beginP"></param>
<param name="currentP"></param>
<param name="endP"></param>
<returns></returns>
private (double beginSide, double endSide) GetRadianDirectionLine(Point beginP, Point currentP, Point endP)
{
double bRadian = GetRadianFrom2Points(currentP, beginP);
double eRadian = GetRadianFrom2Points(currentP, endP);
double midRadian = (bRadian + eRadian) / 2.0;
double bControlRadian, eControlRadian;
if (bRadian > eRadian)
{
bControlRadian = midRadian + (Math.PI / 2.0);
eControlRadian = midRadian - (Math.PI / 2.0);
}
else
{
bControlRadian = midRadian - (Math.PI / 2.0);
eControlRadian = midRadian + (Math.PI / 2.0);
}
return (bControlRadian, eControlRadian);
}
private void ToCurveTypeA(double curve)
{
PointCollection segPoints = GetPolyBezierSegmentPoints(MyBezierPath);
for (int i = 1; i < AnchorPoints.Count - 1; i++)
{
Point beginP = AnchorPoints[i - 1];
Point currentP = AnchorPoints[i];
Point endP = AnchorPoints[i + 1];
double xDiff = (endP.X - beginP.X) * curve;
double yDiff = (endP.Y - beginP.Y) * curve;
segPoints[i * 3 - 2] = new Point(currentP.X - xDiff, currentP.Y - yDiff);
segPoints[i * 3] = new Point(currentP.X + xDiff, currentP.Y + yDiff);
}
}
private void InitializeBezierPath()
{
MyBezierPath.Data = MakeBezierPahtGeometry(AnchorPoints);
MyBezierPath.Stroke = Brushes.GreenYellow;
MyBezierPath.StrokeThickness = 10;
MyBezierPath.StrokeLineJoin = PenLineJoin.Bevel;
}
private void InitializeLinePath()
{
PointCollection segmentPoint = GetPolyBezierSegmentPoints(MyBezierPath);
var pg = new PathGeometry();
for (int i = 2; i < segmentPoint.Count - 1; i += 3)
{
pg.AddGeometry(new LineGeometry(segmentPoint[i], segmentPoint[i - 1]));
pg.AddGeometry(new LineGeometry(segmentPoint[i], segmentPoint[i + 1]));
}
ControlLinePath.Data = pg;
ControlLinePath.Stroke = Brushes.DeepPink;
}
private void InitializeVertexPath()
{
var ps = GetPolyBezierSegmentPoints(MyBezierPath);
var pg = new PathGeometry();
for (int i = 0; i < ps.Count; i++)
{
var ep = new EllipseGeometry(ps[i], 4, 4);
pg.AddGeometry(ep);
}
VertexPath.Data = pg;
VertexPath.Stroke = Brushes.DeepPink;
}
private PointCollection GetPolyBezierSegmentPoints(Path bezierPath)
{
var pg = (PathGeometry)bezierPath.Data;
PathFigure fig = pg.Figures[0];
var seg = (PolyBezierSegment)fig.Segments[0];
return seg.Points;
}
private PolyBezierSegment MakePolyBezierSegment(PointCollection anchorPoints)
{
var seg = new PolyBezierSegment();
seg.Points.Add(anchorPoints[0]);
for (int i = 1; i < anchorPoints.Count - 1; i++)
{
seg.Points.Add(anchorPoints[i]);
seg.Points.Add(anchorPoints[i]);
seg.Points.Add(anchorPoints[i]);
}
seg.Points.Add(anchorPoints[anchorPoints.Count - 1]);
seg.Points.Add(anchorPoints[anchorPoints.Count - 1]);
return seg;
}
private PathGeometry MakeBezierPahtGeometry(PointCollection points)
{
var fig = new PathFigure();
fig.StartPoint = points[0];
fig.Segments.Add(MakePolyBezierSegment(points));
var pg = new PathGeometry();
pg.Figures.Add(fig);
return pg;
}
private PointCollection RandomPoint(int count)
{
var rand = new Random();
var points = new PointCollection();
for (int i = 0; i < count; i++)
{
points.Add(new Point(rand.Next(50, 450), rand.Next(250, 450)));
}
return points;
}
private double GetTotalDistance(PointCollection anchorPoints)
{
double distance = 0;
for (int i = 0; i < anchorPoints.Count - 1; i++)
{
distance += GetDistance(anchorPoints[i], anchorPoints[i + 1]);
}
return distance;
}
private double GetDistance(Point p1, Point p2)
{
return Math.Sqrt(Math.Pow(p2.X - p1.X, 2.0) + Math.Pow(p2.Y - p1.Y, 2.0));
}
private double GetRadianFrom2Points(Point begin, Point end)
{
return Math.Atan2(end.Y - begin.Y, end.X - begin.X);
}
}
}