Одним из способов является использование QuadraticBezierSegment
или BezierSegment
.
Например, вот так:
<Path Stroke="Red" StrokeThickness="2" >
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure StartPoint="0,40">
<PathFigure.Segments>
<PathSegmentCollection>
<BezierSegment Point1="0,93"
Point2="90,117"
Point3="80,50"
/>
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
<Path Stroke="Red" StrokeThickness="2" >
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure StartPoint="0,40">
<PathFigure.Segments>
<PathSegmentCollection>
<BezierSegment Point1="0,-13"
Point2="70,-17"
Point3="80,50"
/>
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
<Polygon Points="0,0 70,0 90,100 0,80"></Polygon>
![it look like this](https://i.stack.imgur.com/WoUUE.jpg)
это не точное решение, для точного вы должны вычислить точные точки для кривых и использовать 4 QuadraticBezierSegment
Edit:
Пример для QuadraticBezierSegment
<Path Stroke="Red" StrokeThickness="1">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure StartPoint="0,40">
<PathFigure.Segments>
<PathSegmentCollection>
<QuadraticBezierSegment Point1="6,79"
Point2="45,90"
/>
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
<Path Stroke="Red" StrokeThickness="1">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure StartPoint="45,90">
<PathFigure.Segments>
<PathSegmentCollection>
<QuadraticBezierSegment Point1="80,91"
Point2="80,50"
/>
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
<Path Stroke="Red" StrokeThickness="1">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure StartPoint="0,40">
<PathFigure.Segments>
<PathSegmentCollection>
<QuadraticBezierSegment Point1="2,3"
Point2="35,0"
/>
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
<Path Stroke="Red" StrokeThickness="1">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure StartPoint="35,0">
<PathFigure.Segments>
<PathSegmentCollection>
<QuadraticBezierSegment Point1="72,8"
Point2="80,50"
/>
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
<Polygon Name="pol" Points="0,0 70,0 90,100 0,80" Stroke="Red" StrokeThickness="1"</Polygon>
![this is image of this example](https://i.stack.imgur.com/IvTlL.jpg)
это все еще экспериментальная, не расчетная точка, но довольно точная.
Edit2:
Вы можете рассчитать точки кривых с использованием этого изображения и моих комментариев:
![enter image description here](https://i.stack.imgur.com/19aR5.jpg)
Кривые
имеют начальную точку, среднюю точку и конечную точку. На этом изображении начало и конец piont L,M,N,O
; и midle W,X,Y,Z
.
Как, например, мы вычисляем точку L
:
С помощью уравнения прямой y = k * x + b
находим уравнение линии AB,DC,AC,DB,AD
. Как пересечь AC
и DB
мы находим R
. Как пересечь AB
и DC
мы находим E
. После этого мы находим уравнение прямой ER
и как пересечение ER
и AD
находим L
.
Как мы вычисляем точку W
:
С помощью уравнения для длины l = sqrt(sqr(x2 - x1) + sqr(y2 - y1))
найдите длину AR
. AW = AR/(4*pi)
и с помощью этого коэффициента, а также уравнения линии и уравнения для длины, после решения квадратного уравнения находим W
.
Другие точки, которые мы находим аналогично.
Этот алгоритм не работает только для многоугольника, который имеет параллельную линию, но в этом случае алгоритм проще. И коэффициент для длины одинаковы.
С помощью этого алгоритма я нахожу точку для 3 кривых вашего примера:
<Path Stroke="Red" StrokeThickness="1">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure StartPoint="0,36">
<PathFigure.Segments>
<PathSegmentCollection>
<QuadraticBezierSegment Point1="4.7,74.6"
Point2="39.9,88.9"
/>
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
<Path Stroke="Red" StrokeThickness="1">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure StartPoint="39.9,88.9">
<PathFigure.Segments>
<PathSegmentCollection>
<QuadraticBezierSegment Point1="83.43,92.7"
Point2="78.8,43.9"
/>
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
<Path Stroke="Red" StrokeThickness="1">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure StartPoint="0,36">
<PathFigure.Segments>
<PathSegmentCollection>
<QuadraticBezierSegment Point1="3.55,3.94"
Point2="31.8,0"
/>
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
И он изгибается точно так же, как линия эллипса. Изображение ниже:
![enter image description here](https://i.stack.imgur.com/cI5kQ.jpg)
Вы можете перевести этот алгоритм на «формулу» и найти свое решение.
Для этого вам нужно 4 функции:
1) найти линейные коэффициенты по координатам 2 пионтов
2) найти координаты Пионта как пересечь 2 линии из его коэффициентов
3) найти длину отрезка по координатам 2 точек
4) найти координаты пионта, который находится на линии с этой начальной точкой и этой длиной из линейных коэффициентов и координат начальной точки и длины, которые вы найдете в предыдущей функции, деленными на (4 * pi)
Edit3:
Вы можете оптимизировать это решение, у него есть некоторые недостатки, как параллельная линия и т. Д. Но оно быстрое, и если вы его оптимизируете, оно может удовлетворить ваши требования.
Xaml:
<Path Stroke="Red" StrokeThickness="1">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure x:Name="pathleftdown" StartPoint="0,0">
<PathFigure.Segments>
<PathSegmentCollection>
<QuadraticBezierSegment x:Name="bezleftdown" Point1="0,0"
Point2="0,0"
/>
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
<Path Stroke="Red" StrokeThickness="1">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure x:Name="pathrigthdown" StartPoint="0,0">
<PathFigure.Segments>
<PathSegmentCollection>
<QuadraticBezierSegment x:Name="bezrigthdown" Point1="0,0"
Point2="0,0"
/>
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
<Path Stroke="Red" StrokeThickness="1">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure x:Name="pathleftup" StartPoint="0,0">
<PathFigure.Segments>
<PathSegmentCollection>
<QuadraticBezierSegment x:Name="bezleftup" Point1="0,0"
Point2="0,0"
/>
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
<Path Stroke="Red" StrokeThickness="1">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure x:Name="pathrigthup" StartPoint="0,0">
<PathFigure.Segments>
<PathSegmentCollection>
<QuadraticBezierSegment x:Name="bezrigthup" Point1="0,0"
Point2="0,0"
/>
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
<Polygon Name="pol" Points="0,0 250,0 251,340 0,341" Stroke="Red" StrokeThickness="1"></Polygon>
<Button Content="Generate" Width ="80" Height="30" HorizontalAlignment="Right" VerticalAlignment="Top" Click="Button_Click"></Button>
и код:
private class pointXY
{
public double x;
public double y;
}
private class lineKB
{
public double k;
public double b;
public bool flagXconst = false;
public double xConst = 0;
}
private lineKB GetLineFromPonts(pointXY A, pointXY B)
{
lineKB line = new lineKB();
if ((B.x - A.x) != 0)
{
line.k = (B.y - A.y) / (B.x - A.x);
line.b = A.y - A.x * line.k;
}
else
{
line.xConst = A.x;
line.flagXconst = true;
}
return line;
}
private pointXY GetPointFromLines(lineKB a, lineKB b)
{
pointXY point = new pointXY();
if (a.flagXconst)
{
point.x = a.xConst;
point.y = a.xConst * b.k + b.b;
}else
if (b.flagXconst)
{
point.x = b.xConst;
point.y = b.xConst * a.k + a.b;
}
else
{
point.x = (a.b - b.b) / (b.k - a.k);
point.y = a.k * point.x + a.b;
}
return point;
}
private double LengthOfLine(pointXY A, pointXY B)
{
return Math.Sqrt((B.x - A.x) * (B.x - A.x) + (B.y - A.y) * (B.y - A.y));
}
private pointXY GetMidlePoint(pointXY S, double l, lineKB line, bool leftright)
{
double b = -2 * S.x - 2 * line.k * (-line.b + S.y);
double a = (1 + line.k * line.k);
double c = (S.x * S.x - l * l + (-line.b + S.y) * (-line.b + S.y));
double d = b*b - 4 * a * c;
double x1 = (-b + Math.Sqrt(d)) / (2 * a);
double x2 = (-b - Math.Sqrt(d)) / (2 * a);
pointXY ret = new pointXY();
if (leftright)
if (x1 > S.x) ret.x = x1;
else ret.x = x2;
else
if (x1 < S.x) ret.x = x1;
else ret.x = x2;
ret.y = line.k * ret.x + line.b;
return ret;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
pointXY A = new pointXY();
A.x = pol.Points[0].X;
A.y = pol.Points[0].Y;
pointXY B = new pointXY();
B.x = pol.Points[1].X;
B.y = pol.Points[1].Y;
pointXY C = new pointXY();
C.x = pol.Points[2].X;
C.y = pol.Points[2].Y;
pointXY D = new pointXY();
D.x = pol.Points[3].X;
D.y = pol.Points[3].Y;
lineKB AC = GetLineFromPonts(A, C);
lineKB BD = GetLineFromPonts(B, D);
pointXY R = GetPointFromLines(AC, BD);
lineKB AB = GetLineFromPonts(A, B);
lineKB BC = GetLineFromPonts(B, C);
lineKB CD = GetLineFromPonts(C, D);
lineKB DA = GetLineFromPonts(D, A);
pointXY E = GetPointFromLines(AB, CD);
lineKB ER = GetLineFromPonts(E, R);
pointXY L = GetPointFromLines(ER, DA);
pointXY N = GetPointFromLines(ER, BC);
pointXY F = GetPointFromLines(BC, DA);
lineKB FR = GetLineFromPonts(F, R);
pointXY M = GetPointFromLines(FR, AB);
pointXY O = GetPointFromLines(FR, CD);
pointXY W = GetMidlePoint(A, (LengthOfLine(A, R) / (4 * Math.PI)), AC, true);
pointXY X = GetMidlePoint(B, (LengthOfLine(B, R) / (4 * Math.PI)), BD, false);
pointXY Y = GetMidlePoint(C, (LengthOfLine(C, R) / (4 * Math.PI)), AC, false);
pointXY Z = GetMidlePoint(D, (LengthOfLine(D, R) / (4 * Math.PI)), BD, true);
pathleftup.StartPoint = new Point(L.x, L.y);
bezleftup.Point1 = new Point(W.x, W.y);
bezleftup.Point2 = new Point(M.x, M.y);
pathleftdown.StartPoint = new Point(L.x, L.y);
bezleftdown.Point1 = new Point(Z.x, Z.y);
bezleftdown.Point2 = new Point(O.x, O.y);
pathrigthdown.StartPoint = new Point(O.x, O.y);
bezrigthdown.Point1 = new Point(Y.x, Y.y);
bezrigthdown.Point2 = new Point(N.x, N.y);
pathrigthup.StartPoint = new Point(M.x, M.y);
bezrigthup.Point1 = new Point(X.x, X.y);
bezrigthup.Point2 = new Point(N.x, N.y);
}