/// <summary> /// </summary> /// <param name="startSpan"></param> /// <param name="borderDirection"></param> /// <param name="newRegionID"></param> private void partialFloodRegion(OpenHeightSpan startSpan, int borderDirection, int newRegionID) { int antiBorderDirection = NMGenUtility.AntiDir(borderDirection); int regionID = startSpan.regionID(); startSpan.setRegionID(newRegionID); startSpan.setDistanceToRegionCore(0); //???所以这个值 没啥卵用啊,一直都是0的 mwOpenSpans.Push(startSpan); mwBorderDistance.Push(0); while (mwOpenSpans.Count > 0) { OpenHeightSpan span = mwOpenSpans.Pop(); int distance = mwBorderDistance.Pop(); for (int i = 0; i < 4; ++i) { OpenHeightSpan nSpan = span.getNeighbor(i); if (null == nSpan || nSpan.regionID() != regionID) { continue; } int nDistance = distance; if (i == borderDirection) //null region所在的方向 { //这里是不是应该小于等于0呢? // 以这个距离Border为0作为边界,将大于0那一侧的Span全部变成 // 新的Region。然后小于等于0那一侧的作为旧的Region保留下来。 if (0 == distance) { continue; } nDistance--; } else if (i == antiBorderDirection) { nDistance++; } //注意上面的if-else,如果都不是这两个方向的Span //会直接被重新设置为新的Region nSpan.setRegionID(newRegionID); nSpan.setDistanceToRegionCore(0); mwOpenSpans.Push(nSpan); mwBorderDistance.Push(nDistance); } } }
/// <summary> /// 重新设置对应的Region,根据拐点的情况 /// </summary> /// <param name="referenceSpan"></param> /// <param name="borderDirection"></param> /// <param name="cornerDirection"></param> /// <returns></returns> private int selectedRegionID(OpenHeightSpan referenceSpan, int borderDirection, int cornerDirection) { referenceSpan.getDetailedRegionMap(ref mwNeighborRegions, 0); /* * Initial example state: * * a - Known region. * x - Null region. * u - Unknown, not checked yet. * * u u u * u a x * u a a */ int antiBorderDirection = NMGenUtility.AntiDir(borderDirection); int antiCornerDirection = NMGenUtility.AntiDir(cornerDirection); int regionID = mwNeighborRegions[antiBorderDirection]; if (regionID == referenceSpan.regionID() || NULL_REGION == regionID) { /* * The region away from the border is either a null region * or the same region. So we keep the current region. * * u u u u u u * a a x or x a x <-- Potentially bad, but stuck with it. * u a a u a a */ return(referenceSpan.regionID()); } int potentialRegion = regionID; regionID = mwNeighborRegions[antiCornerDirection]; if (regionID == referenceSpan.regionID() || NULL_REGION == regionID) { /* * The region opposite from the corner direction is * either a null region or the same region. So we * keep the current region. * * u a u u x u * b a x or b a x * u a a u a a */ return(referenceSpan.regionID()); } int potentialCount = 0; int currentCount = 0; for (int i = 0; i < 8; ++i) { if (mwNeighborRegions[i] == referenceSpan.regionID()) { currentCount++; } else if (mwNeighborRegions[i] == potentialRegion) { potentialCount++; } } return(potentialCount < currentCount ? referenceSpan.regionID() : potentialRegion); }
public void apply(OpenHeightfield field) { if (null == field) { Logger.LogError("[CLeanNullRegionBorders][apply]field null"); return; } int nextRegionID = field.regionCount(); OpenHeightfield.OpenHeightFieldIterator iter = field.GetEnumerator(); while (iter.MoveNext()) { OpenHeightSpan span = iter.Current; if (span.flags != 0) { continue; } span.flags = 1; OpenHeightSpan workingSpan = null; int edgeDirection = -1; if (NULL_REGION == span.regionID()) { //找到Border Span第一个非空的邻居 edgeDirection = getNonNullBorderDrection(span); if (-1 == edgeDirection) { continue; } //起点Span为有所属Region的Span //而行走方向为 null Region所在的方向 workingSpan = span.getNeighbor(edgeDirection); //转180度 edgeDirection = NMGenUtility.AntiDir(edgeDirection); } else if (!mUseOnlyNullSpans) { //起点Span为 null Region的Span //而行走方向即为有所属 Region 的 Span edgeDirection = getNullBorderDrection(span); if (-1 == edgeDirection) { continue; } workingSpan = span; } else { continue; } //上面两个分支都会保证workingSpan是有所属Region的 //而Dir 即是 Region 为 Null Region的Dir bool isEncompassedNullRegion = processNullRegion(workingSpan, edgeDirection); if (isEncompassedNullRegion) //确定以这个Span为起点的Region,是一个单一Region,并且内含了一个Null Region { //如果是完全包含了不可走的NullRegion ,就将这个Region分割成两个Region partialFloodRegion(workingSpan, edgeDirection, nextRegionID); nextRegionID++; } } field.setRegionCount(nextRegionID); iter.Reset(); while (iter.MoveNext()) { iter.Current.flags = 0; } }