详解WPF Blend工具中的复合路径功能 ( 含路径标记语法 )
写此文章的目的是为了简单分析一下 Blend工具中提供的"复合路径"功能.有人在我的博文中留言问我复合路径的问题.

稍微琢磨一下,觉得应该是对的.因此贴出来和大家分享.有不对的说错的欢迎指正.
在此之前我们先了解一下WPF的"路径标记语法"
M:表示绘制起点 // M 0,0
L:表示绘制直线 (H:横线 V:竖线) // L 100,0
C:三次方贝塞尔曲线 // C 100,200 200,400 300,200
Q: 二次曲线
z:闭合
......
要注意的是 每一次的绘制都是基于上一次的终点(或者原点M)
例如 M 0,0 L 100,0 L200,50 表示 移动绘制原点到(0,0) 然后绘制直线到(100,0) 紧接着从(100,0)开始再绘制直线到(200,50),也就是说每一次绘制命令都是接着上一次开始的.
*手写语法命令的时候注意空格的使用,以及逗号的使用.
等等 MSDN有详细介绍 不了解的可以去看看.
大致了解路径标记语法后我们来探讨一下"复合路径"功能.
首先我们绘制两条线
(一)
<Canvas >
<Path Data="M0,0 L50,120 " Stretch="Fill" Stroke="red" StrokeThickness="5"/>
<Path Data="M100,0 L250,120 " Stretch="Fill" Stroke="green" StrokeThickness="5"/>
</Canvas>
看下效果

我们在看Blend->复合路径后的代码

<Path Data="M2.5,2.5 L52.5,122.5 M2.5,2.5 L152.5,122.5" Stretch="Fill" Stroke="red" StrokeThickness="5" />
我们仔细观察 复合前的2个Path.Data的语法和复合后的Path.Data的差别.
看看看看看看....嗯... IQ处理中......................
我们把前两个拼起来看看!
//拼前:
<Path Data="M0,0 L50,120 " Stretch="Fill" Stroke="red" StrokeThickness="5"/>
<Path Data="M100,0 L250,120 " Stretch="Fill" Stroke="green" StrokeThickness="5"/> //拼后 : <Path Data="M0,0 L50,120 M100,0 L250,120 " Stretch="Fill" Stroke="red" StrokeThickness="5"/> // Blend复合的: <Path Data="M2.5,2.5 L52.5,122.5 M2.5,2.5 L152.5,122.5" Stretch="Fill" Stroke="red" StrokeThickness="5" />
看看后两个Path有什么一样的地方吗?!
是的 Blend好像也是给拼接起来的? 可是为什么有2.5的误差呢?为什么每个数都是2.5 怎么不是0.1不是其他呢? 奥秘就在这里:StrokeThickness="5"
2.5正好是5的一半嘛,是的,这个2.5只是算了粗细而已.我们可以去掉它也不会影响整体的形状的.
当我们把5改为1后(什么你说改成0?? 0像素好粗啊 会闪下我氪金狗眼的!别闹~~~)
再使用复合路径得到的数据是 M0.5,0.5 L50.5,120.5 M0.5,0.5 L150.5,120.5 , 看看"误差"变为0.5了吧.如果你手动去掉所有的小数,那么你会看到形状不变的.这里我就不去演示了.
那么我们初步得到结论:复合路径 =路径1+路径2+路径3+..... (拼接所有的路径部分) .
(二)
下面我们再来看一组数据:
<Path Data="M0,0 L50,120 " Stretch="Fill" Stroke="red" StrokeThickness="5"/>
<Path Data="M100,0 L300,120 " Canvas.Left="50" Stretch="Fill" Stroke="red" StrokeThickness="5"/>
效果:

在看Blend复合后的代码:
<Path Data="M2.5,2.5 L52.5,122.5 M52.5,2.5 L252.5,122.5" Stretch="Fill" Stroke="red" StrokeThickness="5" />
首先我们基于(一)的结论忽略掉粗细误差2.5(顺便验证一下这个结论)得到结果
<Path Data="M0,0 L50,120 M50,0 L250,120" Stretch="Fill" Stroke="red" StrokeThickness="5" />
Blend中我们看到形状位置都没变.
接下来我们尝试手动拼接上面(二)的2个Path得到
<Path Data="M0,0 L50,120 " Stretch="Fill" Stroke="red" StrokeThickness="5"/>
<Path Data="M100,0 L300,120 " Canvas.Left="50" Stretch="Fill" Stroke="green" StrokeThickness="5"/> 手动拼接: <Path Data="M0,0 L50,120 M100,0 L300,120" Stretch="Fill" Stroke="red" StrokeThickness="5"/>

这是为什么? 怎么分离的这么远?
我们来解密一下:
看看第二条Path 他有这个附加属性 Canvas.Left="50" 居然给右移了50!!!! 那么我们给他挪回去试试?
得到
<Path Data="M0,0 L50,120 " Stretch="Fill" Stroke="red" StrokeThickness="5"/>
<Path Data="M100,0 L300,120 " Canvas.Left="50" Stretch="Fill" Stroke="green" StrokeThickness="5"/> 手动拼接: <Path Data="M0,0 L50,120 M100,0 L300,120" Stretch="Fill" Stroke="red" StrokeThickness="5"/>
把第二个Path的Left 50 左移回去得到: <Path Data="M0,0 L50,120 M50,0 L250,120" Stretch="Fill" Stroke="red" StrokeThickness="5"/>
左移后 <Path Data="M0,0 L50,120 M50,0 L250,120" Stretch="Fill" Stroke="red" StrokeThickness="5"/>效果:是不是一样了! 左移第二条线是移动原点M和L的横坐标 所以得到M50,0 L250,120"
( 被左移 - X需要减掉相应值 . 被右移 - X需要加上相应值 )
上下移同理,上移(Top负数)需加,下移(Top正数)需减
这个过程我们暂且称为"复位"
因此我们又得到一个结论 Canvas.Left 同样会影响复合路径!当然这里也包括Canvas.Top /Right/Bottom ,
值得提醒的是当 Left /Top等 的值为负数时 直接简单拼接和"复位" 是不对的.因为你可能复不到位.不信你试试看. 这里稍微解释一下标记语法一个特别的地方(我猜的!没有去MSDN考证.)
<Path Data="M100,0 L300,120 " Stretch="Fill" Stroke="green" StrokeThickness="5"/>
<Path Data="M0,0 L200,120 " Stretch="Fill" Stroke="green" StrokeThickness="5"/>
<Path Data="M-100,0 L100,120 " Stretch="Fill" Stroke="green" StrokeThickness="5"/>
这3个Path是一样的!
当Path中只有一段图形时(这里是只有一段Line) , Line整体平移(指的是原点从0,0 平移到100,0 且 端点从200,120平移到300,120)是不会影响Path形状和位置的.
因此在只有一段图形的Path中我们可以约掉这个平移 我们暂且称为"约分"(参考数学分数的约分哈,不严谨 好记而已~~) 所以上面我说 当Canvas.Left为负数时 不能简单直接拼接和复位.怎么办呢?我们需要先约分!先把所有能约分的线段的原点约分到不能再约分的实际原点,
例如上面的三个Path的实际原点其实都是M 0,0 .约分处理完所有图形片段后 再进行 拼接和复位.最后就能得到复合路径的结果了. 另外,凡是所有能影响Path位置的属性改变都会影响复合路径的结果,比如 RenderTransform 和Margin 等. 如果想手动去算复合路径可能是非常繁琐的一个过程~~~ 您可能需要为所有影响Path位置变化的属性改变都写一个复位的方法.在执行复合路径之前需要先调用所有的复位/约分方法来恢复Path的Data到实际值.再进行拼接计算. 以上是我粗略分析后的一些看法和结论.我之前也不知道这些的,只不过是在我的一片自定义MessageBox的文章中有人问我这个问题,我就试着猜猜.
这位童鞋@距离永远 您可请俺喝酒啊!! 嘻嘻~~ 如果哪位童鞋有在code中动态计算路径的需求,不妨参考一下此文.
在下拙见,若有达人,不吝赐教!
/*******************************************************/
欢迎转载!欢迎拍砖!
版权所有 © Vito野子
E-mail: vito2015@live.com
转载请注明出处 http://www.cnblogs.com/Vito2008/p/CompoundPath.html
/*******************************************************/
详解WPF Blend工具中的复合路径功能 ( 含路径标记语法 )的更多相关文章
- 详解LUA开发工具及其环境配置
LUA开发工具及其环境配置是本文要介绍的内容,主要是来了解并学习lua开发工具的使用和环境的配置,第一次接触LUA的话,就跟本人一起学习吧.看我能不能忽悠到你. LUA是语言,那么一定有编写的工具.第 ...
- 详解如何在CentOS7中使用Nginx和PHP7-FPM安装Nextcloud
转载地址:https://www.jb51.net/article/109382.htm 这篇文章主要介绍了详解如何在CentOS7中使用Nginx和PHP7-FPM安装Nextcloud,会通过 N ...
- Scala 深入浅出实战经典 第61讲:Scala中隐式参数与隐式转换的联合使用实战详解及其在Spark中的应用源码解析
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载: 百度云盘:http://pan.baidu.com/s/1c0noOt ...
- Scala 深入浅出实战经典 第60讲:Scala中隐式参数实战详解以及在Spark中的应用源码解析
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...
- 详解OJ(Online Judge)中PHP代码的提交方法及要点【举例:ZOJ 1001 (A + B Problem)】
详解OJ(Online Judge)中PHP代码的提交方法及要点 Introduction of How to submit PHP code to Online Judge Systems Int ...
- 详解Linux下iptables中的DNAT与SNAT设置(转)
详解Linux下iptables中的DNAT与SNAT设置 这篇文章主要介绍了Linux下iptables中的DNAT与SNAT设置,是Linux网络配置中的基础知识,需要的朋友可以参考下 原文连 ...
- Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制
Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制 JAVA 中原生的 socket 通信机制 摘要:本文属于原创,欢迎转载,转载请保留出处:https://github.co ...
- 详解在Linux系统中安装Tomcat
本文以在CentOS 7.6中安装Tomcat8.5为例进行安装,其他系统和版本都是大同小异的. 安装JDK 安装Tomcat之前,需要先安装JDK,可以参看之前的文章详解在Linux系统中安装JDK ...
- 详解如何在Laravel中增加自定义全局函数
http://www.php.cn/php-weizijiaocheng-383928.html 如何在Laravel中增加自定义全局函数?在我们的应用里经常会有一些全局都可能会用的函数,我们应该怎么 ...
随机推荐
- PowerDesigner建立与数据库的连接,以便生成数据库和从数据库生成到PD中。
第一步,打开PD15,找到[Database],如图所示: 第二步,点击新建按钮,创建一个新的ODBC连接. 第三步,这里选择系统数据源,并选择Oracle 第四步,这里需要注意,服务器需要写的是Or ...
- Weblogic控制器的部署
WebLogic的安装 一 WebLogic安装 1. 打开WebLogic安装程序:oepe11_wls1031.exe(我们选用的是WebLogic 10.3g).如图1-1所示: 图1-1 ...
- CF#FF(255)-div1-C【水题,枚举】
[吐槽]:本来没打算写这题的题解的,但惨不忍睹得WA了13次,想想还是记录一下吧.自己的“分类讨论能力”本来就很差. 刚开始第一眼扫过去以为是LIS,然后忽略了复杂度,果断TLE了,说起来也好惭愧,也 ...
- HUD-1142
A Walk Through the Forest Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Jav ...
- Linux同步机制 - 基本概念(死锁,活锁,饿死,优先级反转,护航现象)
死锁(deadlock) 是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进 ...
- UVa 424 Integer Inquiry
之前杭电上也做过a + b的高精度的题,不过这道题的区别是有多组数据. 之前做的时候开了3个字符数组a,b,c,在计算的时候还要比较a,b长度,短的那个还要加'0',还设置了一个add来存放进位. 现 ...
- PHP后台执行
php中实现后台执行的方法: ignore_user_abort(true); // 后台运行set_time_limit(0); // 取消脚本运行时间的超时上限后台运行的后面还要,set_time ...
- BZOJ 4415 发牌
线段树就好了啊. 为什么一眼splay啊... 其实splay也能过,但是线段树更方便? #include<iostream> #include<cstdio> #includ ...
- matplotlib 绘制柱状图的几个例子
1 error bar #!/usr/bin/env python # a bar plot with errorbars import numpy as np import matplotlib.p ...
- MAC OSX 下安装 CTAGS
由于本子跟风换了骚货MBP,因而开发要迁移到MAC OSX下,mac os 下的ctags不一样,所以需要自己编译一个 Lion内置了ctags,但是不我所需要,因此得在网上去弄,最新的版本是 5 ...
是不是一样了! 左移第二条线是移动原点M和L的横坐标 所以得到M50,0 L250,120"