zoukankan      html  css  js  c++  java
  • 详解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

     /*******************************************************/

     
  • 相关阅读:
    【原】作一个有自控力的人,开始你的时间规划吧!
    【原】关于Python中setuptools安装的问题
    【原】2014年3月学习进度报告
    【原】2014年1月、2月学习进度报告
    【原】我的2014年学习提升计划
    【原】得心应手小工具开发——IE代理快速切换工具
    【原】从头学习设计模式(七)——适配器模式
    【原】从头学习设计模式(六)——观察者模式
    【原】从头学习设计模式(五)——装饰者模式
    【原】从头学习设计模式(四)——抽象工厂模式
  • 原文地址:https://www.cnblogs.com/Vito2008/p/CompoundPath.html
Copyright © 2011-2022 走看看