/// <summary> /// Insert a segment into the array /// </summary> /// <param name="ints">The array of segments</param> /// <param name="nints">The number of segments</param> /// <param name="maxInts">The maximium number of segments allowed</param> /// <param name="tmin">Parameter t minimum</param> /// <param name="tmax">Parameter t maximum</param> /// <param name="reference">Polygon reference</param> public void InsertInterval(SegInterval[] ints, ref int nints, int maxInts, int tmin, int tmax, PolyId reference) { if (nints + 1 > maxInts) return; //find insertion point int idx = 0; while (idx < nints) { if (tmax <= ints[idx].TMin) break; idx++; } //move current results if (nints - idx > 0) { for (int i = 0; i < nints - idx; i++) ints[idx + 1 + i] = ints[idx + i]; } //store ints[idx].Reference = reference; ints[idx].TMin = tmin; ints[idx].TMax = tmax; nints++; }
/// <summary> /// Collect all the edges from a polygon. /// </summary> /// <param name="reference">The polygon reference</param> /// <param name="segmentVerts">Segment vertices</param> /// <param name="segmentRefs">The polygon reference containing the segment</param> /// <param name="segmentCount">The number of segments stored</param> /// <param name="maxSegments">The maximum number of segments allowed</param> /// <returns>True, unless the polygon reference is invalid</returns> public bool GetPolyWallSegments(PolyId reference, Crowds.LocalBoundary.Segment[] segmentVerts, PolyId[] segmentRefs, ref int segmentCount, int maxSegments) { segmentCount = 0; MeshTile tile; Poly poly; if (nav.TryGetTileAndPolyByRef(reference, out tile, out poly) == false) return false; int n = 0; int MAX_INTERVAL = 16; SegInterval[] ints = new SegInterval[MAX_INTERVAL]; int nints; bool storePortals = segmentRefs.Length != 0; for (int i = 0, j = poly.VertCount - 1; i < poly.VertCount; j = i++) { //skip non-solid edges nints = 0; if ((poly.Neis[j] & Link.External) != 0) { //tile border for (int k = poly.FirstLink; k != Link.Null; k = tile.Links[k].Next) { Link link = tile.Links[k]; if (link.Edge == j) { if (link.Reference != PolyId.Null) { MeshTile neiTile; Poly neiPoly; nav.TryGetTileAndPolyByRefUnsafe(link.Reference, out neiTile, out neiPoly); InsertInterval(ints, ref nints, MAX_INTERVAL, link.BMin, link.BMax, link.Reference); } } } } else { //internal edge PolyId neiRef = PolyId.Null; if (poly.Neis[j] != 0) { int idx = poly.Neis[j] - 1; PolyId id = nav.GetPolyRefBase(tile); PolyId.SetPolyIndex(ref id, idx, out neiRef); } //if the edge leads to another polygon and portals are not stored, skip if (neiRef != PolyId.Null && !storePortals) continue; if (n < maxSegments) { Vector3 vj = tile.Verts[poly.Verts[j]]; Vector3 vi = tile.Verts[poly.Verts[i]]; segmentVerts[n].Start = vj; segmentVerts[n].End = vi; segmentRefs[n] = neiRef; n++; //could be n += 2, since segments have 2 vertices } continue; } //add sentinels InsertInterval(ints, ref nints, MAX_INTERVAL, -1, 0, PolyId.Null); InsertInterval(ints, ref nints, MAX_INTERVAL, 255, 256, PolyId.Null); //store segments Vector3 vj2 = tile.Verts[poly.Verts[j]]; Vector3 vi2 = tile.Verts[poly.Verts[i]]; for (int k = 1; k < nints; k++) { //portal segment if (storePortals && ints[k].Reference != PolyId.Null) { float tmin = ints[k].TMin / 255.0f; float tmax = ints[k].TMax / 255.0f; if (n < maxSegments) { Vector3.Lerp(ref vj2, ref vi2, tmin, out segmentVerts[n].Start); Vector3.Lerp(ref vj2, ref vi2, tmax, out segmentVerts[n].End); segmentRefs[n] = ints[k].Reference; n++; } } //wall segment int imin = ints[k - 1].TMax; int imax = ints[k].TMin; if (imin != imax) { float tmin = imin / 255.0f; float tmax = imax / 255.0f; if (n < maxSegments) { Vector3.Lerp(ref vj2, ref vi2, tmin, out segmentVerts[n].Start); Vector3.Lerp(ref vj2, ref vi2, tmax, out segmentVerts[n].End); segmentRefs[n] = PolyId.Null; n++; } } } } segmentCount = n; return true; }