Advertisement
Guest User

Untitled

a guest
Sep 18th, 2014
172
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.38 KB | None | 0 0
  1. <Polyline Points="0,0 0,100 200,100" StrokeLineJoin="Round" />
  2.  
  3. <Border CornerRadius="8" ... />
  4.  
  5. <myCustomControls:RoundPolyline Points="0,0 0,100 200,100" Radius="10" />
  6.  
  7. using System;
  8. using System.Reflection;
  9. using System.Windows;
  10. using System.Windows.Media;
  11. using System.Windows.Shapes;
  12.  
  13. namespace MyControls
  14. {
  15. public sealed class RoundPolyline : Shape
  16. {
  17. public static readonly DependencyProperty FillRuleProperty = DependencyProperty.Register("FillRule", typeof(FillRule), typeof(RoundPolyline), new FrameworkPropertyMetadata(FillRule.EvenOdd, FrameworkPropertyMetadataOptions.AffectsRender));
  18. public static readonly DependencyProperty PointsProperty = DependencyProperty.Register("Points", typeof(PointCollection), typeof(RoundPolyline), new FrameworkPropertyMetadata(GetEmptyPointCollection(), FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure));
  19. public static readonly DependencyProperty RadiusProperty = DependencyProperty.Register("Radius", typeof(double), typeof(RoundPolyline), new FrameworkPropertyMetadata(6.0, FrameworkPropertyMetadataOptions.AffectsRender));
  20.  
  21. private Geometry _geometry;
  22. private void DefineGeometry()
  23. {
  24. PointCollection points = Points;
  25. if (points == null)
  26. {
  27. _geometry = Geometry.Empty;
  28. return;
  29. }
  30.  
  31. PathFigure figure = new PathFigure();
  32. if (points.Count > 0)
  33. {
  34. // start point
  35. figure.StartPoint = points[0];
  36.  
  37. if (points.Count > 1)
  38. {
  39. // points between
  40. double desiredRadius = Radius;
  41. for (int i = 1; i < (points.Count - 1); i++)
  42. {
  43. // adjust radius if points are too close
  44. Vector v1 = points[i] - points[i - 1];
  45. Vector v2 = points[i + 1] - points[i];
  46. double radius = Math.Min(Math.Min(v1.Length, v2.Length) / 2, desiredRadius);
  47.  
  48. // draw the line, and stop before the next point
  49. double len = v1.Length;
  50. v1.Normalize();
  51. v1 *= (len - radius);
  52. LineSegment line = new LineSegment(points[i - 1] + v1, true);
  53. figure.Segments.Add(line);
  54.  
  55. // draw the arc to the next point
  56. v2.Normalize();
  57. v2 *= radius;
  58. SweepDirection direction = (Vector.AngleBetween(v1, v2) > 0) ? SweepDirection.Clockwise : SweepDirection.Counterclockwise;
  59. ArcSegment arc = new ArcSegment(points[i] + v2, new Size(radius, radius), 0, false, direction, true);
  60. figure.Segments.Add(arc);
  61. }
  62.  
  63. // last point
  64. figure.Segments.Add(new LineSegment(points[points.Count - 1], true));
  65. }
  66. }
  67. PathGeometry geometry = new PathGeometry();
  68. geometry.Figures.Add(figure);
  69. geometry.FillRule = FillRule;
  70. if (geometry.Bounds == Rect.Empty)
  71. {
  72. _geometry = Geometry.Empty;
  73. }
  74. else
  75. {
  76. _geometry = geometry;
  77. }
  78. }
  79.  
  80. protected override Size MeasureOverride(Size constraint)
  81. {
  82. DefineGeometry();
  83. return base.MeasureOverride(constraint);
  84. }
  85.  
  86. protected override Geometry DefiningGeometry
  87. {
  88. get
  89. {
  90. return _geometry;
  91. }
  92. }
  93.  
  94. public double Radius
  95. {
  96. get
  97. {
  98. return (double)GetValue(RadiusProperty);
  99. }
  100. set
  101. {
  102. SetValue(RadiusProperty, value);
  103. }
  104. }
  105.  
  106. public FillRule FillRule
  107. {
  108. get
  109. {
  110. return (FillRule)GetValue(FillRuleProperty);
  111. }
  112. set
  113. {
  114. SetValue(FillRuleProperty, value);
  115. }
  116. }
  117.  
  118. public PointCollection Points
  119. {
  120. get
  121. {
  122. return (PointCollection)GetValue(PointsProperty);
  123. }
  124. set
  125. {
  126. SetValue(PointsProperty, value);
  127. }
  128. }
  129.  
  130. // NOTE: major hack because none of this is public, and this is very unfortunate, it should be...
  131. private static PointCollection _emptyPointCollection;
  132. private static ConstructorInfo _freezableDefaultValueFactoryCtor;
  133. private static object GetEmptyPointCollection()
  134. {
  135. if (_freezableDefaultValueFactoryCtor == null)
  136. {
  137. _emptyPointCollection = (PointCollection)typeof(PointCollection).GetProperty("Empty", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null, null);
  138. Type freezableDefaultValueFactoryType = typeof(DependencyObject).Assembly.GetType("MS.Internal.FreezableDefaultValueFactory");
  139. _freezableDefaultValueFactoryCtor = freezableDefaultValueFactoryType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)[0];
  140. }
  141. return _freezableDefaultValueFactoryCtor.Invoke(new object[] { _emptyPointCollection });
  142. }
  143. }
  144. }
  145.  
  146. public sealed class ArcPolygon : Shape
  147. {
  148. public bool RefreshOnPointAdd { get; set; }
  149.  
  150. private readonly Geometry _geometry;
  151. private readonly PathFigure _figure;
  152.  
  153. public ArcPolygon()
  154. {
  155. RefreshOnPointAdd = true;
  156.  
  157. _geometry = new PathGeometry();
  158. _figure = new PathFigure();
  159.  
  160. ((PathGeometry)_geometry).Figures.Add(_figure);
  161.  
  162. _pointCollection = new ArcPointCollection();
  163. _pointCollection.CollectionChanged += PointCollectionChanged;
  164. }
  165.  
  166. public static readonly DependencyProperty FillRuleProperty = DependencyProperty.Register("FillRule", typeof(FillRule), typeof(ArcPolygon), new FrameworkPropertyMetadata(FillRule.EvenOdd, FrameworkPropertyMetadataOptions.AffectsRender));
  167. public static readonly DependencyProperty RadiusProperty = DependencyProperty.Register("Radius", typeof(double?), typeof(ArcPolygon), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));
  168.  
  169. public void Refresh()
  170. {
  171. DefineGeometry();
  172. }
  173.  
  174. private void DefineGeometry()
  175. {
  176. var points = PointCollection;
  177.  
  178. _figure.Segments.Clear();
  179.  
  180. if(points.Any())
  181. {
  182. // start point
  183. _figure.StartPoint = points[0];
  184.  
  185. if(points.Count > 1)
  186. {
  187. // points between
  188. for(int i = 1; i < (points.Count - 1); i++)
  189. {
  190. // adjust radius if points are too close
  191. var v1 = (Point)points[i] - points[i - 1];
  192. var v2 = (Point)points[i + 1] - points[i];
  193.  
  194. var radius = (points[i].Radius ?? Radius) ?? 0;
  195.  
  196. radius = Math.Min(Math.Min(v1.Length, v2.Length) / 2, radius);
  197.  
  198. // draw the line, and stop before the next point
  199. double len = v1.Length;
  200. v1.Normalize();
  201. v1 *= (len - radius);
  202. var line = new LineSegment((Point)points[i - 1] + v1, true);
  203. _figure.Segments.Add(line);
  204.  
  205. // draw the arc to the next point
  206. v2.Normalize();
  207. v2 *= radius;
  208. var direction = (Vector.AngleBetween(v1, v2) > 0) ? SweepDirection.Clockwise : SweepDirection.Counterclockwise;
  209. var arc = new ArcSegment((Point)points[i] + v2, new Size(radius, radius), 0, false, direction, true);
  210. _figure.Segments.Add(arc);
  211. }
  212.  
  213. // last point
  214. _figure.Segments.Add(new LineSegment(points[points.Count - 1], true));
  215. }
  216. }
  217. }
  218.  
  219. protected override Size MeasureOverride(Size constraint)
  220. {
  221. DefineGeometry();
  222. return base.MeasureOverride(constraint);
  223. }
  224.  
  225. protected override Geometry DefiningGeometry
  226. {
  227. get
  228. {
  229. return _geometry;
  230. }
  231. }
  232.  
  233. public double? Radius
  234. {
  235. get
  236. {
  237. return (double?)GetValue(RadiusProperty);
  238. }
  239. set
  240. {
  241. SetValue(RadiusProperty, value);
  242. }
  243. }
  244.  
  245. public FillRule FillRule
  246. {
  247. get
  248. {
  249. return (FillRule)GetValue(FillRuleProperty);
  250. }
  251. set
  252. {
  253. SetValue(FillRuleProperty, value);
  254. ((PathGeometry)_geometry).FillRule = value;
  255. }
  256. }
  257.  
  258. private ArcPointCollection _pointCollection;
  259. /// <summary>
  260. /// Gets or sets a collection that contains the points of the polygon.
  261. /// </summary>
  262. public ArcPointCollection PointCollection
  263. {
  264. get { return _pointCollection; }
  265. set
  266. {
  267. _pointCollection = value;
  268. if(RefreshOnPointAdd) Refresh();
  269. }
  270. }
  271.  
  272. // <summary>
  273. // Gets or sets the control's text
  274. // </summary>
  275. public string Points
  276. {
  277. get
  278. {
  279. return string.Join(" ", PointCollection.Select(x => x.ToString()));
  280. }
  281.  
  282. set
  283. {
  284. var pointCollection = new ArcPointCollection();
  285.  
  286. //10,50,45 180,50 180,150,45 10,150
  287. var points = value.Split(' ');
  288. foreach(var point in points)
  289. {
  290. if(point.Trim() == string.Empty) continue;
  291.  
  292. var xyarc = point.Split(',');
  293. var item = new ArcPoint();
  294. if(xyarc.Length >= 1) item.X = double.Parse(xyarc[0], CultureInfo.InvariantCulture);
  295. if(xyarc.Length >= 2) item.Y = double.Parse(xyarc[1], CultureInfo.InvariantCulture);
  296. if(xyarc.Length >= 3) item.Radius = double.Parse(xyarc[2], CultureInfo.InvariantCulture);
  297.  
  298. pointCollection.Add(item);
  299. }
  300.  
  301. PointCollection = pointCollection;
  302. }
  303. }
  304.  
  305. private void PointCollectionChanged(object sender, EventArgs e)
  306. {
  307. if(RefreshOnPointAdd) Refresh();
  308. }
  309.  
  310. public void Reset()
  311. {
  312. _pointCollection.Clear();
  313. }
  314.  
  315. public void AddPoint(double x, double y)
  316. {
  317. _pointCollection.Add(x, y);
  318. }
  319.  
  320. public void AddPoint(double x, double y, double? radius)
  321. {
  322. _pointCollection.Add(x, y, radius);
  323. }
  324. }
  325.  
  326. public sealed class ArcPoint
  327. {
  328. public double X { get; set; }
  329. public double Y { get; set; }
  330. public double? Radius { get; set; }
  331.  
  332. public ArcPoint()
  333. {
  334. }
  335.  
  336. public ArcPoint(double x, double y)
  337. {
  338. this.X = x;
  339. this.Y = y;
  340. }
  341.  
  342. public ArcPoint(double x, double y, double? radius)
  343. {
  344. this.X = x;
  345. this.Y = y;
  346. this.Radius = radius;
  347. }
  348.  
  349. public static implicit operator Point(ArcPoint point)
  350. {
  351. return new Point(point.X, point.Y);
  352. }
  353. public static implicit operator ArcPoint(Point point)
  354. {
  355. return new ArcPoint(point.X, point.Y);
  356. }
  357.  
  358. public override string ToString()
  359. {
  360. if(Radius == null)
  361. return string.Format(CultureInfo.InvariantCulture, "{0},{1}", X, Y);
  362. return string.Format(CultureInfo.InvariantCulture, "{0},{1},{2}", X, Y, Radius);
  363. }
  364. }
  365.  
  366. public sealed class ArcPointCollection : ObservableCollection<ArcPoint>
  367. {
  368. public void Add(double x, double y)
  369. {
  370. Add(new ArcPoint(x, y));
  371. }
  372.  
  373. public void Add(double x, double y, double? radius)
  374. {
  375. Add(new ArcPoint(x, y, radius));
  376. }
  377. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement