//dynamically add pillars in //x ~ (0, setting.maxX * power(2, subdivision)), x ~ (0, setting.maxZ * power(2, subdivision)) public void AddPillar(int subdivision, int x, int z, OrderedSlices rawSlices) { //first grade int u = x >> subdivision; // x / power(2, subdivision); int v = z >> subdivision; int subx = x - u * (1 << subdivision); int subz = z - v * (1 << subdivision); --subdivision; int idx = (subx >> subdivision) * 2 + (subz >> subdivision); if (subdivision > 0) { if (Children[idx] is QuadTreeLeaf) { SubdividLeaf(idx); } QuadTreeNode node = (QuadTreeNode)Children[idx]; node.AddPillar(subdivision, subx, subz, rawSlices); } else { if (Children[idx] is QuadTreeNode) { MPLog.LogError("AddPillar leaf still a tree : " + subdivision); return; } QuadTreeLeaf leaf = (QuadTreeLeaf)Children[idx]; if (leaf.Slices != null) { HeightSlicePool.Push(leaf.Header, leaf.Slices); } leaf.Reset(rawSlices.Count, rawSlices.HashValue); for (int i = 0; i < rawSlices.Count; ++i) { leaf.Slices[i] = SliceAccessor.packVal(rawSlices[i].heightGrade, 0, 0, rawSlices[i].flag); } } }
public void Unify(float startHeight, float heightPerGrade) { SortSlices(); if (Count == 0) { MPLog.LogError("pillar is empty."); } //merge the slices, slices should be floor|ceiling|floor|ceiling....|floor bool bNeedMerge = true; while (bNeedMerge && Count > 0) { bNeedMerge = false; for (int i = 0; i < Count - 1; ++i) { if (this[i].flag == this[i + 1].flag) { if ((this[i].flag & SliceAccessor.SliceCeiling) > 0) {//ceiling use lower one RemoveAt(i + 1); } else {//floor use higher one RemoveAt(i); } bNeedMerge = true; break; } } } HashValue = 0; for (int i = 0; i < Count; ++i) { RawSlice slice = this[i]; slice.heightGrade = (ushort)Math.Ceiling((slice.height - startHeight) / heightPerGrade); HashValue += SliceAccessor.packVal(slice.heightGrade, 0, 0, slice.flag); } }
private QuadTreeLeaf Combine(float dx, float dz, float sliceThickness, float slopeErr) { if (Children[0] == null || !(Children[0] is QuadTreeLeaf)) { return(null); } QuadTreeLeaf leaf = (QuadTreeLeaf)Children[0]; for (int i = 1; i < Children.Length; ++i) { if (Children[i] == null || !(Children[i] is QuadTreeLeaf)) { return(null); } if (!leaf.IsCombinable((QuadTreeLeaf)Children[i])) { return(null); } } for (int s = 0; s < leaf.Slices.Length; ++s) { ulong leafS = leaf.Slices[s]; byte flag = SliceAccessor.flag(leafS); //x axis short slopeU = GetSlope(leafS, ((QuadTreeLeaf)Children[1]).Slices[s], dx, sliceThickness); short slopeU1 = GetSlope(((QuadTreeLeaf)Children[2]).Slices[s], ((QuadTreeLeaf)Children[3]).Slices[s], dx, sliceThickness); if ((slopeU != 0 && slopeU1 != 0 && Math.Abs(slopeU1 - slopeU) > slopeErr * SliceAccessor.slopeMagnify)) { return(null); } slopeU += slopeU1; slopeU /= 2; //z axis short slopeV = GetSlope(leafS, ((QuadTreeLeaf)Children[2]).Slices[s], dz, sliceThickness); short slopeV1 = GetSlope(((QuadTreeLeaf)Children[1]).Slices[s], ((QuadTreeLeaf)Children[3]).Slices[s], dz, sliceThickness); if ((slopeV != 0 && slopeV1 != 0 && Math.Abs(slopeV1 - slopeV) > slopeErr * SliceAccessor.slopeMagnify)) { return(null); } slopeV += slopeV1; slopeV /= 2; ushort updateH = 0; for (int i = 0; i < Children.Length; ++i) { QuadTreeLeaf l = (QuadTreeLeaf)Children[i]; ulong lS = l.Slices[s]; if (leaf.HashVal != l.HashVal) { byte f = SliceAccessor.flag(lS); short sU = SliceAccessor.slopeUGrade(lS); short sV = SliceAccessor.slopeVGrade(lS); //floor cant match ceiling if (flag != f) { return(null); } //slope error if ((sU != 0 && Math.Abs(sU - slopeU) > slopeErr * SliceAccessor.slopeMagnify) || (sV != 0 && Math.Abs(sV - slopeV) > slopeErr * SliceAccessor.slopeMagnify)) { return(null); } } updateH += SliceAccessor.heightGrade(lS); } updateH >>= 2;//average height leaf.Slices[s] = SliceAccessor.packVal(updateH, slopeU, slopeV, flag); } leaf.RefreshHash(); return(leaf); }