private static bool isBorderByPosition(int vertex, V2FDict ref_dict) { #if IGNORE_NEAR if (checkNear(vertex) >= 0) { return(false); } #endif if (ref_dict[vertex].Count < MIN_FACES) { return(true); } PEPlugin.SDX.V3 around = new PEPlugin.SDX.V3(0.0f, 0.0f, 0.0f); foreach (int[] face in ref_dict[vertex]) { int pos = Array.IndexOf(face, vertex); int v1 = face[(pos + 1) % 3]; int v2 = face[(pos + 2) % 3]; PEPlugin.SDX.V3 sub = all_vertex_list[v2].Position - all_vertex_list[v1].Position; around = around + sub; } return(norm2(around) > NEAR * NEAR); }
// key: 頂点番号, value: key頂点を含む面のリスト private static V2FDict makeRefDict(IList <IPXFace> faces) { V2FDict ref_dict = new V2FDict(); foreach (IPXFace face in faces) { int[] v_list = new int[3] { v2i(face.Vertex1), v2i(face.Vertex2), v2i(face.Vertex3) }; foreach (int v in v_list) { if (!ref_dict.ContainsKey(v)) { ref_dict[v] = new List <int[]>(); } ref_dict[v].Add(v_list); } } #if IGNORE_NEAR // 材質が持つ頂点のソート情報グローバル変数を更新 int[] param = ref_dict.Keys.ToArray(); Tuple <int[], Dictionary <int, int> > t = sortVertexList(param); sorted_v = t.Item1; reverse_v = t.Item2; #endif return(ref_dict); }
private static List <int> selectConnectedBorderWrapper( IList <int> target_list, V2FDict ref_dict) { HashSet <int> vset = new HashSet <int>(); HashSet <int> visited = new HashSet <int>(); foreach (int selected_v in target_list) { vset = selectConnectedBorder( selected_v, ref_dict, vset, visited); } return(new List <int>(vset)); }
// 材質が持つ全ての頂点を判定 private static List <int> selectAllBorder(V2FDict ref_dict) { List <int> vlist = new List <int>(); foreach (int vertex in ref_dict.Keys) { if (isBorder(vertex, ref_dict)) { vlist.Add(vertex); } } return(vlist); }
private static void plugin_main( IPXPmx pmx, IPEViewConnector view, IPEFormConnector form) { int selected_m = form.SelectedMaterialIndex; //int selected_v = form.SelectedVertexIndex; int [] selected_vs = view.PMDView.GetSelectedVertexIndices(); if (selected_m >= 0) { IList <IPXFace> faces = pmx.Material[selected_m].Faces; V2FDict ref_dict = makeRefDict(faces); List <int> filtered = new List <int>(); foreach (int selected_v in selected_vs) { if (selected_v >= 0 && ref_dict.ContainsKey(selected_v)) { filtered.Add(selected_v); } } if (selected_vs.Length > 0 && filtered.Count <= 0) { MessageBox.Show( "選択した頂点は選択した材質に含まれていません"); } List <int> vlist; if (filtered.Count > 0) { vlist = selectConnectedBorderWrapper(filtered, ref_dict); } else // all { vlist = selectAllBorder(ref_dict); } var vedit = view.PMDViewHelper.VertexEdit; #if USE_MEM_SLOT vedit.SetVertexMemory(MEMORY_SLOT, vlist.ToArray()); #endif view.PMDView.SetSelectedVertexIndices(vlist.ToArray()); } else { throw new System.Exception("材質を選択してください"); } }
// 面の接続を辿って判定 private static HashSet <int> selectConnectedBorder( int vertex, V2FDict ref_dict, HashSet <int> result = null, HashSet <int> visited = null) { if (null == result) { result = new HashSet <int>(); } if (null == visited) { visited = new HashSet <int>(); } if (visited.Contains(vertex)) { return(result); } else { visited.Add(vertex); } if (isBorder(vertex, ref_dict)) { result.Add(vertex); var conn = new HashSet <int>(); // 面で繋がっている頂点群を把握 foreach (int[] face in ref_dict[vertex]) { int pos = Array.IndexOf(face, vertex); conn.Add(face[(pos + 1) % 3]); conn.Add(face[(pos + 2) % 3]); } foreach (int v in conn) { if (!visited.Contains(v)) { selectConnectedBorder( v, ref_dict, result, visited); } } } return(result); }
private static bool isBorderByLink(int vertex, V2FDict ref_dict) { #if IGNORE_NEAR // 重複頂点を境界扱いしない(探索中止) if (checkNear(vertex) >= 0) { return(false); } #endif if (ref_dict[vertex].Count < MIN_FACES) { return(true); } List <int> from_v = new List <int>(); List <int> to_v = new List <int>(); foreach (int[] face in ref_dict[vertex]) { int pos = Array.IndexOf(face, vertex); from_v.Add(face[(pos + 1) % 3]); to_v.Add(face[(pos + 2) % 3]); } int i = 0; int start = from_v[i]; while (true) { int to_node = to_v[i]; from_v.RemoveAt(i); to_v.RemoveAt(i); i = from_v.IndexOf(to_node); if (i < 0) { // [(0 -> 1), (3 -> 4), (1 -> 2), (4 -> 5), (5 -> 0)] return(true); } if (from_v.Count == 1) { // [(0 -> 1), (3 -> 4), (2 -> 3), (1 -> 2), (4 -> ?)] return(to_v[0] != start); } } }