/// <summary> /// A splitter can split a vertex-indexed face set, based on the /// supplied array of vertexHeights, which indicate for each vertex /// vi if it belongs to the negative split side (vertexHeights[vi] /// < 0.0) or positive split side (vertexHeights[vi] >= 0.0). /// </summary> public PolygonSplitter( int[] fia, int faceCount, int[] via, int maxFaceVertexCount, double[] vertexHeights, double eps, SplitterOptions options) { int vc = vertexHeights.Length; int vertexIndexCount = fia[faceCount]; bool doNeg = (options & SplitterOptions.Negative) != 0; bool doPos = (options & SplitterOptions.Positive) != 0; if (doPos && vertexHeights.All(h => h >= -eps)) { m_pfia = fia; m_pvia = via; m_ofia = null; return; } if (doNeg && vertexHeights.All(h => h <= eps)) { m_nfia = fia; m_nvia = via; m_ofia = null; return; } m_ofia = fia; var lineMap = new Dict <Line1i, (int, int, int)>(); m_spl = doNeg ? new List <SplitPoint>() : null; m_nvl = doPos ? new List <Vertex>() : null; m_pvl = doPos ? new List <Vertex>() : null; m_nfl = doNeg ? new List <Face>() : null; m_pfl = doPos ? new List <Face>() : null; int[] nffm = doNeg ? new int[faceCount].Set(-1) : null; int[] pffm = doPos ? new int[faceCount].Set(-1) : null; int[] nvfm = doNeg ? new int[vc].Set(-1) : null; int[] pvfm = doPos ? new int[vc].Set(-1) : null; var ha = new double[maxFaceVertexCount]; int nfc = 0, pfc = 0, nvic = 0, pvic = 0, nvc = 0, pvc = 0; for (int fvi = fia[0], fi = 0; fi < faceCount; fi++) { int nc = 0, pc = 0, zc = 0, fve = fia[fi + 1], fvc = fve - fvi; for (int fs = 0; fs < fvc; fs++) { double height = ha[fs] = vertexHeights[via[fvi + fs]]; if (height < -eps) { ++nc; continue; } if (height > +eps) { ++pc; continue; } ++zc; } if (nc == 0) { if (doPos) { pffm[fi] = pfc++; pvic += fvc; for (int fs = 0; fs < fvc; fs++) { pvfm.ForwardMapAdd(via[fvi + fs], ref pvc); } } } else if (pc == 0) { if (doNeg) { nffm[fi] = nfc++; nvic += fvc; for (int fs = 0; fs < fvc; fs++) { nvfm.ForwardMapAdd(via[fvi + fs], ref nvc); } } } else { if (zc > 2) { Report.Warn("non-convex polygon encountered"); } var nfvl = new List <FaceVertex>(nc + 2); var pfvl = new List <FaceVertex>(pc + 2); int sb = ha[0] > eps ? 1 : (ha[0] < -eps ? -1 : 0), vib = via[fvi]; int i0 = 0, s0 = sb, vi0 = vib; if (doNeg && sb <= 0) { nfvl.Add(new FaceVertex(nvfm.ForwardMapAdd(vib, ref nvc), 0)); } if (doPos && sb >= 0) { pfvl.Add(new FaceVertex(pvfm.ForwardMapAdd(vib, ref pvc), 0)); } for (int i1 = 1; i1 < fvc; i0 = i1++) { int s1 = ha[i1] > eps ? 1 : (ha[i1] < -eps ? -1 : 0), vi1 = via[fvi + i1]; if (s0 != 0 && s1 != 0 && s0 != s1) { double t = ha[i0] / (ha[i0] - ha[i1]); var key = Line1i.CreateSorted(vi0, vi1); (int, int, int)v; if (!lineMap.TryGetValue(key, out v)) { v = lineMap[key] = (nvc++, pvc++, m_spl.Count); m_spl.Add(new SplitPoint(t, vi0, vi1)); } if (doNeg) { m_nvl.Add(new Vertex(v.Item1, v.Item3, t, i0)); nfvl.Add(new FaceVertex(v.Item1, -m_nvl.Count)); } if (doPos) { m_pvl.Add(new Vertex(v.Item2, v.Item3, t, i0)); pfvl.Add(new FaceVertex(v.Item2, -m_pvl.Count)); } } if (doNeg && s1 <= 0) { nfvl.Add(new FaceVertex(nvfm.ForwardMapAdd(vi1, ref nvc), i1)); } if (doPos && s1 >= 0) { pfvl.Add(new FaceVertex(pvfm.ForwardMapAdd(vi1, ref pvc), i1)); } vi0 = vi1; s0 = s1; } if (s0 != 0 && sb != 0 && s0 != sb) { double t = ha[i0] / (ha[i0] - ha[0]); var key = Line1i.CreateSorted(vi0, vib); (int, int, int)v; if (!lineMap.TryGetValue(key, out v)) { v = lineMap[key] = (nvc++, pvc++, m_spl.Count); m_spl.Add(new SplitPoint(t, vi0, vib)); } if (doNeg) { m_nvl.Add(new Vertex(v.Item1, v.Item3, t, i0)); nfvl.Add(new FaceVertex(v.Item1, -m_nvl.Count)); } if (doPos) { m_pvl.Add(new Vertex(v.Item2, v.Item3, t, i0)); pfvl.Add(new FaceVertex(v.Item2, -m_pvl.Count)); } } if (doNeg && nfvl.Count > 2) { m_nfl.Add(new Face(fi, nfvl)); nvic += nfvl.Count; } if (doPos && pfvl.Count > 2) { m_pfl.Add(new Face(fi, pfvl)); pvic += pfvl.Count; } } fvi = fve; } if (doNeg && (nfc > 0 || m_nfl.Count > 0)) { CalculateIndices(fia, faceCount, via, nfc, nvic, nvc, nffm, m_nfl, nvfm, out m_nfia, out m_nvia, out m_nfbm, out m_nvbm); } if (doPos && (pfc > 0 || m_pfl.Count > 0)) { CalculateIndices(fia, faceCount, via, pfc, pvic, pvc, pffm, m_pfl, pvfm, out m_pfia, out m_pvia, out m_pfbm, out m_pvbm); } }
/// <summary> /// A splitter can split a vertex-indexed triangle set, based on the /// supplied array of vertexHeights, which indicate for each vertex /// vi if it belongs to the negative split side (vertexHeights[vi] /// < 0.0) or positive split side (vertexHeights[vi] >= 0.0). /// </summary> public TriangleSplitter(int[] indices, double[] vertexHeights, double eps, SplitterOptions options) { m_negativeIndices = null; m_positiveIndices = null; bool doNeg = (options & SplitterOptions.Negative) != 0; bool doPos = (options & SplitterOptions.Positive) != 0; if (doPos && vertexHeights.All(h => h >= -eps)) { m_positiveIndices = indices; m_positiveVertexBackwardMap = null; // flag: move input to positive return; } if (doNeg && vertexHeights.All(h => h <= eps)) { m_negativeIndices = indices; m_negativeVertexBackwardMap = null; // flag: move input to negative return; } var lineMap = new Dictionary <Line1i, Line1i>(); var negTriangleList = doNeg ? new List <(int, Triangle1i)>() : null; var posTriangleList = doPos ? new List <(int, Triangle1i)>() : null; m_negVertexMap = doNeg ? new Dictionary <int, Line1iPoint>() : null; m_posVertexMap = doPos ? new Dictionary <int, Line1iPoint>() : null; int tc = indices.Length / 3; int ntc = 0; int ptc = 0; int nvc = 0; int pvc = 0; int[] negTriangleForwardMap = doNeg ? new int[tc].Set(-1) : null; int[] posTriangleForwardMap = doPos ? new int[tc].Set(-1) : null; int[] negVertexForwardMap = doNeg ? new int[vertexHeights.Length].Set(-1) : null; int[] posVertexForwardMap = doPos ? new int[vertexHeights.Length].Set(-1) : null; var ia = new int[3]; var ha = new double[3]; var negIndices = new List <int>(4); var posIndices = new List <int>(4); for (int ti = 0; ti < tc; ti++) { int nc = 0, pc = 0; int tvi = 3 * ti; for (int ts = 0; ts < 3; ts++) { int vi = indices[tvi + ts]; ia[ts] = vi; double height = ha[ts] = vertexHeights[vi]; if (height < -eps) { ++nc; continue; } if (height > +eps) { ++pc; continue; } } if (nc == 0) { if (doPos) { posTriangleForwardMap[ti] = ptc++; foreach (var vi in ia) { posVertexForwardMap.ForwardMapAdd(vi, ref pvc); } } } else if (pc == 0) { if (doNeg) { negTriangleForwardMap[ti] = ntc++; foreach (var vi in ia) { negVertexForwardMap.ForwardMapAdd(vi, ref nvc); } } } else { int sb = ha[0] > eps ? 1 : (ha[0] < -eps ? -1 : 0); int vi = ia[0]; if (doNeg && sb <= 0) { negIndices.Add(negVertexForwardMap.ForwardMapAdd(vi, ref nvc)); } if (doPos && sb >= 0) { posIndices.Add(posVertexForwardMap.ForwardMapAdd(vi, ref pvc)); } int i0 = 0, i1 = 1; int s0 = sb; while (i1 < 3) { int s1 = ha[i1] > eps ? 1 : (ha[i1] < -eps ? -1 : 0); if (s0 != 0 && s1 != 0 && s0 != s1) { double t = ha[i0] / (ha[i0] - ha[i1]); int vi0 = ia[i0], vi1 = ia[i1]; var key = Line1i.CreateSorted(vi0, vi1); if (!lineMap.TryGetValue(key, out Line1i line)) { var sp = new Line1iPoint(vi0, vi1, t); if (doNeg) { m_negVertexMap[line.I0 = nvc++] = sp; } if (doPos) { m_posVertexMap[line.I1 = pvc++] = sp; } lineMap[key] = line; } if (doNeg) { negIndices.Add(line.I0); } if (doPos) { posIndices.Add(line.I1); } } vi = ia[i1]; if (doNeg && s1 <= 0) { negIndices.Add(negVertexForwardMap.ForwardMapAdd(vi, ref nvc)); } if (doPos && s1 >= 0) { posIndices.Add(posVertexForwardMap.ForwardMapAdd(vi, ref pvc)); } i0 = i1++; s0 = s1; } if (s0 != 0 && sb != 0 && s0 != sb) { double t = ha[i0] / (ha[i0] - ha[0]); int vi0 = ia[i0], vi1 = ia[0]; var key = Line1i.CreateSorted(vi0, vi1); if (!lineMap.TryGetValue(key, out Line1i line)) { var sp = new Line1iPoint(vi0, vi1, t); if (doNeg) { m_negVertexMap[line.I0 = nvc++] = sp; } if (doPos) { m_posVertexMap[line.I1 = pvc++] = sp; } lineMap[key] = line; } if (doNeg) { negIndices.Add(line.I0); } if (doPos) { posIndices.Add(line.I1); } } // at this point we have lists of indices for the positive and // negative triangles if (doNeg && negIndices.Count > 2) { for (int i = 1; i < negIndices.Count - 1; i++) { negTriangleList.Add( (ntc++, new Triangle1i(negIndices[0], negIndices[i], negIndices[i + 1]))); } } if (doPos && posIndices.Count > 2) { for (int i = 1; i < posIndices.Count - 1; i++) { posTriangleList.Add( (ptc++, new Triangle1i(posIndices[0], posIndices[i], posIndices[i + 1]))); } } negIndices.Clear(); posIndices.Clear(); } } if (doNeg && ntc > 0) { m_negativeIndices = CalculateIndices(indices, ntc, negTriangleForwardMap, negTriangleList, negVertexForwardMap); m_negativeVertexBackwardMap = negVertexForwardMap.CreateBackMap(nvc); } if (doPos && ptc > 0) { m_positiveIndices = CalculateIndices(indices, ptc, posTriangleForwardMap, posTriangleList, posVertexForwardMap); m_positiveVertexBackwardMap = posVertexForwardMap.CreateBackMap(pvc); } }