2007年9月18日 星期二

[轉貼]數學面積計算公式大全

[轉貼]數學面積計算公式大全
長方形=長*寬
平行四邊形=長*高
三角形=長*高/2
正方形=邊長*邊長
圓=圓周率*半徑的平方

這些是小學的,我已經挖空心思了,
我是六年級的

又找了一些:
我給的確實是初中的數學定理和公式大全,樓主看不懂問題不在這裡,建議樓主先從基礎知識抓起,光記公式而不理解是不行的,介紹
幾個初中生學習網站初中數學資源網
http://www.1230.org/
初中數學網
http://www.czsx.com.cn/
初中數學樂園
http://www.0618.org/
華師大初中數學網站
http://www.hsdczsx.com/Article_Index.asp
中學數學題庫
http://www.tiku.net/
這是初中的代數公式:
http://www.edu3g.com/math/expressions/czds/index1.html

初中數學常用公式:
http://edu.northeast.cn/system/2006/09/11/050545772.shtml

初中數學公式,這個需要下載:
http://www.hnmaths.com/Soft/czsx/200605/693.html

常用數學公式表:
http://www.wen8.net/html/307.htm

http://forum.heftyedu.com/viewthread.php?tid=740

另外關於學習方法的:(那個同學跟你的情況有點類似吧)
http://zhidao.baidu.com/question/18903134.html
希望對你有幫助,





1 過兩點有且只有一條直線
2 兩點之間線段最短
3 同角或等角的補角相等
4 同角或等角的余角相等
5 過一點有且只有一條直線和已知直線垂直
6 直線外一點與直線上各點連接的所有線段中,垂線段最短
7 平行公理 經過直線外一點,有且只有一條直線與這條直線平行
8 如果兩條直線都和第三條直線平行,這兩條直線也互相平行
9 同位角相等,兩直線平行
10 內錯角相等,兩直線平行
11 同旁內角互補,兩直線平行
12兩直線平行,同位角相等
13 兩直線平行,內錯角相等
14 兩直線平行,同旁內角互補
15 定理 三角形兩邊的和大於第三邊
16 推論 三角形兩邊的差小於第三邊
17 三角形內角和定理 三角形三個內角的和等於180°
18 推論1 直角三角形的兩個銳角互余
19 推論2 三角形的一個外角等於和它不相鄰的兩個內角的和
20 推論3 三角形的一個外角大於任何一個和它不相鄰的內角
21 全等三角形的對應邊、對應角相等
22邊角邊公理(SAS) 有兩邊和它們的夾角對應相等的兩個三角形全等
23 角邊角公理( ASA)有兩角和它們的夾邊對應相等的兩個三角形全等
24 推論(AAS) 有兩角和其中一角的對邊對應相等的兩個三角形全等
25 邊邊邊公理(SSS) 有三邊對應相等的兩個三角形全等
26 斜邊、直角邊公理(HL) 有斜邊和一條直角邊對應相等的兩個直角三角形全等
27 定理1 在角的平分線上的點到這個角的兩邊的距離相等
28 定理2 到一個角的兩邊的距離相同的點,在這個角的平分線上
29 角的平分線是到角的兩邊距離相等的所有點的集合
30 等腰三角形的性質定理 等腰三角形的兩個底角相等 (即等邊對等角)
31 推論1 等腰三角形頂角的平分線平分底邊並且垂直於底邊
32 等腰三角形的頂角平分線、底邊上的中線和底邊上的高互相重合
33 推論3 等邊三角形的各角都相等,並且每一個角都等於60°
34 等腰三角形的判定定理 如果一個三角形有兩個角相等,那麼這兩個角所對的邊也相等(等角對等邊)
35 推論1 三個角都相等的三角形是等邊三角形
36 推論 2 有一個角等於60°的等腰三角形是等邊三角形
37 在直角三角形中,如果一個銳角等於30°那麼它所對的直角邊等於斜邊的一半
38 直角三角形斜邊上的中線等於斜邊上的一半
39 定理 線段垂直平分線上的點和這條線段兩個端點的距離相等
40 逆定理 和一條線段兩個端點距離相等的點,在這條線段的垂直平分線上
41 線段的垂直平分線可看作和線段兩端點距離相等的所有點的集合
42 定理1 關於某條直線對稱的兩個圖形是全等形
43 定理 2 如果兩個圖形關於某直線對稱,那麼對稱軸是對應點連線的垂直平分線
44定理3 兩個圖形關於某直線對稱,如果它們的對應線段或延長線相交,那麼交點在對稱軸上
45逆定理 如果兩個圖形的對應點連線被同一條直線垂直平分,那麼這兩個圖形關於這條直線對稱
46勾股定理 直角三角形兩直角邊a、b的平方和、等於斜邊c的平方,即a^2+b^2=c^2
47勾股定理的逆定理 如果三角形的三邊長a、b、c有關係a^2+b^2=c^2 ,那麼這個三角形是直角三角形
48定理 四邊形的內角和等於360°
49四邊形的外角和等於360°
50多邊形內角和定理 n邊形的內角的和等於(n-2)×180°
51推論 任意多邊的外角和等於360°
52平行四邊形性質定理1 平行四邊形的對角相等
53平行四邊形性質定理2 平行四邊形的對邊相等
54推論 夾在兩條平行線間的平行線段相等
55平行四邊形性質定理3 平行四邊形的對角線互相平分
56平行四邊形判定定理1 兩組對角分別相等的四邊形是平行四邊形
57平行四邊形判定定理2 兩組對邊分別相等的四邊形是平行四邊形
58平行四邊形判定定理3 對角線互相平分的四邊形是平行四邊形
59平行四邊形判定定理4 一組對邊平行相等的四邊形是平行四邊形
60矩形性質定理1 矩形的四個角都是直角
61矩形性質定理2 矩形的對角線相等
62矩形判定定理1 有三個角是直角的四邊形是矩形
63矩形判定定理2 對角線相等的平行四邊形是矩形
64菱形性質定理1 菱形的四條邊都相等
65菱形性質定理2 菱形的對角線互相垂直,並且每一條對角線平分一組對角
66菱形面積=對角線乘積的一半,即S=(a×b)÷2
67菱形判定定理1 四邊都相等的四邊形是菱形
68菱形判定定理2 對角線互相垂直的平行四邊形是菱形
69正方形性質定理1 正方形的四個角都是直角,四條邊都相等
70正方形性質定理2正方形的兩條對角線相等,並且互相垂直平分,每條對角線平分一組對角
71定理1 關於中心對稱的兩個圖形是全等的
72定理2 關於中心對稱的兩個圖形,對稱點連線都經過對稱中心,並且被對稱中心平分
73逆定理 如果兩個圖形的對應點連線都經過某一點,並且被這一
點平分,那麼這兩個圖形關於這一點對稱
74等腰梯形性質定理 等腰梯形在同一底上的兩個角相等
75等腰梯形的兩條對角線相等
76等腰梯形判定定理 在同一底上的兩個角相等的梯形是等腰梯形
77對角線相等的梯形是等腰梯形
78平行線等分線段定理 如果一組平行線在一條直線上截得的線段
相等,那麼在其他直線上截得的線段也相等
79 推論1 經過梯形一腰的中點與底平行的直線,必平分另一腰
80 推論2 經過三角形一邊的中點與另一邊平行的直線,必平分第
三邊
81 三角形中位線定理 三角形的中位線平行於第三邊,並且等於它
的一半
82 梯形中位線定理 梯形的中位線平行於兩底,並且等於兩底和的
一半 L=(a+b)÷2 S=L×h
83 (1)比例的基本性質 如果a:b=c:d,那麼ad=bc
如果ad=bc,那麼a:b=c:d
84 (2)合比性質 如果a/b=c/d,那麼(a±b)/b=(c±d)/d
85 (3)等比性質 如果a/b=c/d=…=m/n(b+d+…+n≠0),那麼
(a+c+…+m)/(b+d+…+n)=a/b
86 平行線分線段成比例定理 三條平行線截兩條直線,所得的對應
線段成比例
87 推論 平行於三角形一邊的直線截其他兩邊(或兩邊的延長線),所得的對應線段成比例
88 定理 如果一條直線截三角形的兩邊(或兩邊的延長線)所得的對應線段成比例,那麼這條直線平行於三角形的第三邊
89 平行於三角形的一邊,並且和其他兩邊相交的直線,所截得的三角形的三邊與原三角形三邊對應成比例
90 定理 平行於三角形一邊的直線和其他兩邊(或兩邊的延長線)相交,所構成的三角形與原三角形相似
91 相似三角形判定定理1 兩角對應相等,兩三角形相似(ASA)
92 直角三角形被斜邊上的高分成的兩個直角三角形和原三角形相似
93 判定定理2 兩邊對應成比例且夾角相等,兩三角形相似(SAS)
94 判定定理3 三邊對應成比例,兩三角形相似(SSS)
95 定理 如果一個直角三角形的斜邊和一條直角邊與另一個直角三
角形的斜邊和一條直角邊對應成比例,那麼這兩個直角三角形相似
96 性質定理1 相似三角形對應高的比,對應中線的比與對應角平
分線的比都等於相似比
97 性質定理2 相似三角形周長的比等於相似比
98 性質定理3 相似三角形面積的比等於相似比的平方
99 任意銳角的正弦值等於它的余角的餘弦值,任意銳角的餘弦值等
於它的余角的正弦值
100任意銳角的正切值等於它的余角的余切值,任意銳角的余切值等
於它的余角的正切值
101圓是定點的距離等於定長的點的集合
102圓的內部可以看作是圓心的距離小於半徑的點的集合
103圓的外部可以看作是圓心的距離大於半徑的點的集合
104同圓或等圓的半徑相等
105到定點的距離等於定長的點的軌跡,是以定點為圓心,定長為半
徑的圓
106和已知線段兩個端點的距離相等的點的軌跡,是著條線段的垂直
平分線
107到已知角的兩邊距離相等的點的軌跡,是這個角的平分線
108到兩條平行線距離相等的點的軌跡,是和這兩條平行線平行且距
離相等的一條直線
109定理 不在同一直線上的三點確定一個圓。
110垂徑定理 垂直於弦的直徑平分這條弦並且平分弦所對的兩條弧
111推論1 ①平分弦(不是直徑)的直徑垂直於弦,並且平分弦所對的兩條弧
②弦的垂直平分線經過圓心,並且平分弦所對的兩條弧
③平分弦所對的一條弧的直徑,垂直平分弦,並且平分弦所對的另一條弧
112推論2 圓的兩條平行弦所夾的弧相等
113圓是以圓心為對稱中心的中心對稱圖形
114定理 在同圓或等圓中,相等的圓心角所對的弧相等,所對的弦
相等,所對的弦的弦心距相等
115推論 在同圓或等圓中,如果兩個圓心角、兩條弧、兩條弦或兩
弦的弦心距中有一組量相等那麼它們所對應的其餘各組量都相等
116定理 一條弧所對的圓周角等於它所對的圓心角的一半
117推論1 同弧或等弧所對的圓周角相等;同圓或等圓中,相等的圓周角所對的弧也相等
118推論2 半圓(或直徑)所對的圓周角是直角;90°的圓周角所
對的弦是直徑
119推論3 如果三角形一邊上的中線等於這邊的一半,那麼這個三角形是直角三角形
120定理 圓的內接四邊形的對角互補,並且任何一個外角都等於它
的內對角
121①直線L和⊙O相交 d<r
②直線L和⊙O相切 d=r
③直線L和⊙O相離 d>r
122切線的判定定理 經過半徑的外端並且垂直於這條半徑的直線是圓的切線
123切線的性質定理 圓的切線垂直於經過切點的半徑
124推論1 經過圓心且垂直於切線的直線必經過切點
125推論2 經過切點且垂直於切線的直線必經過圓心
126切線長定理 從圓外一點引圓的兩條切線,它們的切線長相等,
圓心和這一點的連線平分兩條切線的夾角
127圓的外切四邊形的兩組對邊的和相等
128弦切角定理 弦切角等於它所夾的弧對的圓周角
129推論 如果兩個弦切角所夾的弧相等,那麼這兩個弦切角也相等
130相交弦定理 圓內的兩條相交弦,被交點分成的兩條線段長的積
相等
131推論 如果弦與直徑垂直相交,那麼弦的一半是它分直徑所成的
兩條線段的比例中項
132切割線定理 從圓外一點引圓的切線和割線,切線長是這點到割
線與圓交點的兩條線段長的比例中項
133推論 從圓外一點引圓的兩條割線,這一點到每條割線與圓的交點的兩條線段長的積相等
134如果兩個圓相切,那麼切點一定在連心線上
135①兩圓外離 d>R+r ②兩圓外切 d=R+r
③兩圓相交 R-r<d<R+r(R>r)
④兩圓內切 d=R-r(R>r) ⑤兩圓內含d<R-r(R>r)
136定理 相交兩圓的連心線垂直平分兩圓的公共弦
137定理 把圓分成n(n3):
⑴依次連結各分點所得的多邊形是這個圓的內接正n邊形
⑵經過各分點作圓的切線,以相鄰切線的交點為頂點的多邊形是這個圓的外切正n邊形
138定理 任何正多邊形都有一個外接圓和一個內切圓,這兩個圓是同心圓
139正n邊形的每個內角都等於(n-2)×180°/n
140定理 正n邊形的半徑和邊心距把正n邊形分成2n個全等的直角三角形
141正n邊形的面積Sn=pnrn/2 p表示正n邊形的周長
142正三角形面積√3a/4 a表示邊長
143如果在一個頂點周圍有k個正n邊形的角,由於這些角的和應為
360°,因此k×(n-2)180°/n=360°化為(n-2)(k-2)=4
144弧長計算公式:L=n兀R/180
145扇形面積公式:S扇形=n兀R^2/360=LR/2
146內公切線長= d-(R-r) 外公切線長= d-(R+r)
(還有一些,大家幫補充吧)

實用工具:常用數學公式


公式分類 公式表達式

乘法與因式分 a2-b2=(a+b)(a-b) a3+b3=(a+b)(a2-ab+b2) a3-b3=(a-b(a2+ab+b2)

三角不等式 |a+b||a|+|b| |a-b||a|+|b| |a|b<=>-bab

|a-b||a|-|b| -|a|a|a|

一元二次方程的解 -b+√(b2-4ac)/2a -b-√(b2-4ac)/2a

根與係數的關係 X1+X2=-b/a X1*X2=c/a 註:韋達定理

判別式
b2-4ac=0 註:方程有兩個相等的實根
b2-4ac>0 註:方程有兩個不等的實根
b2-4ac<0 註:方程沒有實根,有共軛複數根

三角函數公式

兩角和公式
sin(A+B)=sinAcosB+cosAsinB sin(A-B)=sinAcosB-sinBcosA
cos(A+B)=cosAcosB-sinAsinB cos(A-B)=cosAcosB+sinAsinB
tan(A+B)=(tanA+tanB)/(1-tanAtanB) tan(A-B)=(tanA-tanB)/(1+tanAtanB)
ctg(A+B)=(ctgActgB-1)/(ctgB+ctgA) ctg(A-B)=(ctgActgB+1)/(ctgB-ctgA)

倍角公式
tan2A=2tanA/(1-tan2A) ctg2A=(ctg2A-1)/2ctga
cos2a=cos2a-sin2a=2cos2a-1=1-2sin2a

半角公式
sin(A/2)=√((1-cosA)/2) sin(A/2)=-√((1-cosA)/2)
cos(A/2)=√((1+cosA)/2) cos(A/2)=-√((1+cosA)/2)
tan(A/2)=√((1-cosA)/((1+cosA)) tan(A/2)=-√((1-cosA)/((1+cosA))
ctg(A/2)=√((1+cosA)/((1-cosA)) ctg(A/2)=-√((1+cosA)/((1-cosA))

和差化積
2sinAcosB=sin(A+B)+sin(A-B) 2cosAsinB=sin(A+B)-sin(A-B)
2cosAcosB=cos(A+B)-sin(A-B) -2sinAsinB=cos(A+B)-cos(A-B)
sinA+sinB=2sin((A+B)/2)cos((A-B)/2 cosA+cosB=2cos((A+B)/2)sin((A-B)/2)
tanA+tanB=sin(A+B)/cosAcosB tanA-tanB=sin(A-B)/cosAcosB
ctgA+ctgBsin(A+B)/sinAsinB -ctgA+ctgBsin(A+B)/sinAsinB

某些數列前n項和
1+2+3+4+5+6+7+8+9+…+n=n(n+1)/2 1+3+5+7+9+11+13+15+…+(2n-1)=n2
2+4+6+8+10+12+14+…+(2n)=n(n+1) 12+22+32+42+52+62+72+82+…+n2=n(n+1)(2n+1)/6
13+23+33+43+53+63+…n3=n2(n+1)2/4 1*2+2*3+3*4+4*5+5*6+6*7+…+n(n+1)=n(n+1)(n+2)/3

正弦定理 a/sinA=b/sinB=c/sinC=2R 註: 其中 R 表示三角形的外接圓半徑

餘弦定理 b2=a2+c2-2accosB 註:角B是邊a和邊c的夾角

圓的標準方程 (x-a)2+(y-b)2=r2 註:(a,b)是圓心坐標
圓的一般方程 x2+y2+Dx+Ey+F=0 註:D2+E2-4F>0
拋物線標準方程 y2=2px y2=-2px x2=2py x2=-2py

直稜柱側面積 S=c*h 斜稜柱側面積 S=c'*h
正稜錐側面積 S=1/2c*h' 正稜台側面積 S=1/2(c+c')h'
圓台側面積 S=1/2(c+c')l=pi(R+r)l 球的表面積 S=4pi*r2
圓柱側面積 S=c*h=2pi*h 圓錐側面積 S=1/2*c*l=pi*r*l

弧長公式 l=a*r a是圓心角的弧度數r >0 扇形面積公式 s=1/2*l*r

錐體體積公式 V=1/3*S*H 圓錐體體積公式 V=1/3*pi*r2h
斜稜柱體積 V=S'L 註:其中,S'是直截面面積, L是側稜長
柱體體積公式 V=s*h 圓柱體 V=pi*r2h

[轉貼]計算幾何常用算法介紹

[轉貼]計算幾何常用算法介紹
http://www.blogjava.net/sishuiweilan/archive/2007/09/07/143474.html

1. 矢量減法


設二維矢量 P = (x1,y1) ,Q = (x2,y2)
則矢量減法定義為: P - Q = ( x1 - x2 , y1 - y2 )
顯然有性質 P - Q = - ( Q - P )
如不加說明,下面所有的點都看作矢量,兩點的減法就是矢量相減;


2.矢量叉積


設矢量P = (x1,y1) ,Q = (x2,y2)
則矢量叉積定義為:  P × Q = x1*y2 - x2*y1   得到的是一個標量顯然有性質 P × Q = - ( Q × P )   P × ( - Q ) = - ( P × Q )
如不加說明,下面所有的點都看作矢量,點的乘法看作矢量叉積;

叉乘的重要性質:

        > 若 P × Q  > 0 ,  則P 在Q的順時針方向
        > 若 P × Q  < 0 ,  則P 在Q的逆時針方向
        > 若 P × Q  = 0 ,  則P 與Q共線,但可能同向也可能反向


3.判斷點在線段上


設點為Q,線段為P1P2 ,判斷點Q在該線段上的依據是:( Q - P1 ) × ( P2 - P1 ) = 0  且 Q 在以 P1,P2為對角頂點的矩形內


4.判斷兩線段是否相交


我們分兩步確定兩條線段是否相交:

(1).   快速排斥試驗

設以線段 P1P2 為對角線的矩形為R, 設以線段 Q1Q2 為對角線的矩形為T,如果R和T不相交,顯然兩線段不會相交;

(2).   跨立試驗

如果兩線段相交,則兩線段必然相互跨立對方,如圖1所示。在圖1中,P1P2跨立Q1Q2 ,則矢量 ( P1 - Q1 ) 和( P2 - Q1 )位於矢量( Q2 - Q1 ) 的兩側,即( P1 - Q1 ) × ( Q2 - Q1 )  *  ( P2 - Q1 ) × ( Q2 - Q1 )  <  0上式可改寫成   ( P1 - Q1 ) × ( Q2 - Q1 )  *  ( Q2 - Q1 ) × ( P2 - Q1 )  >  0當( P1 - Q1 ) × ( Q2 - Q1 ) = 0 時,說明( P1 - Q1 ) 和 ( Q2 - Q1 )共線,但是因為已經通過快速排斥試驗,所以 P1 一定在線段 Q1Q2上;同理,( Q2 - Q1 ) ×( P2 - Q1 )  = 0 說明 P2 一定在線段 Q1Q2上。

所以判斷P1P2跨立Q1Q2的依據是:

( P1 - Q1 ) × ( Q2 - Q1 )  *  ( Q2 - Q1 ) × ( P2 - Q1 )  ぼ  0

同理判斷Q1Q2跨立P1P2的依據是:

( Q1 - P1 ) × ( P2 - P1 )  *  ( P2 - P1 ) × ( Q2 - P1 )  ぼ  0

至此已經完全解決判斷線段是否相交的問題。


5.判斷線段和直線是否相交


如果線段 P1P2和直線Q1Q2相交,則P1P2跨立Q1Q2,即:

( P1 - Q1 ) × ( Q2 - Q1 )  *  ( Q2 - Q1 ) × ( P2 - Q1 )  ぼ  0


6.判斷矩形是否包含點


只要判斷該點的橫坐標和縱坐標是否夾在矩形的左右邊和上下邊之間。

6.判斷線段、折線、多邊形是否在矩形中

因為矩形是個凸集,所以只要判斷所有端點是否都在矩形中就可以了。

7.判斷矩形是否在矩形中

只要比較左右邊界和上下邊界就可以了。

8.判斷圓是否在矩形中

圓在矩形中的充要條件是:圓心在矩形中且圓的半徑小於等於圓心到矩形四邊的距離的最小值。

9.判斷點是否在多邊形中

以點P為端點,向左方作射線L,由於多邊形是有界的,所以射線L的左端一定在多邊形外,考慮沿著L從無窮遠處開始自左向右移動,遇到和多邊形的第一個交點的時候,進入到了多邊形的內部,遇到第二個交點的時候,離開了多邊形,……所以很容易看出當L和多邊形的交點數目C是奇數的時候,P在多邊形內,是偶數的話P在多邊形外。

但是有些特殊情況要加以考慮。如果L和多邊形的頂點相交,有些情況下交點只能計算一個,有些情況下交點不應被計算(自己畫個圖就明白了);如果L和多邊形的一條邊重合,這條邊應該被忽略不計。為了統一起見,我們在計算射線L和多邊形的交點的時候,1。對於多邊形的水平邊不作考慮;2。對於多邊形的頂點和L相交的情況,如果該頂點是其所屬的邊上縱坐標較大的頂點,則計數,否則忽略;3。對於P在多邊形邊上的情形,直接可判斷P屬於多邊行。由此得出算法的偽代碼如下:


1. count ← 0;
2. 以P為端點,作從右向左的射線L;
3. for 多邊形的每條邊s
4.   do if P在邊s上
5.          then return true;
6.      if s不是水平的
7.          then if s的一個端點在L上且該端點是s兩端點中縱坐標較大的端點
9.                  then count ← count+1
10.              else if s和L相交
11.                 then count ← count+1;
12. if count mod 2 = 1
13.   then return true
14.   else return false;

其中做射線L的方法是:設P'的縱坐標和P相同,橫坐標為正無窮大(很大的一個正數),則P和P'就確定了射線L。這個算法的複雜度為O(n)。


10.判斷線段是否在多邊形內

線段在多邊形內的一個必要條件是線段的兩個端點都在多邊形內;如果線段和多邊形的某條邊內交(兩線段內交是指兩線段相交且交點不在兩線段的端點),因為多邊形的邊的左右兩側分屬多邊形內外不同部分,所以線段一定會有一部分在多邊形外。於是我們得到線段在多邊形內的第二個必要條件:線段和多邊形的所有邊都不內交;

線段和多邊形交於線段的兩端點並不會影響線段是否在多邊形內;但是如果多邊形的某個頂點和線段相交,還必須判斷兩相鄰交點之間的線段是否包含與多邊形內部。因此我們可以先求出所有和線段相交的多邊形的頂點,然後按照X-Y坐標排序,這樣相鄰的兩個點就是在線段上相鄰的兩交點,如果任意相鄰兩點的中點也在多邊形內,則該線段一定在多邊形內。證明如下:

命題1:

如果線段和多邊形的兩相鄰交點P1 ,P2的中點P' 也在多邊形內,則P1, P2之間的所有點都在多邊形內。

證明:

假設P1,P2之間含有不在多邊形內的點,不妨設該點為Q,在P1, P'之間,因為多邊形是閉合曲線,所以其內外部之間有界,而P1屬於多邊行內部,Q屬於多邊性外部,P'屬於多邊性內部,P1-Q-P'完全連續,所以P1Q和QP'一定跨越多邊形的邊界,因此在P1,P'之間至少還有兩個該線段和多邊形的交點,這和P1P2是相鄰兩交點矛盾,故命題成立。證畢

由命題1直接可得出推論:

推論2:

設多邊形和線段PQ的交點依次為P1,P2,……Pn,其中Pi和Pi+1是相鄰兩交點,線段PQ在多邊形內的充要條件是:P,Q在多邊形內且對於i =1, 2,……, n-1,Pi ,Pi+1的中點也在多邊形內。

在實際編程中,沒有必要計算所有的交點,首先應判斷線段和多邊形的邊是否內交,倘若線段和多邊形的某條邊內交則線段一定在多邊形外;如果線段和多邊形的每一條邊都不內交,則線段和多邊形的交點一定是線段的端點或者多邊形的頂點,只要判斷點是否在線段上就可以了。

至此我們得出算法如下:


1. if 線端PQ的端點不都在多邊形內
2.   then return false;
3. 點集pointSet初始化為空;
4. for 多邊形的每條邊s
5.   do if 線段的某個端點在s上
6.         then 將該端點加入pointSet;
7.      else if s的某個端點在線段PQ上
8.         then 將該端點加入pointSet;
9.      else if s和線段PQ相交        // 這時候可以肯定是內交
10.        then return false;
11. 將pointSet中的點按照X-Y坐標排序,X坐標小的排在前面,
    對於X坐標相同的點,Y坐標小的排在前面;
12. for pointSet中每兩個相鄰點 pointSet[i] , pointSet[ i+1]
13.    do if pointSet[i] , pointSet[ i+1] 的中點不在多邊形中
14.         then return false;
15. return true;


這個算法的複雜度也是O(n)。其中的排序因為交點數目肯定遠小於多邊形的頂點數目n,所以最多是常數級的複雜度,幾乎可以忽略不計。


11.判斷折線在多邊形內只要判斷折線的每條線段是否都在多邊形內即可。設折線有m條線段,多邊形有n個頂點,則複雜度為O(m*n)。


12.判斷多邊形是否在多邊形內只要判斷多邊形的每條邊是否都在多邊形內即可。判斷一個有m個頂點的多邊形是否在一個有n個頂點的多邊形內複雜度為O(m*n)。


13.判斷矩形是否在多邊形內將矩形轉化為多邊形,然後再判斷是否在多邊形內。


14.判斷圓是否在多邊形內只要計算圓心到多邊形的每條邊的最短距離,如果該距離大於等於圓半徑則該圓在多邊形內。計算圓心到多邊形每條邊最短距離的算法在後文闡述。


15.判斷點是否在圓內計算圓心到該點的距離,如果小於等於半徑則該點在圓內。

16.判斷線段、折線、矩形、多邊形是否在圓內因為圓是凸集,所以只要判斷是否每個頂點都在圓內即可。

17.判斷圓是否在圓內

設兩圓為O1,O2,半徑分別為r1, r2,要判斷O2是否在O1內。先比較r1,r2的大小,如果r1<r2則O2不可能在O1內;否則如果兩圓心的距離大於r1 - r2 ,則O2不在O1內;否則O2在O1內。

18.計算點到線段的最近點

如果該線段平行於X軸(Y軸),則過點point作該線段所在直線的垂線,垂足很容易求得,然後計算出垂足,如果垂足在線段上則返回垂足,否則返回離垂足近的端點;

如果該線段不平行於X軸也不平行於Y軸,則斜率存在且不為0。設線段的兩端點為pt1和pt2,斜率為:
k = ( pt2.y - pt1. y ) / (pt2.x - pt1.x );
該直線方程為:
y = k* ( x - pt1.x) + pt1.y
其垂線的斜率為 - 1 / k,
垂線方程為:
y = (-1/k) * (x - point.x) + point.y
聯立兩直線方程解得:
x  =  ( k^2 * pt1.x + k * (point.y - pt1.y ) + point.x ) / ( k^2 + 1)
y  =  k * ( x - pt1.x) + pt1.y;

然後再判斷垂足是否在線段上,如果在線段上則返回垂足;如果不在則計算兩端點到垂足的距離,選擇距離垂足較近的端點返回。

19.計算點到折線、矩形、多邊形的最近點只要分別計算點到每條線段的最近點,記錄最近距離,取其中最近距離最小的點即可。

20.計算點到圓的最近距離

如果該點在圓心,則返回UNDEFINED
連接點P和圓心O,如果PO平行於X軸,則根據P在O的左邊還是右邊計算出最近點的橫坐標為centerPoint.x - radius 或 centerPoint.x + radius, 如圖4 (a)所示;如果PO平行於Y軸,則根據P在O的上邊還是下邊計算出最近點的縱坐標為centerPoint.y + radius 或 centerPoint.y - radius, 如圖4 (b)所示。

如果PO不平行於X軸和Y軸,則PO的斜率存在且不為0,如圖4(c)所示。這時直線PO斜率為
k = ( P.y - O.y )/  ( P.x - O.x )
直線PO的方程為:
y = k * ( x - P.x) + P.y
設圓方程為:
(x - O.x ) ^2 + ( y - O.y ) ^2 = r ^2,
聯立兩方程組可以解出直線PO和圓的交點,取其中離P點較近的交點即可。

21.計算兩條共線的線段的交點

對於兩條共線的線段,它們之間的位置關係有圖5所示的幾種情況。圖5(a)中兩條線段沒有交點;圖5 (b) 和 (d) 中兩條線段有無窮焦點;圖5 (c)中兩條線段有一個交點。設line1是兩條線段中較長的一條,line2是較短的一條,如果line1包含了line2的兩個端點,則是圖5(d)的情況,兩線段有無窮交點;如果line1只包含line2的一個端點,那麼如果line1的某個端點等於被line1包含的line2的那個端點,則是圖5(c)的情況,這時兩線段只有一個交點,否則就是圖5(c)的情況,兩線段也是有無窮的交點;如果line1不包含line2的任何端點,則是圖5(a)的情況,這時兩線段沒有交點。


22.計算線段或直線與線段的交點

設一條線段為L0 = P1P2,另一條線段或直線為L1 = Q1Q2 ,要計算的就是L0和L1的交點。

1.首先判斷L0和L1是否相交(方法已在前文討論過),如果不相交則沒有交點,否則說明L0和L1一定有交點,下面就將L0和L1都看作直線來考慮。

2.如果P1和P2橫坐標相同,即L0平行於Y軸
  a)若L1也平行於Y軸,
      i.若P1的縱坐標和Q1的縱坐標相同,說明L0和L1共線,假如L1是直線的話他們有無窮的交點,假如L1是線段的話可用"計算兩條共線線段的交點"的算法求他們的交點(該方法在前文已討論過);
      ii.否則說明L0和L1平行,他們沒有交點;
  b)若L1不平行於Y軸,則交點橫坐標為P1的橫坐標,代入到L1的直線方程中可以計算出交點縱坐標;
3.如果P1和P2橫坐標不同,但是Q1和Q2橫坐標相同,即L1平行於Y軸,則交點橫坐標為Q1的橫坐標,代入到L0的直線方程中可以計算出交點縱坐標;
4.如果P1和P2縱坐標相同,即L0平行於X軸
  a)若L1也平行於X軸,
      i.若P1的橫坐標和Q1的橫坐標相同,說明L0和L1共線,假如L1是直線的話他們有無窮的交點,假如L1是線段的話可用"計算兩條共線線段的交點"的算法求他們的交點(該方法在前文已討論過);
     ii.否則說明L0和L1平行,他們沒有交點;

   b)若L1不平行於X軸,則交點縱坐標為P1的縱坐標,代入到L1的直線方程中可以計算出交點橫坐標;
5.如果P1和P2縱坐標不同,但是Q1和Q2縱坐標相同,即L1平行於X軸,則交點縱坐標為Q1的縱坐標,代入到L0的直線方程中可以計算出交點橫坐標;
6.剩下的情況就是L1和L0的斜率均存在且不為0的情況
   a)計算出L0的斜率K0,L1的斜率K1 ;
   b)如果K1 = K2
      i.如果Q1在L0上,則說明L0和L1共線,假如L1是直線的話有無窮交點,假如L1是線段的話可用"計算兩條共線線段的交點"的算法求他們的交點(該方法在前文已討論過);
     ii.如果Q1不在L0上,則說明L0和L1平行,他們沒有交點。
   c)聯立兩直線的方程組可以解出交點來

說明:這個算法並不複雜,但是要分情況討論清楚,尤其是當兩條線段共線的情況需要單獨考慮,所以在前文將求兩條共線線段的算法單獨寫出來。另外,一開始就先利用矢量叉乘判斷線段與線段(或直線)是否相交,如果結果是相交,那麼在後面就可以將線段全部看作直線來考慮。

23.求線段或直線與折線、矩形、多邊形的交點分別求與每條邊的交點即可。

24.求線段或直線與圓的交點

 

設圓心為O,圓半徑為r,直線(或線段)L上的兩點為P1,P2。
1.如果L是線段且P1,P2都包含在圓O內,則沒有交點;否則進行下一步
2.如果L平行於Y軸,
  a)計算圓心到L的距離dis
  b)如果dis > r 則L和圓沒有交點;
  c)利用勾股定理,可以求出兩交點坐標,如圖6(a)所示;但要注意考慮L和圓的相切情況
3.如果L平行於X軸,做法與L平行於Y軸的情況類似;
4.如果L既不平行X軸也不平行Y軸,可以求出L的斜率K,然後列出L的點斜式方程,和圓方程聯立即可求解出L和圓的兩個交點;
5.如果L是線段,對於2,3,4中求出的交點還要分別判斷是否屬於該線段的範圍內。

2007年9月7日 星期五

微軟如何輸掉API戰爭

微軟如何輸掉API戰爭

作者:周思博 (Joel Spolsky)
譯:Paul May 梅普華
Sunday, June 13, 2004
屬於Joel on Software, http://www.joelonsoftware.com


這陣子你應該聽過某種理論:「微軟要完蛋了。只要Linux在桌上型市場有些進展,而web
應用程式又取代桌上型系統的應用程式,這個強盛帝國就會崩潰了。」

雖然Linux的確是微軟的心頭大患,不過至少要預言這個Redmond公司滅亡還言之過早。微
軟銀行裡的現金多得不得了,而且仍是非常的賺錢,還要很久很久才可能倒。微軟可以胡
搞個十年才會開始有點危險,而且你永遠不會知道……他們可能在最後一刻變身成刨冰公
司。所以別這麼快就看衰他們。90年代初期大家都認為IBM徹底完蛋了,因為大型主機(
mainframe)已經成為歷史!那時候Robert X. Cringely預言主機時代會在2000年一月一
日結束,屆時所有用COBOL寫的程式都會出問題。由於原始碼都早已遺失(據稱),所以
沒有人會去修正這件程式,大家都會針對主從架構的平台把這些程式全部重寫過。

好吧,猜猜結果如何。大型主機仍然與我們同在,2000年一月一日什麼事都沒發生,而
IBM則是變身成一家巨大的老牌技術顧問公司,同時恰巧也在製造便宜塑膠電話
  (http://www.google.com/froogle?q= ... tnG=Search+Froogle)
。所以只由少數幾個資料就推斷出微軟要完蛋的理論,實在是有點誇大了。

不過大多數人並未注意到一個較不為人知的現象:微軟在戰略上最重要的寶物Windows
API要輸了。Windows與Office的利潤豐厚,幾乎貢獻微軟所有的收入,還養活大量不賺錢
或賺很少的產品線。這些賺錢產品的特權和微軟的壟斷勢力都是以Windows API為基石。
不過它對開發人員不再那麼有吸引力了。生金蛋的鵝還沒死,不過已經得了還沒人注意到
的絕症。

既然我已經說了,請容我為前一段的大言不慚和炫耀說聲抱歉。我想我看起來開始像那些
商業小報的評論主筆,喋喋不休地談論Windows API這個微軟的策略資產。我打算在這裡
用幾頁的篇幅,來解釋我真正的意思並闡明我的論點。在我解釋清楚之前請不要直接下任
何結論。這會是篇很長的文章,我得解釋什麼是Windows API;我也得說明它為什麼是微
軟最重要的策略式資產,還要解釋它會怎麼輸掉以及輸掉這件事長期的含意。另外既然是
在談大趨勢,難免也得誇大其詞和泛泛空談囉。

開發者、開發者、開發者、開發者
還記得作業系統的定義嗎?它負責管理一台電腦的資源讓應用程式能執行。大家其實並不
太在意作業系統;比較重視那些依賴作業系統的應用程式。像是文書處理器、即時通訊、
電子郵件、應付帳款管理、有Paris Hilton照片的網站等等。作業系統本身並沒什麼用。
大家會買作業系統是因為上面可以執行有用的應用程式。因此最有用的作業系統就是擁有
最有用應用程式的作業系統。

由這裡可以合理推出一個結論,如果你想要賣作業系統,最重要的就是讓軟體開發者願意
替你的作業系統寫軟體。所以Steve Ballmer才會跳上舞台
  (http://www.ntk.net/ballmer/mirrors.html)大喊「開發者、開發者、開發者、開發者
。」這對微軟實在是太重要了。微軟沒有公然發放Windows開發工具,唯一的理由就是怕
不小心砍斷競爭開發工具商的生路(嗯,是指還活著的那些)。因為有各種開發工具可以
選擇,會讓他們的平台更能吸引開發人員。不過他們其實真的想要發放開放工具。你可以
透過他們的Empower ISV
(http://members.microsoft.com/par ... power/default.aspx)
深耕計劃,以大約375美元買到五套完整的MSDN Universal(也就是「除模擬飛行外的所
有微軟產品」)。免費的.NET runtime附有命令列版本的.NET語言編譯器...也是免費的
。現在C++編譯器也免費 (http://msdn.microsoft.com/visualc/vctoolkit2003/)了。微
軟盡各種方法鼓勵開發者支持.NET平台,只是為了不要害死Borland這些公司才收斂一點


為什麼蘋果和Sun不能賣電腦
好吧,這樣說當然是有點蠢。蘋果和Sun當然可以賣電腦,但不是在最賺錢的企業桌上型
電腦和家用電腦兩個市場。蘋果的佔有率低到只有個位數,而Sun也只有自己公司的人在
用。(請理解我這裡談的是大趨勢,所以當我用「沒人」等說法其實是指「少於一千萬人
」。請如此類推。)

為什麼呢?因為蘋果和Sun的電腦都不能執行Windows的程式,就算可以也是要用某種昂貴
的模擬模式勉強執行。記住,大家是為了要執行應用程式才買電腦的,而Windows上好的
桌面應用程式比麥金塔多太多了,所以麥金塔的用戶實在很難當。

附欄「API」是什麼東西?

如果你正在寫一支程式(假設是個文書處理器),你想顯示選單或是寫檔案時得呼叫作業
系統替你完成,這時會用到一組每個作業系統都不相同的函數。這些函數就叫做API,也
就是作業系統(如Windows)提供給應用程式開發者(如寫文書處理器或試算表等等的程式
師)的介面。它是一組數量上千,複雜而講究的函數和副程式,可以讓程式師指示作業系
統做些有趣的事(如顯示選單和讀寫檔案)、奇怪的事(如把指定的日期用塞爾維亞語表
示),以及非常複雜的事(比如在視窗裡顯示一個網頁)。如果你的程式使用了Windows
的API,就不能在提供不同API呼叫的Linux上執行。有時候API做的事是差不多的。
Windows軟體不能在Linux上執行有一個重要的原因。因為想讓Windows程式在Linux上執行
,就得重新實作 (http://www.winehq.com/)整個Windows API。這包括數千個複雜的函數
,規模幾乎和實作Windows本身一樣大,其中有些東西微軟用了數千個人年才做出來。如
果你犯了個小錯誤或是漏了某個應用程式需要的函數,那個應用程式就會當掉。


而這正是Windows API對微軟是極重要資產的原因。

(我知道,我知道,這時候佔全世界電腦人口2.3%的麥金塔用戶,正要打開電子郵件程式
寫信我說他們多麼喜愛麥金塔。再次聲明,我在談大趨勢和一般化,所以別浪費你的時間
。我知道你愛你的麥金塔,也知道它可以執行所有你需要的東西。我愛你,你是個好人,
不過你只是全部的2.3%,所以這篇文章不關你事。)

微軟內的兩股力量
微軟內部有兩股相對的力量,我稱之為(雖然有點諷刺意味)Raymond Chen陣營和MSDN雜
誌陣營。

Raymond Chen是微軟Windows團隊的開發人員,從1992年起就在那裡了。他的網誌"The
Old New Thing (http://weblogs.asp.net/oldnewthing/)"裡有很多詳細的技術性文章,
解釋Windows裡某些東西為什麼會是現在的樣子,甚至很蠢的東西其實也有著很好的理由


看Raymond的網誌時令人印象最深刻的是這些年來Windows團隊為了維持向後相容,投入難
以置信努力 (http://weblogs.asp.net/oldnewthing/archive/2003/10/15/55296.aspx)
的故事 (http://weblogs.asp.net/oldnewthing/archive/2003/12/23/45481.aspx)

由客戶觀點來看看這個情境。你買了程式X和Y還有Z,後來升級到Windows XP。現在電腦
會亂當機,而且程式Z還不能動。你會告訴朋友:「不要升級到Windows XP。它會亂當機
而且跟程式Z不相容。」你會去查看看是不是程式X造成當機嗎?或是去查出其實程式Z用
了未公開的視窗訊息所以不會動嗎?當然不會。你只會把整盒Windows XP拿回去退費。(
程式X和Y和Z都是幾個月前買的。30天內退貨的時限已經超過,你也只能退Windows XP了
。)
我最初是由熱賣遊戲SimCity的某位作者聽到這些事的。他說他的程式裡有隻大蟲,會在
釋放記憶體後馬上又用到,這是個大問題,在DOS上恰巧能動,不過在Windows就會出事,
因為釋放的記憶體立刻就會被其他程式拿去用。Windows團隊的測試人員測遍各種常見的
應用程式,要確定是否都能正常執行,可是SimCity一直當機。他們把這個狀況回報給
Windows開發人員,開發人員就反組譯SimCity用除錯器逐行追查找出問題,然後加上特別
的程式碼檢查SimCity是否正在執行,如果有的話就把記憶體配置程式切成特殊模式,讓
記憶體在釋放後還可以使用。

這並不是特例。Windows測試團隊非常巨大,而他們最重要的責任之一就是要保證不管裝
了什麼程式,每個人都要能安然無事地升級作業系統,而且即使這些程式做了壞事或呼叫
未公開函數,或是依賴在Windows n有但n+1版修好的問題,都必須能繼續執行。事實上如
果你在registry登錄資料庫的AppCompatibility區到處看看,就會看到一大堆要特別處理
的應用程式,Windows會模擬各種舊問題和古怪的行為讓這些程式能繼續執行。Raymond
Chen寫道 (http://weblogs.asp.net/oldnewthing/archive/2003/10/15/55296.aspx)
「有人指控微軟在OS升級時惡意地妨害應用程式時我會覺得很生氣。如果有任何程式不能
在Windows 95執行,我會視為個人的失敗。我有很多個晚上沒睡去修正別人的程式,只是
為了讓它們能在Windows 95執行。」

很多開發人員和工程師都不同意這種作法。他們認為如果應用程式做了壞事或依賴某些未
公開的行為,應該讓它們在OS升級後直接掛掉。蘋果公司的麥金塔OS開發人員一直都在這
個陣營。這也是很少麥金塔早期的程式還能動的原因。舉例來說,很多開發人員為了加速
自己的麥金塔應用程式,會把中斷跳躍表的指標複製出來直接呼叫,而不按正常方法使用
處理器的中斷功能。雖然蘋果的官方麥金塔程式設計聖經Inside Macintosh裡有段技術註
記寫著「你不可以這樣做」,這些人還是照樣做了,程式會動而且跑得更快...結果等下
一版作業系統出來這些程式就完全不能動了。如果寫這些應用程式的公司因而沒了生意(
大多數的確如此),好吧兄弟,只能怪你們運氣太差了。

對照之下,由於Raymond Chen陣營的努力,我1983年在最早期IBM PC上寫的DOS程式還能
正常執行。我知道這當然不只是Raymond一個人,這是整個核心Windows API團體的工作精
神,不過Raymond用他出色的網站The Old New Thing
(http://weblogs.asp.net/oldnewthing/)把它公佈出來,所以我才用他的名字。

這是其中一個陣營。另一個陣營我稱之為MSDN雜誌陣營,是以某一本開發人員雜誌來命名
,這本雜誌充滿了讓人興奮的文章,都在教你用各種在自己軟體裡結合微軟產品的神秘方
法來害死自己。MSDN雜誌陣營總是試圖說服你用新而複雜的外部技術,比如COM+、MSMQ、
MSDE、Microsoft Office、Internet Explorer及其元件、MSXML、DirectX(請用最新版
)、Windows Media Player、以及Sharepoint... Sharepoint!這個沒有人有的東西名符
其實的有一大堆壯觀的外部關聯,當你要把應用程式發行給付錢的客戶時,每個關聯都會
變成大麻煩,而且沒有辦法弄好。這種事的技術性名稱叫DLL地獄。在我這裡能動,為什
麼在那裡不會動了?

Raymond Chen陣營相信,讓開發人員寫一次程式能到處(好吧,在所有的Windows上)執
行,可以讓他們更容易做事。而MSDN雜誌陣營則認為要提供一些功能很強的程式給開發人
員使用,才能讓他們更輕鬆,前提是開發人員願意承受難以置信的複雜部署和安裝麻煩,
更別提巨大的學習曲線了。Raymond陣營想的是強化(consolidation)。請不要讓事情變得
更糟,只要讓我們原有的東西能繼續動就好了。MSDN雜誌陣營則是得一直生產出大量的技
術,卻沒有人能跟得上。

下面是這件事要緊的原因。

微軟失去向後相容的信仰
在微軟內部,MSDN雜誌陣營已經贏了這場戰役。

第一個大勝利是讓Visual Basic.NET不必向後與VB 6.0相容。這是記憶中第一次買了微軟
產品的升級版後,無法安靜而完美的匯入舊資料(也就是你用VB6寫的程式)。這也是第
一次微軟的升級版不尊重使用者用該產品之前版本所做的成果。

而且天似乎還沒有塌下來,至少微軟內部沒出事。VB6開發人員極力反對,不過反正他們
也正在消失中,因為這些人大多都是企業開發人員,反正正在轉移到web開發。真正的長
期傷害就被隱藏起來了。

MSDN雜誌陣營挾著這次大勝接管一切。突然間改東西變得理所當然了。IIS 6.0用了不同
的執行緒模型,讓某些舊應用程式不能動。我很震驚地發現用Windows Server 2003的客
戶不能執行FogBugz。然後.NET 1.1不能完全向後相容於1.0。而現在秘密終於揭露,OS團
隊也心領神會,決定不再為Windows API增加新功能而是完全取代掉。我們被告知不要再
用Win32了,現在要開始準備迎接WinFX
(http://www.gartner.com/DisplayDocument?doc_cd=118261):下一代的Windows API。
全部都不一樣了。現在依據的是用受控代碼(managed code)的.NET、XAML、Avalon。是
的,我得承認遠遠優於Win32。不過這並不是升級,而是對過去的破壞。

Windows開發的複雜困擾了外界的開發人員,他們被微軟整個平台打敗了,現在已經在發
展web平台了。在dotcom興旺初期建立了Yahoo! Store的Paul Graham很有力地總結
  (http://www.paulgraham.com/road.html):「新創公司現在有更多的理由去寫
Web-based軟體,因為桌面軟體寫起來已經不那麼好玩了。現在想寫桌面軟體就要照微軟
的規矩,呼叫他們的API還要應付他們多蟲的OS。另外如果你真的寫出什麼熱門的東西,
可能會發現自己只是在替微軟做市場研究。」

微軟已經大到有太多的開發人員,這些人太沈溺於增加收益,因此他們突然決定把每件事
徹底重做過並不是太了不起的計畫。該死的,我們還可以做兩次啊。舊的微軟(Raymond
Chen的微軟)可能會把Avalon(新的繪圖系統)這種東西實作成一系列的DLL,不但能在
任何版本的Windows上執行,還可以和需要用到的應用程式包在一起。並沒有任何技術上
的理由不這樣做,不過微軟必須找個藉口讓你買Longhorn。他們想弄出大量的改變,就像
Windows取代DOS時那麼多的變化。問題是Longhorn並沒有比Windows XP先進太多;根本不
到Windows超越DOS的那種程度。或許它的吸引力並不足讓人像對Windows那樣,為它買全
新的電腦和應用程式。好吧,或許它有這個能耐,微軟一定得讓它有,不過就我目前所看
到的實在沒什麼說服力。微軟很多東西都賭錯了。舉例來說
  (http://weblog.infoworld.com/udell/2004/06/02.html#a1012),WinFS的宣傳是以關
聯式資料庫方式製作檔案系統,以達成搜尋功能的一種作法,卻忽略了事實上要達成搜尋
功能的真實作法就是要達成搜尋功能(the real way to make searching work is by
making searching work)。不要讓我替所有檔案輸入提示資料然後用查詢語言去搜尋。
只要幫我個忙去搜尋該死的硬碟,快速地找到我打的字串,隨便你用全文檢索或其他1973
年就有的技術。

自動排檔獲得最後勝利
不想把我想錯了……我認為.NET是個很偉大的開發環境,我也相信搭配XAML的Avalon比
Windows舊GUI應用程式的寫法先進許多。.NET最大的優勢就是擁有自動化的記憶體管理。


我們很多人都認為1990年代最大的戰爭就是程序化程式設計與物件導向程式設計間的戰爭
,而且我們認為物件導向程式設計能讓程式師的生產力大幅提升,我當時也是其中之一,
而有些人到現在也還是這麼認為。不過結果我們錯了,物件導向程式師設計是很方便的好
東西,不過並不能像它承諾地大幅提升生產力。真正讓程式師大幅提升生產力的,其實是
那些會替你自動管理記憶體的程式語言。它可以是參照計數(reference counting)或記
憶體回收(garbage collection);可以是Java、Lisp、Visual Basic(連1.0版也算)
、Smalltalk或是多種腳本語言其中之一。如果你的程式語言能讓你抓一塊記憶體來用,
又不用考慮用完後要如何釋放,你用的就是會管理記憶體的程式語言,那麼你的效率會遠
遠超過那些使用得明確管理記憶體的語言的程式師。當你聽到某些人誇耀他們的程式語言
生產力有多好時,他們的生產力可能大多是自動化記憶體管理所貢獻的,只是他們弄錯原
因而已。

附欄
為什麼自動化記憶體管理能大幅提升生產力? 1)因為你可以寫f(g(x))卻不用擔心要如何
釋放g的傳回值,這表示你的函數可以回傳很複雜資料型態,而這樣的函數能讓你以更高
階層的抽象想法來作業。 2)因為你不必花任何時間寫程式碼去釋放記憶體或追查記憶體
漏洞(memory leak)。 3)因為你不再需要小心安排函數的離開點以確保記憶體都有釋放乾
淨。


賽車迷可能會因而寫信罵我,不過就我的經驗而言,在正常駕駛時好的自排只有在一種狀
況下會不如手排。軟體開發也是類似的:幾乎在所有的狀況下,自動化記憶體管理都比手
動記憶體管理更好,而且能讓程式師生產力提升許多。

在Windows初期要開發桌面應用程式,微軟提供兩種作法,可以寫C程式直接呼叫Windows
API並自行管理自己的記憶體,或者用Visual Basic並把記憶體交給它管理。這也是我個
人過去13年來用得最多的兩個開發環境,用到熟得不得了,而我的經驗是Visual Basic的
生產力好非常多。我時常會寫相同的程式,用C++呼叫Windows API寫一次,用Visual
Basic也寫一次,C++通常要花三到四倍的工作時間。為什麼呢?答案是記憶體管理。要瞭
解原因最簡單的方法,就是去看任何會傳回字串的Windows API函數文件。仔細看看有多
少篇幅在討論該字串的記憶體由誰配置,或是如何協商需要的記憶體數量。通常你得呼叫
函數兩次,第一次告訴它你配置了0個位元組,函數會傳回「配置記憶體不足」的訊息,
順便還告訴你需要配置多少記憶體。這還是簡單的情形,如果運氣不好呼叫到的函數要傳
回字串的串列或是整個長度不定的結構就更麻煩了。不管如何,像開檔案寫入字串然後關
閉檔案之類簡單的操作,直接呼叫Windows API都需要一整頁的程式碼。在Visual Basic
類似的操作只要三行。

所以你有了這兩種程式設計的世界。每個人都斷定受控代碼的世界遠比未受控代碼世界更
優越。Visual Basic是有史以來(恐怕現在還是)賣得最好的程式語言產品,而且開發人
員在發展Windows程式時會優先選它而非C或C++。不過產品名稱裡有"Basic"這個事實卻讓
硬派程式師迴避,雖然它其實是個相當現代的程式語言,有很多物件導向功能而殘留的髒
東西也極少(行號和LET敘述早就不見了)。VB的另一個問題是部署時需要附上VB
runtime。這對透過數據機散播的共享軟體是個大問題,而更糟的是VB runtime會讓其他
程式師發現你的應用程式是用(可恥的!)Visual Basic開發的。

一個Runtime全部搞定
接下來又出現了.NET。這是個宏大的計畫,一個要把所有髒污一次清乾淨的超級偉大一統
計畫。當然它會有記憶體管理,也有Visual Basic,不過已經是種新語言。精神基本上還
是與原Visual Basic一樣,不過改用大括號和分號等類似C的語法。而最好的一點是這個
新的Visual Basic/C合體叫做Visual C#,所以再也不用對別人說你是一個"Basic"程式師
了。所有那些可怕的Windows函數,加上它們那些尾巴和掛入功能(hook)還有向後相容
問題與不可能弄懂
  
(http://msdn.microsoft.com/librar ... ileVersionInfo.asp)
的字串回傳機制全部一掃而空,取而代之的是個單一乾淨只有一種字串的物件導向介面。
一個Runtime全部搞定。真是漂亮。就技術面而言他們也的確成功了。.NET是個偉大的程
式設計環境,可以管理你的記憶體並提供一組豐富完整且一致的作業系統介面,另外還有
一組豐富而超完整又優雅的物件程式庫提供各種基本的操作。

不過,大家還是沒有真正大量使用.NET。

噢,當然某些人是有啦。

不過建立一個完全嶄新的程式設計環境來一統Visual Basic和Windows API程式設計的混
亂,而且這個新環境並不是用一種或二種語言,而是有三種程式語言(或許是四種嗎?)
,這種作法實在有點像用壓倒性的音量大喊「閉嘴!」讓兩個小孩停止吵架。這種作法只
有在電視上行得通。在真實世界裡,如果你對兩個大聲吵架的人喊「閉嘴!」,結果只會
變成三個人在吵架。

(順便一提,網誌聚合器格式是個神秘而充滿政治味的世界,有在注意的讀者可以看到那
裡面發生的事情是一樣的。RSS已經變得支離破碎了,原因是有數個不多的版本,規格不
正確又有很多政治鬥爭。有人試圖建立叫Atom的另一種格式來消弭混亂,結果只是在RSS
的眾多版本外再加一個Atom而已,規格還是不正確而政治鬥爭依舊很多。當你創造第三方
案想藉以一統兩股對抗的力量時,最後只會變成三股敵對的力量。你並不會一統什麼也沒
有真的修正什麼。)

於是我們現在並沒有出現.NET的一統和單純,反而是擁有六重的複雜,每個人都試圖在這
團亂中找出所用的開發策略,以及是否有本錢把應用程式移植到.NET。

不管微軟的市場訊息有多麼一致(「只用.NET就對了?把我們當白痴啊!」),他們大部
份客戶還是在用C、C++、Visual Basic 6.0以及原本的ASP,更別提其他那些來自別的公
司的各種開發工具了。而在用.NET的都是在用ASP.NET來開發web應用程式,只會在
Windows伺服器上執行並不需要Windows的用戶端系統。這正是個關鍵點,後面寫到web時
會深入探討。

噢,等一下,還有其他東西要出來!
現在微軟有太多的開發人員在做事,徹底重做整個Windows API還不夠看,他們必須重做
兩次。去年的PDC中他們預先發表了下一個重大的作業系統改版,這個代號Longhorn的系
統除了其他東西之外,將會有一組代碼為Avalon的全新使用介面API。這組API是運用現代
電腦快速顯示硬體及即時3D成像能力重新建立的。如果你現在正在開發Windows GUI應用
程式,而且是用微軟「官方」最新最偉大的Windows程式設計環境WinForms的話,為了支
援Longhorn和Avalon兩年內就得重來一遍了。這說明了為什麼WinForms完全的難產。希望
你在這上面還沒有投資太多。Jon Udell找到一份標題為「如何在Windows Forms和Avalon
間選擇?」微軟的投影片,裡頭問道
  (http://weblog.infoworld.com/udell/2004/06/09.html#a1019):「我們為什麼要在
Windows Forms和Avalon間選擇一個呢?」真是個好問題,而且還是個他找不到好答案的
問題。

所以你有了Windows API,有了VB,現在還有.NET,雖然有多種程式語言可選,不過不要
跟任何一種牽涉太深,因為我們正在製作Avalon,而你知道它只能在最新的微軟作業系統
上執行,而這個系統要等很久很久才會出現。就我個人來說還沒空很深入的學習.NET,而
我們也沒有把Fog Creek的兩套產品由傳統的ASP及Visual Basic 6.0移植到.NET,因為投
資完全不會有報酬。以我來看這只是邊開火邊移動的掩護行動。微軟會很樂意看到我們停
止為我們的問題追蹤軟體和內容管理軟體增加新功能,然後浪費幾個月把它們移植到別的
程式開發環境上,這個動作不會對任何一個客戶有好處,因此也不會讓我們多賣出一套軟
體。這對微軟非常好,因為他們有內容管理軟體也有問題追蹤軟體,因此他們最高興我浪
費時間空轉追逐流行,然後再浪費一兩年做Avalon的版本,而同時他們卻在自己的相同產
品上一直加新功能。完全正確。

有正職的開發人員不會有時間追得上來自Redmond的所有新開發工具,因為微軟有太多該
死的員工在做開發工具!

這不是1990年代
微軟是在1980和1990年代長大的,當時個人電腦的成長非常的快速,每年新賣出的電腦都
超過原有的電腦數量。這也表示如果你做的產品只能給新電腦用,即使沒有人改用你的產
品,一兩年內還是可以攻下全世界的市場。這也是Word和Excel能如此徹底地取代
WordPerfect和Lotus的原因:微軟只要等下一波硬體升級,把Windows和Word以及Excel賣
給更新桌上型電腦企業就好了(有些還是第一次買電腦)。所以微軟在很多方面從來不需
要學習讓現有的客戶由第N版產品轉換到N+1版。當人們拿到新電腦時,會很樂意在新電腦
上搭配微軟所有的新東西,不過升級的意願就低很多了。當PC產業如野火般成長時這並不
打緊。不過現在這個世界的PC已經飽和了,而且大部份的PC都用得很好。謝謝你,微軟突
然瞭解到最新版的東西沒那麼好推了。他們想把Windows 98完全結束,結果還在使用的人
實在太多,於是他們只好承諾
  (http://www.windows-help.net/microsoft/98-lifecycle.html)會對那個老爺系統再多
支援幾年。

這些勇敢的新策略(.NET、Longhorn、Avalon之類的玩意)試圖建立一組新API把大家鎖
住。問題是大家都還在用1998時買來還很好用的電腦,這種策略是不太行不通的。即使
Longhorn照計畫在2006推出(我根本不相信),大概還得多等幾年,擁有的人數才會多到
能考慮作為開發平台。開發者們才不會聽從微軟那些多重人格失調的軟體開發建議呢!

進入Web
我不知道自己怎麼能寫這麼久還沒提到Web。每個開發人員在計畫新軟體應用程式時都要
做一個選擇,他們可以做成web版本,也可以做一個在PC上執行的"rich client"應用程式
。基本的優缺點很單純:Web應用程式比較容易部署,而rich client應用程式反應較快所
以使用介面比較有趣。

Web應用程式比較容易部署是因為不需要安裝。Web應用程式的安裝等於只是在網址列輸入
一個URL。今天我要安裝Google的新電郵程式,只要按Alt+D、gmail,再按Ctrl+Enter就
好了。相容性問題還有與其他軟體相衝的問題都少太多了。產品所有的使用者都在用相同
的版本,所以你永遠不必支援各種舊版本。你可以用任何喜歡的開發環境,因為只要裝在
自己的伺服器上執行就好了。在這個星球上幾乎每台還可以的電腦自然而然都能用你的應
用程式。而你客戶的資料也很理所當然能用於這星球上任何一台還可以的電腦上。

不過這必須付出使用介面的平順作為代價。下面是幾個web應用程式做不好的例子:

創造一個快速繪圖的程式
寫一個能標示紅色波浪底線的即時拼字檢查程式
在使用者按到瀏覽器的關閉盒時,警告使用者將會遺失其工作成果
不必連到伺服器來回溝通一遍,就能依據使用者的變更來更新小部份的顯示,
建立一個不需滑鼠的快速鍵盤驅動介面
讓大家在沒有連上Internet時繼續作業
這些都不算大問題,其中有些很快就會被聰明的Javascript開發人員解決。有兩個新的
web應用程式Gmail (https://gmail.google.com/)以及Oddpost
(http://www.oddpost.com/)(都是電郵程式)做得相當不錯,避開或完全解決了部份的
問題。另外使用者似乎也不在意UI小問題或web介面的緩慢。不知道為什麼,不管我如何
努力宣揚rich client會,呃,比較豐富,我認識的人幾乎全都對web式的電子郵件軟體十
分滿意。

所以Web使用介面已經有80分了,就算不靠新的web瀏覽器還是有機會達成95分。這對大多
數人來說已經夠好了,當然對開發人員來說也夠了,而且他們也已經實際把幾乎所有重要
的新應用程式都寫成web應用程式。

這表示微軟的API突然間已經不那麼重要了。Web並不需要Windows。

微軟並不是沒注意到這件事發生。他們當然知道,所以他們在局勢浮現時就猛踩煞車。他
們不再在未來計畫裡承諾像HTA
(http://msdn.microsoft.com/worksh ... ew/htaoverview.asp)
DHTML這類的新技術。Internet Explorer團隊似乎也消失了;他們有好幾年似乎完全沒有
動作。微軟不可能容許DHTML變得比現在更好,這對他們的核心事業rich client來說實在
太危險了。微軟最近的重大思想基因(memo)是:「微軟把公司的未來賭在rich client
上。」這句話會遍佈Longhorn相關的每頁簡報上。來自Avalon團隊的Joe Beda說道
  (http://channel9.msdn.com/ShowPost.aspx?PostID=948):「Avalon(大體上還有
Longhorn)是微軟的基石。這句話表示我們相信你桌面的威力,能夠完成各種了不起的東
西,而且是不可或許的。我們正在持續投入桌面,我們認為這會是個好地方,而且我們希
望自己能啟動一波振奮...」

問題是現在已經太遲了。

我本身對這有一點點難過
我本身對這真的有一點點難過。對我來說Web是很不錯,不過Web應用程式的使用介面既爛
又慢也不一致,就日常使用來說實在是倒退一大步。我愛我的rich client應用程式,如
果日常使用的應用程式(Visual Studio、CityDesk、Outlook、Corel PhotoPaint、
QuickBooks)得改用web版本我會瘋掉。不過這正是開發人員正在進行的事。沒有人(再
提一次,我的意思是「少於一千萬人」)想再用Windows API開發程式了。創投業也因為
害怕微軟的競爭,不會再投資Windows應用程式了。而大部份使用者似乎並不像我一樣,
那麼在意不方便的Web使用介面。

以下是關鍵所在:我注意到(而且也和求才業的朋友確認)紐約市這裡會C++和COM程式設
計的Windows API程式師年收入約十三萬美元,而一般用可控代碼語言(Java、PHP、Perl
、甚至ASP.NET)的普通web程式師年收入是八萬美元。這可是很大的差別,而當我和從事
微軟顧問服務的朋友談到這事情時,他們承認微軟已經失去整個世代的開發人員了。要花
十三萬雇一個有COM經驗的人,是因為過去約八年來沒有人自找麻煩去學COM程式設計,所
以你得找個很資深的人來(通常都已經晉身管理階層),說服他們再做個普通程式師去處
理(上帝救救我)marshalling、monikers、apartment threading、aggregate、tearoff
,還有其他一百萬件基本上只有Don Dox會的東西。事實上連Don Box都無法忍受再回來看
這些東西 (http://news.com.com/2100-1046_3-5148148.html)

雖然我很不想這樣說,不過大量的開發人員早就移到web而且拒絕再回來。大部份的.NET
開發人員都是用ASP.NET針對微軟的web伺服器進行開發。ASP.NET很出色。我從事web開發
已經十年,而它真的是比其他工具先進一個世代。不過ASP.NET是伺服器技術,所以用戶
端可以用任意的桌面系統。何況ASP.NET還能在Linux上用Mono
(http://www.go-mono.com/)執行得相當好呢。

這些東西沒有一個對微軟有利,對微軟得力於API權勢的利益也一樣。新的API是HTML,而
能讓HTML唱歌的人將會是應用程式開發市場的新贏家。

這些網頁的內容為表達個人意見。
All contents Copyright c 1999-2006 by Joel Spolsky. All Rights Reserved


2007年9月4日 星期二

LEADER - 引線

 

LEADER
    下列組碼適用於引線圖元。
    引線組碼
        組碼說明
        100子類標記 (AcDbLeader)
        3標注樣式名稱
        71箭頭標誌:0 = 禁用;1 = 可用
        72引線路徑類型:0 = 直線段;1 = 樣條曲線
        73引線創建標誌(缺省值= 3):
        0 = 與文本註釋一起創建引線;
        1 = 與公差註釋一起創建引線;
        2 = 與塊引用註釋一起創建引線;
        3 = 創建引線,沒有任何註釋;
        74鉤線方向標誌:
        0 = 鉤線(或樣條引線的切線結束)方向與水平矢量方向相反;
        1 = 鉤線(或樣條引線的切線結束)方向與水平矢量方向相同(請參見組碼 75);
        75鉤線標誌:0 = 無鉤線;1 = 有鉤線
        40文字註釋高度
        41文字註釋寬度
        76引線中的頂點數(DXFIN 時被忽略)
        10頂點坐標(適用於每個頂點的條目)DXF:X 值;APP:三維點
        20, 30DXF:頂點坐標的 Y 和 Z 值
        77當引線的 DIMCLRD=BYBLOCK 時使用的顏色
        340關聯註釋的固定引用(多行文字,公差或插入圖元)
        210法線矢量。DXF:X 值;APP:三維矢量
        220, 230DXF:法線矢量的 Y 和 Z 值
        211引線的「水平」方向。DXF:X 值;APP:三維矢量。
        221,231DXF:引線的「水平」方向的 Y 和 Z 值
        212塊引用插入點距最終引線頂點的偏移。:X 值;APP:三維矢量
        222,232DXF:塊引用插入點距最終引線頂點的偏移的 Y 和 Z 值。
        213註釋位置點距最終引線頂點的偏移。DXF:X 值;APP:三維矢量
        223,233DXF:註釋位置點距最終引線頂點的偏移的 Y 和 Z 值。


;;#################################################################70
LEADER + reactor
http://www.cadtutor.net/forum/showthread.php?t=13528&page=2
(vl-load-com)
 
(defun c:lron(/ oldName)
  (if(not lr:Name)(setq lr:Name "text"))
  (setq oldName lr:Name)
  (setq lr:Name
  (getstring T
    (strcat "\nSpecify layer to move qleaders <"
     lr:Name ">: ")))
  (if(= "" lr:Name)(setq lr:Name oldName))
  (if(not(tblsearch "LAYER" lr:Name))
 (vla-Add
   (vla-get-Layers
     (vla-get-ActiveDocument
       (vlax-get-acad-object)))lr:Name)
      ); end if
  (if
    (not qleader:Reactor)
    (progn
      (setq qleader:Reactor
      (vlr-command-reactor lr:Name
        '((:vlr-commandended . PutLeaderToText))))
      (princ "\n<<< QLeader reactor now ON >>>")
      ); end progn
      (princ "\nQLeader already ON! ")
    ); end if
  (princ)
  ); end of LeaderToTextLayer
 
(defun c:lroff()
  (if qleader:Reactor
    (progn
      (vlr-Remove qleader:Reactor)
      (setq qleader:Reactor nil)
      (princ "\n<<< QLeader reactor now OFF >>>")
     ); end progn
    ); end if
  (princ)
  ); end of c:lroff
 
 
 
(defun PutLeaderToText(reac args / curText curLead layName)
  (setq layName(vlr-Data reac))
  (if(eq "QLEADER"(car args))
    (progn
      (setq curText(vlax-ename->vla-object(entlast))
     curLead(vlax-ename->vla-object
   (cdr(assoc 330(entget(entlast)))))
     ); end setq
   (if
     (or
      (vl-catch-all-error-p
        (vl-catch-all-apply
  'vla-put-Layer
   (list curText layName)))
      (vl-catch-all-error-p
        (vl-catch-all-apply
  'vla-put-Layer
   (list curLead layName)))
      ); end or
     (princ "*** WARNING! Can't move leader from locked layer. ***")
    ); end if
  ); end progn
      ); end if
  (princ)
  ); end of PutLeaderToText
 
(princ "\nLRON - switch on qleader reactor, LROFF - switch off qleader reactor
 
;;;******************************************************************
http://www.cadopolis.com/shareware/downloadshareware.asp?
 
TheDateTimeFile=1902200320423PMForEachDrawing4Demo.zip&TheDateTimeFile2=ForEachDrawing4
 
;;;******************************************************************
http://www.mjtd.com/bbs/Archive_view.asp?boardID=3&ID=18953
引線標注
;;;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
(defun c:bia(/ n pt txt pt1 pt2 pt3 pttxt d)
  (setq n(getint "\\n 輸入標示零件個數: " )
      txt(getstring "\\n 輸入起始零件序號: " )
 d(getstring "\\n 在左還是在右<在左>: ")
        pt(getpoint "\\n 輸入標記線連接點: " )
   )
(if(= "r" d)
  (setq pt(list (- (car pt) (+ (* 6 n) (* 2 (- n 1)))) (cadr pt)))
  )
 
 
 
  (setq pt1(list (+ (car pt) 6) (cadr pt))
    pttxt(list (+ (car pt) 3) (+ (cadr pt) 2.4))
 )
 

  (setq cl(getvar "clayer"))
  (setq os(getvar "osmode"))
  (setvar "clayer" "w文字標注")
  (setvar "osmode" 0)
 

  (command"line" pt pt1 "")
  (command"text" "mc" pttxt 3.5 0 txt)
 
 
 
  (repeat (- n 1)
    (setq pt2(polar pt1 (/ (* pi 7) 4) 1.41421))
    (command"line" pt1 pt2 "")
    (setq pt3(polar pt2 (/ pi 4) 1.41421))
    (setq pt4(list (+ (car pt3) 6)  (cadr pt3)))
    (command"line" pt2 pt3 pt4 "")
    (setq pttxt(list (+ (car pt3) 3) (+ (cadr pt) 2.4)))  
    (setq txt (rtos (+ (atoi txt) 1) 2 0))
    (print txt)
    (command "text" "MC" pttxt 3.5 0 txt)   
    (setq pt1 pt4)
  )
  (setvar "clayer" cl)
  (setvar "osmode" os)
  )
;;;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;; 版權所有 (C) 1991-2000  明經通道 鄭立楷
;;
;;   本軟件免費可供進行任何用途需求的拷貝、修改及發行, 但請遵循下述原則:
;;
;;   1)  上列的版權通告必須出現在每一份拷貝裡。
;;   2)  相關的說明文檔也必須載有版權通告及本項許可通告。
;;
;;   本軟件僅提供作為應用上的參考, 而未聲明或隱含任何保證; 對於任何特殊
;;   用途之適應性, 以及商業銷售所隱含作出的保證, 在此一概予以否認。
;;
;;   http://www.mjtd.com   http://www.mccad.net
;;
;;   e-mail:mccad@mjtd.com
;;
;;
(princ"\n總裝明細序號填寫程序")
(defun c:mxxh(/ oldecho oldlayer oldstyle oldsize oldpwid oldsnap oldortho
                sele txto txt pt_s pt_m pt_t pt_r pt_l pt_c pt_e tt num)
  (setq oldecho (getvar "cmdecho"))
  (setvar "cmdecho" 0)
  (setq oldlayer (getvar "clayer"))
       (if (=(tblobjname "LAYER" "3") nil)
           (progn
               (entmake (list
                            '(0 . "LAYER")
                            '(100 . "AcDbSymbolTableRecord")
                            '(100 . "AcDbLayerTableRecord")
                            '(6 . "CONTINUOUS")
                            '(62 . 3)
                            '(70 . 0)
                             (cons 2 "3")
                        )
               )
           )
       )
   (setvar "clayer" "3")
  (setq oldstyle (getvar "textstyle"))
  (setq oldsize (getvar "textsize"))
  (setq oldpwid (getvar "plinewid"))
  (setvar "plinewid" 0)
  (setq oldsnap(getvar"osmode"))
  (setq oldortho(getvar"orthomode"))
  (initget "Single Horizonal Vertical")
  (setq sele(getkword "\n部裝明細序號填寫方式[水平多項(H)/垂直多項(V)/單一序號(S)]<單一序號>:"))
  (if (not sele)
    (setq sele "Single")
  )
  (setq txt0 1)
  (while (/= sele "eXit")
    (initget 1)
        (setvar "osmode" 0)
    (setq pt_s(getpoint "\n選擇引線起點:"))
    (initget 1)
        (setvar "osmode" oldsnap)
        (setvar "orthomode" 0)
    (setq pt_m(getpoint pt_s"\n選擇序號起點:"))
    (setq pt_t (polar pt_m (/ PI 2) 3.5))
    (command "donut" "0" "0.5" "non" pt_s "")
    (cond
      ((= sele "Single")
        (princ (strcat"\n請輸入序號<" (itoa txt0) ">:"))
        (setq txt(getint))
        (if (not txt)
          (setq txt txt0)
        )
        (setq txt0 (+ txt 1))
        (if (> (car pt_m)(car pt_s))
          (progn
            (setq pt_c (polar pt_m PI 4))
            (setq pt_e (polar pt_m 0  4))
          )
          (progn
            (setq pt_c (polar pt_m 0  4))
            (setq pt_e (polar pt_m PI 4))
          )
        )
        (command "pline" "non" pt_s "non" pt_c "non" pt_e "")
        (command "text" "m" "non" pt_t "5" "0" txt)
      )
      ((= sele "Vertical")
        (initget 1)
        (setq num(getint"\n請輸入同零件組的項數:"))
        (if (>(car pt_m)(car pt_s))
          (progn
            (setq pt_c(polar pt_m PI 4))
            (setq pt_e(polar pt_m 0  4))
          )
          (progn
            (setq pt_c(polar pt_m 0  4))
            (setq pt_e(polar pt_m PI 4))
          )
        )
        (setq tt 1)
        (while(<= tt num)
          (princ(strcat "\n請輸入序號<" (itoa txt0) ">:"))
          (setq txt(getint))
          (if (not txt)
            (setq txt txt0)
          )
          (setq txt0 (+ txt 1))
          (command "pline" "non" pt_s "non" pt_c "non" pt_e "")
          (command "text" "m" "non" pt_t "5" "0" txt)
          (setq pt_s pt_c)
          (setq pt_c (polar pt_c (/ PI 2) 8))
          (setq pt_e (polar pt_e (/ PI 2) 8))
          (setq pt_t (polar pt_t (/ PI 2) 8))
          (setq tt (1+ tt))
        )
      )
      ((= sele "Horizonal")
        (initget 1)
        (setq num(getint"\n請輸入同零件組的項數:"))
        (setq pt_l(polar pt_m PI 4))
        (setq pt_r(polar pt_l 0 (+(*(- num 1) 10.828) 8)))
        (if (and (<(car pt_l)(car pt_s))(>(abs(- (car pt_l) (car pt_s)))(abs(-(car pt_r)(car pt_s)))))
          (progn
            (command "pline" "non" pt_s "non" pt_r "non" "@8<180" "")
            (setq tt 1)
            (while (< tt num)
              (command "pline" "@" "non" "@2<-135" "non" "@2<135" "non" "@8<180" "")
              (setq tt (1+ tt))
            )
          )
          (progn
            (command "pline" "non" pt_s "non" pt_l "non" "@8<0" "")
            (setq tt 1)
            (while(< tt num)
              (command "pline" "@" "non" "@2<-45" "non" "@2<45" "non" "@8<0" "")
              (setq tt(1+ tt))
            )
          )
        )
        (setq tt 1)
        (while (<= tt num)
          (princ (strcat "\n請輸入序號<" (itoa txt0) ">:"))
          (setq txt (getint))
          (if (not txt)
            (setq txt txt0)
          )
          (setq txt0 (+ txt 1))
          (command "text" "m" "non" pt_t "5" "0" txt)
          (setq pt_t(polar pt_t 0 10.828))
          (setq tt (1+ tt))
        )
      )
    )
    (initget "Single Horizonal Vertical eXit")
    (setq sele(getkword "\n部裝明細序號填寫方式[水平多項(H)/垂直多項(V)/單一序號(S)/退出(X)]<退出>:"))
    (if (not sele)
      (setq sele "eXit")
    )
  )
  (setvar "clayer" oldlayer)
  (setvar "cmdecho" oldecho)
  (setvar "textstyle" oldstyle)
  (setvar "textsize" oldsize)
  (setvar "plinewid" oldpwid)
  (setvar "orthomode" oldortho)
  (princ)
)
(princ"已裝載")
;;;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
(vl-load-com)
(defun Chg_layer (calling-reactor commandInfo / lay doc lays lay1)
  (if (setq lay (cdr (assoc (car commandInfo) lay_lst)))
    (progn
      (setq doc (vla-get-activedocument (vlax-get-acad-object)))
      (setq lays (vla-get-layers doc))
      (setq lay1 (vl-catch-all-apply \'vla-item (list lays lay)))
      (if (vl-catch-all-error-p lay1)
 (setq lay1 (vla-add lays lay))
      )
      (vla-put-activelayer doc lay1)
    )
  )
  (princ)
)
(defun test (lst)
  (vlr-pers (vlr-command-Reactor
       nil
       \'((:VLR-commandWillStart . Chg_layer))
     )
  )
  (setq lay_lst lst)
)
 
;;;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
(defun c:bii(/ n pt txt txt0 pt1 pt2 pt3 pttxt d)
  (setq txt0 1)
  (while (setq pt(getpoint "\\n 輸入標記線連接點: " ))
            (setq n(getint" 請輸入零件數目<1>: "))
      (if(not n)
        (setq n 1)
     )
       (princ (strcat "\\n 輸入起始零件序號<" (itoa txt0) ">:"))
       (setq txt(getint))
    (if(not txt)
      (setq txt txt0)
      )
    (setq d(getstring "\\n 在左還是在右<在左r>: "))
   (if(= "r" d)
      (setq pt(list (- (car pt) (+ (* 6 n) (* 2 (- n 1)))) (cadr pt)))
    )
 

(setq pt1(list (+ (car pt) 6) (cadr pt))
    pttxt(list (+ (car pt) 3) (+ (cadr pt) 2.4))
 )
 
 

  (setq cl(getvar "clayer"))
  (setq os(getvar "osmode"))
  (setvar "clayer" "w文字標注")
  (setvar "osmode" 0)
 

  (command"line" pt pt1 "")
  (command"text" "mc" pttxt 3.5 0 txt)
 
 
 
  (repeat (- n 1)
    (setq pt2(polar pt1 (/ (* pi 7) 4) 1.41421))
    (command"line" pt1 pt2 "")
    (setq pt3(list (+ (car pt1) 2) (cadr pt1)))
    (setq pt4(list (+ (car pt3) 6)  (cadr pt3)))
    (command"line" pt2 pt3 pt4 "")
    (setq pttxt(list (+ (car pt3) 3) (+ (cadr pt) 2.4)))  
    (setq txt (1+ txt))
    (print txt)
    (command "text" "MC" pttxt 3.5 0 txt)   
    (setq pt1 pt4)
  )
   (setq txt0 (+1 txt)
  )
  (setvar "clayer" cl)
  (setvar "osmode" os)
  )
;;;******************************************************************
 

//計算多邊形的形心坐標
BOOL GetPolyCentroid(AcDbPolyline * pPline, ads_point CenPt)
{
unsigned int i, iCount = 0;
AcDbVoidPtrArray curveSegments, regions;
AcGePoint3d LinePt0, LinePt1;
AcGePoint3d origin;
AcGeVector3d xAxis, yAxis;
double perimeter, area, prodInertia;
double momInertia[2], prinMoments[2], radiiGyration[2];
AcGePoint2d centroid;
AcGeVector2d prinAxes[2];
AcGePoint2d extentsLow, extentsHigh;

if (pPline->isClosed() != Adesk::kTrue) {
ads_printf("\n折線不封閉, 無法形成正確的區域。");
return FALSE;
}
curveSegments.append((AcDbCurve *) pPline);

if (AcDbRegion::createFromCurves(curveSegments, regions) != Acad::eOk){
ads_printf("\n創建臨時區域對像失敗!");
//清除Region, 應第9 貼的指點,即使createFromCurves錯誤,也應清除之;
iCount = regions.length();
for(i = 0; i < iCount; i++)
delete (AcDbRegion *)regions.at(i);

return FALSE;
}
AcDbRegion * pRegion;
if ((iCount = regions.length()) == 0){
ads_printf("\n創建臨時區域對像為空!");
return FALSE;
}
if (iCount > 1){
// 多個 AcDbRegion , 無法確定應該返回哪一個,乾脆返回NULL;
ads_printf("\n多個區域實體。");
for(i = 0; i < iCount; i++)
delete (AcDbRegion *)regions.at(i);
return FALSE;
}
pRegion = (AcDbRegion *) regions.at(0);

origin.set(0,0,0); //設置原點坐標
xAxis.set(1,0,0); //設置X Y軸,
yAxis.set(0,1,0);

if (pRegion->getAreaProp(
origin, xAxis, yAxis,
perimeter, area, centroid, momInertia, prodInertia, prinMoments, prinAxes, radiiGyration,
extentsLow, extentsHigh) != Acad::eOk ){
ads_printf("\n區域面積: %.3f, 周長:%.3f", area, perimeter);
ads_printf("\n獲取區域對像屬性失敗!");
delete pRegion;
return FALSE;
}
XYZ_POINT(CenPt, centroid.x, centroid.y, 0); //得到形心坐標
ads_printf("\n區域面積: %.3f, 周長:%.3f", area, perimeter);
pRegion->close();
delete pRegion;

return TRUE;
}


//添加擴展數據
//實體添加擴展數據(字符串)
bool AddXData(CString appName, AcDbObjectId entId,CString data)
{
//open entity for read
AcDbEntity*pEnt;
Acad::ErrorStatus es=acdbOpenAcDbEntity(pEnt,entId,AcDb::kForRead);
if(es!=Acad::eOk)
{
ads_printf("error in open entity\n");
return false;
}
//get XData buffer
struct resbuf*pRb,*pTemp;
pRb=pEnt->xData(appName);
if(pRb!=NULL)//have XData
{
//pTemp移到表尾
pTemp=pRb;
for(pTemp=pRb;pTemp->rbnext!=NULL;pTemp=pTemp->rbnext){;}
}
else//NOT have XData
{
//create new xData
ads_regapp(appName);
pRb=ads_newrb(AcDb::kDxfRegAppName);
pRb->resval.rstring=(char*)malloc(appName.GetLength()+1);
strcpy(pRb->resval.rstring,appName);
pTemp=pRb;
}
//fill xData string
pTemp->rbnext=ads_newrb(AcDb::kDxfXdAsciiString);
pTemp=pTemp->rbnext;
pTemp->resval.rstring=(char*)malloc(data.GetLength()+1);
strcpy(pTemp->resval.rstring,data);
//add xData
es=pEnt->upgradeOpen();
if(es!=Acad::eOk)
{
ads_printf("\nError occur in updateOpen.");
pEnt->close();
ads_relrb(pRb);
return false;
}
es=pEnt->setXData(pRb);
if(es!=Acad::eOk)
{
ads_printf("\nError occur in setXData.");
pEnt->close();
ads_relrb(pRb);
return false;
}
//
pEnt->close();
ads_relrb(pRb);
return true;
}





//發命令前加按了兩個ESCAPE
void SendCommand(char *cmd)
{
HWND wnd;
char cp[3];

wnd = adsw_acadMainWnd();
if(!wnd) return;

COPYDATASTRUCT cmddata;
cp[0] = VK_ESCAPE;
cp[1] = VK_ESCAPE;
cp[2] = NULL;
cmddata.dwData = (DWORD)1;
cmddata.cbData = (DWORD)strlen(cp)+1;
cmddata.lpData = cp;
SendMessage(wnd,WM_COPYDATA,(WPARAM)cp,(LPARAM)&cmddata);

cmddata.dwData = (DWORD)1;
cmddata.cbData = (DWORD)strlen(cmd)+1;
cmddata.lpData = cmd;
SendMessage(wnd,WM_COPYDATA,(WPARAM)wnd,(LPARAM)&cmddata);
}



//函數功能:根據用戶指定的兩點,自動創建破斷線
void CAD_EXTBreakLine()
{
acutPrintf("指定兩點,自動創建折線破斷線\n");

ads_point StartPoint,EndPoint;
if(acedGetPoint(NULL,"\n請指定破斷線的起點:",StartPoint)!=RTNORM) return;
if(acedGetPoint(StartPoint,"\n請指定破斷線的終點:",EndPoint)!=RTNORM) return;
AcGePoint3d Start,End;
End = AcGePoint3d(EndPoint[X],EndPoint[Y],0);
Start = AcGePoint3d(StartPoint[X],StartPoint[Y],0);
float Length = Start.distanceTo(End);

AcGeVector3d Normal = End-Start;
Normal = Normal.normal(AcGeContext::gTol);

AcGePoint3d Point1(Start-Length*Normal*0.15);
AcGePoint3d Point2(Start+Length*Normal*0.45);
AcGePoint3d Point5(End-Length*Normal*0.45);
AcGePoint3d Point6(End+Length*Normal*0.15);

AcGeVector3d Normal2(-Normal.y,Normal.x,0);
AcGePoint3d Point3(Start+Length*Normal*0.5+Length*Normal2*0.10);
AcGePoint3d Point4(Start+Length*Normal*0.5-Length*Normal2*0.10);

AcGePoint3dArray vertices;
vertices.append(Point1);
vertices.append(Point2);
vertices.append(Point3);
vertices.append(Point4);
vertices.append(Point5);
vertices.append(Point6);
AddNewLayer("COMMANTARY");
AcDb2dPolyline* pBreakLine = new AcDb2dPolyline

(AcDb::k2dSimplePoly,vertices,0,Adesk::kTrue,0,0,NULL);
pBreakLine->setLayer("COMMANTARY",TRUE);

AcGeMatrix3d mat;
acdbUcsMatrix(mat,acdbHostApplicationServices()->workingDatabase());
pBreakLine->transformBy(mat);

pBreakLine->makeOpen();
AddEntityToDb(pBreakLine);

}


//******************生成回轉體**********************
/* pt -- 旋轉基點
ver -- 旋轉軸
angle -- 旋轉角度(角度制)
注意: 旋轉軸不能垂直於面域平面、不能穿過面域*/
//**************************************************
void CreatRevolve(AcDbObjectId entid,
AcGeVector3d normal,
AcGePoint3d pt,
AcGeVector3d ver,
double angle)
{
Acad::ErrorStatus es;
AcDbCurve *curve;
AcDbObjectId tm;
if (acdbOpenObject(curve,entid,AcDb::kForWrite)!=Acad::eOk)
{
acutPrintf("打開實體失敗!");
return ;
}
AcDbVoidPtrArray lines,regions1;
lines.append((void*)curve);
curve->close();
es = AcDbRegion::createFromCurves(lines,regions1);
if(es != Acad::eOk)
{
acutPrintf("獲得面域失敗!");
return ;
}
angle = angle*PI/180;
AcDbRegion *pregion1=AcDbRegion::cast((AcRxObject*)regions1[0]);
AcDb3dSolid *p3dobj = new AcDb3dSolid;
es = p3dobj->revolve(pregion1,pt,ver,angle);
if (es != Acad::eOk)
{
acutPrintf("建立回轉體失敗!請檢查回轉軸和基準點是否正確!");
}
pBlockTableRecord->appendAcDbEntity(tm,p3dobj);
p3dobj->close();
delete pregion1;
}






在ObjectARX 實現 Command 的 *Cancel* 功能: (類似 AutoLISP 中的 ^C)
acedCommand(0); // 就可以了
例如:
acedCommand (RTSTR, "dim1", RTSTR, "leader", RTSTR, "0,0", RTSTR, "10,10", 0);
acedCommand (0);



//複製對像
void cloneSameOwnerObjects()
{
// Step 1: Obtain the set of objects to be cloned.
ads_name sset;

if (acedSSGet(NULL, NULL, NULL, NULL, sset) != RTNORM) {
acutPrintf("\nNothing selected");
return;
}

// Step 2: Add obtained object IDs to list of objects
// to be cloned.
long length;
acedSSLength(sset, &length);
AcDbObjectIdArray objList;
AcDbObjectId ownerId = AcDbObjectId::kNull;

for (int i = 0; i < length; i++) {
ads_name ent;
acedSSName(sset, i, ent);
AcDbObjectId objId;
acdbGetObjectId(objId, ent);

// Check to be sure this has the same owner as the first
// object.
//
AcDbObject *pObj;
acdbOpenObject(pObj, objId, AcDb::kForRead);

if (pObj->ownerId() == ownerId)
objList.append(objId);
else if (i == 0) {
ownerId = pObj->ownerId();
objList.append(objId);
}
pObj->close();
}

acedSSFree(sset);

// Step 3: Get the object ID of the desired owner for
// the cloned objects. We'll use model space for
// this example.
//
AcDbBlockTable *pBlockTable;
acdbHostApplicationServices()->workingDatabase()
->getSymbolTable(pBlockTable, AcDb::kForRead);

AcDbObjectId modelSpaceId;
pBlockTable->getAt(ACDB_MODEL_SPACE, modelSpaceId);
pBlockTable->close();

// Step 4: Create a new ID map.
//
AcDbIdMapping idMap;

// Step 5: Call deepCloneObjects().
//
acdbHostApplicationServices()->workingDatabase()
->deepCloneObjects(objList, modelSpaceId, idMap);

// Now we can go through the ID map and do whatever we'd
// like to the original and/or clone objects.
//
// For this example, we'll print out the object IDs of
// the new objects resulting from the cloning process.
//
AcDbIdMappingIter iter(idMap);
for (iter.start(); !iter.done(); iter.next()) {
AcDbIdPair idPair;
iter.getMap(idPair);
if (!idPair.isCloned())
continue;
acutPrintf("\nObjectId is: %Ld",

idPair.value().asOldId());
}

}





void selObj()
{
#ifdef OARXWIZDEBUG
acutPrintf ("\nOARXWIZDEBUG - caditdellayObjdellayObj() called.");

2007年8月13日 星期一

ActiveSync v4.5 Traditional Chinese - 繁體中文

ActiveSync v4.5 Traditional Chinese - 繁體中文
適用於Windows Mobile作業系統的PDA,PPC,Palm
http://www.microsoft.com/downloads/details.aspx?FamilyID=b7b1a7e5-1b41-4c2a-82de-
 
5ee2df4966cb&DisplayLang=zh-tw