欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

WPF+Canvas實(shí)現(xiàn)平滑筆跡的示例代碼

 更新時間:2022年09月05日 14:33:37   作者:小封(鄺攀升)  
這篇文章主要介紹了如何利用WPF+Canvas實(shí)現(xiàn)平滑筆跡效果,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)或工作有一定幫助,需要的可以參考一下

實(shí)現(xiàn)思路

收集路徑點(diǎn)集。

平均采樣路徑點(diǎn)集。

將路徑點(diǎn)集轉(zhuǎn)為 LineB。

把 LineB 數(shù)據(jù)傳給 Path。

實(shí)現(xiàn)效果

實(shí)現(xiàn)代碼

1)Vector2D.cs 代碼如下

using?System;
using?System.Collections.Generic;
using?System.Linq;
using?System.Text;

namespace?WPFDevelopers.Samples.ExampleViews.CanvasHandWriting
{
????public?class?Vector2D
????{
????????public?double?X?{?get;?set;?}?=?0;
????????public?double?Y?{?get;?set;?}?=?0;
???????
????????///?<summary>
????????///?向量的模
????????///?</summary>
????????public?double?Mold
????????{
????????????get
????????????{
????????????????//自身各分量平方運(yùn)算.
????????????????double?X?=?this.X?*?this.X;
????????????????double?Y?=?this.Y?*?this.Y;
????????????????return?Math.Sqrt(X?+?Y);//開根號,最終返回向量的長度/模/大小.
????????????}
????????}
????????///?<summary>
????????///?單位向量
????????///?</summary>
????????public?Vector2D?UnitVector
????????{
????????????get
????????????{
????????????????double?sumSquares?=?(X?*?X)?+?(Y?*?Y);
????????????????return?new?Vector2D(X?/?Math.Sqrt(sumSquares),?Y?/?Math.Sqrt(sumSquares));
????????????}
????????}

????????public?Vector2D()
????????{

????????}
????????public?Vector2D(double?x,?double?y)
????????{
????????????X?=?x;
????????????Y?=?y;
????????}
????????public?Vector2D(System.Windows.Point?point)
????????{
????????????X?=?point.X;
????????????Y?=?point.Y;
????????}

????????public?void?Offset(double?angle,?double?distance,?AngleType?angleType?=?AngleType.Radian)
????????{
????????????var?vector2D?=?Vector2D.CalculateVectorOffset(this,?angle,?distance,?angleType);
????????????X?=?vector2D.X;
????????????Y?=?vector2D.Y;
????????}
????????public?void?Rotate(double?angle,?Vector2D?vectorCenter?=?null,?AngleType?angleType?=?AngleType.Radian)
????????{
????????????vectorCenter?=?vectorCenter?==?null???this?:?vectorCenter;
????????????var?vector2D?=?Vector2D.CalculateVectorRotation(this,?vectorCenter,?angle,?angleType);
????????????X?=?vector2D.X;
????????????Y?=?vector2D.Y;
????????}

????????#region?靜態(tài)方法
????????///?<summary>
????????///?計(jì)算兩個向量之間的距離
????????///?</summary>
????????public?static?double?CalculateVectorDistance(Vector2D?vector2DA,?Vector2D?vector2DB)
????????{
????????????Vector2D?vector2D?=?vector2DA?-?vector2DB;
????????????return?vector2D.Mold;
????????}

????????///?<summary>
????????///?計(jì)算兩點(diǎn)夾角,右側(cè)X軸線為0度,向下為正,向上為負(fù)
????????///?</summary>
????????public?static?double?IncludedAngleXAxis(Vector2D?vector2DA,?Vector2D?vector2DB,?AngleType?angleType?=?AngleType.Radian)
????????{
????????????double?radian?=?Math.Atan2(vector2DB.Y?-?vector2DA.Y,?vector2DB.X?-?vector2DA.X);?//弧度:1.1071487177940904
????????????return?angleType?==?AngleType.Radian???radian?:?ComputingHelper.RadianToAngle(radian);
????????}

????????///?<summary>
????????///?計(jì)算兩點(diǎn)夾角,下側(cè)Y軸線為0度,向右為正,向左為負(fù)
????????///?</summary>
????????public?static?double?IncludedAngleYAxis(Vector2D?vector2DA,?Vector2D?vector2DB,?AngleType?angleType?=?AngleType.Radian)
????????{
????????????double?radian?=?Math.Atan2(vector2DB.X?-?vector2DA.X,?vector2DB.Y?-?vector2DA.Y);?//弧度:0.46364760900080609
????????????return?angleType?==?AngleType.Radian???radian?:?ComputingHelper.RadianToAngle(radian);
????????}

????????///?<summary>
????????///?偏移向量到指定角度,指定距離
????????///?</summary>
????????public?static?Vector2D?CalculateVectorOffset(Vector2D?vector2D,?double?angle,?double?distance,?AngleType?angleType?=?AngleType.Radian)
????????{
????????????Vector2D?pointVector2D?=?new?Vector2D();
????????????if?(angleType?==?AngleType.Angle)
????????????{
????????????????angle?=?angle?/?(180?/?Math.PI);//角度轉(zhuǎn)弧度
????????????}
????????????double?width?=?Math.Cos(Math.Abs(angle))?*?distance;
????????????double?height?=?Math.Sin(Math.Abs(angle))?*?distance;
????????????if(angle?<=?Math.PI?&&?angle?>=?0)
????????????//if?(angle?is?<=?Math.PI?and?>=?0)
????????????{
????????????????pointVector2D.X?=?vector2D.X?-?width;
????????????????pointVector2D.Y?=?vector2D.Y?-?height;
????????????}
????????????if?(angle?>=?(-Math.PI)?&&?angle?<=?0)
????????????//if?(angle?is?>=?(-Math.PI)?and?<=?0)
????????????{
????????????????pointVector2D.X?=?vector2D.X?-?width;
????????????????pointVector2D.Y?=?vector2D.Y?+?height;
????????????}
????????????return?pointVector2D;
????????}

????????///?<summary>
????????///?圍繞一個中心點(diǎn),旋轉(zhuǎn)一個向量,相對旋轉(zhuǎn)
????????///?</summary>
????????public?static?Vector2D?CalculateVectorRotation(Vector2D?vector2D,?Vector2D?vectorCenter,?double?radian,?AngleType?angleType?=?AngleType.Radian)
????????{
????????????radian?=?angleType?==?AngleType.Radian???radian?:?ComputingHelper.RadianToAngle(radian);
????????????double?x1?=?(vector2D.X?-?vectorCenter.X)?*?Math.Sin(radian)?+?(vector2D.Y?-?vectorCenter.Y)?*?Math.Cos(radian)?+?vectorCenter.X;
????????????double?y1?=?-(vector2D.X?-?vectorCenter.X)?*?Math.Cos(radian)?+?(vector2D.Y?-?vectorCenter.Y)?*?Math.Sin(radian)?+?vectorCenter.Y;
????????????return?new?Vector2D(x1,?y1);
????????}
????????public?static?Vector2D?CalculateVectorCenter(Vector2D?vector2DA,?Vector2D?vector2DB)
????????{
????????????return?new?Vector2D((vector2DA.X?+?vector2DB.X)?/?2,?(vector2DA.Y?+?vector2DB.Y)?/?2);
????????}

????????///?<summary>
????????///?判斷坐標(biāo)點(diǎn)是否在多邊形區(qū)域內(nèi),射線法
????????///?</summary>
????????public?static?bool?IsPointPolygonalArea(Vector2D?vector2D,?List<Vector2D>?aolygonaArrayList)
????????{
????????????var?N?=?aolygonaArrayList.Count;
????????????var?boundOrVertex?=?true;?//如果點(diǎn)位于多邊形的頂點(diǎn)或邊上,也算做點(diǎn)在多邊形內(nèi),直接返回true
????????????var?crossNumber?=?0;?//x的交叉點(diǎn)計(jì)數(shù)
????????????var?precision?=?2e-10;?//浮點(diǎn)類型計(jì)算時候與0比較時候的容差
????????????Vector2D?p1,?p2;?//neighbour?bound?vertices
????????????var?p?=?vector2D;?//測試點(diǎn)
????????????p1?=?aolygonaArrayList[0];?//left?vertex????????
????????????for?(var?i?=?1;?i?<=?N;?++i)
????????????{
????????????????//check?all?rays????????????
????????????????if?(p.X.Equals(p1.X)?&&?p.Y.Equals(p1.Y))
????????????????{
????????????????????return?boundOrVertex;?//p?is?an?vertex
????????????????}

????????????????p2?=?aolygonaArrayList[i?%?N];?//right?vertex????????????
????????????????if?(p.X?<?Math.Min(p1.X,?p2.X)?||?p.X?>?Math.Max(p1.X,?p2.X))
????????????????{
????????????????????//ray?is?outside?of?our?interests????????????????
????????????????????p1?=?p2;
????????????????????continue;?//next?ray?left?point
????????????????}

????????????????if?(p.X?>?Math.Min(p1.X,?p2.X)?&&?p.X?<?Math.Max(p1.X,?p2.X))
????????????????{
????????????????????//ray?is?crossing?over?by?the?algorithm?(common?part?of)
????????????????????if?(p.Y?<=?Math.Max(p1.Y,?p2.Y))
????????????????????{
????????????????????????//x?is?before?of?ray????????????????????
????????????????????????if?(p1.X?==?p2.X?&&?p.Y?>=?Math.Min(p1.Y,?p2.Y))
????????????????????????{
????????????????????????????//overlies?on?a?horizontal?ray
????????????????????????????return?boundOrVertex;
????????????????????????}

????????????????????????if?(p1.Y?==?p2.Y)
????????????????????????{
????????????????????????????//ray?is?vertical????????????????????????
????????????????????????????if?(p1.Y?==?p.Y)
????????????????????????????{
????????????????????????????????//overlies?on?a?vertical?ray
????????????????????????????????return?boundOrVertex;
????????????????????????????}
????????????????????????????else
????????????????????????????{
????????????????????????????????//before?ray
????????????????????????????????++crossNumber;
????????????????????????????}
????????????????????????}
????????????????????????else
????????????????????????{
????????????????????????????//cross?point?on?the?left?side????????????????????????
????????????????????????????var?xinters?=
????????????????????????????????(p.X?-?p1.X)?*?(p2.Y?-?p1.Y)?/?(p2.X?-?p1.X)?+
????????????????????????????????p1.Y;?//cross?point?of?Y????????????????????????
????????????????????????????if?(Math.Abs(p.Y?-?xinters)?<?precision)
????????????????????????????{
????????????????????????????????//overlies?on?a?ray
????????????????????????????????return?boundOrVertex;
????????????????????????????}

????????????????????????????if?(p.Y?<?xinters)
????????????????????????????{
????????????????????????????????//before?ray
????????????????????????????????++crossNumber;
????????????????????????????}
????????????????????????}
????????????????????}
????????????????}
????????????????else
????????????????{
????????????????????//special?case?when?ray?is?crossing?through?the?vertex????????????????
????????????????????if?(p.X?==?p2.X?&&?p.Y?<=?p2.Y)
????????????????????{
????????????????????????//p?crossing?over?p2????????????????????
????????????????????????var?p3?=?aolygonaArrayList[(i?+?1)?%?N];?//next?vertex????????????????????
????????????????????????if?(p.X?>=?Math.Min(p1.X,?p3.X)?&&?p.X?<=?Math.Max(p1.X,?p3.X))
????????????????????????{
????????????????????????????//p.X?lies?between?p1.X?&?p3.X
????????????????????????????++crossNumber;
????????????????????????}
????????????????????????else
????????????????????????{
????????????????????????????crossNumber?+=?2;
????????????????????????}
????????????????????}
????????????????}
????????????????p1?=?p2;?//next?ray?left?point
????????????}
????????????if?(crossNumber?%?2?==?0)
????????????{
????????????????//偶數(shù)在多邊形外
????????????????return?false;
????????????}
????????????else
????????????{
????????????????//奇數(shù)在多邊形內(nèi)
????????????????return?true;
????????????}
????????}

????????///?<summary>
????????///?判斷一個點(diǎn)是否在一條邊內(nèi)
????????///?</summary>
??????
????????public?static?bool?IsPointEdge(Vector2D?point,?Vector2D?startPoint,?Vector2D?endPoint)
????????{
????????????return?(point.X?-?startPoint.X)?*?(endPoint.Y?-?startPoint.Y)?==?(endPoint.X?-?startPoint.X)?*?(point.Y?-?startPoint.Y)
????????????????&&?Math.Min(startPoint.X,?endPoint.X)?<=?point.X?&&?point.X?<=?Math.Max(startPoint.X,?endPoint.X)
????????????????&&?Math.Min(startPoint.Y,?endPoint.Y)?<=?point.Y?&&?point.Y?<=?Math.Max(startPoint.Y,?endPoint.Y);
????????}
????????#endregion?靜態(tài)方法

????????#region?運(yùn)算符重載
????????///?<summary>
????????///?重載運(yùn)算符,和運(yùn)算,可以用來計(jì)算兩向量距離
????????///?</summary>
????????public?static?Vector2D?operator?+(Vector2D?vector2DA,?Vector2D?vector2DB)
????????{
????????????Vector2D?vector2D?=?new?Vector2D();
????????????vector2D.X?=?vector2DA.X?+?vector2DB.X;
????????????vector2D.Y?=?vector2DA.Y?+?vector2DB.Y;
????????????return?vector2D;
????????}

????????///?<summary>
????????///?重載運(yùn)算符,差運(yùn)算,可以用來計(jì)算兩向量距離
????????///?</summary>
????????public?static?Vector2D?operator?-(Vector2D?vector2DA,?Vector2D?vector2DB)
????????{
????????????Vector2D?vector2D?=?new?Vector2D();
????????????vector2D.X?=?vector2DA.X?-?vector2DB.X;
????????????vector2D.Y?=?vector2DA.Y?-?vector2DB.Y;
????????????return?vector2D;
????????}

????????///?<summary>
????????///?重載運(yùn)算符,差運(yùn)算,可以用來計(jì)算兩向量距離
????????///?</summary>
????????public?static?Vector2D?operator?-(Vector2D?vector2D,?double?_float)
????????{
????????????return?new?Vector2D(vector2D.X?-?_float,?vector2D.Y?-?_float);
????????}

????????///?<summary>
????????///?重載運(yùn)算符,點(diǎn)積運(yùn)算,可以用來計(jì)算兩向量夾角
????????///?</summary>
????????public?static?double?operator?*(Vector2D?vector2DA,?Vector2D?vector2DB)
????????{
????????????return?(vector2DA.X?*?vector2DB.X)?+?(vector2DA.Y?*?vector2DB.Y);
????????}
????????public?static?double?operator?*(Vector2D?vector2D,?double?_float)
????????{
????????????return?(vector2D.X?*?_float)?+?(vector2D.Y?*?_float);
????????}

????????///?<summary>
????????///?重載運(yùn)算符,點(diǎn)積運(yùn)算,可以用來計(jì)算兩向量夾角
????????///?</summary>
????????public?static?double?operator?/(Vector2D?vector2D,?double?para)
????????{
????????????return?(vector2D.X?/?para)?+?(vector2D.Y?/?para);
????????}

????????///?<summary>
????????///?重載運(yùn)算符
????????///?</summary>
????????
????????public?static?bool?operator?>=(Vector2D?vector2D,?double?para)
????????{
????????????if?(vector2D.Mold?>=?para)
????????????{
????????????????return?true;
????????????}
????????????else
????????????{
????????????????return?false;
????????????}
????????}

????????public?static?bool?operator?<=(Vector2D?vector2D,?double?para)
????????{
????????????if?(vector2D.Mold?<=?para)
????????????{
????????????????return?true;
????????????}
????????????else
????????????{
????????????????return?false;
????????????}
????????}

????????public?static?bool?operator?>(Vector2D?vector2D,?double?para)
????????{
????????????if?(vector2D.Mold?>?para)
????????????{
????????????????return?true;
????????????}
????????????else
????????????{
????????????????return?false;
????????????}
????????}

????????public?static?bool?operator?<(Vector2D?vector2D,?double?para)
????????{
????????????if?(vector2D.Mold?<?para)
????????????{
????????????????return?true;
????????????}
????????????else
????????????{
????????????????return?false;
????????????}
????????}
????????#endregion?運(yùn)算符重載

????????#region?隱式轉(zhuǎn)換
????????///?<summary>
????????///?重載隱式轉(zhuǎn)換,可以直接使用Point
????????///?</summary>
????????///?<param?name="v"></param>
????????public?static?implicit?operator?Vector2D(System.Windows.Point?v)//隱式轉(zhuǎn)換
????????{
????????????return?new?Vector2D(v.X,?v.Y);
????????}
????????///?<summary>
????????///?重載隱式轉(zhuǎn)換,可以直接使用Point
????????///?</summary>
????????///?<param?name="v"></param>
????????public?static?implicit?operator?System.Windows.Point(Vector2D?v)//隱式轉(zhuǎn)換
????????{
????????????return?new?System.Windows.Point(v.X,?v.Y);
????????}
????????///?<summary>
????????///?重載隱式轉(zhuǎn)換,可以直接使用double
????????///?</summary>
????????///?<param?name="v"></param>
????????public?static?implicit?operator?Vector2D(double?v)//隱式轉(zhuǎn)換
????????{
????????????return?new?Vector2D(v,?v);
????????}
????????#endregion?隱式轉(zhuǎn)換

????????#region?ToString
????????public?override?string?ToString()
????????{
????????????return?X.ToString()?+?","?+?Y.ToString();
????????}
????????public?string?ToString(string?symbol)
????????{
????????????return?X.ToString()?+?symbol?+?Y.ToString();
????????}
????????public?string?ToString(string?sender,?string?symbol)
????????{
????????????return?X.ToString(sender)?+?symbol?+?Y.ToString(sender);
????????}
????????#endregion
????}
????public?enum?AngleType?
????{
????????Angle,
????????Radian
????}
}

2)ComputingHelper.cs 代碼如下

using?System;
using?System.Collections.Generic;
using?System.Linq;
using?System.Text;

namespace?WPFDevelopers.Samples.ExampleViews.CanvasHandWriting
{
????public?static?class?ComputingHelper
????{
????????public?static?double?AngleToRadian(double?angle)
????????{
????????????return?angle?*?(Math.PI?/?180);
????????}
????????public?static?double?RadianToAngle(double?radian)
????????{
????????????return?radian?*?(180?/?Math.PI);
????????}

????????///?<summary>
????????///?將一個值從一個范圍映射到另一個范圍
????????///?</summary>
????????public?static?double?RangeMapping(double?inputValue,?double?enterLowerLimit,?double?enterUpperLimit,?double?outputLowerLimit,?double?OutputUpperLimit,?CurveType?curveType?=?CurveType.None)
????????{
????????????var?percentage?=?(enterUpperLimit?-?inputValue)?/?(enterUpperLimit?-?enterLowerLimit);
????????????switch?(curveType)
????????????{
????????????????case?CurveType.Sine:
????????????????????percentage?=?Math.Sin(percentage);
????????????????????break;
????????????????case?CurveType.CoSine:
????????????????????percentage?=?Math.Cos(percentage);
????????????????????break;
????????????????case?CurveType.Tangent:
????????????????????percentage?=?Math.Tan(percentage);
????????????????????break;
????????????????case?CurveType.Cotangent:
????????????????????percentage?=?Math.Atan(percentage);
????????????????????break;
????????????????default:
????????????????????break;
????????????}
????????????double?outputValue?=?OutputUpperLimit?-?((OutputUpperLimit?-?outputLowerLimit)?*?percentage);

????????????return?outputValue;
????????}

????????public?static?string?ByteToKB(double?_byte)
????????{
????????????List<string>?unit?=?new?List<string>()?{?"B",?"KB",?"MB",?"GB",?"TB",?"P",?"PB"?};
????????????int?i?=?0;
????????????while?(_byte?>?1024)
????????????{
????????????????_byte?/=?1024;
????????????????i++;
????????????}
????????????_byte?=?Math.Round(_byte,?3);//保留三位小數(shù)
????????????return?_byte?+?unit[i];
????????}

????????///?<summary>
????????///?縮短一個數(shù)組,對其進(jìn)行平均采樣
????????///?</summary>
????????
????????public?static?double[]?AverageSampling(double[]?sourceArray,?int?number)
????????{
????????????if?(sourceArray.Length?<=?number)
????????????{
????????????????return?sourceArray;
????????????????//throw?new?Exception("新的數(shù)組必須比原有的要小!");
????????????}
????????????double[]?arrayList?=?new?double[number];
????????????double?stride?=?(double)sourceArray.Length?/?number;
????????????for?(int?i?=?0,?jIndex?=?0;?i?<?number;?i++,?jIndex++)
????????????{
????????????????double?strideIncrement?=?i?*?stride;
????????????????strideIncrement?=?Math.Round(strideIncrement,?6);
????????????????double?sum?=?0;
????????????????int?firstIndex?=?(int)(strideIncrement);
????????????????double?firstDecimal?=?strideIncrement?-?firstIndex;

????????????????int?tailIndex?=?(int)(strideIncrement?+?stride);
????????????????double?tailDecimal?=?(strideIncrement?+?stride)?-?tailIndex;

????????????????if?(firstDecimal?!=?0)
????????????????????sum?+=?sourceArray[firstIndex]?*?(1?-?firstDecimal);

????????????????if?(tailDecimal?!=?0?&&?tailIndex?!=?sourceArray.Length)
????????????????????sum?+=?sourceArray[tailIndex]?*?(tailDecimal);

????????????????int?startIndex?=?firstDecimal?==?0???firstIndex?:?firstIndex?+?1;
????????????????int?endIndex?=?tailIndex;

????????????????for?(int?j?=?startIndex;?j?<?endIndex;?j++)
????????????????????sum?+=?sourceArray[j];

????????????????arrayList[jIndex]?=?sum?/?stride;
????????????}
????????????return?arrayList;
????????}
????????public?static?List<Vector2D>?AverageSampling(List<Vector2D>?sourceArray,?int?number)
????????{
????????????if?(sourceArray.Count?<=?number?-?2)
????????????{
????????????????return?sourceArray;
????????????}
????????????double[]?x?=?new?double[sourceArray.Count];
????????????double[]?y?=?new?double[sourceArray.Count];
????????????for?(int?i?=?0;?i?<?sourceArray.Count;?i++)
????????????{
????????????????x[i]?=?sourceArray[i].X;
????????????????y[i]?=?sourceArray[i].Y;
????????????}

????????????double[]?X?=?AverageSampling(x,?number?-?2);
????????????double[]?Y?=?AverageSampling(y,?number?-?2);

????????????List<Vector2D>?arrayList?=?new?List<Vector2D>();
????????????for?(int?i?=?0;?i?<?number?-?2;?i++)
????????????{
????????????????arrayList.Add(new?Vector2D(X[i],?Y[i]));
????????????}

????????????arrayList.Insert(0,?sourceArray[0]);//添加首
????????????arrayList.Add(sourceArray[sourceArray.Count?-?1]);//添加尾

????????????return?arrayList;
????????}
????}
????public?enum?CurveType?
????{
????????Sine,
????????CoSine,
????????Tangent,
????????Cotangent,
????????None
????}
}

3)LineB.cs 代碼如下

using?System;
using?System.Collections.Generic;
using?System.Linq;
using?System.Text;
using?System.Windows.Media;

namespace?WPFDevelopers.Samples.ExampleViews.CanvasHandWriting
{
????public?class?LineB
????{
????????private?List<Vector2D>?_vector2DList?=?new?List<Vector2D>();
????????public?List<Vector2D>?Vector2DList
????????{
????????????get?{?return?_vector2DList;?}
????????????set
????????????{
????????????????_vector2DList?=?value;
????????????}
????????}

????????private?List<BezierCurve>?_bezierCurveList?=?new?List<BezierCurve>();
????????public?List<BezierCurve>?BezierCurveList
????????{
????????????get?{?return?_bezierCurveList;?}
????????????private?set?{?_bezierCurveList?=?value;?}
????????}


????????private?double?_tension?=?0.618;
????????public?double?Tension
????????{
????????????get?{?return?_tension;?}
????????????set
????????????{
????????????????_tension?=?value;
????????????????if?(_tension?>?10)
????????????????????_tension?=?10;
????????????????if?(_tension?<?0)
????????????????????_tension?=?0;
????????????}
????????}

????????private?bool?_isClosedCurve?=?true;
????????public?bool?IsClosedCurve
????????{
????????????get?{?return?_isClosedCurve;?}
????????????set?{?_isClosedCurve?=?value;?}
????????}

????????private?string?_pathData?=?string.Empty;
????????public?string?PathData
????????{
????????????get
????????????{
????????????????if?(_pathData?==?string.Empty)
????????????????{
????????????????????_pathData?=?Vector2DToBezierCurve();
????????????????}
????????????????return?_pathData;
????????????}
????????}

????????private?string?Vector2DToBezierCurve()?
????????{
????????????if?(Vector2DList.Count?<?3)
????????????????return?string.Empty;

????????????BezierCurveList.Clear();
????????????for?(int?i?=?0;?i?<?Vector2DList.Count;?i++)
????????????{
????????????????int?pointTwoIndex?=?i?+?1?<?Vector2DList.Count???i?+?1?:?0;
????????????????int?pointThreeIndex?=?i?+?2?<?Vector2DList.Count???i?+?2?:?i?+?2?-?Vector2DList.Count;
????????????????Vector2D?vector2D1?=?Vector2DList[i];
????????????????Vector2D?vector2D2?=?Vector2DList[pointTwoIndex];
????????????????Vector2D?vector2D3?=?Vector2DList[pointThreeIndex];

????????????????Vector2D?startVector2D?=?Vector2D.CalculateVectorCenter(vector2D1,?vector2D2);
????????????????double?startAngle?=?Vector2D.IncludedAngleXAxis(vector2D1,?vector2D2);
????????????????double?startDistance?=?Vector2D.CalculateVectorDistance(startVector2D,?vector2D2)?*?(1?-?Tension);
????????????????Vector2D?startControlPoint?=?Vector2D.CalculateVectorOffset(vector2D2,?startAngle,?startDistance);

????????????????Vector2D?endVector2D?=?Vector2D.CalculateVectorCenter(vector2D2,?vector2D3);
????????????????double?endAngle?=?Vector2D.IncludedAngleXAxis(endVector2D,?vector2D2);
????????????????double?endDistance?=?Vector2D.CalculateVectorDistance(endVector2D,?vector2D2)?*?(1?-?Tension);
????????????????Vector2D?endControlPoint?=?Vector2D.CalculateVectorOffset(endVector2D,?endAngle,?endDistance);

????????????????BezierCurve?bezierCurve?=?new?BezierCurve();
????????????????bezierCurve.StartVector2D?=?startVector2D;
????????????????bezierCurve.StartControlPoint?=?startControlPoint;
????????????????bezierCurve.EndVector2D?=?endVector2D;
????????????????bezierCurve.EndControlPoint?=?endControlPoint;
????????????????BezierCurveList.Add(bezierCurve);
????????????}
????????????if?(!IsClosedCurve)
????????????{
????????????????BezierCurveList[0].StartVector2D?=?Vector2DList[0];
????????????????BezierCurveList.RemoveAt(BezierCurveList.Count?-?1);
????????????????BezierCurveList[BezierCurveList.Count?-?1].EndVector2D?=?Vector2DList[Vector2DList.Count?-?1];
????????????????BezierCurveList[BezierCurveList.Count?-?1].EndControlPoint?=?BezierCurveList[BezierCurveList.Count?-?1].EndVector2D;
????????????}
????????????string?path?=?$"M?{BezierCurveList[0].StartVector2D.ToString()}?";
????????????foreach?(var?item?in?BezierCurveList)
????????????{
????????????????path?+=?$"C?{item.StartControlPoint.ToString("?")},{item.EndControlPoint.ToString("?")},{item.EndVector2D.ToString("?")}?";
????????????}
????????????return?path;
????????}

????????public?LineB()
????????{
????????}
????????public?LineB(List<Vector2D>?verVector2DList,?bool?isClosedCurve?=?true)
????????{
????????????this.Vector2DList?=?verVector2DList;
????????????this.IsClosedCurve?=?isClosedCurve;
????????}

????????///?<summary>
????????///?重載隱式轉(zhuǎn)換,可以直接使用Point
????????///?</summary>
????????///?<param?name="v"></param>
????????public?static?implicit?operator?Geometry(LineB?lineB)//隱式轉(zhuǎn)換
????????{
????????????return?Geometry.Parse(lineB.PathData);
????????}
????}
????public?class?BezierCurve
????{
????????private?Vector2D?_startVector2D?=?new?Vector2D(0,?0);
????????public?Vector2D?StartVector2D
????????{
????????????get?{?return?_startVector2D;?}
????????????set?{?_startVector2D?=?value;?}
????????}

????????private?Vector2D?_startControlPoint?=?new?Vector2D(0,?100);
????????public?Vector2D?StartControlPoint
????????{
????????????get?{?return?_startControlPoint;?}
????????????set?{?_startControlPoint?=?value;?}
????????}

????????private?Vector2D?_endControlPoint?=?new?Vector2D(100,?0);
????????public?Vector2D?EndControlPoint
????????{
????????????get?{?return?_endControlPoint;?}
????????????set?{?_endControlPoint?=?value;?}
????????}

????????private?Vector2D?_endVector2D?=?new?Vector2D(100,?100);
????????public?Vector2D?EndVector2D
????????{
????????????get?{?return?_endVector2D;?}
????????????set?{?_endVector2D?=?value;?}
????????}


????}
}

4)CanvasHandWritingExample.xaml 代碼如下

<UserControl?x:Class="WPFDevelopers.Samples.ExampleViews.CanvasHandWriting.CanvasHandWritingExample"
?????????????xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
?????????????xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
?????????????xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"?
?????????????xmlns:d="http://schemas.microsoft.com/expression/blend/2008"?
?????????????xmlns:local="clr-namespace:WPFDevelopers.Samples.ExampleViews.CanvasHandWriting"
?????????????mc:Ignorable="d"?
?????????????d:DesignHeight="450"?d:DesignWidth="800">
????<UserControl.Resources>
????????<Style?TargetType="{x:Type?TextBlock}">
????????????<Setter?Property="Foreground"?Value="{StaticResource?PrimaryTextSolidColorBrush}"?/>
????????</Style>
????</UserControl.Resources>
????<Grid>
????????<Grid.RowDefinitions>
????????????<RowDefinition?Height="auto"/>
????????????<RowDefinition/>
????????</Grid.RowDefinitions>
????????<StackPanel?Orientation="Horizontal"?Margin="4">
????????????<TextBlock?Text="張力:"?VerticalAlignment="Center"/>
????????????<TextBox?Text="{Binding?Tension,RelativeSource={RelativeSource?AncestorType=local:CanvasHandWritingExample}}"/>
????????????<Slider?Width="100"?SmallChange="0.01"?
????????????????????Value="{Binding?Tension,RelativeSource={RelativeSource?AncestorType=local:CanvasHandWritingExample}}"?Maximum="1"?
????????????????????VerticalAlignment="Center"?
????????????????????Margin="5,0"/>
????????????<TextBlock??Text="平滑采樣:"?VerticalAlignment="Center"/>
????????????<TextBox?Text="{Binding?SmoothSampling,RelativeSource={RelativeSource?AncestorType=local:CanvasHandWritingExample}}"
?????????????????????Margin="5,0"/>
????????????<Slider?Value="{Binding?SmoothSampling,RelativeSource={RelativeSource?AncestorType=local:CanvasHandWritingExample}}"
????????????????????Width="100"?
????????????????????VerticalAlignment="Center"?
????????????????????SmallChange="0.01"?Maximum="1"?
????????????????????TickFrequency="0.1"/>
????????????<CheckBox?Content="橡皮擦"?
??????????????????????VerticalAlignment="Center"
??????????????????????Margin="5,0"
??????????????????????IsChecked="{Binding?IsEraser,RelativeSource={RelativeSource?AncestorType=local:CanvasHandWritingExample}}"/>
????????????<Button?Content="清空畫布"?Click="btnClertCanvas_Click"/>
????????</StackPanel>
????????<Canvas?x:Name="drawingCanvas"?
????????????????Grid.Row="1"?Background="Black"?
????????????????PreviewMouseLeftButtonDown="DrawingCanvas_PreviewMouseLeftButtonDown"
????????????????PreviewMouseMove="DrawingCanvas_PreviewMouseMove"
????????????????PreviewMouseLeftButtonUp="DrawingCanvas_PreviewMouseLeftButtonUp"/>
??????????
????</Grid>
</UserControl>

5)CanvasHandWritingExample.xaml.cs 代碼如下

using?System;
using?System.Collections.Generic;
using?System.Threading;
using?System.Threading.Tasks;
using?System.Windows;
using?System.Windows.Controls;
using?System.Windows.Input;
using?System.Windows.Media;
using?System.Windows.Shapes;

namespace?WPFDevelopers.Samples.ExampleViews.CanvasHandWriting
{
????///?<summary>
????///?????CanvasHandWritingExample.xaml?的交互邏輯
????///?</summary>
????public?partial?class?CanvasHandWritingExample?:?UserControl
????{
????????public?static?readonly?DependencyProperty?TensionProperty?=
????????????DependencyProperty.Register("Tension",?typeof(double),?typeof(CanvasHandWritingExample),
????????????????new?PropertyMetadata(0.618));

????????public?static?readonly?DependencyProperty?SmoothSamplingProperty?=
????????????DependencyProperty.Register("SmoothSampling",?typeof(double),?typeof(CanvasHandWritingExample),
????????????????new?UIPropertyMetadata(OnSmoothSamplingChanged));

????????public?static?readonly?DependencyProperty?IsEraserProperty?=
????????????DependencyProperty.Register("IsEraser",?typeof(bool),?typeof(CanvasHandWritingExample),
????????????????new?PropertyMetadata(false));

????????private?readonly?Dictionary<Path,?List<Vector2D>>?_PathVector2DDictionary?;

????????volatile?bool?_IsStart?=?false;
????????Path?_DrawingPath?=?default;

????????private?static?void?OnSmoothSamplingChanged(DependencyObject?d,?DependencyPropertyChangedEventArgs?e)
????????{
????????????var?mWindow?=?(CanvasHandWritingExample)d;
????????????foreach?(var?item?in?mWindow._PathVector2DDictionary.Keys)
????????????{
????????????????mWindow.DrawLine(item);
????????????}
????????}
????????public?CanvasHandWritingExample()
????????{
????????????InitializeComponent();
????????????_PathVector2DDictionary?=?new?Dictionary<Path,?List<Vector2D>>();
????????????SmoothSampling?=?0.8;
????????}

????????private?void?DrawingCanvas_PreviewMouseLeftButtonDown(object?sender,?MouseButtonEventArgs?e)
????????{
????????????_IsStart?=?true;
????????????_DrawingPath?=?new?Path()
????????????{
????????????????StrokeDashCap?=?PenLineCap.Round,
????????????????StrokeStartLineCap?=?PenLineCap.Round,
????????????????StrokeEndLineCap?=?PenLineCap.Round,
????????????????StrokeLineJoin?=?PenLineJoin.Round,
????????????};

????????????if?(IsEraser)
????????????{
????????????????_DrawingPath.Stroke?=?new?SolidColorBrush(Colors.Black);
????????????????_DrawingPath.StrokeThickness?=?40;
????????????}
????????????else
????????????{
????????????????var?random?=?new?Random();
????????????????var?strokeBrush?=?new?SolidColorBrush(Color.FromRgb((byte)random.Next(200,?255),?(byte)random.Next(0,?255),?(byte)random.Next(0,?255)));
????????????????_DrawingPath.Stroke?=?strokeBrush;
????????????????_DrawingPath.StrokeThickness?=?10;
????????????}
????????????_PathVector2DDictionary.Add(_DrawingPath,?new?List<Vector2D>());
????????????drawingCanvas.Children.Add(_DrawingPath);
????????}

????????private?void?DrawingCanvas_PreviewMouseLeftButtonUp(object?sender,?MouseButtonEventArgs?e)
????????{
????????????_IsStart?=?false;
????????????_DrawingPath?=?default;
????????}

????????private?void?DrawingCanvas_PreviewMouseMove(object?sender,?MouseEventArgs?e)
????????{
????????????if?(!_IsStart)
????????????????return;

????????????if?(_DrawingPath?is?null)
????????????????return;

????????????Vector2D?currenPoint?=?e.GetPosition(drawingCanvas);
????????????if?(currenPoint.X?<?0?||?currenPoint.Y?<?0)
????????????????return;

????????????if?(currenPoint.X?>?drawingCanvas.ActualWidth?||?currenPoint.Y?>?drawingCanvas.ActualHeight)
????????????????return;

????????????if?(_PathVector2DDictionary[_DrawingPath].Count?>?0)
????????????{
????????????????if?(Vector2D.CalculateVectorDistance(currenPoint,?_PathVector2DDictionary[_DrawingPath][_PathVector2DDictionary[_DrawingPath].Count?-?1])?>?1)
????????????????????_PathVector2DDictionary[_DrawingPath].Add(e.GetPosition(drawingCanvas));
????????????}
????????????else
????????????????_PathVector2DDictionary[_DrawingPath].Add(e.GetPosition(drawingCanvas));

????????????DrawLine(_DrawingPath);
????????}


????????public?double?Tension
????????{
????????????get?=>?(double)GetValue(TensionProperty);
????????????set?=>?SetValue(TensionProperty,?value);
????????}

????????public?double?SmoothSampling
????????{
????????????get?=>?(double)GetValue(SmoothSamplingProperty);
????????????set?=>?SetValue(SmoothSamplingProperty,?value);
????????}

????????public?bool?IsEraser
????????{
????????????get?=>?(bool)GetValue(IsEraserProperty);
????????????set?=>?SetValue(IsEraserProperty,?value);
????????}

???????

????????private?void?DrawLine(Path?path)
????????{
????????????if?(_PathVector2DDictionary[path].Count?>?2)
????????????{
????????????????var?pathVector2Ds?=?_PathVector2DDictionary[path];
????????????????var?smoothNum?=?(int)(_PathVector2DDictionary[path].Count?*?SmoothSampling);
????????????????if?(smoothNum?>?1)
????????????????????pathVector2Ds?=?ComputingHelper.AverageSampling(_PathVector2DDictionary[path],?smoothNum);
????????????????var?lineB?=?new?LineB(pathVector2Ds,?false);
????????????????lineB.Tension?=?Tension;

????????????????path.Data?=?lineB;
????????????}
????????}

????????private?void?btnClertCanvas_Click(object?sender,?RoutedEventArgs?e)
????????{
????????????drawingCanvas.Children.Clear();
????????????_PathVector2DDictionary.Clear();
????????}
????}
}

到此這篇關(guān)于WPF+Canvas實(shí)現(xiàn)平滑筆跡的示例代碼的文章就介紹到這了,更多相關(guān)WPF Canvas平滑筆跡內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論