寫此文章的目的是為了簡單分析一下 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
/*******************************************************/