public static bool IsWindingInside(WindingRule rule, int n) { switch (rule) { case WindingRule.EvenOdd: return((n & 1) == 1); case WindingRule.NonZero: return(n != 0); case WindingRule.Positive: return(n > 0); case WindingRule.Negative: return(n < 0); case WindingRule.AbsGeqTwo: if (n < 2) { return(n <= -2); } return(true); default: throw new Exception("Wrong winding rule"); } }
public void Tessellate(WindingRule windingRule, ElementType elementType, int polySize, CombineCallback combineCallback) { _normal = Vec3.Zero; _vertices = null; _elements = null; _windingRule = windingRule; _combineCallback = combineCallback; if (_mesh != null) { ProjectPolygon(); ComputeInterior(); if (elementType == ElementType.BoundaryContours) { SetWindingNumber(1, true); } else { TessellateInterior(); } if (elementType == ElementType.BoundaryContours) { OutputContours(); } else { OutputPolymesh(elementType, polySize); } if (UsePooling) { _mesh.Free(); } _mesh = null; } }
public static void Triangulate(Vector2[][] paths, float edgeSmoothing, bool nonzero, out Vector2[] vertices, out ushort[] triangles) { Tess tess = new Tess(); foreach (Vector2[] path in paths) { List <ContourVertex> contour = new List <ContourVertex>(); for (var i = 0; i < path.Length; i++) { Vector2 oldPos = path[(path.Length + i - 1) % path.Length]; Vector2 currentPos = path[i]; Vector2 nextPos = path[(i + 1) % path.Length]; //edge smoothing if (Vector2.Dot((currentPos - oldPos).normalized, (nextPos - oldPos).normalized) >= 0.99f + Mathf.Pow(edgeSmoothing, 3) * 0.01) { continue; } contour.Add(new ContourVertex(new Vec3(currentPos.x, currentPos.y, 0))); } tess.AddContour(contour, ContourOrientation.CounterClockwise); } WindingRule windingRule = nonzero ? WindingRule.NonZero : WindingRule.EvenOdd; tess.Tessellate(windingRule); vertices = (tess.Vertices ?? Array.Empty <ContourVertex>()).Select(v => new Vector2(v.Position.X, v.Position.Y)).ToArray(); triangles = (tess.Elements ?? Array.Empty <int>()).Select(t => (ushort)t).ToArray(); }
public static bool IsWindingInside(WindingRule rule, int n) { switch (rule) { case WindingRule.EvenOdd: return((n & 1) == 1); case WindingRule.NonZero: return(n != 0); case WindingRule.Positive: return(n > 0); case WindingRule.Negative: return(n < 0); case WindingRule.AbsGeqTwo: return(n >= 2 || n <= -2); case WindingRule.OddPositive: return((n & 1) == 1 && n > 0); case WindingRule.OddNegative: return((n & 1) == 1 && n < 0); case WindingRule.EvenPositive: return((n & 1) == 0 && n > 0); case WindingRule.EvenNegative: return((n & 1) == 0 && n < 0); } throw new Exception("Wrong winding rule"); }
public Tess() { _normal = Vec3.Zero; _bminX = (_bminY = (_bmaxX = (_bmaxY = 0f))); _windingRule = WindingRule.EvenOdd; _mesh = null; _vertices = null; _vertexCount = 0; _elements = null; _elementCount = 0; }
public static bool IsWindingInside(WindingRule rule, int n) { return(rule switch { WindingRule.EvenOdd => (n & 1) == 1, WindingRule.NonZero => n != 0, WindingRule.Positive => n > 0, WindingRule.Negative => n < 0, WindingRule.AbsGeqTwo => n is >= 2 or <= -2, _ => throw new Exception("Wrong winding rule") });
public void Tessellate(WindingRule windingRule, ElementType elementType, int polySize, CombineCallback combineCallback) { _normal = Vec3.Zero; _vertices = null; _elements = null; _windingRule = windingRule; _combineCallback = combineCallback; if (_mesh == null) { return; } // Determine the polygon normal and project vertices onto the plane // of the polygon. ProjectPolygon(); // ComputeInterior computes the planar arrangement specified // by the given contours, and further subdivides this arrangement // into regions. Each region is marked "inside" if it belongs // to the polygon, according to the rule given by windingRule. // Each interior region is guaranteed be monotone. ComputeInterior(); // If the user wants only the boundary contours, we throw away all edges // except those which separate the interior from the exterior. // Otherwise we tessellate all the regions marked "inside". if (elementType == ElementType.BoundaryContours) { SetWindingNumber(1, true); } else { TessellateInterior(); } _mesh.Check(); if (elementType == ElementType.BoundaryContours) { OutputContours(); } else { OutputPolymesh(elementType, polySize); } if (UsePooling) { _mesh.Free(); } _mesh = null; }
private void SetWindingRule(WindingRule windingRule) { for (int i = 0; i < _windingRules.Length; i++) { if (_windingRules[i] == Enum.GetName(windingRule.GetType(), windingRule)) { toolStripWinding.SelectedIndex = i; break; } } }
public TestData ParseTestData(WindingRule winding, int elementSize, Stream resourceStream) { var lines = new List <string>(); bool found = false; using (var stream = new StreamReader(resourceStream)) { string line; while ((line = stream.ReadLine()) != null) { line = line.Trim(); if (found && string.IsNullOrEmpty(line)) { break; } if (found) { lines.Add(line); } var parts = line.Split(' '); if (parts.FirstOrDefault() == winding.ToString() && Int32.Parse(parts.LastOrDefault()) == elementSize) { found = true; } } } var indices = new List <int>(); foreach (var line in lines) { var parts = line.Split(' '); if (parts.Length != elementSize) { continue; } foreach (var part in parts) { indices.Add(Int32.Parse(part)); } } if (found) { return(new TestData() { ElementSize = elementSize, Indices = indices.ToArray() }); } return(null); }
public TestData ParseTestData(WindingRule winding, int elementSize, Stream resourceStream) { var lines = new List<string>(); bool found = false; using (var stream = new StreamReader(resourceStream)) { string line; while ((line = stream.ReadLine()) != null) { line = line.Trim(); if (found && string.IsNullOrEmpty(line)) { break; } if (found) { lines.Add(line); } var parts = line.Split(' '); if (parts.FirstOrDefault() == winding.ToString() && Int32.Parse(parts.LastOrDefault()) == elementSize) { found = true; } } } var indices = new List<int>(); foreach (var line in lines) { var parts = line.Split(' '); if (parts.Length != elementSize) { continue; } foreach (var part in parts) { indices.Add(Int32.Parse(part)); } } if (found) { return new TestData() { ElementSize = elementSize, Indices = indices.ToArray() }; } return null; }
public static bool IsWindingInside(WindingRule rule, int n) { switch (rule) { case WindingRule.EvenOdd: return (n & 1) == 1; case WindingRule.NonZero: return n != 0; case WindingRule.Positive: return n > 0; case WindingRule.Negative: return n < 0; case WindingRule.AbsGeqTwo: return n >= 2 || n <= -2; } throw new Exception("Wrong winding rule"); }
public Tess(IPool pool) { _normal = Vec3.Zero; _bminX = _bminY = _bmaxX = _bmaxY = 0; _windingRule = WindingRule.EvenOdd; _pool = _pool switch { null => new NullPool(), _ => pool }; _mesh = null; _vertices = null; _vertexCount = 0; _elements = null; _elementCount = 0; }
public Tess(IPool pool) { _normal = Vec3.Zero; _bminX = _bminY = _bmaxX = _bmaxY = 0; _windingRule = WindingRule.EvenOdd; _pool = pool; if (_pool == null) { _pool = new NullPool(); } _mesh = null; _vertices = null; _vertexCount = 0; _elements = null; _elementCount = 0; }
/** * This method tests if the point is on the polygon. */ public bool PointInPoly(Point2d p, WindingRule windingRule, bool extendedAlgorithm, double epsilon = MathUtils.EPSILON) { switch (windingRule) { case WindingRule.EvenOdd: { return(this.PointInPolyEvenOdd(p, extendedAlgorithm, epsilon)); } case WindingRule.NonZero: { return(this.PointInPolyNonZero(p, extendedAlgorithm, epsilon)); } default: { throw new IndexOutOfRangeException(); } } }
public void Tessellate(WindingRule windingRule, ElementType elementType, int polySize, CombineCallback combineCallback) { Tessellate(windingRule, elementType, polySize, combineCallback, Vec3.Zero); }
public MainForm() { InitializeComponent(); _canvas = new Canvas(); _canvas.Dock = DockStyle.Fill; panel.Controls.Add(_canvas); _assets = _data.AssetNames; Array.Sort(_assets); foreach (var asset in _assets) { toolStripAssets.Items.Add(asset); } toolStripAssets.SelectedIndexChanged += delegate(object sender, EventArgs e) { RefreshAsset(toolStripAssets.SelectedIndex); }; _windingRules = Enum.GetNames(typeof(WindingRule)); foreach (var windingRule in _windingRules) { toolStripWinding.Items.Add(windingRule); } toolStripWinding.SelectedIndexChanged += delegate(object sender, EventArgs e) { _windingRule = (WindingRule)toolStripWinding.SelectedIndex; if (toolStripAssets.SelectedIndex >= 0) { RefreshAsset(toolStripAssets.SelectedIndex); } }; toolStripPolySize.KeyDown += delegate(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) { PolySizeEvent(); } }; toolStripPolySize.Leave += delegate(object sender, EventArgs e) { PolySizeEvent(); }; toolStripButtonShowInput.CheckedChanged += delegate(object sender, EventArgs e) { _canvas.ShowInput = toolStripButtonShowInput.Checked; toolStripButtonShowWinding.Enabled = _canvas.ShowInput; if (toolStripAssets.SelectedIndex >= 0) { RefreshAsset(toolStripAssets.SelectedIndex); } }; toolStripButtonShowWinding.CheckedChanged += delegate(object sender, EventArgs e) { _canvas.ShowWinding = toolStripButtonShowWinding.Checked; if (toolStripAssets.SelectedIndex >= 0) { RefreshAsset(toolStripAssets.SelectedIndex); } }; toolStripButtonBench.Click += delegate(object sender, EventArgs e) { new BenchForm().ShowDialog(this); }; SetAsset("redbook-winding"); SetShowInput(true); SetShowWinding(false); SetPolySize(3); SetWindingRule(WindingRule.EvenOdd); }
public Tess() { _normal = Vector3.Zero; _bminX = _bminY = _bmaxX = _bmaxY = 0.0f; _windingRule = WindingRule.EvenOdd; _mesh = null; _vertices = new CCRawList<Vector3>(true); _elements = new CCRawList<int>(true); }
void OnGUI() { DTInspectorNode.IsInsideInspector = false; if (Curves.Count == 0) { return; } Mode = GUILayout.SelectionGrid(Mode, new GUIContent[] { new GUIContent("Closed Shape", "Export a closed shape with triangles"), new GUIContent("Vertex Line", "Export a vertex line") }, 2); if (!string.IsNullOrEmpty(TriangulationMessage) && !TriangulationMessage.Contains("Angle must be >0")) { EditorGUILayout.HelpBox(TriangulationMessage, MessageType.Error); } scroll = EditorGUILayout.BeginScrollView(scroll); // OUTLINE GUIRenderer.RenderSectionHeader(nSplines); if (nSplines.ContentVisible) { Winding = (WindingRule)EditorGUILayout.EnumPopup("Winding", Winding, GUILayout.Width(285)); GUILayout.BeginHorizontal(); GUILayout.Label(new GUIContent("Spline", "Note: Curves from a SplineGroup needs to be connected!"), EditorStyles.boldLabel, GUILayout.Width(140)); GUILayout.Label("Vertex Generation", EditorStyles.boldLabel, GUILayout.Width(160)); GUILayout.Label("Orientation", EditorStyles.boldLabel); GUILayout.EndHorizontal(); CurveGUI(Curves[0]); if (Mode == CLOSEDSHAPE) { for (int i = 1; i < Curves.Count; i++) { CurveGUI(Curves[i]); } if (GUILayout.Button(CurvyStyles.AddSmallTexture, GUILayout.ExpandWidth(false))) { Curves.Add(new SplinePolyLine(null)); } } } mNeedRepaint = mNeedRepaint || nSplines.NeedRepaint; GUIRenderer.RenderSectionFooter(nSplines); // TEXTURING GUIRenderer.RenderSectionHeader(nTexture); if (nTexture.ContentVisible) { Mat = (Material)EditorGUILayout.ObjectField("Material", Mat, typeof(Material), true, GUILayout.Width(285)); UVTiling = EditorGUILayout.Vector2Field("Tiling", UVTiling, GUILayout.Width(285)); UVOffset = EditorGUILayout.Vector2Field("Offset", UVOffset, GUILayout.Width(285)); } GUIRenderer.RenderSectionFooter(nTexture); mNeedRepaint = mNeedRepaint || nTexture.NeedRepaint; // EXPORT GUIRenderer.RenderSectionHeader(nExport); if (nExport.ContentVisible) { EditorGUILayout.HelpBox("Export is 2D (x/y) only!", MessageType.Info); MeshName = EditorGUILayout.TextField("Mesh Name", MeshName, GUILayout.Width(285)); UV2 = EditorGUILayout.Toggle("Add UV2", UV2); GUILayout.BeginHorizontal(); if (GUILayout.Button("Save as Asset")) { string path = EditorUtility.SaveFilePanelInProject("Save Mesh", MeshName + ".asset", "asset", "Choose a file location"); if (!string.IsNullOrEmpty(path)) { Mesh msh = clonePreviewMesh(); if (msh) { msh.name = MeshName; AssetDatabase.DeleteAsset(path); AssetDatabase.CreateAsset(msh, path); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); DTLog.Log("[Curvy] Export: Mesh Asset saved!"); } } } if (GUILayout.Button("Create GameObject")) { Mesh msh = clonePreviewMesh(); if (msh) { msh.name = MeshName; var go = new GameObject(MeshName, typeof(MeshRenderer), typeof(MeshFilter)); go.GetComponent <MeshFilter>().sharedMesh = msh; go.GetComponent <MeshRenderer>().sharedMaterial = Mat; Selection.activeGameObject = go; DTLog.Log("[Curvy] Export: GameObject created!"); } else { DTLog.LogWarning("[Curvy] Export: Unable to triangulate spline!"); } } GUILayout.EndHorizontal(); } GUIRenderer.RenderSectionFooter(nExport); mNeedRepaint = mNeedRepaint || nExport.NeedRepaint; EditorGUILayout.EndScrollView(); refreshNow = refreshNow || GUI.changed; if (mNeedRepaint) { Repaint(); mNeedRepaint = false; } }
public void Tessellate(WindingRule windingRule, ElementType elementType, int polySize) { Tessellate(windingRule, elementType, polySize, null); }
public MainForm() { InitializeComponent(); _canvas = new Canvas(); _canvas.Dock = DockStyle.Fill; panel.Controls.Add(_canvas); foreach (var asset in _data.Assets) { toolStripAssets.Items.Add(asset); } toolStripAssets.SelectedIndexChanged += delegate(object sender, EventArgs e) { if (toolStripAssets.SelectedIndex >= 0) { var asset = toolStripAssets.SelectedItem as DataLoader.Asset; _polys = asset.Polygons; RefreshCanvas(); } }; _windingRules = Enum.GetNames(typeof(WindingRule)); foreach (var windingRule in _windingRules) { toolStripWinding.Items.Add(windingRule); } toolStripWinding.SelectedIndexChanged += delegate(object sender, EventArgs e) { _windingRule = (WindingRule)toolStripWinding.SelectedIndex; RefreshCanvas(); }; toolStripPolySize.KeyDown += delegate(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) { PolySizeEvent(); } }; toolStripPolySize.Leave += delegate(object sender, EventArgs e) { PolySizeEvent(); }; toolStripButtonShowInput.CheckedChanged += delegate(object sender, EventArgs e) { _canvas.ShowInput = toolStripButtonShowInput.Checked; toolStripButtonShowWinding.Enabled = _canvas.ShowInput; RefreshCanvas(); }; toolStripButtonShowWinding.CheckedChanged += delegate(object sender, EventArgs e) { _canvas.ShowWinding = toolStripButtonShowWinding.Checked; RefreshCanvas(); }; toolStripButtonNoEmpty.CheckedChanged += delegate(object sender, EventArgs e) { _tess.NoEmptyPolygons = toolStripButtonNoEmpty.Checked; RefreshCanvas(); }; toolStripButtonBench.Click += delegate(object sender, EventArgs e) { new BenchForm().ShowDialog(this); }; toolStripButtonFile.Click += delegate(object sender, EventArgs e) { var dialog = new OpenFileDialog(); dialog.Filter = "Test Files (*.dat)|*.dat|All Files (*.*)|*.*"; dialog.FilterIndex = 1; dialog.RestoreDirectory = true; if (dialog.ShowDialog() == DialogResult.OK) { var polygons = DataLoader.LoadDat(dialog.OpenFile()); _polys = polygons; RefreshCanvas(); toolStripAssets.SelectedIndex = -1; } }; toolStripButtonFolder.Click += delegate(object sender, EventArgs e) { var dialog = new FolderBrowserDialog(); if (dialog.ShowDialog() == DialogResult.OK) { var files = Directory.GetFiles(dialog.SelectedPath, "*.dat"); if (files.Length > 0) { toolStripAssets.Items.Clear(); _polys = null; foreach (var file in files) { using (var stream = new FileStream(file, FileMode.Open)) { var polygons = DataLoader.LoadDat(stream); if (_polys == null) { _polys = polygons; } toolStripAssets.Items.Add(new DataLoader.Asset() { Name = Path.GetFileName(file), Polygons = polygons }); } } toolStripAssets.SelectedIndex = 0; RefreshCanvas(); } } }; SetAsset("redbook-winding"); SetShowInput(true); SetShowWinding(false); SetPolySize(3); SetWindingRule(WindingRule.EvenOdd); }
public Tess() { _normal = Vec3.Zero; _bminX = _bminY = _bmaxX = _bmaxY = 0.0f; _windingRule = WindingRule.EvenOdd; _mesh = null; _vertices = null; _vertexCount = 0; _elements = null; _elementCount = 0; }
public MainForm() { InitializeComponent(); _canvas = new Canvas(); _canvas.Dock = DockStyle.Fill; panel.Controls.Add(_canvas); _assets = _data.AssetNames; Array.Sort(_assets); foreach (var asset in _assets) { toolStripAssets.Items.Add(asset); } toolStripAssets.SelectedIndexChanged += delegate(object sender, EventArgs e) { RefreshAsset(toolStripAssets.SelectedIndex); }; _windingRules = Enum.GetNames(typeof(WindingRule)); foreach (var windingRule in _windingRules) { toolStripWinding.Items.Add(windingRule); } toolStripWinding.SelectedIndexChanged += delegate(object sender, EventArgs e) { _windingRule = (WindingRule)toolStripWinding.SelectedIndex; if (toolStripAssets.SelectedIndex >= 0) { RefreshAsset(toolStripAssets.SelectedIndex); } }; toolStripPolySize.KeyDown += delegate(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) { PolySizeEvent(); } }; toolStripPolySize.Leave += delegate(object sender, EventArgs e) { PolySizeEvent(); }; toolStripButtonShowInput.CheckedChanged += delegate(object sender, EventArgs e) { _canvas.ShowInput = toolStripButtonShowInput.Checked; toolStripButtonShowWinding.Enabled = _canvas.ShowInput; RefreshAsset(toolStripAssets.SelectedIndex); }; toolStripButtonShowWinding.CheckedChanged += delegate(object sender, EventArgs e) { _canvas.ShowWinding = toolStripButtonShowWinding.Checked; RefreshAsset(toolStripAssets.SelectedIndex); }; toolStripButtonNoEmpty.CheckedChanged += delegate(object sender, EventArgs e) { _tess.NoEmptyPolygons = toolStripButtonNoEmpty.Checked; RefreshAsset(toolStripAssets.SelectedIndex); }; toolStripButtonBench.Click += delegate(object sender, EventArgs e) { new BenchForm().ShowDialog(this); }; toolStripButtonOpen.Click += delegate(object sender, EventArgs e) { var dialog = new OpenFileDialog(); dialog.Filter = "Test Files (*.dat)|*.dat|All Files (*.*)|*.*"; dialog.FilterIndex = 1; dialog.RestoreDirectory = true; if (dialog.ShowDialog() == DialogResult.OK) { var polygons = DataLoader.LoadDat(dialog.OpenFile()); RefreshAsset(polygons); toolStripAssets.SelectedIndex = -1; } }; SetAsset("redbook-winding"); SetShowInput(true); SetShowWinding(false); SetPolySize(3); SetWindingRule(WindingRule.EvenOdd); }
public void Tessellate(WindingRule windingRule, ElementType elementType, int polySize, CombineCallback combineCallback) { _vertices = null; _elements = null; _windingRule = windingRule; _combineCallback = combineCallback; if (_mesh == null) { return; } // Determine the polygon normal and project vertices onto the plane // of the polygon. ProjectPolygon(); // ComputeInterior computes the planar arrangement specified // by the given contours, and further subdivides this arrangement // into regions. Each region is marked "inside" if it belongs // to the polygon, according to the rule given by windingRule. // Each interior region is guaranteed be monotone. ComputeInterior(); // If the user wants only the boundary contours, we throw away all edges // except those which separate the interior from the exterior. // Otherwise we tessellate all the regions marked "inside". if (elementType == ElementType.BoundaryContours) { SetWindingNumber(1, true); } else { TessellateInterior(); } _mesh.Check(); if (elementType == ElementType.BoundaryContours) { OutputContours(); } else { OutputPolymesh(elementType, polySize); } _mesh = null; }
/// <summary> /// Tessellates the input contours. /// </summary> /// <param name="windingRule"> Winding rule used for tessellation. See <see cref="WindingRule"/> for details. </param> /// <param name="elementType"> Tessellation output type. See <see cref="ElementType"/> for details. </param> /// <param name="polySize"> Number of vertices per polygon if output is polygons. </param> /// <param name="combineCallback"> Interpolator used to determine the data payload of generated vertices. </param> /// <param name="normal"> Normal of the input contours. If set to zero, the normal will be calculated during tessellation. </param> public void Tessellate(WindingRule windingRule = WindingRule.EvenOdd, ElementType elementType = ElementType.Polygons, int polySize = 3, CombineCallback combineCallback = null, Vector3 normal = new Vector3()) { tess.Tessellate(windingRule, elementType, polySize, combineCallback, new Vec3(normal.x, normal.y, normal.z)); }
public MainForm() { InitializeComponent(); _canvas = new Canvas(); _canvas.Dock = DockStyle.Fill; panel.Controls.Add(_canvas); _assets = _data.AssetNames; Array.Sort(_assets); foreach (var asset in _assets) { toolStripAssets.Items.Add(asset); } toolStripAssets.SelectedIndexChanged += delegate(object sender, EventArgs e) { RefreshAsset(toolStripAssets.SelectedIndex); }; _windingRules = Enum.GetNames(typeof(WindingRule)); foreach (var windingRule in _windingRules) { toolStripWinding.Items.Add(windingRule); } toolStripWinding.SelectedIndexChanged += delegate(object sender, EventArgs e) { _windingRule = (WindingRule)toolStripWinding.SelectedIndex; RefreshAsset(toolStripAssets.SelectedIndex); }; toolStripPolySize.KeyDown += delegate(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) { PolySizeEvent(); } }; toolStripPolySize.Leave += delegate(object sender, EventArgs e) { PolySizeEvent(); }; toolStripButtonShowInput.CheckedChanged += delegate(object sender, EventArgs e) { _canvas.ShowInput = toolStripButtonShowInput.Checked; toolStripButtonShowWinding.Enabled = _canvas.ShowInput; RefreshAsset(toolStripAssets.SelectedIndex); }; toolStripButtonShowWinding.CheckedChanged += delegate(object sender, EventArgs e) { _canvas.ShowWinding = toolStripButtonShowWinding.Checked; RefreshAsset(toolStripAssets.SelectedIndex); }; toolStripButtonBench.Click += delegate(object sender, EventArgs e) { new BenchForm().ShowDialog(this); }; SetAsset("redbook-winding"); SetShowInput(true); SetShowWinding(false); SetPolySize(3); SetWindingRule(WindingRule.EvenOdd); }