Created
January 17, 2020 07:01
-
-
Save lowteq/c1864c4c8f5e1d158e153b73a739cff6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
#if UNITY_EDITOR | |
using UnityEditor; | |
public class BroochEditor : EditorWindow | |
{ | |
private class PathTool | |
{ | |
int selectindex = -1; | |
DrawTexture2D drawTexture2d = new DrawTexture2D(); | |
Texture2D texture; | |
bool closed = false; | |
List<Vector2> veclist; | |
float r; | |
int canvasSize; | |
Color pathColor; | |
bool drawtriangles = false; | |
bool drawsurflines = false; | |
int[] trianglesindex; | |
public PathTool(int canvassize,float radius,Color pathCol){ | |
r = radius; | |
canvasSize = canvassize; | |
pathColor = pathCol; | |
veclist = new List<Vector2>(); | |
texture = new Texture2D(canvasSize,canvasSize,TextureFormat.RGBA32,false); | |
drawTexture2d = new DrawTexture2D(); | |
trianglesindex = new int[]{}; | |
} | |
public void createtriangles01(){ | |
} | |
public void ShowListContentsInTheDebugLog<T>(List<T> list) | |
{ | |
string log = ""; | |
foreach (var content in list.Select((val, idx) => new { val, idx })) | |
{ | |
if (content.idx == list.Count - 1) | |
log += content.val.ToString(); | |
else | |
log += content.val.ToString() + ", "; | |
} | |
Debug.Log(log); | |
} | |
private static int mod(int a,int m){ | |
var v = a - m * (int)Math.Floor((double)a/(double)m); | |
//Debug.LogFormat("{0} mod {1} = {2}",a,m,v); | |
return v; | |
} | |
public int[] triangles(){ | |
List<Vector2> vecs = new List<Vector2>(veclist); | |
int c = vecs.Count; | |
//原点から最遠点のindexを求める | |
List<int> searchvecindex = Enumerable.Range(0, c).ToList(); | |
List<int> trianglesindex = new List<int> { }; | |
var orig = new Vector2(0f, 0f); | |
int index = 0; | |
float d = 0; | |
for (var i = 0; i < searchvecindex.Count; i++) | |
{ | |
var dnew = dist2(vecs[searchvecindex[i]],orig); | |
if (dnew > d) | |
{ | |
index = i; | |
d=dnew; | |
} | |
} | |
var a = vecs[(index + 1) % c] - vecs[index]; | |
var b = vecs[mod(index - 1, c)] - vecs[index]; | |
var origincross = cross(a, b); | |
var emargency = 0; | |
var flip = (int)(origincross/Math.Abs(origincross)); | |
Debug.Log("■OriginCross " + origincross); | |
while(true){ | |
Debug.Log("-------------"); | |
Debug.Log("index:"+index); | |
ShowListContentsInTheDebugLog<int>(searchvecindex); | |
emargency++; | |
if(emargency>1000){ | |
Debug.Log("EMARGENCY"); | |
Debug.Log(searchvecindex.Count); | |
break; | |
} | |
var svic = searchvecindex.Count; | |
var aa = vecs[searchvecindex[mod(index + 1,svic)]] - vecs[searchvecindex[index % svic]]; | |
var bb = vecs[searchvecindex[mod(index - 1,svic)]] - vecs[searchvecindex[index % svic]]; | |
var abcross = cross(aa,bb); | |
// a,bの直積の正負と最初の直積の正負が一致しないなら(角度が180°以上なら)選択頂点をとなりに移動してやりなおす | |
var directf = (origincross > 0) == (abcross > 0); | |
if (!directf){ | |
index = (index + 1) % svic; | |
continue; | |
} | |
//他の頂点がaとbからなる三角形に入ってないか | |
bool trianglesIn = false; | |
var v1 = veclist[searchvecindex[index%svic]]; | |
var v2 = veclist[searchvecindex[mod(index-1,svic)]]; | |
var v3 = veclist[searchvecindex[(index+1)%svic]]; | |
for (var i = 0; i < Veclist.Count; i++) | |
{ | |
if (i != searchvecindex[mod(index,svic)] && i != searchvecindex[mod(index + 1,svic)] && i != searchvecindex[mod(index - 1,svic)]) | |
{ | |
if (triangleIn(v1, v2, v3, veclist[i])) | |
{ | |
trianglesIn = true; | |
break; | |
} | |
} | |
} | |
//他のすべての頂点がすべてa,bからなる三角形に入ってないならa,bを分割線として作り選択頂点を検索点列から除外 | |
if (!trianglesIn) | |
{ | |
trianglesindex.AddRange(new int[]{searchvecindex[mod(index ,svic)],searchvecindex[mod(index + 1, svic)],searchvecindex[mod(index - 1, svic)]}); | |
searchvecindex.RemoveAt(index%svic); | |
}else{ | |
index = mod((index + 1),svic); | |
} | |
ShowListContentsInTheDebugLog<int>(searchvecindex); | |
if (searchvecindex.Count == 3) | |
{ | |
trianglesindex.AddRange(new int[] { searchvecindex[mod(index, 3)], searchvecindex[mod(index + 1, 3)], searchvecindex[mod(index - 1, 3)] }); | |
break; | |
} | |
} | |
this.trianglesindex = trianglesindex.ToArray(); | |
return this.trianglesindex; | |
} | |
private static float sign(Vector2 p1,Vector2 p2,Vector2 p3){ | |
return (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y); | |
} | |
private static bool PointInTriangle(Vector2 v1,Vector2 v2,Vector2 v3,Vector2 p){ | |
bool b1,b2,b3; | |
b1 = sign(p, v1, v2) < 0.0f; | |
b2 = sign(p, v2, v3) < 0.0f; | |
b3 = sign(p, v3, v1) < 0.0f; | |
Debug.Log(b1.ToString() + b2.ToString() + b3.ToString()); | |
return (b1== b2 == b3); | |
} | |
private static bool triangleIn(Vector2 t1,Vector2 t2,Vector2 t3,Vector2 p){ | |
var a = cross(t1-t2,p-t2); | |
var b = cross(t2-t3,p-t3); | |
var c = cross(t3-t1,p-t1); | |
Debug.Log("abc:" + a.ToString() + " " + b.ToString() + " " + c.ToString()); | |
if(((a > 0) == (b > 0)) && ((b > 0) == (c > 0))){ | |
return true; | |
}else{ | |
return false; | |
} | |
} | |
private static float cross(Vector2 v1,Vector2 v2){ | |
return v1.x*v2.y - v2.x*v1.y; | |
} | |
/// <summary> | |
/// 点リスト コピーされて渡される | |
/// </summary> | |
/// <value></value> | |
public List<Vector2> Veclist{ | |
get{return new List<Vector2>(this.veclist);} | |
} | |
public bool Closed{ | |
get{return this.closed;} | |
} | |
public Color PathColor{ | |
set{this.pathColor = value;} | |
get{return this.pathColor;} | |
} | |
public bool DrawTriangles{ | |
set{this.drawtriangles = value;} | |
get{return this.drawtriangles;} | |
} | |
public bool Drawsurflines{ | |
set{this.drawsurflines = value;} | |
get{return drawsurflines;} | |
} | |
public Texture2D canvas(){ | |
drawTexture2d.Begin(texture); | |
drawTexture2d.Clear(Color.clear); | |
var trianglec = Color.red; | |
var c = pathColor == null ? new Color(0.5f, 0.5f, 0.5f) : pathColor; | |
if (veclist.Count == 0){ | |
drawTexture2d.End(); | |
return texture; | |
}else{ | |
if (drawtriangles) | |
{ | |
drawTexture2d.Clear(Color.clear); | |
for (var i = 0; i < trianglesindex.Length; i += 3) | |
{ | |
var v1 = veclist[trianglesindex[i]]; | |
var v2 = veclist[trianglesindex[i + 1]]; | |
var v3 = veclist[trianglesindex[i + 2]]; | |
drawTexture2d.DrawLine((int)v1.x, (int)v1.y, (int)v2.x, (int)v2.y, trianglec); | |
drawTexture2d.DrawLine((int)v2.x, (int)v2.y, (int)v3.x, (int)v3.y, trianglec); | |
drawTexture2d.DrawLine((int)v3.x, (int)v3.y, (int)v1.x, (int)v1.y, trianglec); | |
} | |
} | |
drawTexture2d.DrawCircle((int)veclist[0].x, (int)veclist[0].y, (int)r, c); | |
if (drawsurflines){ | |
for(var i=1;i<veclist.Count;i++){ | |
var v1 = veclist[i-1]; | |
var v2 = veclist[i]; | |
drawTexture2d.DrawLine((int)v1.x,(int)v1.y,(int)v2.x,(int)v2.y,c); | |
drawTexture2d.DrawCircle((int)v2.x,(int)v2.y,(int)r,c); | |
} | |
if (closed) | |
{ | |
drawTexture2d.DrawLine((int)veclist[0].x, (int)veclist[0].y, (int)veclist[veclist.Count - 1].x, (int)veclist[veclist.Count - 1].y, c); | |
} | |
} | |
} | |
drawTexture2d.End(); | |
return texture; | |
} | |
public void Clear(){ | |
//veclist = new List<Vector2>(); | |
texture = new Texture2D(canvasSize, canvasSize, TextureFormat.RGBA32, false); | |
drawTexture2d = new DrawTexture2D(); | |
veclist.Clear(); | |
trianglesindex = new int[]{}; | |
drawtriangles = false; | |
closed = false; | |
} | |
public void ReleaseSelect(){ | |
selectindex = -1; | |
} | |
public int Point(Vector2 vec){ | |
for (var i = 0; i < veclist.Count; i++) | |
{ | |
if (circleIn(vec, veclist[i], r)) | |
{ | |
return i; | |
} | |
} | |
return -1; | |
} | |
public void Move(Vector2 vec) | |
{ | |
if(selectindex == -1) return; | |
veclist[selectindex] = vec; | |
} | |
public bool Select(Vector2 vec){ | |
selectindex = -1; | |
for(var i=0;i<veclist.Count;i++){ | |
if(circleIn(vec,veclist[i],r)){ | |
selectindex = i; | |
return true; | |
} | |
} | |
return false; | |
} | |
public bool Add(Vector2 vec){ | |
bool ret = false; | |
for (var i = 0; i < veclist.Count; i++) | |
{ | |
if (circleIn(vec, veclist[i], r)) | |
{ | |
//もし追加しようとしてるvecがveclist内の点付近の場合は追加しない | |
//だたし閉じる処理のveclist[0]のクリックは調べない | |
if(closed) return false; | |
} | |
} | |
if(closed){ | |
for (var i = 1; i < veclist.Count; i++) | |
{ | |
if(lineIn(vec,veclist[i-1],veclist[i],r)){ | |
veclist.Insert(i,vec); | |
ret = true; | |
break; | |
} | |
} | |
if (lineIn(vec, veclist[0], veclist[veclist.Count - 1], r)) | |
{ | |
veclist.Insert(0, vec); | |
ret = true; | |
} | |
}else{ | |
if (veclist.Count > 2) | |
{ | |
if (circleIn(veclist[0], vec, r)) | |
{ | |
//閉じるための処理 | |
closed = true; | |
} | |
else | |
{ | |
//追加する | |
veclist.Add(vec); | |
ret = true; | |
} | |
} | |
else | |
{ | |
veclist.Add(vec); | |
ret = true; | |
} | |
} | |
return ret; | |
} | |
public void Remove(Vector2 vec){ | |
if(veclist.Count <= 3){ | |
return; | |
} | |
for(var i=0;i<veclist.Count;i++){ | |
if (circleIn(veclist[i], vec, r)) | |
{ | |
veclist.RemoveAt(i); | |
break; | |
} | |
} | |
} | |
/// <summary> | |
/// 線分v1-v2上(太さ2*r)にpが存在するか | |
/// 点v1,v2付近ではfalseになる部分がある | |
/// </summary> | |
/// <param name="p"></param> | |
/// <param name="v1"></param> | |
/// <param name="v2"></param> | |
/// <param name="r"></param> | |
/// <returns></returns> | |
private static bool lineIn(Vector2 p,Vector2 v1,Vector2 v2,float r){ | |
float a = v2.x - v1.x; | |
float b = v2.y - v1.y; | |
float a2 = a * a; | |
float b2 = b * b; | |
float r2 = a2 + b2; | |
float tt = -(a*(v1.x-p.x)+b*(v1.y-p.y)); | |
float d2; | |
if(tt < 0){ | |
d2 = (v1.x-p.x)*(v1.x-p.x) + (v1.y-p.y)*(v1.y-p.y); | |
} | |
if(tt > r2){ | |
d2 = (v2.x-p.x)*(v2.x-p.x) + (v2.y-p.y)*(v2.y-p.y); | |
} | |
float f1 = a*(v1.y-p.y)-b*(v1.x-p.x); | |
d2 = (f1*f1)/r2; | |
if (d2<=r && dist2(v1,p) < r2 && dist2(v2,p) < r2){ | |
return true; | |
}else{ | |
return false; | |
} | |
} | |
/// <summary> | |
/// 2点間の距離の2乗 | |
/// </summary> | |
/// <param name="p1"></param> | |
/// <param name="p2"></param> | |
/// <returns></returns> | |
private static float dist2(Vector2 p1,Vector2 p2){ | |
float c =(p2.x - p1.x); | |
float d =(p2.y - p1.y); | |
return c*c + d*d; | |
} | |
private static bool circleIn(Vector2 mousevec, Vector2 plotvec, float r) | |
{ | |
if (Math.Pow(mousevec.x - plotvec.x, 2) + Math.Pow(mousevec.y - plotvec.y, 2) <= r * r) | |
{ | |
return true; | |
} | |
else | |
{ | |
return false; | |
} | |
} | |
} | |
public Material mat1; | |
Texture2D texture = null; | |
Texture2D guitexture = null; | |
private int canvasOffsetX = 240; | |
private int canvasOffsetY = 20; | |
private int canvasSize = 500; | |
private int selGridInt = 0; | |
private Color pathColor = new Color(0.5f,0.5f,0.5f); | |
private PathTool pt; | |
private int hoverindex = -1; | |
private bool drawTriangles; | |
private bool drawSurflines; | |
enum ToolType{ | |
AddEdit = 0,Remove = 1 | |
} | |
private string[] selCaptions = new string[] { | |
"Add/Edit", | |
"Remove", | |
}; | |
[MenuItem("Window/BroochEditor")] | |
private static void Create() | |
{ | |
// 生成 | |
var window = GetWindow<BroochEditor>("Brooch Editor"); | |
window.minSize = new Vector2(320, 320); | |
window.Init(); | |
} | |
private void Init(){ | |
pt = new PathTool(canvasSize, 5,pathColor); | |
mat1 = new Material(Shader.Find("Unlit/Transparent")); | |
} | |
void OnInspectorUpdate() | |
{ | |
if (EditorWindow.focusedWindow == this && | |
EditorWindow.mouseOverWindow == this) | |
{ | |
this.Repaint(); | |
} | |
} | |
public static void SetTextureImporterFormat(Texture2D texture, bool isReadable) | |
{ | |
if (texture.isReadable == isReadable){ | |
return; | |
} | |
string assetPath = AssetDatabase.GetAssetPath(texture); | |
var tImporter = AssetImporter.GetAtPath(assetPath) as TextureImporter; | |
if (tImporter != null) | |
{ | |
//tImporter.textureType = TextureImporterType.Default; | |
tImporter.isReadable = isReadable; | |
AssetDatabase.ImportAsset(assetPath); | |
AssetDatabase.Refresh(); | |
} | |
} | |
private void canvasClear(){ | |
pt.Clear(); | |
} | |
private void CreateMesh(){ | |
pt.triangles(); | |
pt.DrawTriangles = true; | |
} | |
void OnGUI() | |
{ | |
Event e = Event.current; | |
var cmp = new Vector2(e.mousePosition.x - canvasOffsetX,e.mousePosition.y - canvasOffsetY); | |
EditorGUILayout.BeginHorizontal(GUILayout.MaxWidth(200));{ | |
EditorGUILayout.BeginVertical(GUI.skin.box);{ | |
EditorGUILayout.BeginVertical(GUI.skin.box); | |
{ | |
var mp = e.mousePosition; | |
EditorGUILayout.LabelField("x:" + mp.x + " y:" + mp.y + " index:"+ hoverindex); | |
// if (e.type == EventType.MouseDown){ | |
// Debug.Log(mp); | |
// } | |
drawTriangles = EditorGUILayout.Toggle("drawTriangles",drawTriangles); | |
drawSurflines = EditorGUILayout.Toggle("drawSurflines",drawSurflines); | |
pt.DrawTriangles = drawTriangles; | |
pt.Drawsurflines = drawSurflines; | |
} | |
EditorGUILayout.EndVertical(); | |
EditorGUILayout.BeginVertical(GUI.skin.box);{ | |
EditorGUI.BeginChangeCheck(); | |
texture = EditorGUILayout.ObjectField("Reference Texture:", texture, typeof(Texture), false) as Texture2D; | |
if(EditorGUI.EndChangeCheck()){ | |
Debug.Log("ChangeTexture"); | |
if (texture != null){ | |
//SetTextureImporterFormat(texture,true); | |
} | |
} | |
}EditorGUILayout.EndVertical(); | |
EditorGUILayout.BeginVertical(GUI.skin.box);{ | |
EditorGUILayout.LabelField("Tools",EditorStyles.boldLabel); | |
selGridInt = GUILayout.SelectionGrid(selGridInt, selCaptions, 1, EditorStyles.radioButton); | |
EditorGUI.BeginChangeCheck(); | |
pathColor = EditorGUILayout.ColorField("Path Color", pathColor); | |
if(EditorGUI.EndChangeCheck()){ | |
pt.PathColor = pathColor; | |
guitexture = pt.canvas(); | |
} | |
}EditorGUILayout.EndVertical(); | |
// EditorGUILayout.BeginVertical(GUI.skin.box);{ | |
// GUILayout.Label("Base Settings", EditorStyles.boldLabel); | |
// // myString = EditorGUILayout.TextField("Text Field", myString); | |
// }EditorGUILayout.EndVertical(); | |
GUILayout.Label("Menu",EditorStyles.boldLabel); | |
if(GUILayout.Button("Clear")){ | |
canvasClear(); | |
guitexture = pt.canvas(); | |
} | |
EditorGUILayout.Space(); | |
EditorGUI.BeginDisabledGroup(!(pt.Closed && texture!=null));{ | |
if (GUILayout.Button("Create")) | |
{ | |
CreateMesh(); | |
} | |
}EditorGUI.EndDisabledGroup(); | |
}EditorGUILayout.EndVertical(); | |
} | |
if (texture != null) | |
{ | |
EditorGUI.DrawPreviewTexture(new Rect(240,20, 500, 500),texture,null,ScaleMode.StretchToFill,1,-1,UnityEngine.Rendering.ColorWriteMask.All); | |
} | |
if (0 < cmp.x && cmp.x < canvasSize && 0 < cmp.y && cmp.y < canvasSize) | |
{ | |
guitexture = CanvasBehaviour(e, cmp); | |
} | |
if(guitexture != null){ | |
EditorGUI.DrawPreviewTexture(new Rect(240,20,500,500),guitexture,mat1,ScaleMode.StretchToFill,0,-1,UnityEngine.Rendering.ColorWriteMask.All); | |
} | |
} | |
private Texture2D CanvasBehaviour(Event e,Vector2 canvasMousePosition){ | |
// if((ToolType)selGridInt==ToolType.Add){ | |
// switch(e.type){ | |
// case EventType.MouseDown: | |
// pt.Add(canvasMousePosition); | |
// break; | |
// } | |
// } | |
hoverindex = pt.Point(canvasMousePosition); | |
if((ToolType)selGridInt==ToolType.Remove){ | |
switch(e.type){ | |
case EventType.MouseDown: | |
pt.Remove(canvasMousePosition); | |
break; | |
} | |
}else if((ToolType)selGridInt==ToolType.AddEdit){ | |
switch(e.type){ | |
case EventType.MouseDown: | |
if(!pt.Add(canvasMousePosition)){ | |
pt.Select(canvasMousePosition); | |
} | |
break; | |
case EventType.MouseDrag: | |
pt.Move(canvasMousePosition); | |
break; | |
case EventType.MouseUp: | |
pt.ReleaseSelect(); | |
break; | |
} | |
} | |
pt.Point(canvasMousePosition); | |
return pt.canvas(); | |
} | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment