<?xml version="1.0" standalone="yes"?>
<?xml-stylesheet type="text/xsl" href="css/rss.xslt"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>ZwqXin - 图形相关算法</title><link>http://www.zwqxin.com/</link><description>    一起学习OPENGL吧 - </description><generator>RainbowSoft Studio Z-Blog 1.8 Arwen Build 90619</generator><language>zh-CN</language><copyright>Copyright 2008-2010 ZwqXin. Some Rights Reserved. Theme edited from ipati. </copyright><pubDate>Fri, 10 Sep 2010 12:16:21 +0800</pubDate><item><title>QuickSort 快速排序的实现</title><author>a@b.com (zwqxin)</author><link>http://www.zwqxin.com/archives/arithmetic/quick-sort-implement.html</link><pubDate>Wed, 06 May 2009 01:21:55 +0800</pubDate><guid>http://www.zwqxin.com/archives/arithmetic/quick-sort-implement.html</guid><description><![CDATA[<p>QuickSort，快速排序。数据结构必然遇上之，原理都知道是分治法，但不实现一次总有些心慌。而一步一步实现算法的时候，往往会遇到新问题，新困难，新考验。本篇从QuickSort算法的理解说起，希望我不会又忘记了吧~&mdash;&mdash;<a href="http://www.zwqxin.com/">ZwqXin</a>.com</p><p>1.二分治十分喜欢logN</p><p>我不太清楚这鼓仰慕之情是从哪里来的，是偶然的吗？不，大妈都说，只有必然。因此，请相信严谨的数学大师给予我们的教诲：二分治就是就是喜欢logN。而QuickSort是二分治，所以说起QuickSort，我们就联想起logN......注意底数是二哦。</p><p>把一个问题分解为两个，把两个问题分解为四个......分解直到能轻易解决当前问题的地步，再如同聚焦一样反噬回来&mdash;&mdash;把原问题解决。假设底线是分解为N个，那么共经过logN次分解行为。当然这每次分解行为都包含了多个分解动作，但只要它们是同时发生的，就不必区分它们&mdash;&mdash;这是什么道理？</p><p>2.QuickSort的道理</p><p>QuickSort处理N个数的时候，就是按上思路，先选取一个&ldquo;主元&rdquo;，再把整个数列分割成两部分，前部分的值小于&ldquo;主元&rdquo;，后部分的值大于&ldquo;主元&rdquo;&mdash;&mdash;主元位于这两部分之间。然后分别对这两部分再做此处理（递归），最后就成了一组从小到大排列的数表了。主元的选取本来应该很考究，但为了效率应该随便选一个。理想情况是主元位是当前排序表中间大的元素，这样分出来的两子列将基本等大；如果不好采每次选的主元都是最小的那个，那就等着N^2的复杂度来收尾吧。但若非精心安排，是难以出现这个局面的，这里有篇文章[<a target="_blank" href="http://www.comp.nus.edu.sg/~xujia/mirror/algorithm.myrice.com/algorithm/commonalg/sort/internal_sorting/quick_sort/quick_sort.htm">算法与数据结构&mdash;&mdash;快速排序</a>]用一堆数学证明了平均情况跟最好情况一样是N*logN（最好情况：二分，分解logN次，每次里都蕴涵N次比较换位）。</p><p>3.大于.小于</p><p>比较动作涉及比较换位，若是数值类型还好办，其他类型的怎么办呢？很明显需要自定义我们的&ldquo;大于.小于&rdquo;。由于相反性，就考虑小于就可以了（元素相等也得处理啊，归于&ldquo;大于&rdquo;那里吧）。抽象出这个&ldquo;小于&rdquo;函数，设为QSCompareL(A，B)，则整个QS算法弄成以下模样：</p><div class="HighLighter" contenteditable="false"><div class="dp-highlighter" contenteditable="false"><div class="bar">&nbsp;</div><ol class="dp-c">    <li class="alt"><span><span>template&lt;typename&nbsp;ObjectQS&gt; </span></span></li>    <li><span class="keyword">int</span><span>&nbsp;QSort&lt;ObjectQS&gt;::Partition(ObjectQS&nbsp;*buffer,&nbsp;</span><span class="keyword">int</span><span>&nbsp;low,&nbsp;</span><span class="keyword">int</span><span>&nbsp;high,&nbsp;</span><span class="keyword">bool</span><span>&nbsp;(*QSCompareL)(&nbsp;ObjectQS&nbsp;A,&nbsp;&nbsp;ObjectQS&nbsp;B)) </span></li>    <li class="alt"><span>{ </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;ObjectQS&nbsp;pivotkey&nbsp;=&nbsp;buffer[low]; </span></li>    <li class="alt">&nbsp;</li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">while</span><span>(low&lt;high) </span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;{ </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//while(low&lt;high&nbsp;&amp;&amp;&nbsp;buffer[high].ID&nbsp;&gt;=&nbsp;pivotkey) </span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//while(low&lt;high&nbsp;&amp;&amp;&nbsp;QsortCompareGE(buffer[high],&nbsp;pivotkey)&nbsp;) </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">while</span><span>(low&lt;high&nbsp;&amp;&amp;&nbsp;!(*QSCompareL)(buffer[high],&nbsp;pivotkey)&nbsp;) </span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;high--; </span></li>    <li>&nbsp;</li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>(low&nbsp;&lt;&nbsp;high) </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buffer[low++]&nbsp;=&nbsp;buffer[high]; </span></li>    <li class="alt">&nbsp;</li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//while(low&lt;high&nbsp;&amp;&amp;&nbsp;buffer[low].ID&nbsp;&lt;=&nbsp;pivotkey) </span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//while(low&lt;high&nbsp;&amp;&amp;&nbsp;QsortCompareLE(buffer[low],&nbsp;pivotkey)&nbsp;)&nbsp;&nbsp; </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">while</span><span>(low&lt;high&nbsp;&amp;&amp;&nbsp;(*QSCompareL)(buffer[low],&nbsp;pivotkey)&nbsp;)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;low++; </span></li>    <li>&nbsp;</li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>(low&nbsp;&lt;&nbsp;high) </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buffer[high--]&nbsp;=&nbsp;buffer[low]; </span></li>    <li class="alt">&nbsp;</li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} </span></li>    <li class="alt">&nbsp;</li>    <li>&nbsp;</li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;buffer[low]&nbsp;=&nbsp;pivotkey; </span></li>    <li>&nbsp;</li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;SORTtimes++; </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;low; </span></li>    <li class="alt"><span>} </span></li>    <li>&nbsp;</li>    <li class="alt"><span>template&lt;typename&nbsp;ObjectQS&gt; </span></li>    <li><span class="keyword">void</span><span>&nbsp;QSort&lt;ObjectQS&gt;::SetQSortObject(ObjectQS&nbsp;*buffer,&nbsp;</span><span class="keyword">int</span><span>&nbsp;low,&nbsp;</span><span class="keyword">int</span><span>&nbsp;high,&nbsp;</span><span class="keyword">bool</span><span>&nbsp;(*QSCompareL)(&nbsp;ObjectQS&nbsp;A,&nbsp;&nbsp;ObjectQS&nbsp;B)) </span></li>    <li class="alt"><span>{ </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;QSortObject&nbsp;=&nbsp;buffer; </span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;mLow&nbsp;=&nbsp;low; </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;mHigh&nbsp;=&nbsp;high; </span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp; </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;QSCompareL_Func&nbsp;=&nbsp;QSCompareL; </span></li>    <li class="alt">&nbsp;</li>    <li><span>} </span></li>    <li class="alt">&nbsp;</li>    <li><span>template&lt;typename&nbsp;ObjectQS&gt; </span></li>    <li class="alt"><span class="keyword">void</span><span>&nbsp;QSort&lt;ObjectQS&gt;::CalQSortProcess(</span><span class="keyword">int</span><span>&nbsp;low,&nbsp;</span><span class="keyword">int</span><span>&nbsp;high) </span></li>    <li><span>{ </span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>(low&lt;high) </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;{ </span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">int</span><span>&nbsp;pivotloc&nbsp;=&nbsp;Partition(QSortObject,&nbsp;low,&nbsp;high,&nbsp;QSCompareL_Func); </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CalQSortProcess(low,&nbsp;pivotloc-1); </span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CalQSortProcess(pivotloc+1,&nbsp;high); </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} </span></li>    <li class="alt"><span>} </span></li>    <li>&nbsp;</li>    <li class="alt"><span>template&lt;typename&nbsp;ObjectQS&gt; </span></li>    <li><span class="keyword">void</span><span>&nbsp;QSort&lt;ObjectQS&gt;::QSortProcess() </span></li>    <li class="alt"><span>{&nbsp; </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;CalQSortProcess(mLow,&nbsp;mHigh); </span></li>    <li class="alt"><span>}</span></li></ol></div><div class="c#" contenteditable="false" style="display: none"><pre>template&lt;typename ObjectQS&gt;<br/>int QSort&lt;ObjectQS&gt;::Partition(ObjectQS *buffer, int low, int high, bool (*QSCompareL)( ObjectQS A,  ObjectQS B))<br/>{<br/>    ObjectQS pivotkey = buffer[low];<br/><br/>	while(low&lt;high)<br/>	{<br/>		//while(low&lt;high &amp;&amp; buffer[high].ID &gt;= pivotkey)<br/>		//while(low&lt;high &amp;&amp; QsortCompareGE(buffer[high], pivotkey) )<br/>          while(low&lt;high &amp;&amp; !(*QSCompareL)(buffer[high], pivotkey) )<br/>			high--;<br/><br/>		if(low &lt; high)<br/>			buffer[low++] = buffer[high];<br/><br/>		//while(low&lt;high &amp;&amp; buffer[low].ID &lt;= pivotkey)<br/>		//while(low&lt;high &amp;&amp; QsortCompareLE(buffer[low], pivotkey) )	<br/>		  while(low&lt;high &amp;&amp; (*QSCompareL)(buffer[low], pivotkey) )			<br/>			low++;<br/><br/>		if(low &lt; high)<br/>			buffer[high--] = buffer[low];<br/><br/>	}<br/><br/><br/>	buffer[low] = pivotkey;<br/><br/>	SORTtimes++;<br/>    return low;<br/>}<br/><br/>template&lt;typename ObjectQS&gt;<br/>void QSort&lt;ObjectQS&gt;::SetQSortObject(ObjectQS *buffer, int low, int high, bool (*QSCompareL)( ObjectQS A,  ObjectQS B))<br/>{<br/>	QSortObject = buffer;<br/>    mLow = low;<br/>	mHigh = high;<br/>    <br/>	QSCompareL_Func = QSCompareL;<br/><br/>}<br/><br/>template&lt;typename ObjectQS&gt;<br/>void QSort&lt;ObjectQS&gt;::CalQSortProcess(int low, int high)<br/>{<br/>	if(low&lt;high)<br/>	{<br/>		int pivotloc = Partition(QSortObject, low, high, QSCompareL_Func);<br/>		CalQSortProcess(low, pivotloc-1);<br/>		CalQSortProcess(pivotloc+1, high);<br/>	}<br/>}<br/><br/>template&lt;typename ObjectQS&gt;<br/>void QSort&lt;ObjectQS&gt;::QSortProcess()<br/>{ <br/>	CalQSortProcess(mLow, mHigh);<br/>}</pre></div><div contenteditable="false"><link href="/admin/FCKeditor/editor/plugins/highlighter/dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css" type="text/css" rel="stylesheet" /></div></div><p>上面的注释行表明了一路下来代码的进化。递归的思路就不多说了，QSORT的核心是Partition函数和CalQSortProcess。基本上外调用之QSortProcess函数要知道的是待比较表和表的起始和结束位置，还有比较函数。这由SetQSortObject设置。函数编写运用了类模板，ObjectQS是随意的类型，因此使用者要自定义比较函数&mdash;&mdash;当然对单纯的数值类型也可以不用，因为我给了个默认形参QsortCompareL专门比较数值类型的。</p><p>4.在游戏中的运用</p><p>排序是到处都需要用的东西。比起冒泡，Qsort具有明显的优势，事实上VC函数库也给出了简单数值的QSORT的API调用，STL里面的通用函数SORT很明显跟QSORT有关，我也很明显是看着STL之SORT来作为程序完备性的衡量.....</p><p>在游戏中，有时候需要给眼前怪物的ID排序，有时候需要知道怪物位置前后信息&hellip;&hellip;实在太多应用了，只有你想不到的。</p><div class="HighLighter" contenteditable="false"><div class="dp-highlighter" contenteditable="false"><div class="bar">&nbsp;</div><ol class="dp-c">    <li class="alt"><span><span>typedef&nbsp;</span><span class="keyword">struct</span><span>&nbsp;tagObjectX{ </span></span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;</span><span class="keyword">int</span><span>&nbsp;ID; </span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;CVector3&nbsp;&nbsp;Position; </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;CVector3&nbsp;&nbsp;Rotation; </span></li>    <li class="alt">&nbsp;</li>    <li><span>}&nbsp;ObjectX; </span></li>    <li class="alt">&nbsp;</li>    <li><span class="keyword">bool</span><span>&nbsp;CompareObjectX_ID(ObjectX&nbsp;A,&nbsp;ObjectX&nbsp;B){&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;A.ID&nbsp;&lt;&nbsp;B.ID;&nbsp;} </span></li>    <li class="alt"><span class="keyword">bool</span><span>&nbsp;CompareObjectX_PosZ(ObjectX&nbsp;A,&nbsp;ObjectX&nbsp;B){&nbsp;</span><span class="keyword">return</span><span>&nbsp;A.Position.z&nbsp;&lt;&nbsp;B.Position.z;&nbsp;} </span></li>    <li>&nbsp;</li>    <li class="alt"><span class="keyword">int</span><span>&nbsp;main(</span><span class="keyword">int</span><span>&nbsp;argc,&nbsp;</span><span class="keyword">char</span><span>*&nbsp;argv[]) </span></li>    <li><span>{ </span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;ObjectX&nbsp;ObjectArray[10]&nbsp;=&nbsp;{.....}; </span></li>    <li>&nbsp;</li>    <li class="alt">&nbsp;</li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//qsortX.SetQSortObject(ObjectArray,&nbsp;0,&nbsp;9,&nbsp;CompareObjectX_PosZ); </span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;qsortX.SetQSortObject(ObjectArray,&nbsp;0,&nbsp;9,&nbsp;CompareObjectX_ID); </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;qsortX.QSortProcess(); </span></li>    <li class="alt">&nbsp;</li>    <li>&nbsp;</li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">int</span><span>&nbsp;buffer[40]&nbsp;=&nbsp;{23,56,23,....,50,100,98}; </span></li>    <li>&nbsp;</li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;qsortX2.SetQSortObject(buffer,&nbsp;0,&nbsp;39); </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;qsortX2.QSortProcess(); </span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp; </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span class="string">&quot;SORTtimes:%d\n&quot;</span><span>,qsortX2.GetSortTimes()); </span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span class="string">&quot;index:%d\n&quot;</span><span>,&nbsp;qsortX2.GetElementIndex(88)&nbsp;); </span></li>    <li>&nbsp;</li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;0; </span></li>    <li><span>} </span></li>    <li class="alt">&nbsp;</li></ol></div><div class="c#" contenteditable="false" style="display: none"><pre>typedef struct tagObjectX{<br/>	unsigned int ID;<br/>    CVector3  Position;<br/>	CVector3  Rotation;<br/><br/>} ObjectX;<br/><br/>bool CompareObjectX_ID(ObjectX A, ObjectX B){	return A.ID &lt; B.ID; }<br/>bool CompareObjectX_PosZ(ObjectX A, ObjectX B){	return A.Position.z &lt; B.Position.z; }<br/><br/>int main(int argc, char* argv[])<br/>{<br/>   ObjectX ObjectArray[10] = {.....};<br/><br/><br/>	//qsortX.SetQSortObject(ObjectArray, 0, 9, CompareObjectX_PosZ);<br/>	qsortX.SetQSortObject(ObjectArray, 0, 9, CompareObjectX_ID);<br/>    qsortX.QSortProcess();<br/><br/><br/>	  	int buffer[40] = {23,56,23,....,50,100,98};<br/><br/>      qsortX2.SetQSortObject(buffer, 0, 39);<br/>      qsortX2.QSortProcess();<br/> 	<br/>	  printf(&quot;SORTtimes:%d\n&quot;,qsortX2.GetSortTimes());<br/>	  printf(&quot;index:%d\n&quot;, qsortX2.GetElementIndex(88) );<br/><br/>	return 0;<br/>}<br/><br/></pre></div><div contenteditable="false"><link href="/admin/FCKeditor/editor/plugins/highlighter/dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css" type="text/css" rel="stylesheet" /></div></div><p>最后一行是返回查找元素的索引，既然都排好序了，何不用折半查找？于是就实现了一下折半查找，恩，又是递归，又是二分治，又是logN。</p><p>放出DEMO：<a target="_blank" href="http://www.zwqxin.com/upload/2009/5/QuickSort-searchByZwqXin.rar">QuickSort-searchByZwqXin.rar</a></p>]]></description><category>图形相关算法</category><comments>http://www.zwqxin.com/archives/arithmetic/quick-sort-implement.html#comment</comments><wfw:comment>http://www.zwqxin.com/</wfw:comment><wfw:commentRss>http://www.zwqxin.com/feed.asp?cmt=51</wfw:commentRss><trackback:ping>http://www.zwqxin.com/cmd.asp?act=tb&amp;id=51&amp;key=842ce102</trackback:ping></item><item><title>3D数学：求点到直线的投影</title><author>a@b.com (zwqxin)</author><link>http://www.zwqxin.com/archives/arithmetic/project-point-to-line.html</link><pubDate>Wed, 04 Mar 2009 14:26:13 +0800</pubDate><guid>http://www.zwqxin.com/archives/arithmetic/project-point-to-line.html</guid><description><![CDATA[<p>今天思考一个问题的时候，考虑到把空间中一个点投影到一个向量上，也就是project-point-to-vector，发现原来自己想不出来，惟有求助google，算法理解。&mdash;&mdash;<a href="http://www.zwqxin.com/">ZwqXin</a>.com</p><p>事情是这样的，在OPENGL中，点的坐标定义于其模型坐标系XYZ，现在我经过某个转换生成了另一个3维坐标系X'Y'Z'，反映于原坐标系，就是三个满足正交的方向向量，干脆叫做X'和Y'和Z'。现在我有一个定义于模型坐标系XYZ的点阵，我需要把这些点分别投影到X'和Y'和Z'上，求投影点坐标。</p><p style="text-align: left">问题有点虚，所以考虑把这三个正交向量看作三条直线，问题就变成了：求点到直线的投影。考虑一个点和一条直线，描述这条直线需要两个点P<sub>1</sub>和P<sub>2 </sub>（顺带一提，P<sub>2 </sub>-P<sub>1</sub>就是相应的那向量），待投影的点叫P<sub>3。</sub>不妨设P<sub>3</sub>投影到该直线后所得的点是P<sub>3</sub>'<sub>，</sub>注意P<sub>3</sub>'与P<sub>1、</sub>P<sub>2 </sub>共线，因此必然有一个比例因子t，令</p><p style="text-align: center">t * （P<sub>2&nbsp; </sub>- P<sub>1</sub>） = &nbsp; P<sub>3</sub>' - P<sub>1</sub></p><p style="text-align: left">因此问题变为：已知P<sub>1、</sub>P<sub>2 、</sub>P<sub>3 </sub>， P<sub>1</sub>和P<sub>2 </sub>共线，求比例因子t 。令vec1 = P<sub>3</sub> - P<sub>1&nbsp; ， </sub>vec2 = P<sub>2&nbsp; </sub>- P<sub>1，</sub>显然dis = vec1 * vec2（点乘）就是vec1在vec2上的投影，既然vec1与vec2共享一个起点P<sub>1，</sub>那么dis就是P<sub>1</sub>到投影点P<sub>3</sub>'的距离了。于是</p><p style="text-align: center">t = dis / length(P<sub>&nbsp;1</sub>P<sub>2</sub>) = vec1 * vec2 / length(P<sub>&nbsp;1</sub>P<sub>2</sub>)<br /><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = (P<sub>3</sub> - P1) * (P<sub>2&nbsp; </sub>- P<sub>1</sub>)&nbsp; /&nbsp;abs (P<sub>2&nbsp; </sub>- P<sub>1</sub>)<br /><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = (P<sub>3</sub> - P1) * (P<sub>2&nbsp; </sub>- P<sub>1</sub>)&nbsp; /&nbsp;(P<sub>2&nbsp; </sub>- P<sub>1</sub>) *(P<sub>2&nbsp; </sub>- P<sub>1</sub>)</p><p style="text-align: left">abs (P<sub>2&nbsp; </sub>- P<sub>1</sub>)表示求模（也就是线段P<sub>&nbsp;1</sub>P<sub>2</sub>的长度），abs (P<sub>2&nbsp; </sub>- P<sub>1</sub>) = (P<sub>2&nbsp; </sub>- P<sub>1</sub>) *(P<sub>2&nbsp; </sub>- P<sub>1</sub>) 。由上两式子就能求出P<sub>3</sub>' 了。这么简单..........看来脑袋锈豆不浅。算法写进我的CVector3类里了。直线还原成向量的样子，相当于把直线用一个向量和一个参考点描述。</p><div class="HighLighter" contenteditable="false"><div class="dp-highlighter" contenteditable="false"><div class="bar">&nbsp;</div><ol class="dp-c">    <li class="alt"><span><span>&nbsp;</span><span class="comment">//点到矢量vec2的投影，ori_vec2表示vec2起点（投影参照点） </span></span></li>    <li><span>&nbsp;&nbsp;inline&nbsp;CVector3&nbsp;Project2Vector(CVector3&amp;&nbsp;vec2,&nbsp;CVector3&nbsp;ori_vec2){ </span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CVector3&nbsp;dir&nbsp;=&nbsp;(*</span><span class="keyword">this</span><span>)&nbsp;-&nbsp;ori_vec2; </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">double</span><span>&nbsp;t&nbsp;=&nbsp;dir.DotProd(vec2)&nbsp;/&nbsp;vec2.DotProd(vec2); </span></li>    <li class="alt">&nbsp;</li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;ori_vec2&nbsp;+&nbsp;vec2&nbsp;*&nbsp;t; </span></li>    <li class="alt"><span>&nbsp;&nbsp;}; </span></li>    <li>&nbsp;</li>    <li class="alt">&nbsp;</li>    <li><span class="comment">//例子 </span></li>    <li class="alt"><span>{ </span></li>    <li><span>CVector3&nbsp;pt&nbsp;=&nbsp;CVector3(.....);</span><span class="comment">//待投影的点 </span></li>    <li class="alt"><span>CVector3&nbsp;ori_pt&nbsp;=&nbsp;CVector3(.....);</span><span class="comment">//投影参考点,也就是上文的P1 </span></li>    <li><span>CVector3&nbsp;vector&nbsp;=&nbsp;CVector3(.....);</span><span class="comment">//待投影于其上的某向量 </span></li>    <li class="alt">&nbsp;</li>    <li><span>CVector3&nbsp;point; </span></li>    <li class="alt"><span>point&nbsp;=&nbsp;pt&nbsp;.Project2Vector（vector，&nbsp;ori_pt&nbsp;）； </span></li>    <li><span>}</span></li></ol></div><div class="c#" contenteditable="false" style="display: none"><pre> //点到矢量vec2的投影，ori_vec2表示vec2起点（投影参照点）<br/>  inline CVector3 Project2Vector(CVector3&amp; vec2, CVector3 ori_vec2){<br/>	  CVector3 dir = (*this) - ori_vec2;<br/>	  double t = dir.DotProd(vec2) / vec2.DotProd(vec2);<br/><br/>	  return ori_vec2 + vec2 * t;<br/>  };<br/><br/><br/>//例子<br/>{<br/>CVector3 pt = CVector3(.....);//待投影的点<br/>CVector3 ori_pt = CVector3(.....);//投影参考点,也就是上文的P1<br/>CVector3 vector = CVector3(.....);//待投影于其上的某向量<br/><br/>CVector3 point;<br/>point = pt .Project2Vector（vector， ori_pt ）；<br/>}</pre></div><div contenteditable="false"><link href="/admin/FCKeditor/editor/plugins/highlighter/dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css" type="text/css" rel="stylesheet" /></div></div><p>另：点到线段P<sub>&nbsp;1</sub>P<sub>2</sub>的投影：</p><div class="HighLighter" contenteditable="false"><div class="dp-highlighter" contenteditable="false"><div class="bar">&nbsp;</div><ol class="dp-c">    <li class="alt"><span><span>CVector3&nbsp;ClosestPointOnSegment(CVector3&nbsp;p,&nbsp;CVector3&nbsp;p1,&nbsp;CVector3&nbsp;p2) </span></span></li>    <li><span>{ </span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;CVector3&nbsp;diff&nbsp;=&nbsp;p-p1; </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;CVector3&nbsp;dir&nbsp;=&nbsp;p2-p1; </span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">float</span><span>&nbsp;dot1&nbsp;=&nbsp;dot(diff,dir); </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(dot1&nbsp;&lt;=&nbsp;0.0f)&nbsp;{ </span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;p1; </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp; </span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">float</span><span>&nbsp;dot2&nbsp;=&nbsp;dot(dir,dir); </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(dot2&nbsp;&lt;=&nbsp;dot1)&nbsp;{ </span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;p2; </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} </span></li>    <li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">float</span><span>&nbsp;t=dot1/dot2; </span></li>    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;p1&nbsp;+&nbsp;t&nbsp;*&nbsp;dir; </span></li>    <li class="alt"><span>}</span></li></ol></div><div class="c#" contenteditable="false" style="display: none"><pre>CVector3 ClosestPointOnSegment(CVector3 p, CVector3 p1, CVector3 p2)<br/>{<br/>    CVector3 diff = p-p1;<br/>    CVector3 dir = p2-p1;<br/>    float dot1 = dot(diff,dir);<br/>    if (dot1 &lt;= 0.0f) {<br/>        return p1;<br/>    }    <br/>    float dot2 = dot(dir,dir);<br/>    if (dot2 &lt;= dot1) {<br/>        return p2;<br/>    }<br/>    float t=dot1/dot2;<br/>    return p1 + t * dir;<br/>}</pre></div><div contenteditable="false"><link href="/admin/FCKeditor/editor/plugins/highlighter/dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css" type="text/css" rel="stylesheet" /></div></div>]]></description><category>图形相关算法</category><comments>http://www.zwqxin.com/archives/arithmetic/project-point-to-line.html#comment</comments><wfw:comment>http://www.zwqxin.com/</wfw:comment><wfw:commentRss>http://www.zwqxin.com/feed.asp?cmt=36</wfw:commentRss><trackback:ping>http://www.zwqxin.com/cmd.asp?act=tb&amp;id=36&amp;key=59942ab6</trackback:ping></item></channel></rss>
