/* 参考 :http://www.cnblogs.com/wantnon/p/4947067.html * http://fab.cba.mit.edu/classes/S62.12/docs/Meijster_distance.pdf * 具体算法名:Saito算法 * 因为初始化值都是未知的,通过一个大约估计的初始化,来重复来回算一个大致准确的距离 * 值 ? */ public void generateDistanceField(OpenHeightfield field) { if (field == null) { Logger.LogError("[OpenHeightfieldBuilder][generateNeighborLinks]field Empty"); return; } /* * 先将OpenHeightField的Span数据转换成0和1的二值图。如果是边缘Span * 那么就是0,否则就是NEEDS_INIT。 */ OpenHeightfield.OpenHeightFieldIterator iter = field.GetEnumerator(); while( iter.MoveNext() ) { OpenHeightSpan span = iter.Current; bool isBorder = false; for(int dir = 0; dir < 4; ++dir) { OpenHeightSpan nSpan = span.getNeighbor(dir); if( null == nSpan || nSpan.getNeighbor(dir == 3 ? 0 : dir + 1) == null) { //如果8个邻居有任何一个缺失的话,那么就是边界Border isBorder = true; break; } } if( isBorder ) { //自己就是边界Border span.setDistanceToBorder(BORDER); } else { //需要再次计算 span.setDistanceToBorder(NEEDS_INIT); } } //while /* * 逆时针访问? * * (-1,1) (0,1) (1,1) * (-1,0) x (1,0) * (-1,-1) (0,-1) (1,-1) */ //Pass 1 //顺序访问 (-1,0) (-1,-1) (0,-1) (1,-1) iter.Reset(); while( iter.MoveNext() ) { OpenHeightSpan span = iter.Current; int selfDist = span.distanceToBorder(); if( selfDist == BORDER) { continue; } //(-1,0) OpenHeightSpan nSpan = span.getNeighbor(0); selfDist = calcMiniDistanceToBorder(selfDist, nSpan, true); //(-1,-1),左下角的领域 nSpan = nSpan.getNeighbor(3); //领域0的领域3,也就是原Span的左下角 selfDist = calcMiniDistanceToBorder(selfDist, nSpan, false); //(0,-1) nSpan = span.getNeighbor(3); selfDist = calcMiniDistanceToBorder(selfDist, nSpan, true); //(1,-1) nSpan = nSpan.getNeighbor(2); selfDist = calcMiniDistanceToBorder(selfDist, nSpan, true); span.setDistanceToBorder(selfDist); } // while //Pass 2 //顺序访问 (1,0) (1,1) (0,1) (-1,1) //注意这个是反向遍历 iter.ReverseReset(); while( iter.MoveNext() ) { OpenHeightSpan span = iter.Current; int selfDist = span.distanceToBorder(); if( selfDist == BORDER ) { continue; } /* * 因为经过Pass1之后 ,所有的Span要么就是Border * 要么就是有个大概值的,不会等于NEED_INIT的。 * 所以直接按照按照上面的流程跑 */ //(1,0) OpenHeightSpan nSpan = span.getNeighbor(2); selfDist = calcMiniDistanceToBorder(selfDist, nSpan, true); //(1,1) nSpan = nSpan.getNeighbor(1); selfDist = calcMiniDistanceToBorder(selfDist, nSpan, false); //(0,1) nSpan = span.getNeighbor(1); selfDist = calcMiniDistanceToBorder(selfDist, nSpan, true); //(-1,1) nSpan = nSpan.getNeighbor(0); selfDist = calcMiniDistanceToBorder(selfDist, nSpan, false); span.setDistanceToBorder(selfDist); } field.clearBorderDistanceBounds(); }