/// <summary> /// Returns true if vertex lies on the edge of triangle mesh /// </summary> /// <param name="vertex"></param> /// <returns></returns> public static bool IsOnEdge(Vector3 vertex, SceneBrep scene) { bool onEdge = false; var handle = scene.GetVertex(vertex); List <int> trianglePtr = new List <int>(); // get triangles for (int i = 0; i < scene.vertexPtr.Count; i++) { if (scene.vertexPtr[i] == handle) { if (i % 3 == 0) { trianglePtr.Add(i / 3); } else if (i % 3 == 1) { trianglePtr.Add((i - 1) / 3); } else if (i % 3 == 2) { trianglePtr.Add((i - 2) / 3); } } } // is triangle on edge? foreach (var ptr in trianglePtr) { // get handle of corners of triangle var c1 = Scene3D.SceneBrep.tCorner(ptr); var c2 = c1 + 1; var c3 = c1 + 2; if (scene.cOpposite(c1) == -1) { onEdge = true; } else if (scene.cOpposite(c2) == -1) { onEdge = true; } else if (scene.cOpposite(c3) == -1) { onEdge = true; } } return(onEdge); }
/// <summary> /// Do Loop subdivision of the input control triangle mesh. /// </summary> /// <param name="scene">Input scene (must not be changed).</param> /// <param name="epsilon">Reference error toleration (size of undivided triangle).</param> /// <param name="normals">Generate normals? (optional)</param> /// <param name="colors">Generate colors? (optional)</param> /// <param name="txtcoord">Generate texture coordinates? (optional)</param> /// <param name="time">Current time for animation (optional)</param> /// <param name="param">Optional additional parameters.</param> /// <returns>Number of generated points.</returns> public int Subdivide(SceneBrep scene, float epsilon, bool normals, bool colors, bool txtcoord, float time, string param) { result = scene.Clone(); // !!!{{ TODO: put your Loop subdivision code here // pilot: do one (trivial) division int triangles = result.Triangles; int tr; for (tr = 0; tr < triangles; tr++) { int A, B, C; result.GetTriangleVertices(tr, out A, out B, out C); Vector3 vA = result.GetVertex(A); Vector3 vB = result.GetVertex(B); Vector3 vC = result.GetVertex(C); Vector3 vA2 = (vB + vC) * 0.5f; Vector3 vB2 = (vA + vC) * 0.5f; Vector3 vC2 = (vA + vB) * 0.5f; int A2 = result.AddVertex(vA2); int B2 = result.AddVertex(vB2); int C2 = result.AddVertex(vC2); result.AddTriangle(B2, C2, A2); result.AddTriangle(B2, A2, C); result.AddTriangle(C2, B, A2); result.SetTriangleVertices(tr, A, C2, B2); } //result.BuildCornerTable(); return(result.Vertices); // !!!}} }
/// <summary> /// Writes the whole B-rep scene to a given text stream (uses text variant of Wavefront OBJ format). /// </summary> /// <param name="writer">Already open text writer</param> /// <param name="scene">Scene to write</param> public void WriteBrep(StreamWriter writer, SceneBrep scene) { if (scene == null || scene.Triangles < 1) { return; } int i; for (i = 0; i < scene.Vertices; i++) { Vector3 v = scene.GetVertex(i); writer.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0} {1} {2} {3}", new object[] { VERTEX, v.X, v.Y, v.Z })); } bool hasNormals = scene.Normals > 0; if (hasNormals) { for (i = 0; i < scene.Vertices; i++) { Vector3 n = scene.GetNormal(i); writer.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0} {1} {2} {3}", new object[] { VERTEX_NORMAL, n.X, n.Y, n.Z })); } } for (i = 0; i < scene.Triangles; i++) { int A, B, C; scene.GetTriangleVertices(i, out A, out B, out C); A++; B++; C++; if (hasNormals) { writer.WriteLine("{0} {1}//{1} {2}//{2} {3}//{3}", FACE, A, B, C); } else { writer.WriteLine("{0} {1} {2} {3}", FACE, A, B, C); } } }
public EarClipping(List <int> pointers, Scene3D.SceneBrep scene) { // Polygon has at least 3 vertices if (pointers.Count < 3) { return; } this.Scene = scene; // Get coordinates from vertex pointers PolygonVertices = new List <Vector3>(); pointers.ForEach(x => PolygonVertices.Add(Scene.GetVertex(x))); PrepareNormal(PolygonVertices); polygon = new Polygon(); copy = new Polygon(); CreatePolygon(polygon, PolygonVertices); CreatePolygon(copy, PolygonVertices); }
/// <summary> /// Writes the whole B-rep scene to a given text stream (uses text variant of Wavefront OBJ format). /// </summary> /// <param name="writer">Already open text writer</param> /// <param name="scene">Scene to write</param> public void WriteBrep( StreamWriter writer, SceneBrep scene ) { if ( scene == null || scene.Triangles < 1 ) return; int i; for ( i = 0; i < scene.Vertices; i++ ) { Vector3 v = scene.GetVertex( i ); writer.WriteLine( String.Format( CultureInfo.InvariantCulture, "{0} {1} {2} {3}", new object[] { VERTEX, v.X, v.Y, v.Z } ) ); } bool hasNormals = scene.Normals > 0; if ( hasNormals ) for ( i = 0; i < scene.Vertices; i++ ) { Vector3 n = scene.GetNormal( i ); writer.WriteLine( String.Format( CultureInfo.InvariantCulture, "{0} {1} {2} {3}", new object[] { VERTEX_NORMAL, n.X, n.Y, n.Z } ) ); } for ( i = 0; i < scene.Triangles; i++ ) { int A, B, C; scene.GetTriangleVertices( i, out A, out B, out C ); A++; B++; C++; if ( hasNormals ) writer.WriteLine( "{0} {1}//{1} {2}//{2} {3}//{3}", FACE, A, B, C ); else writer.WriteLine( "{0} {1} {2} {3}", FACE, A, B, C ); } }
public void Render(Bitmap output, SceneBrep scene) { if (output == null || scene == null) { return; } Vector3 center; float diameter = scene.GetDiameter(out center); if (Distance < diameter) { Distance = diameter; } // and the rest of projection matrix goes here: int width = output.Width; int height = output.Height; float aspect = width / (float)height; double az = Azimuth / 180.0 * Math.PI; double el = Elevation / 180.0 * Math.PI; Vector3 eye = new Vector3((float)(center.X + Distance * Math.Sin(az) * Math.Cos(el)), (float)(center.Y + Distance * Math.Sin(el)), (float)(center.Z + Distance * Math.Cos(az) * Math.Cos(el))); Matrix4 modelView = Matrix4.LookAt(eye, center, Vector3.UnitY); Matrix4 proj; if (Perspective) { float vv = (float)(2.0 * Math.Atan2(diameter * 0.5, Distance)); proj = Matrix4.CreatePerspectiveFieldOfView(vv, aspect, 1.0f, 50.0f); } else { float vHalf = diameter * 0.52f; proj = Matrix4.CreateOrthographicOffCenter(-vHalf, vHalf, -vHalf / aspect, vHalf / aspect, 1.0f, 50.0f); } Matrix4 compound = Matrix4.Mult(modelView, proj); Matrix4 viewport = Geometry.SetViewport(0, 0, width, height); compound = Matrix4.Mult(compound, viewport); // wireframe rendering: Graphics gr = Graphics.FromImage(output); Pen pen = new Pen(Color.FromArgb(255, 255, 80), 1.0f); int n = scene.Triangles; for (int i = 0; i < n; i++) { Vector4 A, B, C; scene.GetTriangleVertices(i, out A, out B, out C); A = Vector4.Transform(A, compound); B = Vector4.Transform(B, compound); C = Vector4.Transform(C, compound); Vector2 a = new Vector2(A.X / A.W, A.Y / A.W); Vector2 b = new Vector2(B.X / B.W, B.Y / B.W); Vector2 c = new Vector2(C.X / C.W, C.Y / C.W); gr.DrawLine(pen, a.X, a.Y, b.X, b.Y); gr.DrawLine(pen, b.X, b.Y, c.X, c.Y); gr.DrawLine(pen, c.X, c.Y, a.X, a.Y); } if (DrawNormals && scene.Normals > 0) { pen = new Pen(Color.FromArgb(255, 80, 80), 1.0f); n = scene.Vertices; for (int i = 0; i < n; i++) { Vector4 V = new Vector4(scene.GetVertex(i), 1.0f); Vector3 N = scene.GetNormal(i); N.Normalize(); N *= diameter * 0.03f; Vector4 W = V + new Vector4(N); V = Vector4.Transform(V, compound); W = Vector4.Transform(W, compound); Vector2 v = new Vector2(V.X / V.W, V.Y / V.W); Vector2 w = new Vector2(W.X / W.W, W.Y / W.W); gr.DrawLine(pen, v.X, v.Y, w.X, w.Y); } } }
public void Render( Bitmap output, SceneBrep scene ) { if ( output == null || scene == null ) return; // center of the object = point to look at: double cx = 0.0; double cy = 0.0; double cz = 0.0; float minx = float.MaxValue; float miny = float.MaxValue; float minz = float.MaxValue; float maxx = float.MinValue; float maxy = float.MinValue; float maxz = float.MinValue; int n = scene.Vertices; int i; for ( i = 0; i < n; i++ ) { Vector3 vi = scene.GetVertex( i ); cx += vi.X; cy += vi.Y; cz += vi.Z; if ( vi.X < minx ) minx = vi.X; if ( vi.Y < miny ) miny = vi.Y; if ( vi.Z < minz ) minz = vi.Z; if ( vi.X > maxx ) maxx = vi.X; if ( vi.Y > maxy ) maxy = vi.Y; if ( vi.Z > maxz ) maxz = vi.Z; } Vector3 center = new Vector3( (float)(cx / n), (float)(cy / n), (float)(cz / n) ); float diameter = (float)Math.Sqrt( (maxx - minx) * (maxx - minx) + (maxy - miny) * (maxy - miny) + (maxz - minz) * (maxz - minz) ); if ( Distance < diameter ) Distance = diameter; // and the rest of projection matrix goes here: int width = output.Width; int height = output.Height; float aspect = width / (float)height; double az = Azimuth / 180.0 * Math.PI; double el = Elevation / 180.0 * Math.PI; Vector3 eye = new Vector3( (float)(center.X + Distance * Math.Sin( az ) * Math.Cos( el )), (float)(center.Y + Distance * Math.Sin( el )), (float)(center.Z + Distance * Math.Cos( az ) * Math.Cos( el )) ); Matrix4 modelView = Matrix4.LookAt( eye, center, Vector3.UnitY ); Matrix4 proj; if ( Perspective ) { float vv = (float)(2.0 * Math.Atan2( diameter * 0.5, Distance )); proj = Matrix4.CreatePerspectiveFieldOfView( vv, aspect, 1.0f, 50.0f ); } else { float vHalf = diameter * 0.52f; proj = Matrix4.CreateOrthographicOffCenter( -vHalf, vHalf, -vHalf / aspect, vHalf / aspect, 1.0f, 50.0f ); } Matrix4 compound = Matrix4.Mult( modelView, proj ); Matrix4 viewport = Geometry.SetViewport( 0, 0, width, height ); compound = Matrix4.Mult( compound, viewport ); // wireframe rendering: Graphics gr = Graphics.FromImage( output ); Pen pen = new Pen( Color.FromArgb( 255, 255, 80 ), 1.0f ); n = scene.Triangles; for ( i = 0; i < n; i++ ) { Vector4 A, B, C; scene.GetTriangleVertices( i, out A, out B, out C ); A = Vector4.Transform( A, compound ); B = Vector4.Transform( B, compound ); C = Vector4.Transform( C, compound ); Vector2 a = new Vector2( A.X / A.W, A.Y / A.W ); Vector2 b = new Vector2( B.X / B.W, B.Y / B.W ); Vector2 c = new Vector2( C.X / C.W, C.Y / C.W ); gr.DrawLine( pen, a.X, a.Y, b.X, b.Y ); gr.DrawLine( pen, b.X, b.Y, c.X, c.Y ); gr.DrawLine( pen, c.X, c.Y, a.X, a.Y ); } if ( DrawNormals && scene.Normals > 0 ) { pen = new Pen( Color.FromArgb( 255, 80, 80 ), 1.0f ); n = scene.Vertices; for ( i = 0; i < n; i++ ) { Vector4 V = new Vector4( scene.GetVertex( i ), 1.0f ); Vector3 N = scene.GetNormal( i ); N.Normalize(); N *= diameter * 0.03f; Vector4 W = V + new Vector4( N ); V = Vector4.Transform( V, compound ); W = Vector4.Transform( W, compound ); Vector2 v = new Vector2( V.X / V.W, V.Y / V.W ); Vector2 w = new Vector2( W.X / W.W, W.Y / W.W ); gr.DrawLine( pen, v.X, v.Y, w.X, w.Y ); } } }
/// <summary> /// Writes the whole B-rep scene to a given text stream (uses text variant of Stanford PLY format). /// </summary> /// <param name="writer">Already open text writer</param> /// <param name="scene">Scene to write</param> public void WriteBrepSelection(StreamWriter writer, SceneBrep scene, Selection selection, IProgress <string> progress, CancellationToken cancel, out List <int> trianglePointers, out List <int> vertexPointers) { DoNormals = true; DoTxtCoords = true; DoColors = true; vertexPointers = new List <int>(); trianglePointers = new List <int>(); if (scene == null || selection.GetCount() < 3) { return; } vertexPointers = selection.SelectionPointers; Debug.Assert(TextFormat); if (!NativeNewLine) { writer.NewLine = "\r"; // CR only } bool writeNormals = DoNormals && scene.HasNormals(); bool writeTxtCoords = DoTxtCoords && scene.HasTxtCoords(); bool writeColors = DoColors && scene.HasColors(); writer.WriteLine(HEADER); writer.WriteLine(FORMAT_TEXT); // vertex-header: writer.WriteLine("{0} {1} {2}", ELEMENT, VERTEX, selection.GetCount()); writer.WriteLine("{0} float x", PROPERTY); writer.WriteLine("{0} float {1}", PROPERTY, Orientation ? 'z' : 'y'); writer.WriteLine("{0} float {1}", PROPERTY, Orientation ? 'y' : 'z'); if (writeNormals) { writer.WriteLine("{0} float {1}", PROPERTY, NORMAL_X); writer.WriteLine("{0} float {1}", PROPERTY, Orientation ? NORMAL_Z : NORMAL_Y); writer.WriteLine("{0} float {1}", PROPERTY, Orientation ? NORMAL_Y : NORMAL_Z); } if (writeTxtCoords) { writer.WriteLine("{0} float {1}", PROPERTY, TEXTURE_S); writer.WriteLine("{0} float {1}", PROPERTY, TEXTURE_T); } if (writeColors) { writer.WriteLine("{0} float {1}", PROPERTY, COLOR_R); writer.WriteLine("{0} float {1}", PROPERTY, COLOR_G); writer.WriteLine("{0} float {1}", PROPERTY, COLOR_B); } var triangles = selection.GetSelectedTriangles(); var list = new List <int>(); int A, B, C; for (int j = 0; j < triangles.Count; j++) { scene.GetTriangleVertices(triangles[j], out A, out B, out C); int Anew = selection.SelectionPointers.IndexOf(A); int Bnew = selection.SelectionPointers.IndexOf(B); int Cnew = selection.SelectionPointers.IndexOf(C); // if this vertex was not selected, do not export the triangle containing it if (Anew == -1 || Bnew == -1 || Cnew == -1) { continue; } // save vertex indices of triangles that were selected // this supports bach export trianglePointers.Add(triangles[j]); // otherwise add vertices with their new indices to list list.Add(Anew); list.Add(Bnew); list.Add(Cnew); cancel.ThrowIfCancellationRequested(); } // face-header: writer.WriteLine("{0} {1} {2}", ELEMENT, FACE, list.Count / 3); writer.WriteLine("{0} list uchar int vertex_indices", PROPERTY); writer.WriteLine(END_HEADER); // vertex-data: int i; Vector3 v3; Vector2 v2; StringBuilder sb = new StringBuilder(); var selectionEnum = selection.GetEnumerator(); int totalCount = selection.GetCount() + list.Count / 3; for (i = 0; i < selection.GetCount(); i++) { cancel.ThrowIfCancellationRequested(); selectionEnum.MoveNext(); v3 = scene.GetVertex(selectionEnum.Current); sb.Clear(); sb.AppendFormat(CultureInfo.InvariantCulture, "{0} {1} {2}", v3.X, v3.Y, v3.Z); if (writeNormals) { v3 = scene.GetNormal(selectionEnum.Current); sb.AppendFormat(CultureInfo.InvariantCulture, " {0} {1} {2}", v3.X, v3.Y, v3.Z); } if (writeTxtCoords) { v2 = scene.GetTxtCoord(selectionEnum.Current); sb.AppendFormat(CultureInfo.InvariantCulture, " {0} {1}", v2.X, v2.Y); } if (writeColors) { v3 = scene.GetColor(selectionEnum.Current); sb.AppendFormat(CultureInfo.InvariantCulture, " {0} {1} {2}", v3.X, v3.Y, v3.Z); } writer.WriteLine(sb.ToString()); if (progress != null) { progress.Report((i * 100 / totalCount).ToString()); } } // face-data: for (i = 0; i < list.Count; i += 3) { writer.WriteLine("3 {0} {1} {2}", list[i], Orientation ? list[i + 2] : list[i + 1], Orientation ? list[i + 1] : list[i + 2]); if (progress != null) { progress.Report(((i / 3 + selection.GetCount()) * 100 / totalCount).ToString()); } cancel.ThrowIfCancellationRequested(); } }
/// <summary> /// Writes the whole B-rep scene to a given text stream (uses text variant of Stanford PLY format). /// </summary> /// <param name="writer">Already open text writer</param> /// <param name="scene">Scene to write</param> public void WriteBrep(StreamWriter writer, SceneBrep scene) { DoNormals = true; DoTxtCoords = true; DoColors = true; if (scene == null || scene.Triangles < 1) { return; } Debug.Assert(TextFormat); if (!NativeNewLine) { writer.NewLine = "\r"; // CR only } bool writeNormals = DoNormals && scene.HasNormals(); bool writeTxtCoords = DoTxtCoords && scene.HasTxtCoords(); bool writeColors = DoColors && scene.HasColors(); writer.WriteLine(HEADER); writer.WriteLine(FORMAT_TEXT); // vertex-header: writer.WriteLine("{0} {1} {2}", ELEMENT, VERTEX, scene.Vertices); writer.WriteLine("{0} float x", PROPERTY); writer.WriteLine("{0} float {1}", PROPERTY, Orientation ? 'z' : 'y'); writer.WriteLine("{0} float {1}", PROPERTY, Orientation ? 'y' : 'z'); if (writeNormals) { writer.WriteLine("{0} float {1}", PROPERTY, NORMAL_X); writer.WriteLine("{0} float {1}", PROPERTY, Orientation ? NORMAL_Z : NORMAL_Y); writer.WriteLine("{0} float {1}", PROPERTY, Orientation ? NORMAL_Y : NORMAL_Z); } if (writeTxtCoords) { writer.WriteLine("{0} float {1}", PROPERTY, TEXTURE_S); writer.WriteLine("{0} float {1}", PROPERTY, TEXTURE_T); } if (writeColors) { writer.WriteLine("{0} float {1}", PROPERTY, COLOR_R); writer.WriteLine("{0} float {1}", PROPERTY, COLOR_G); writer.WriteLine("{0} float {1}", PROPERTY, COLOR_B); } // face-header: writer.WriteLine("{0} {1} {2}", ELEMENT, FACE, scene.Triangles); writer.WriteLine("{0} list uchar int vertex_indices", PROPERTY); writer.WriteLine(END_HEADER); // vertex-data: int i; Vector3 v3; Vector2 v2; StringBuilder sb = new StringBuilder(); for (i = 0; i < scene.Vertices; i++) { v3 = scene.GetVertex(i); sb.Clear(); sb.AppendFormat(CultureInfo.InvariantCulture, "{0} {1} {2}", v3.X, v3.Y, v3.Z); if (writeNormals) { v3 = scene.GetNormal(i); sb.AppendFormat(CultureInfo.InvariantCulture, " {0} {1} {2}", v3.X, v3.Y, v3.Z); } if (writeTxtCoords) { v2 = scene.GetTxtCoord(i); sb.AppendFormat(CultureInfo.InvariantCulture, " {0} {1}", v2.X, v2.Y); } if (writeColors) { v3 = scene.GetColor(i); sb.AppendFormat(CultureInfo.InvariantCulture, " {0} {1} {2}", v3.X, v3.Y, v3.Z); } writer.WriteLine(sb.ToString()); } // face-data: int A, B, C; for (i = 0; i < scene.Triangles; i++) { scene.GetTriangleVertices(i, out A, out B, out C); writer.WriteLine("3 {0} {1} {2}", A, Orientation ? C : B, Orientation ? B : C); } }
public void WriteBrepSelection(StreamWriter writer, SceneBrep scene, Selection selection, IProgress <string> progress, CancellationToken cancel, out List <int> trianglePointers, out List <int> vertexPointers) { vertexPointers = selection.SelectionPointers; trianglePointers = new List <int>(); if (scene == null || selection.GetCount() < 1) { return; } int i; var selectionEnum = selection.GetEnumerator(); var triangles = selection.GetSelectedTriangles(); var list = new List <int>(); // get vertex pointers in new mesh // they are dependent on its order in SelectionPointers list int A, B, C; for (int j = 0; j < triangles.Count; j++) { cancel.ThrowIfCancellationRequested(); scene.GetTriangleVertices(triangles[j], out A, out B, out C); int Anew = selection.SelectionPointers.IndexOf(A); int Bnew = selection.SelectionPointers.IndexOf(B); int Cnew = selection.SelectionPointers.IndexOf(C); // not selected vertex if (Anew == -1 || Bnew == -1 || Cnew == -1) { continue; } trianglePointers.Add(triangles[j]); list.Add(Anew + 1); list.Add(Bnew + 1); list.Add(Cnew + 1); } int totalCount = selection.GetCount() * 2 + list.Count / 3; for (i = 0; i < selection.GetCount(); i++) { cancel.ThrowIfCancellationRequested(); selectionEnum.MoveNext(); Vector3 v = scene.GetVertex(selectionEnum.Current); writer.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0} {1} {2} {3}", new object[] { VERTEX, v.X, v.Y, v.Z })); if (progress != null) { progress.Report((i / totalCount).ToString()); } } bool hasNormals = scene.Normals > 0; selectionEnum = selection.GetEnumerator(); if (hasNormals) { for (i = 0; i < selection.GetCount(); i++) { cancel.ThrowIfCancellationRequested(); selectionEnum.MoveNext(); Vector3 n = scene.GetNormal(selectionEnum.Current); writer.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0} {1} {2} {3}", new object[] { VERTEX_NORMAL, n.X, n.Y, n.Z })); if (progress != null) { progress.Report(((selection.GetCount() + i) * 100 / totalCount).ToString()); } } } for (i = 0; i < list.Count; i += 3) { /*if ( hasNormals ) * { * writer.WriteLine( "{0} {1}//{1} {2}//{2} {3}//{3}", FACE, list[ i ], list[ i + 1 ], list[ i + 2 ] ); * } * * else*/ writer.WriteLine("{0} {1} {2} {3}", FACE, list[i], list[i + 1], list[i + 2]); if (progress != null) { progress.Report(((selection.GetCount() * 2 + i / 3) * 100 / totalCount).ToString()); } } }