using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; using QuantumConcepts.Formats.StereoLithography; namespace QuantumConcepts.Formats.StereoLithography { /// A simple XYZ representation of a vertex. public class Vertex : IEquatable { /// The X coordinate of this . public float X { get; set; } /// The Y coordinate of this . public float Y { get; set; } /// The Z coordinate of this . public float Z { get; set; } /// Creates a new, empty . public Vertex() { } /// Creates a new using the provided coordinates. /// /// /// public Vertex(float x, float y, float z) : this() { this.X = x; this.Y = y; this.Z = z; } /// Shifts the by the X, Y and Z values in the parameter. /// The amount to shift the vertex. public void Shift(Vertex shift) { this.X += shift.X; this.Y += shift.Y; this.Z += shift.Z; } /// Writes the as text to the . /// The writer to which the will be written at the current position. public void Write(StreamWriter writer) { writer.WriteLine("\t\t\t{0}".Interpolate(this.ToString())); } /// Writes the as binary to the . /// The writer to which the will be written at the current position. public void Write(BinaryWriter writer) { writer.Write(this.X); writer.Write(this.Y); writer.Write(this.Z); } /// Returns the string representation of this . public override string ToString() { //return "vertex {0} {1} {2}".FormatString(this.X, this.Y, this.Z); return String.Format(CultureInfo.InvariantCulture, "vertex {0} {1} {2}", this.X, this.Y, this.Z); } /// Determines whether or not this instance is the same as the instance. /// The to which to compare. public bool Equals(Vertex other) { return (this.X.Equals(other.X) && this.Y.Equals(other.Y) && this.Z.Equals(other.Z)); } /// Reads a single from the . /// The reader which contains a to be read at the current position public static Vertex ReadRegex(StreamReader reader) { // vertex 5.417830e-001 2.674600e-001 -4.180212e+000 const string regex = @"\s*(facet normal|vertex)\s+(?[^\s]+)\s+(?[^\s]+)\s+(?[^\s]+)"; const NumberStyles numberStyle = (NumberStyles.AllowExponent | NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign); string data = null; float x, y, z; Match match = null; if (reader == null) return null; //Read the next line of data. data = reader.ReadLine(); if (data == null) return null; //Ensure that the data is formatted correctly. match = Regex.Match(data, regex, RegexOptions.IgnoreCase); if (!match.Success) return null; //Parse the three coordinates. if (!float.TryParse(match.Groups["X"].Value, numberStyle, CultureInfo.InvariantCulture, out x)) throw new FormatException("Could not parse X coordinate \"{0}\" as a decimal.".Interpolate(match.Groups["X"])); if (!float.TryParse(match.Groups["Y"].Value, numberStyle, CultureInfo.InvariantCulture, out y)) throw new FormatException("Could not parse Y coordinate \"{0}\" as a decimal.".Interpolate(match.Groups["Y"])); if (!float.TryParse(match.Groups["Z"].Value, numberStyle, CultureInfo.InvariantCulture, out z)) throw new FormatException("Could not parse Z coordinate \"{0}\" as a decimal.".Interpolate(match.Groups["Z"])); return new Vertex() { X = x, Y = y, Z = z }; } /// Reads a single from the . /// The reader which contains a to be read at the current position public static Vertex Read(StreamReader reader) { // facet normal -1.732201e-002 1.019131e-001 -9.946425e-001 // vertex 5.417830e-001 2.674600e-001 -4.180212e+000 const NumberStyles numberStyle = (NumberStyles.AllowExponent | NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign); string data = null; float x, y, z; Match match = null; if (reader == null) return null; //Read the next line of data. data = reader.ReadLine(); if (data == null) return null; string[] tmp = data.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); if (tmp.Length > 0 && tmp[0].Length == 8 && tmp[0].ToLower() == "endsolid") return null; int start; if (tmp.Length == 4) start = 1; else if (tmp.Length == 5) start = 2; else return null; //Parse the three coordinates. if (!float.TryParse(tmp[start + 0], numberStyle, CultureInfo.InvariantCulture, out x)) throw new FormatException("Could not parse X coordinate \"{0}\" as a decimal.".Interpolate(match.Groups["X"])); if (!float.TryParse(tmp[start + 1], numberStyle, CultureInfo.InvariantCulture, out y)) throw new FormatException("Could not parse Y coordinate \"{0}\" as a decimal.".Interpolate(match.Groups["Y"])); if (!float.TryParse(tmp[start + 2], numberStyle, CultureInfo.InvariantCulture, out z)) throw new FormatException("Could not parse Z coordinate \"{0}\" as a decimal.".Interpolate(match.Groups["Z"])); return new Vertex() { X = x, Y = y, Z = z }; } /// Reads a single from the . /// The reader which contains a to be read at the current position public static Vertex Read(BinaryReader reader) { const int floatSize = sizeof(float); const int vertexSize = (floatSize * 3); if (reader == null) return null; //Read 3 floats. byte[] data = new byte[vertexSize]; int bytesRead = reader.Read(data, 0, data.Length); //If no bytes are read then we're at the end of the stream. if (bytesRead == 0) return null; else if (bytesRead != data.Length) throw new FormatException("Could not convert the binary data to a vertex. Expected {0} bytes but found {1}.".Interpolate(vertexSize, bytesRead)); //Convert the read bytes to their numeric representation. return new Vertex() { X = BitConverter.ToSingle(data, 0), Y = BitConverter.ToSingle(data, floatSize), Z = BitConverter.ToSingle(data, (floatSize * 2)) }; } } }