private static VertexInfo[][] tubeFromCurve(Pt[] pts, double radius, int revSteps) { var normals = new Pt[pts.Length]; normals[0] = ((pts[1] - pts[0]) * pt(0, 1, 0)).Normalize() * radius; for (int i = 1; i < pts.Length - 1; i++) { normals[i] = normals[i - 1].ProjectOntoPlane((pts[i + 1] - pts[i]) + (pts[i] - pts[i - 1])).Normalize() * radius; } normals[pts.Length - 1] = normals[pts.Length - 2].ProjectOntoPlane(pts[pts.Length - 1] - pts[pts.Length - 2]).Normalize() * radius; var axes = pts.Select((p, i) => i == 0 ? new { Start = pts[0], End = pts[1] } : i == pts.Length - 1 ? new { Start = pts[pts.Length - 2], End = pts[pts.Length - 1] } : new { Start = p, End = p + (pts[i + 1] - p) + (p - pts[i - 1]) }).ToArray(); return(Enumerable.Range(0, pts.Length) .Select(ix => new { Axis = axes[ix], Perp = pts[ix] + normals[ix], Point = pts[ix] }) .Select(inf => Enumerable.Range(0, revSteps) .Select(i => 360 * i / revSteps) .Select(angle => inf.Perp.Rotate(inf.Axis.Start, inf.Axis.End, angle)) .Select(p => new VertexInfo { Point = p, Normal = p - inf.Point }).Reverse().ToArray()) .ToArray()); }
public static Pt RotateX(this Pt p, double angle) { return(new Pt(p.X, p.Y * cos(angle) - p.Z * sin(angle), p.Y * sin(angle) + p.Z * cos(angle))); }
public static IEnumerable <Pt[]> Move(this IEnumerable <Pt[]> faces, Pt by) { return(faces.Select(face => Move(face, by))); }
public static Pt[][] Move(this Pt[][] faces, Pt by) { return(faces.Select(face => Move(face, by)).ToArray()); }
public static IEnumerable <Pt> Move(this IEnumerable <Pt> face, Pt by) { return(face.Select(p => p + by)); }
public static Pt[] Move(this Pt[] face, Pt by) { return(face.Select(p => p + by).ToArray()); }
public static Mesh GenerateWire(System.Random rnd, int lengthIndex, int color, WirePiece piece, bool highlight) { var length = GetWireLength(lengthIndex); var thickness = highlight ? _wireRadiusHighlight : _wireRadius; var firstControlHeight = highlight ? _firstControlHeightHighlight : _firstControlHeight; var interpolateHeight = highlight ? _interpolateHeightHighlight : _interpolateHeight; var start = pt(0, 0, 0); var startControl = pt(length / 10, 0, firstControlHeight); var endControl = pt(length * 9 / 10, 0, firstControlHeight); var end = pt(length, 0, 0); var numSegments = new[] { 6, 4, 4 }[lengthIndex]; var bézierSteps = 16; var tubeRevSteps = 16; var interpolateStart = pt(0, 0, interpolateHeight); var interpolateEnd = pt(length, 0, interpolateHeight); var intermediatePoints = newArray(numSegments - 1, i => interpolateStart + (interpolateEnd - interpolateStart) * (i + 1) / numSegments + pt(rnd.NextDouble() - .5, rnd.NextDouble() - .5, rnd.NextDouble() - .5) * _wireMaxSegmentDeviation); var deviations = newArray(numSegments - 1, _ => pt(rnd.NextDouble(), rnd.NextDouble(), rnd.NextDouble()) * _wireMaxBézierDeviation); if (piece == WirePiece.Uncut) { var points = new[] { new { ControlBefore = default(Pt), Point = start, ControlAfter = startControl } } .Concat(intermediatePoints.Select((p, i) => new { ControlBefore = p - deviations[i], Point = p, ControlAfter = p + deviations[i] })) .Concat(new[] { new { ControlBefore = endControl, Point = end, ControlAfter = default(Pt) } }) .SelectConsecutivePairs(false, (one, two) => bézier(one.Point, one.ControlAfter, two.ControlBefore, two.Point, bézierSteps)) .SelectMany((x, i) => i == 0 ? x : x.Skip(1)) .ToArray(); return(toMesh(createFaces(false, true, tubeFromCurve(points, thickness, tubeRevSteps)), _colors[color])); } var partialWire = new Func <IEnumerable <CPC>, IEnumerable <VertexInfo[]> >(pts => { var points = pts .SelectConsecutivePairs(false, (one, two) => bézier(one.Point, one.ControlAfter, two.ControlBefore, two.Point, bézierSteps)) .SelectMany((x, i) => i == 0 ? x : x.Skip(1)) .ToArray(); var reserveForCopper = 6; var discardCopper = 2; if (piece == WirePiece.Cut) { var tube = tubeFromCurve(points, thickness, tubeRevSteps).SkipLast(reserveForCopper).ToArray(); var capCenter = points[points.Length - 1 - reserveForCopper]; var normal = capCenter - points[points.Length - 2 - reserveForCopper]; var cap = tube[tube.Length - 1].SelectConsecutivePairs(true, (v1, v2) => new[] { capCenter, v2.Point, v1.Point }.Select(p => new VertexInfo { Point = p, Normal = normal }).ToArray()).ToArray(); return(createFaces(false, true, tube).Concat(cap)); } else { var copper = tubeFromCurve(points.TakeLast(reserveForCopper + 2).SkipLast(discardCopper).ToArray(), thickness / 2, tubeRevSteps).Skip(1).ToArray(); var copperCapCenter = points[points.Length - 1 - discardCopper]; var copperNormal = copperCapCenter - points[points.Length - 2]; var copperCap = copper[copper.Length - 1].SelectConsecutivePairs(true, (v1, v2) => new[] { copperCapCenter, v2.Point, v1.Point }.Select(p => new VertexInfo { Point = p, Normal = copperNormal }).ToArray()).ToArray(); return(createFaces(false, true, copper).Concat(copperCap)); } }); var rotAngle = (rnd.NextDouble() * 7 + 5) * (rnd.Next(2) == 0 ? -1 : 1); var rotAxisStart = new Pt(0, 0, 0); var rotAxisEnd = new Pt(rnd.NextDouble() * .01, rnd.NextDouble() * .01, 1); Func <Pt, Pt> rot = p => p.Rotate(rotAxisStart, rotAxisEnd, rotAngle); var beforeCut = new[] { new CPC { ControlBefore = default(Pt), Point = start, ControlAfter = startControl } } .Concat(intermediatePoints.Take(numSegments / 2).Select((p, i) => new CPC { ControlBefore = rot(p - deviations[i]), Point = rot(p), ControlAfter = rot(p + deviations[i]) })); var bcTube = partialWire(beforeCut); var cutOffPoint = (numSegments - 1) / 2; rotAngle = (rnd.NextDouble() * 7 + 5) * (rnd.Next(2) == 0 ? -1 : 1); rotAxisStart = new Pt(length, 0, 0); rotAxisEnd = new Pt(length + rnd.NextDouble() * .01, rnd.NextDouble() * .01, 1); var afterCut = new[] { new CPC { ControlBefore = default(Pt), Point = end, ControlAfter = endControl } } .Concat(intermediatePoints.Skip(cutOffPoint).Select((p, i) => new CPC { ControlBefore = rot(p + deviations[i + cutOffPoint]), Point = rot(p), ControlAfter = rot(p - deviations[i + cutOffPoint]) }).Reverse()); var acTube = partialWire(afterCut); return(toMesh(bcTube.Concat(acTube).ToArray(), _colors[color])); }
private static IEnumerable <Pt> bézier(Pt start, Pt control1, Pt control2, Pt end, int steps) { return(Enumerable.Range(0, steps) .Select(i => (double)i / (steps - 1)) .Select(t => pow(1 - t, 3) * start + 3 * pow(1 - t, 2) * t * control1 + 3 * (1 - t) * t * t * control2 + pow(t, 3) * end)); }