/// <summary> /// Reverse direction of glulam. /// </summary> public void Reverse() { Curve Reversed = Centreline.DuplicateCurve(); Reversed.Reverse(); Orientation.Remap(Centreline, Reversed); Centreline = Reversed; }
public override Curve CreateOffsetCurve(double x, double y, bool rebuild = false, int rebuild_pts = 20) { Vector3d v = Orientation.GetOrientation(Centreline, Centreline.Domain.Min); Plane p = tas.Core.Util.Misc.PlaneFromNormalAndYAxis(Centreline.PointAtStart, Centreline.TangentAtStart, v); Curve copy = Centreline.DuplicateCurve(); copy.Transform(Rhino.Geometry.Transform.Translation(p.XAxis * x + p.YAxis * y)); return(copy); }
public override Curve CreateOffsetCurve(double x, double y, bool offset_start, bool offset_end, bool rebuild = false, int rebuild_pts = 20) { if (!offset_start && !offset_end) { return(Centreline.DuplicateCurve()); } if (offset_start && offset_end) { return(CreateOffsetCurve(x, y, rebuild, rebuild_pts)); } List <Point3d> pts = new List <Point3d>(); double[] t = Centreline.DivideByCount(this.Data.Samples, true); double tmin = offset_start ? t.First() : t.Last(); double tmax = offset_end ? t.Last() : t.First(); for (int i = 0; i < t.Length; ++i) { Plane p = GetPlane(t[i]); double l = Ease.QuadOut(Interpolation.Unlerp(tmin, tmax, t[i])); pts.Add(p.Origin + p.XAxis * l * x + p.YAxis * l * y); } Curve new_curve = Curve.CreateInterpolatedCurve(pts, 3, CurveKnotStyle.Uniform, Centreline.TangentAtStart, Centreline.TangentAtEnd); if (new_curve == null) { throw new Exception(this.ToString() + "::CreateOffsetCurve:: Failed to create interpolated curve!"); } double len = new_curve.GetLength(); new_curve.Domain = new Interval(0.0, len); if (rebuild) { new_curve = new_curve.Rebuild(rebuild_pts, new_curve.Degree, true); } return(new_curve); }
public override Glulam Overbend(double t) { PolyCurve pc = Centreline.DuplicateCurve() as PolyCurve; if (pc == null) { return(this); } // fix this domain issue... not working for some reason PolyCurve pco = pc.OverBend(t); pco.Domain = pc.Domain; FreeformGlulam g = this.Duplicate() as FreeformGlulam; g.Centreline = pco; return(g); }
/// <summary> /// Duplicate glulam data. /// </summary> /// <returns></returns> public Glulam Duplicate() => CreateGlulam(Centreline.DuplicateCurve(), Orientation.Duplicate(), Data.Duplicate());
/// <summary> /// Generate a series of planes on the glulam cross-section. TODO: Re-implement as GlulamOrientation function /// </summary> /// <param name="N">Number of planes to extract.</param> /// <param name="extension">Extension of the centreline curve</param> /// <param name="frames">Output cross-section planes.</param> /// <param name="parameters">Output t-values along centreline curve.</param> /// <param name="interpolation">Type of interpolation to use (default is Linear).</param> public override void GenerateCrossSectionPlanes(int N, out Plane[] frames, out double[] parameters, GlulamData.Interpolation interpolation = GlulamData.Interpolation.LINEAR) { Curve curve = Centreline; double multiplier = RhinoMath.UnitScale(Rhino.RhinoDoc.ActiveDoc.ModelUnitSystem, UnitSystem.Millimeters); //PolylineCurve discrete = curve.ToPolyline(Glulam.Tolerance * 10, Glulam.AngleTolerance, 0.0, 0.0); PolylineCurve discrete = curve.ToPolyline(multiplier * Tolerance, AngleTolerance, multiplier * MininumSegmentLength, curve.GetLength() / MinimumNumSegments); if (discrete.TryGetPolyline(out Polyline discrete2)) { N = discrete2.Count; parameters = new double[N]; for (int i = 0; i < N; ++i) { curve.ClosestPoint(discrete2[i], out parameters[i]); } } else { parameters = curve.DivideByCount(N - 1, true).ToArray(); } //frames = parameters.Select(x => GetPlane(x)).ToArray(); //return; frames = new Plane[parameters.Length]; var vectors = Orientation.GetOrientations(curve, parameters); Plane temp; for (int i = 0; i < parameters.Length; ++i) { temp = Misc.PlaneFromNormalAndYAxis( curve.PointAt(parameters[i]), curve.TangentAt(parameters[i]), vectors[i]); if (temp.IsValid) { frames[i] = temp; } else { throw new Exception(string.Format("Plane is invalid: vector {0} tangent {1}", vectors[i], curve.TangentAt(parameters[i]))); } // TODO: Make back-up orientation direction in this case. } return; N = Math.Max(N, 2); frames = new Plane[N]; Curve CL; double extension = 0; if (Centreline.IsClosed) { CL = Centreline.DuplicateCurve(); } else { CL = Centreline.Extend(CurveEnd.Both, extension, CurveExtensionStyle.Smooth); } parameters = CL.DivideByCount(N - 1, true); GlulamOrientation TempOrientation = Orientation.Duplicate(); TempOrientation.Remap(Centreline, CL); for (int i = 0; i < N; ++i) { Vector3d v = TempOrientation.GetOrientation(CL, parameters[i]); frames[i] = tas.Core.Util.Misc.PlaneFromNormalAndYAxis(CL.PointAt(parameters[i]), CL.TangentAt(parameters[i]), v); } return; /* * double[] ft = new double[Frames.Count]; * double[] fa = new double[Frames.Count]; * * Plane temp; * for (int i = 0; i < Frames.Count; ++i) * { * CL.PerpendicularFrameAt(Frames[i].Item1, out temp); * ft[i] = Frames[i].Item1; * //fa[i] = Math.Acos(temp.YAxis * Frames[i].Item2.YAxis); * fa[i] = Vector3d.VectorAngle(temp.YAxis, Frames[i].Item2.YAxis, Frames[i].Item2); * } * * for (int i = 1; i < fa.Length; ++i) * { * if (fa[i] - fa[i - 1] > Math.PI) * fa[i] -= Constants.Tau; * else if (fa[i] - fa[i - 1] < -Math.PI) * fa[i] += Constants.Tau; * } * * int res; * int max = ft.Length - 1; * double mu; * * double[] angles = new double[N]; * * if (Frames.Count < 3) * interpolation = GlulamData.Interpolation.LINEAR; * * switch (interpolation) * { * case (GlulamData.Interpolation.HERMITE): // Hermite Interpolation * for (int i = 0; i < N; ++i) * { * if (t[i] < ft[0]) * { * angles[i] = fa[0]; * continue; * } * else if (t[i] > ft.Last()) * { * angles[i] = fa.Last(); * continue; * } * * res = Array.BinarySearch(ft, t[i]); * if (res < 0) * { * res = ~res; * res--; * } * * if (res == 0 && res < max - 1) * { * mu = (t[i] - ft[0]) / (ft[1] - ft[0]); * angles[i] = Interpolation.HermiteInterpolate(fa[0], fa[0], fa[1], fa[2], mu, 0, 0); * } * else if (res > 0 && res < max - 1) * { * mu = (t[i] - ft[res]) / (ft[res + 1] - ft[res]); * angles[i] = Interpolation.HermiteInterpolate(fa[res - 1], fa[res], fa[res + 1], fa[res + 2], mu, 0, 0); * * } * else if (res > 0 && res < max) * { * mu = (t[i] - ft[res]) / (ft[res + 1] - ft[res]); * angles[i] = Interpolation.HermiteInterpolate(fa[res - 1], fa[res], fa[res + 1], fa[res + 1], mu, 0, 0); * } * else if (res == max) * { * angles[i] = fa[res]; * } * * else * continue; * } * break; * * case (GlulamData.Interpolation.CUBIC): // Cubic Interpolation * for (int i = 0; i < N; ++i) * { * if (t[i] <= ft[0]) * { * angles[i] = fa[0]; * continue; * } * else if (t[i] >= ft.Last()) * { * angles[i] = fa.Last(); * continue; * } * * res = Array.BinarySearch(ft, t[i]); * if (res < 0) * { * res = ~res; * res--; * } * * if (res == 0 && res < max - 1) * { * mu = (t[i] - ft[0]) / (ft[1] - ft[0]); * angles[i] = Interpolation.CubicInterpolate(fa[0], fa[0], fa[1], fa[2], mu); * } * else if (res > 0 && res < max - 1) * { * mu = (t[i] - ft[res]) / (ft[res + 1] - ft[res]); * angles[i] = Interpolation.CubicInterpolate(fa[res - 1], fa[res], fa[res + 1], fa[res + 2], mu); * * } * else if (res > 0 && res < max) * { * mu = (t[i] - ft[res]) / (ft[res + 1] - ft[res]); * angles[i] = Interpolation.CubicInterpolate(fa[res - 1], fa[res], fa[res + 1], fa[res + 1], mu); * } * else if (res == max) * { * angles[i] = fa[res]; * } * * else * continue; * } * break; * * default: // Default linear interpolation * for (int i = 0; i < N; ++i) * { * res = Array.BinarySearch(ft, t[i]); * if (res < 0) * { * res = ~res; * res--; * } * if (res >= 0 && res < max) * { * if (ft[res + 1] - ft[res] == 0) * mu = 0.5; * else * mu = Math.Min(1.0, Math.Max(0, (t[i] - ft[res]) / (ft[res + 1] - ft[res]))); * angles[i] = Interpolation.Lerp(fa[res], fa[res + 1], mu); * } * else if (res < 0) * angles[i] = fa[0]; * else if (res >= max) * angles[i] = fa[max]; * } * break; * } * * for (int i = 0; i < N; ++i) * { * CL.PerpendicularFrameAt(t[i], out temp); * temp.Transform(Rhino.Geometry.Transform.Rotation(angles[i], temp.ZAxis, temp.Origin)); * planes[i] = temp; * } */ }
public Brep GetSideSurface(int side, double offset, double width, double extension = 0.0, bool flip = false) { // TODO: Create access for Glulam ends, with offset (either straight or along Centreline). side = side.Modulus(2); double w2 = width / 2; Curve c = Centreline.DuplicateCurve(); if (extension > 0.0) { c = c.Extend(CurveEnd.Both, extension, CurveExtensionStyle.Smooth); } int N = Math.Max(6, Data.Samples); GenerateCrossSectionPlanes(N, out Plane[] planes, out double[] parameters, Data.InterpolationType); Curve[] rules = new Curve[planes.Length]; double offsetX, offsetY; GetSectionOffset(out offsetX, out offsetY); for (int i = 0; i < planes.Length; ++i) { Plane p = planes[i]; if (side == 0) { rules[i] = new Line( p.Origin + p.XAxis * (offset + offsetX) + p.YAxis * (w2 + offsetY), p.Origin + p.XAxis * (offset + offsetX) - p.YAxis * (w2 - offsetY) ).ToNurbsCurve(); } else { rules[i] = new Line( p.Origin + p.YAxis * (offset + offsetY) + p.XAxis * (w2 + offsetX), p.Origin + p.YAxis * (offset + offsetY) - p.XAxis * (w2 - offsetX) ).ToNurbsCurve(); } } Brep[] loft = Brep.CreateFromLoft(rules, Point3d.Unset, Point3d.Unset, LoftType.Normal, false); if (loft == null || loft.Length < 1) { throw new Exception("Glulam::GetSideSurface::Loft failed!"); } Brep brep = loft[0]; Point3d pt = brep.Faces[0].PointAt(brep.Faces[0].Domain(0).Mid, brep.Faces[0].Domain(1).Mid); Vector3d nor = brep.Faces[0].NormalAt(brep.Faces[0].Domain(0).Mid, brep.Faces[0].Domain(1).Mid); double ct; Centreline.ClosestPoint(pt, out ct); Vector3d nor2 = Centreline.PointAt(ct) - pt; nor2.Unitize(); if (nor2 * nor < 0.0) { brep.Flip(); } if (flip) { brep.Flip(); } return(brep); }
/// <summary> /// Map points from beam space to world space. /// </summary> /// <param name="pts"></param> /// <returns></returns> public Point3d[] FromBeamSpace(IList <Point3d> pts, bool extend = true) { Point3d[] m_output_pts = new Point3d[pts.Count]; var curve = Centreline.DuplicateCurve(); double length = curve.GetLength(); if (extend) { double maxZ = 0; foreach (Point3d pt in pts) { maxZ = Math.Max(maxZ, pt.Z); } if (maxZ > length) { curve = curve.Extend(CurveEnd.End, maxZ - length + 1, CurveExtensionStyle.Line); } } /* * double min_z = double.MaxValue; * double max_z = double.MinValue; * * foreach (var pt in pts) * { * min_z = Math.Min(min_z, pt.Z); * max_z = Math.Max(max_z, pt.Z); * } * * double ext_min = Math.Min(0, Centreline.Domain.Min - min_z); * double ext_max = Math.Max(0, max_z - Centreline.Domain.Max); * double tolerance = 5.0; * * double ext = Math.Max(ext_min, ext_max) + tolerance; * * Curve c = Centreline.Extend(CurveEnd.Both, ext, CurveExtensionStyle.Line); */ if (curve.IsLinear()) { curve.Domain = new Interval(0, length); Parallel.For(0, pts.Count, i => { Plane m_plane; //m_plane = Utility.PlaneFromNormalAndYAxis( //Centreline.PointAtStart + Centreline.TangentAtStart * (pts[i].Z), //Centreline.TangentAtStart, //Orientation.GetOrientation(Centreline, pts[i].Z)); m_plane = GetPlane(pts[i].Z, curve); m_output_pts[i] = m_plane.PointAt(pts[i].X, pts[i].Y); }); } else { //Parallel.For(0, pts.Count, i => //{ for (int i = 0; i < pts.Count; ++i) { Plane m_plane; curve.LengthParameter(pts[i].Z, out double t); m_plane = GetPlane(t, curve); m_output_pts[i] = m_plane.PointAt(pts[i].X, pts[i].Y); } //}); } return(m_output_pts); }