// Transform by quaternion public void PlaneTransformTest2() { Plane <float> target = new Plane <float>(1, 2, 3, 4); target = Plane.Normalize(target); Matrix4X4 <float> m = Matrix4X4.CreateRotationX(MathHelper.ToRadians(30.0f)) * Matrix4X4.CreateRotationY(MathHelper.ToRadians(30.0f)) * Matrix4X4.CreateRotationZ(MathHelper.ToRadians(30.0f)); Quaternion <float> q = Quaternion <float> .CreateFromRotationMatrix(m); Plane <float> expected = new Plane <float>(); float x = target.Normal.X, y = target.Normal.Y, z = target.Normal.Z, w = target.Distance; expected.Normal = new Vector3D <float>( x * m.M11 + y * m.M21 + z * m.M31 + w * m.M41, x * m.M12 + y * m.M22 + z * m.M32 + w * m.M42, x * m.M13 + y * m.M23 + z * m.M33 + w * m.M43); expected.Distance = x * m.M14 + y * m.M24 + z * m.M34 + w * m.M44; Plane <float> actual; actual = Plane.Transform(target, q); Assert.True(MathHelper.Equal(expected, actual), "Plane<float>.Transform did not return the expected value."); }
public override Task Rebuild() { this.DebugDepth("Rebuild"); bool valuesChanged = false; using (RebuildLock()) { var sides = Sides.ClampIfNotCalculated(this, 3, 180, ref valuesChanged); using (new CenterAndHeightMaintainer(this)) { var path = new VertexStorage(); path.MoveTo(Width.Value(this) / 2, 0); for (int i = 1; i < sides; i++) { var angle = MathHelper.Tau * i / 2 / (sides - 1); path.LineTo(Math.Cos(angle) * Width.Value(this) / 2, Math.Sin(angle) * Width.Value(this) / 2); } var mesh = VertexSourceToMesh.Extrude(path, Depth.Value(this)); mesh.Transform(Matrix4X4.CreateRotationX(MathHelper.Tau / 4)); Mesh = mesh; } } Invalidate(InvalidateType.DisplayValues); Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Mesh)); return(Task.CompletedTask); }
public void TestGetHashCode() { { Vector2 a = new Vector2(10, 11); Vector2 b = new Vector2(10, 11); Assert.IsTrue(a.GetHashCode() == b.GetHashCode()); } { Vector3 a = new Vector3(10, 11, 12); Vector3 b = new Vector3(10, 11, 12); Assert.IsTrue(a.GetHashCode() == b.GetHashCode()); } { Vector4 a = new Vector4(10, 11, 12, 13); Vector4 b = new Vector4(10, 11, 12, 13); Assert.IsTrue(a.GetHashCode() == b.GetHashCode()); } { Quaternion a = new Quaternion(10, 11, 12, 13); Quaternion b = new Quaternion(10, 11, 12, 13); Assert.IsTrue(a.GetHashCode() == b.GetHashCode()); } { Matrix4X4 a = Matrix4X4.CreateRotationX(3); Matrix4X4 b = Matrix4X4.CreateRotationX(3); Assert.IsTrue(a.GetHashCode() == b.GetHashCode()); } }
private void Rebuild(UndoBuffer undoBuffer) { this.DebugDepth("Rebuild"); using (RebuildLock()) { var startingAabb = this.GetAxisAlignedBoundingBox(); // remove whatever rotation has been applied (they go in reverse order) Matrix = Matrix4X4.Identity; // add the current rotation Matrix = this.ApplyAtPosition(startingAabb.Center, Matrix4X4.CreateRotationX(MathHelper.DegreesToRadians(RotationXDegrees))); Matrix = this.ApplyAtPosition(startingAabb.Center, Matrix4X4.CreateRotationY(MathHelper.DegreesToRadians(RotationYDegrees))); Matrix = this.ApplyAtPosition(startingAabb.Center, Matrix4X4.CreateRotationZ(MathHelper.DegreesToRadians(RotationZDegrees))); if (startingAabb.ZSize > 0) { // If the part was already created and at a height, maintain the height. PlatingHelper.PlaceMeshAtHeight(this, startingAabb.minXYZ.Z); } } Invalidate(new InvalidateArgs(this, InvalidateType.Matrix, null)); }
private void Rebuild(UndoBuffer undoBuffer) { this.DebugDepth("Rebuild"); using (RebuildLock()) { var aabb = this.GetAxisAlignedBoundingBox(); var path = new VertexStorage(); path.MoveTo(Width / 2, 0); for (int i = 1; i < Sides; i++) { var angle = MathHelper.Tau * i / 2 / (Sides - 1); path.LineTo(Math.Cos(angle) * Width / 2, Math.Sin(angle) * Width / 2); } var mesh = VertexSourceToMesh.Extrude(path, Depth); mesh.Transform(Matrix4X4.CreateRotationX(MathHelper.Tau / 4)); Mesh = mesh; if (aabb.ZSize > 0) { // If the part was already created and at a height, maintain the height. PlatingHelper.PlaceMeshAtHeight(this, aabb.minXYZ.Z); } } Invalidate(new InvalidateArgs(this, InvalidateType.Mesh)); }
// Transform by matrix public void PlaneTransformTest1() { Plane <float> target = new Plane <float>(1, 2, 3, 4); target = Plane.Normalize(target); Matrix4X4 <float> m = Matrix4X4.CreateRotationX(MathHelper.ToRadians(30.0f)) * Matrix4X4.CreateRotationY(MathHelper.ToRadians(30.0f)) * Matrix4X4.CreateRotationZ(MathHelper.ToRadians(30.0f)); m.M41 = 10.0f; m.M42 = 20.0f; m.M43 = 30.0f; Plane <float> expected = new Plane <float>(); Matrix4X4 <float> inv; Matrix4X4.Invert(m, out inv); Matrix4X4 <float> itm = Matrix4X4.Transpose(inv); float x = target.Normal.X, y = target.Normal.Y, z = target.Normal.Z, w = target.Distance; expected.Normal = new Vector3D <float>( x * itm.M11 + y * itm.M21 + z * itm.M31 + w * itm.M41, x * itm.M12 + y * itm.M22 + z * itm.M32 + w * itm.M42, x * itm.M13 + y * itm.M23 + z * itm.M33 + w * itm.M43); expected.Distance = x * itm.M14 + y * itm.M24 + z * itm.M34 + w * itm.M44; Plane <float> actual; actual = Plane.Transform(target, m); Assert.True(MathHelper.Equal(expected, actual), "Plane<float>.Transform did not return the expected value."); }
public void RotateAbsolute(double x, double y, double z) { Matrix4X4 M1 = Matrix4X4.Identity; Matrix4X4 M2 = Matrix4X4.Identity; Matrix4X4 M3 = Matrix4X4.Identity; Matrix4X4 M4 = Matrix4X4.Identity; Vector3 save1; // save the old position save1.x = AxisToWorld[3, 0]; save1.y = AxisToWorld[3, 1]; save1.z = AxisToWorld[3, 2]; M1 = Matrix4X4.CreateRotationX(x); M2 = Matrix4X4.CreateRotationY(y); M3 = Matrix4X4.CreateRotationZ(z); // 1 * 2 * 3 M4 = M2 * M1; AxisToWorld = M3 * M4; // stuff the old position back in AxisToWorld[3, 0] = save1.x; AxisToWorld[3, 1] = save1.y; AxisToWorld[3, 2] = save1.z; AxisToWorld = Matrix4X4.Invert(WorldToAxis); }
public void Can_Rotate_Point_Around_X() { var point = new Point(0, 1, 0); var halfQuarter = Matrix4X4.CreateRotationX(Math.PI / 4); var fullQuarter = Matrix4X4.CreateRotationX(Math.PI / 2); (halfQuarter * point).ShouldBe(new Point(0, Math.Sqrt(2) / 2, Math.Sqrt(2) / 2)); (fullQuarter * point).ShouldBe(new Point(0, 0, 1)); (halfQuarter.Invert().inverse *point).ShouldBe(new Point(0, Math.Sqrt(2) / 2, -Math.Sqrt(2) / 2)); }
public override Task Rebuild() { this.DebugDepth("Rebuild"); bool valuesChanged = false; var roundSegments = RoundSegments.ClampIfNotCalculated(this, 2, 90, ref valuesChanged); Invalidate(InvalidateType.DisplayValues); using (RebuildLock()) { var height = Height.Value(this); var width = Width.Value(this); using (new CenterAndHeightMaintainer(this)) { var path = new VertexStorage(); path.MoveTo(0, 0); path.LineTo(width, 0); var range = 360 / 4.0; switch (Round) { case RoundTypes.Up: for (int i = 1; i < roundSegments - 1; i++) { var angle = range / (roundSegments - 1) * i; var rad = MathHelper.DegreesToRadians(angle); path.LineTo(Math.Cos(rad) * width, Math.Sin(rad) * height); } break; case RoundTypes.Down: for (int i = 1; i < roundSegments - 1; i++) { var angle = range / (roundSegments - 1) * i; var rad = MathHelper.DegreesToRadians(angle); path.LineTo(width - Math.Sin(rad) * width, height - Math.Cos(rad) * height); } break; } path.LineTo(0, height); Mesh = VertexSourceToMesh.Extrude(path, Depth.Value(this)); Mesh.Transform(Matrix4X4.CreateRotationX(MathHelper.Tau / 4)); } } Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Mesh)); return(Task.CompletedTask); }
public void Vector3TransformByQuaternionTest() { Vector3D <float> v = new Vector3D <float>(1.0f, 2.0f, 3.0f); Matrix4X4 <float> m = Matrix4X4.CreateRotationX <float>(MathHelper.ToRadians(30.0f)) * Matrix4X4.CreateRotationY <float>(MathHelper.ToRadians(30.0f)) * Matrix4X4.CreateRotationZ <float>(MathHelper.ToRadians(30.0f)); Quaternion <float> q = Quaternion <float> .CreateFromRotationMatrix(m); Vector3D <float> expected = Vector3D.Transform(v, m); Vector3D <float> actual = Vector3D.Transform(v, q); Assert.True(MathHelper.Equal(expected, actual), "Vector3D<float>f.Transform did not return the expected value."); }
public override void SetPosition(IObject3D selectedItem) { Vector3 boxCenter = GetControlCenter(selectedItem); double distBetweenPixelsWorldSpace = InteractionContext.World.GetWorldUnitsPerScreenPixelAtPosition(boxCenter); GetCornerPosition(selectedItem, out int cornerIndexOut); Matrix4X4 centerMatrix = Matrix4X4.Identity; switch (RotationAxis) { case 0: if (cornerIndexOut == 1 || cornerIndexOut == 3) { centerMatrix *= Matrix4X4.CreateRotationX(MathHelper.DegreesToRadians(90)); } else { centerMatrix *= Matrix4X4.CreateRotationY(MathHelper.DegreesToRadians(-90)); } centerMatrix *= Matrix4X4.CreateRotationZ(MathHelper.DegreesToRadians(90) * cornerIndexOut); break; case 1: if (cornerIndexOut == 1 || cornerIndexOut == 3) { centerMatrix *= Matrix4X4.CreateRotationY(MathHelper.DegreesToRadians(-90)); } else { centerMatrix *= Matrix4X4.CreateRotationX(MathHelper.DegreesToRadians(90)); } centerMatrix *= Matrix4X4.CreateRotationZ(MathHelper.DegreesToRadians(90) * cornerIndexOut); break; case 2: centerMatrix *= Matrix4X4.CreateRotationZ(MathHelper.DegreesToRadians(90) * cornerIndexOut); break; } centerMatrix *= Matrix4X4.CreateScale(distBetweenPixelsWorldSpace) * Matrix4X4.CreateTranslation(boxCenter); TotalTransform = centerMatrix; }
public void Vector3TransformNormalTest() { Vector3D <float> v = new Vector3D <float>(1.0f, 2.0f, 3.0f); Matrix4X4 <float> m = Matrix4X4.CreateRotationX <float>(MathHelper.ToRadians(30.0f)) * Matrix4X4.CreateRotationY <float>(MathHelper.ToRadians(30.0f)) * Matrix4X4.CreateRotationZ <float>(MathHelper.ToRadians(30.0f)); m.M41 = 10.0f; m.M42 = 20.0f; m.M43 = 30.0f; Vector3D <float> expected = new Vector3D <float>(2.19198728f, 1.53349364f, 2.61602545f); Vector3D <float> actual; actual = Vector3D.TransformNormal(v, m); Assert.True(MathHelper.Equal(expected, actual), "Vector3D<float>f.TransformNormal did not return the expected value."); }
public void Vector2TransformNormalTest() { Vector2D <float> v = new Vector2D <float>(1.0f, 2.0f); Matrix4X4 <float> m = Matrix4X4.CreateRotationX <float>(MathHelper.ToRadians(30.0f)) * Matrix4X4.CreateRotationY <float>(MathHelper.ToRadians(30.0f)) * Matrix4X4.CreateRotationZ <float>(MathHelper.ToRadians(30.0f)); m.M41 = 10.0f; m.M42 = 20.0f; m.M43 = 30.0f; Vector2D <float> expected = new Vector2D <float>(0.3169873f, 2.18301272f); Vector2D <float> actual; actual = Vector2D.TransformNormal(v, m); Assert.True(MathHelper.Equal(expected, actual), "Vector2f.Tranform did not return the expected value."); }
public void QuaternionFromRotationMatrixWithScaledMatrixTest3() { float angle = MathHelper.ToRadians(180.0f); Matrix4X4 <float> matrix = Matrix4X4.CreateRotationX <float>(angle) * Matrix4X4.CreateRotationY <float>(angle); Quaternion <float> expected = Quaternion <float> .CreateFromAxisAngle(Vector3D <float> .UnitY, angle) * Quaternion <float> .CreateFromAxisAngle(Vector3D <float> .UnitX, angle); Quaternion <float> actual = Quaternion <float> .CreateFromRotationMatrix(matrix); Assert.True(MathHelper.EqualRotation(expected, actual), $"Quaternion<float>.CreateFromRotationMatrix did not return the expected value: expected {expected} actual {actual}"); // make sure convert back to matrix is same as we passed matrix. Matrix4X4 <float> m2 = Matrix4X4.CreateFromQuaternion <float>(actual); Assert.True(MathHelper.Equal(matrix, m2), $"Quaternion<float>.CreateFromQuaternion did not return the expected value: matrix {matrix} m2 {m2}"); }
public void QuaternionFromRotationMatrixTest2() { for (float angle = 0.0f; angle < 720.0f; angle += 10.0f) { Matrix4X4 <float> matrix = Matrix4X4.CreateRotationX <float>(angle); Quaternion <float> expected = Quaternion <float> .CreateFromAxisAngle(Vector3D <float> .UnitX, angle); Quaternion <float> actual = Quaternion <float> .CreateFromRotationMatrix(matrix); Assert.True(MathHelper.EqualRotation(expected, actual), $"Quaternion<float>.CreateFromRotationMatrix angle:{angle} did not return the expected value: expected {expected} actual {actual}"); // make sure convert back to matrix is same as we passed matrix. Matrix4X4 <float> m2 = Matrix4X4.CreateFromQuaternion <float>(actual); Assert.True(MathHelper.Equal(matrix, m2), $"Quaternion<float>.CreateFromQuaternion angle:{angle} did not return the expected value: matrix {matrix} m2 {m2}"); } }
public override Task Rebuild() { this.DebugDepth("Rebuild"); bool valuesChanged = false; RoundSegments = agg_basics.Clamp(RoundSegments, 3, 360 / 4 - 2, ref valuesChanged); if (valuesChanged) { Invalidate(InvalidateType.DisplayValues); } using (RebuildLock()) { using (new CenterAndHeightMaintainer(this)) { var path = new VertexStorage(); path.MoveTo(0, 0); path.LineTo(Width, 0); if (Round) { var range = 360 / 4.0; for (int i = 1; i < RoundSegments - 1; i++) { var angle = range / (RoundSegments - 1) * i; var rad = MathHelper.DegreesToRadians(angle); path.LineTo(Width - Math.Sin(rad) * Width, Height - Math.Cos(rad) * Height); } } path.LineTo(0, Height); Mesh = VertexSourceToMesh.Extrude(path, Depth); Mesh.Transform(Matrix4X4.CreateRotationX(MathHelper.Tau / 4)); } } Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Mesh)); return(Task.CompletedTask); }
public static async Task <CylinderObject3D> Create(double diameterBottom, double diameterTop, double height, int sides, Alignment alignment = Alignment.Z) { var item = new CylinderObject3D() { Advanced = true, Diameter = diameterBottom, DiameterTop = diameterTop, Height = height, Sides = sides, }; await item.Rebuild(); switch (alignment) { case Alignment.X: item.Matrix = Matrix4X4.CreateRotationY(MathHelper.Tau / 4); break; case Alignment.Y: item.Matrix = Matrix4X4.CreateRotationX(MathHelper.Tau / 4); break; case Alignment.Z: // This is the natural case (how it was modeled) break; case Alignment.negX: item.Matrix = Matrix4X4.CreateRotationY(-MathHelper.Tau / 4); break; case Alignment.negY: item.Matrix = Matrix4X4.CreateRotationX(-MathHelper.Tau / 4); break; case Alignment.negZ: item.Matrix = Matrix4X4.CreateRotationX(MathHelper.Tau / 2); break; } return(item); }
override public Task Rebuild() { this.DebugDepth("Rebuild"); using (RebuildLock()) { using (new CenterAndHeightMantainer(this)) { var path = new VertexStorage(); path.MoveTo(0, 0); path.LineTo(Width, 0); path.LineTo(Width / 2, Height); var mesh = VertexSourceToMesh.Extrude(path, Depth); mesh.Transform(Matrix4X4.CreateRotationX(MathHelper.Tau / 4)); Mesh = mesh; } } Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Mesh)); return(Task.CompletedTask); }
public override Task Rebuild() { this.DebugDepth("Rebuild"); using (RebuildLock()) { using (new CenterAndHeightMantainer(this)) { var startingAabb = this.GetAxisAlignedBoundingBox(); // remove whatever rotation has been applied (they go in reverse order) Matrix = Matrix4X4.Identity; // add the current rotation Matrix = this.ApplyAtPosition(startingAabb.Center, Matrix4X4.CreateRotationX(MathHelper.DegreesToRadians(RotationXDegrees))); Matrix = this.ApplyAtPosition(startingAabb.Center, Matrix4X4.CreateRotationY(MathHelper.DegreesToRadians(RotationYDegrees))); Matrix = this.ApplyAtPosition(startingAabb.Center, Matrix4X4.CreateRotationZ(MathHelper.DegreesToRadians(RotationZDegrees))); } } Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Matrix)); return(Task.CompletedTask); }
public void Rebuild(UndoBuffer undoBuffer) { using (RebuildLock()) { var aabb = this.GetAxisAlignedBoundingBox(); this.Children.Modify(list => { list.Clear(); }); var brailleLetter = new BrailleObject3D() { TextToEncode = Letter.ToString(), BaseHeight = BaseHeight, }; brailleLetter.Rebuild(null); this.Children.Add(brailleLetter); var textObject = new TextObject3D() { PointSize = 46, Color = Color.LightBlue, NameToWrite = Letter.ToString(), Height = BaseHeight }; textObject.Invalidate(new InvalidateArgs(textObject, InvalidateType.Properties, null)); IObject3D letterObject = new RotateObject3D(textObject, MathHelper.Tau / 4); letterObject = new AlignObject3D(letterObject, FaceAlign.Bottom | FaceAlign.Front, brailleLetter, FaceAlign.Top | FaceAlign.Front, 0, 0, 3.5); letterObject = new SetCenterObject3D(letterObject, brailleLetter.GetCenter(), true, false, false); this.Children.Add(letterObject); var basePath = new RoundedRect(0, 0, 22, 34, 3) { ResolutionScale = 10 }; IObject3D basePlate = new Object3D() { Mesh = VertexSourceToMesh.Extrude(basePath, BaseHeight), Matrix = Matrix4X4.CreateRotationX(MathHelper.Tau / 4) }; basePlate = new AlignObject3D(basePlate, FaceAlign.Bottom | FaceAlign.Back, brailleLetter, FaceAlign.Bottom | FaceAlign.Back); basePlate = new SetCenterObject3D(basePlate, brailleLetter.GetCenter(), true, false, false); this.Children.Add(basePlate); IObject3D underline = new CubeObject3D(basePlate.XSize(), .2, 1); underline = new AlignObject3D(underline, FaceAlign.Bottom, brailleLetter, FaceAlign.Top); underline = new AlignObject3D(underline, FaceAlign.Back | FaceAlign.Left, basePlate, FaceAlign.Front | FaceAlign.Left, 0, .01); this.Children.Add(underline); if (aabb.ZSize > 0) { // If the part was already created and at a height, maintain the height. PlatingHelper.PlaceMeshAtHeight(this, aabb.minXYZ.Z); } } Invalidate(new InvalidateArgs(this, InvalidateType.Content)); }
public static Mesh Revolve(this IVertexSource source, int angleSteps = 30, double angleStart = 0, double angleEnd = MathHelper.Tau, bool revolveAroundZ = true) { angleStart = MathHelper.Range0ToTau(angleStart); angleEnd = MathHelper.Range0ToTau(angleEnd); // make sure we close 360 shapes angleStart = fixCloseAngles(angleStart); angleEnd = fixCloseAngles(angleEnd); if (angleStart == 0 && angleEnd == MathHelper.Tau) { angleSteps = Math.Max(angleSteps, 3); } else { angleSteps = Math.Max(angleSteps, 1); } // convert to clipper polygons and scale so we can ensure good shapes Polygons polygons = source.CreatePolygons(); if (polygons.Select(poly => poly.Where(pos => pos.X < 0)).Any()) { // ensure good winding and consistent shapes polygons = polygons.GetCorrectedWinding(); var bounds = polygons.GetBounds(); bounds.Inflate(10); // clip against x=0 left and right var leftClip = new Polygon(); leftClip.Add(new IntPoint(0, bounds.Bottom)); leftClip.Add(new IntPoint(0, bounds.Top)); leftClip.Add(new IntPoint(bounds.Left, bounds.Top)); leftClip.Add(new IntPoint(bounds.Left, bounds.Bottom)); var rightStuff = polygons.Subtract(leftClip); var rightClip = new Polygon(); rightClip.Add(new IntPoint(0, bounds.Top)); rightClip.Add(new IntPoint(0, bounds.Bottom)); rightClip.Add(new IntPoint(bounds.Right, bounds.Bottom)); rightClip.Add(new IntPoint(bounds.Right, bounds.Top)); var leftStuff = polygons.Subtract(rightClip); // mirror left material across the origin var leftAdd = leftStuff.Scale(-1, 1); if (leftAdd.Count > 0) { if (rightStuff.Count > 0) { polygons = rightStuff.Union(leftAdd); } else { polygons = leftAdd; } } else { // there is nothing on the left polygons = rightStuff; } } // convert the data back to PathStorage VertexStorage cleanedPath = polygons.CreateVertexStorage(); var mesh = new Mesh(); var hasStartAndEndFaces = angleStart > 0.000001; hasStartAndEndFaces |= angleEnd < MathHelper.Tau - 0.000001; // check if we need to make closing faces if (hasStartAndEndFaces) { // make a face for the start Mesh extrudedVertexSource = cleanedPath.TriangulateFaces(); if (revolveAroundZ) { extrudedVertexSource.Transform(Matrix4X4.CreateRotationX(MathHelper.Tau / 4)); extrudedVertexSource.Transform(Matrix4X4.CreateRotationZ(angleStart)); } else { extrudedVertexSource.Transform(Matrix4X4.CreateRotationY(angleStart)); } mesh.CopyFaces(extrudedVertexSource); } // make the outside shell double angleDelta = (angleEnd - angleStart) / angleSteps; double currentAngle = angleStart; if (!hasStartAndEndFaces) { angleSteps--; } for (int i = 0; i < angleSteps; i++) { AddRevolveStrip(cleanedPath, mesh, currentAngle, currentAngle + angleDelta, revolveAroundZ); currentAngle += angleDelta; } if (!hasStartAndEndFaces) { if (((angleEnd - angleStart) < .0000001 || (angleEnd - MathHelper.Tau - angleStart) < .0000001) && (angleEnd - currentAngle) > .0000001) { // make sure we close the shape exactly AddRevolveStrip(cleanedPath, mesh, currentAngle, angleStart, revolveAroundZ); } } else // add the end face { // make a face for the end Mesh extrudedVertexSource = cleanedPath.TriangulateFaces(); if (revolveAroundZ) { extrudedVertexSource.Transform(Matrix4X4.CreateRotationX(MathHelper.Tau / 4)); extrudedVertexSource.Transform(Matrix4X4.CreateRotationZ(currentAngle)); } else { extrudedVertexSource.Transform(Matrix4X4.CreateRotationY(angleStart)); } extrudedVertexSource.ReverseFaces(); mesh.CopyFaces(extrudedVertexSource); } mesh.CleanAndMerge(); // return the completed mesh return(mesh); }
private void Rebuild(UndoBuffer undoBuffer) { this.DebugDepth("Rebuild"); bool propertyUpdated = Diameter == double.MinValue; if (StartPercent < 0 || StartPercent > 100) { StartPercent = Math.Min(100, Math.Max(0, StartPercent)); propertyUpdated = true; } using (RebuildLock()) { ResetMeshWrapperMeshes(Object3DPropertyFlags.All, CancellationToken.None); // remember the current matrix then clear it so the parts will rotate at the original wrapped position var currentMatrix = Matrix; Matrix = Matrix4X4.Identity; var meshWrapperEnumerator = WrappedObjects(); var aabb = this.GetAxisAlignedBoundingBox(); if (Diameter == double.MinValue) { // uninitialized set to a reasonable value Diameter = (int)aabb.XSize; // TODO: ensure that the editor display value is updated } if (Diameter > 0) { var radius = Diameter / 2; var circumference = MathHelper.Tau * radius; rotationCenter = new Vector2(aabb.minXYZ.X + (aabb.maxXYZ.X - aabb.minXYZ.X) * (StartPercent / 100), aabb.maxXYZ.Y + radius); foreach (var object3Ds in meshWrapperEnumerator) { var originalMatrix = object3Ds.original.WorldMatrix(this); var curvedMesh = object3Ds.meshCopy.Mesh; var originalMesh = object3Ds.original.Mesh; if (false) { int sidesPerRotation = 30; double numRotations = aabb.XSize / circumference; double numberOfCuts = numRotations * sidesPerRotation; var maxXLength = aabb.XSize / numberOfCuts; // chop any segment that is too short in x for (int i = curvedMesh.MeshEdges.Count - 1; i >= 0; i--) { var edgeToSplit = curvedMesh.MeshEdges[i]; var start = edgeToSplit.VertexOnEnd[0].Position; var end = edgeToSplit.VertexOnEnd[1].Position; var edgeXLength = Math.Abs(end.X - start.X); int numberOfDivides = (int)(edgeXLength / maxXLength); if (numberOfDivides > 1) { for (int j = 1; j < numberOfDivides - 1; j++) { IVertex newVertex; MeshEdge newMeshEdge; curvedMesh.SplitMeshEdge(edgeToSplit, out newVertex, out newMeshEdge); var otherIndex = newMeshEdge.GetVertexEndIndex(newVertex); var ratio = (numberOfDivides - j) / (double)numberOfDivides; newVertex.Position = start + (end - start) * ratio; edgeToSplit = newMeshEdge; start = edgeToSplit.VertexOnEnd[0].Position; end = edgeToSplit.VertexOnEnd[1].Position; foreach (var face in edgeToSplit.FacesSharingMeshEdge()) { Face newFace; curvedMesh.SplitFace(face, edgeToSplit.VertexOnEnd[0], edgeToSplit.VertexOnEnd[1], out newMeshEdge, out newFace); } } } } } for (int i = 0; i < originalMesh.Vertices.Count; i++) { var matrix = originalMatrix; if (!BendCcw) { // rotate around so it will bend correctly matrix *= Matrix4X4.CreateTranslation(0, -aabb.maxXYZ.Y, 0); matrix *= Matrix4X4.CreateRotationX(MathHelper.Tau / 2); matrix *= Matrix4X4.CreateTranslation(0, aabb.maxXYZ.Y - aabb.YSize, 0); } var worldPosition = Vector3.Transform(originalMesh.Vertices[i].Position, matrix); var angleToRotate = ((worldPosition.X - rotationCenter.X) / circumference) * MathHelper.Tau - MathHelper.Tau / 4; var distanceFromCenter = rotationCenter.Y - worldPosition.Y; var rotatePosition = new Vector3(Math.Cos(angleToRotate), Math.Sin(angleToRotate), 0) * distanceFromCenter; rotatePosition.Z = worldPosition.Z; var worldWithBend = rotatePosition + new Vector3(rotationCenter.X, radius + aabb.maxXYZ.Y, 0); curvedMesh.Vertices[i].Position = Vector3.Transform(worldWithBend, matrix.Inverted); } // the vertices need to be resorted as they have moved relative to each other curvedMesh.Vertices.Sort(); curvedMesh.MarkAsChanged(); curvedMesh.CalculateNormals(); } if (!BendCcw) { // fix the stored center so we draw correctly rotationCenter = new Vector2(rotationCenter.X, aabb.minXYZ.Y - radius); } } // set the matrix back Matrix = currentMatrix; } base.OnInvalidate(new InvalidateArgs(this, InvalidateType.Mesh)); if (propertyUpdated) { base.OnInvalidate(new InvalidateArgs(this, InvalidateType.Properties)); } }
private static World CreateWorld() { var floor = new Sphere(Matrix4X4.CreateScale(10, 0.01, 10)) { Material = new Material { Color = new Color(1, 0.9, 0.9), Specular = 0, } }; var leftWall = new Sphere(Matrix4X4.CreateTranslation(0, 0, 5) * Matrix4X4.CreateRotationY(-Math.PI / 4) * Matrix4X4.CreateRotationX(Math.PI / 2) * Matrix4X4.CreateScale(10, 0.01, 10)) { Material = new Material { Color = new Color(1, 0.9, 0.9), Specular = 0, } }; var rightWall = new Sphere(Matrix4X4.CreateTranslation(0, 0, 5) * Matrix4X4.CreateRotationY(Math.PI / 4) * Matrix4X4.CreateRotationX(Math.PI / 2) * Matrix4X4.CreateScale(10, 0.01, 10)) { Material = new Material { Color = new Color(1, 0.9, 0.9), Specular = 0, } }; var middleSphere = new Sphere(Matrix4X4.CreateTranslation(-0.5, 1, 0.5)) { Material = new Material { Color = new Color(0.1, 1, 0.5), Diffuse = 0.7, Specular = 0.3, } }; var rightSphere = new Sphere(Matrix4X4.CreateTranslation(1.5, 0.5, -0.5) * Matrix4X4.CreateScale(0.5, 0.5, 0.5)) { Material = new Material { Color = new Color(0.5, 1, 0.1), Diffuse = 0.7, Specular = 0.3, } }; var leftSphere = new Sphere(Matrix4X4.CreateTranslation(-1.5, 0.33, -0.75) * Matrix4X4.CreateScale(0.33, 0.33, 0.33)) { Material = new Material { Color = new Color(1, 0.8, 0.1), Diffuse = 0.7, Specular = 0.3, } }; var light = new PointLight(new Point(-10, 10, -10), new Color(1, 1, 1)); return new World { Objects = {floor, rightWall, leftWall, middleSphere, rightSphere, leftSphere}, PointLights = {light}, }; }
public void RotateRelative(double x, double y, double z) { #if true if (x != 0) { Matrix4X4 M1 = Matrix4X4.Identity; M1 = Matrix4X4.CreateRotationX(x); if (y != 0) { Matrix4X4 M2 = Matrix4X4.Identity; Matrix4X4 M4 = Matrix4X4.Identity; M2 = Matrix4X4.CreateRotationY(y); M4 = M2 * M1; if (z != 0) { Matrix4X4 M3 = Matrix4X4.Identity; M3 = Matrix4X4.CreateRotationZ(z); Matrix4X4 Delta = Matrix4X4.Identity; Delta = M3 * M4; AxisToWorld *= Delta; } else { AxisToWorld *= M4; } } else { if (z != 0) { Matrix4X4 M3 = Matrix4X4.Identity; M3 = Matrix4X4.CreateRotationZ(z); Matrix4X4 Delta = Matrix4X4.Identity; Delta = M3 * M1; AxisToWorld *= Delta; } else { AxisToWorld *= M1; } } } else { if (y != 0) { Matrix4X4 M2 = Matrix4X4.Identity; M2 = Matrix4X4.CreateRotationY(y); if (z != 0) { Matrix4X4 M3 = Matrix4X4.Identity; M3 = Matrix4X4.CreateRotationZ(z); Matrix4X4 Delta = Matrix4X4.Identity; Delta = M3 * M2; AxisToWorld *= Delta; } else { AxisToWorld *= M2; } } else { if (z != 0) { Matrix4X4 M3 = Matrix4X4.Identity; M3 = Matrix4X4.CreateRotationZ(z); AxisToWorld *= M3; } } } WorldToAxis = Matrix4X4.Invert(AxisToWorld); #else M1.Rotate(0, x); M2.Rotate(1, y); M3.Rotate(2, z); // 1 * 2 * 3 M4 = M2 * M1; Delta = M3 * M4; AxisToWorld = AxisToWorld * Delta; WorldToAxis = AxisToWorld.GetInverse(); #endif }
public static Mesh Revolve(IVertexSource source, int angleSteps = 30, double angleStart = 0, double angleEnd = MathHelper.Tau) { angleSteps = Math.Max(angleSteps, 3); angleStart = MathHelper.Range0ToTau(angleStart); angleEnd = MathHelper.Range0ToTau(angleEnd); // convert to clipper polygons and scale so we can ensure good shapes Polygons polygons = source.CreatePolygons(); // ensure good winding and consistent shapes // clip against x=0 left and right // mirror left material across the origin // union mirrored left with right material // convert the data back to PathStorage VertexStorage cleanedPath = polygons.CreateVertexStorage(); Mesh mesh = new Mesh(); var hasStartAndEndFaces = angleStart > 0.000001; hasStartAndEndFaces |= angleEnd < MathHelper.Tau - 0.000001; // check if we need to make closing faces if (hasStartAndEndFaces) { // make a face for the start CachedTesselator teselatedSource = new CachedTesselator(); Mesh extrudedVertexSource = TriangulateFaces(source, teselatedSource); extrudedVertexSource.Transform(Matrix4X4.CreateRotationX(MathHelper.Tau / 4)); extrudedVertexSource.Transform(Matrix4X4.CreateRotationZ(angleStart)); mesh.CopyFaces(extrudedVertexSource); } // make the outside shell double angleDelta = (angleEnd - angleStart) / angleSteps; double currentAngle = angleStart; if (!hasStartAndEndFaces) { angleSteps--; } for (int i = 0; i < angleSteps; i++) { AddRevolveStrip(cleanedPath, mesh, currentAngle, currentAngle + angleDelta); currentAngle += angleDelta; } if (!hasStartAndEndFaces) { if (((angleEnd - angleStart) < .0000001 || (angleEnd - MathHelper.Tau - angleStart) < .0000001) && (angleEnd - currentAngle) > .0000001) { // make sure we close the shape exactly AddRevolveStrip(cleanedPath, mesh, currentAngle, angleStart); } } else // add the end face { // make a face for the end CachedTesselator teselatedSource = new CachedTesselator(); Mesh extrudedVertexSource = TriangulateFaces(source, teselatedSource); extrudedVertexSource.Transform(Matrix4X4.CreateRotationX(MathHelper.Tau / 4)); extrudedVertexSource.Transform(Matrix4X4.CreateRotationZ(currentAngle)); extrudedVertexSource.ReverseFaceEdges(); mesh.CopyFaces(extrudedVertexSource); } // return the completed mesh return(mesh); }
public override async Task Rebuild() { using (RebuildLock()) { using (new CenterAndHeightMantainer(this)) { this.Children.Modify(list => { list.Clear(); }); var brailleLetter = new BrailleObject3D() { TextToEncode = Letter.ToString(), BaseHeight = BaseHeight, }; await brailleLetter.Rebuild(); this.Children.Add(brailleLetter); var textObject = new TextObject3D() { PointSize = 46, Color = Color.LightBlue, NameToWrite = Letter.ToString(), Height = BaseHeight }; await textObject.Rebuild(); IObject3D letterObject = new RotateObject3D_2(textObject, Vector3.UnitX, -90); await letterObject.Rebuild(); var scaleRatio = Math.Max(letterObject.XSize() / 17, letterObject.ZSize() / 17); if (scaleRatio > 1) { letterObject = new ScaleObject3D(letterObject, 1.0 / scaleRatio, 1, 1.0 / scaleRatio); } letterObject = new AlignObject3D(letterObject, FaceAlign.Bottom | FaceAlign.Front, brailleLetter, FaceAlign.Top | FaceAlign.Front, 0, 0, 3.5); letterObject = new SetCenterObject3D(letterObject, brailleLetter.GetCenter(), true, false, false); this.Children.Add(letterObject); var basePath = new RoundedRect(0, 0, 22, 34, 3) { ResolutionScale = 10 }; IObject3D basePlate = new Object3D() { Mesh = VertexSourceToMesh.Extrude(basePath, BaseHeight), Matrix = Matrix4X4.CreateRotationX(MathHelper.Tau / 4) }; basePlate = new AlignObject3D(basePlate, FaceAlign.Bottom | FaceAlign.Back, brailleLetter, FaceAlign.Bottom | FaceAlign.Back); basePlate = new SetCenterObject3D(basePlate, brailleLetter.GetCenter(), true, false, false); this.Children.Add(basePlate); IObject3D underline = await CubeObject3D.Create(basePlate.XSize(), .2, 1); underline = new AlignObject3D(underline, FaceAlign.Bottom, brailleLetter, FaceAlign.Top); underline = new AlignObject3D(underline, FaceAlign.Back | FaceAlign.Left, basePlate, FaceAlign.Front | FaceAlign.Left, 0, .01); this.Children.Add(underline); } } Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children)); }
public override Task Rebuild() { this.DebugDepth("Rebuild"); bool valuesChanged = Diameter == double.MinValue; if (StartPercent < 0 || StartPercent > 100) { StartPercent = Math.Min(100, Math.Max(0, StartPercent)); valuesChanged = true; } using (RebuildLock()) { ResetMeshWrapperMeshes(Object3DPropertyFlags.All, CancellationToken.None); // remember the current matrix then clear it so the parts will rotate at the original wrapped position var currentMatrix = Matrix; Matrix = Matrix4X4.Identity; var meshWrapperEnumerator = WrappedObjects(); var aabb = this.GetAxisAlignedBoundingBox(); if (Diameter == double.MinValue) { // uninitialized set to a reasonable value Diameter = (int)aabb.XSize; // TODO: ensure that the editor display value is updated } if (Diameter > 0) { var radius = Diameter / 2; var circumference = MathHelper.Tau * radius; rotationCenter = new Vector2(aabb.MinXYZ.X + (aabb.MaxXYZ.X - aabb.MinXYZ.X) * (StartPercent / 100), aabb.MaxXYZ.Y + radius); foreach (var object3Ds in meshWrapperEnumerator) { var matrix = object3Ds.original.WorldMatrix(this); if (!BendCcw) { // rotate around so it will bend correctly matrix *= Matrix4X4.CreateTranslation(0, -aabb.MaxXYZ.Y, 0); matrix *= Matrix4X4.CreateRotationX(MathHelper.Tau / 2); matrix *= Matrix4X4.CreateTranslation(0, aabb.MaxXYZ.Y - aabb.YSize, 0); } var matrixInv = matrix.Inverted; var curvedMesh = object3Ds.meshCopy.Mesh; // split long edges so it will be curved if (false) { double numRotations = aabb.XSize / circumference; double numberOfCuts = numRotations * MinSidesPerRotation; var maxXLength = aabb.XSize / numberOfCuts; var maxXLengthSqrd = maxXLength * maxXLength; // convert the mesh into vertex and face arrays double[] v; int[] f; v = curvedMesh.Vertices.ToDoubleArray(object3Ds.meshCopy.Matrix); f = curvedMesh.Faces.ToIntArray(); // make lists so we can add to them var vL = v.ToVector3List(); vL.Transform(matrix); var fL = new FaceList(f, curvedMesh.Vertices); Teselate.SplitEdges(vL, fL, maxXLength); vL.Transform(matrixInv); // convert the lists back into the mesh object3Ds.meshCopy.Mesh = new Mesh(vL, fL); curvedMesh = object3Ds.meshCopy.Mesh; } for (int i = 0; i < curvedMesh.Vertices.Count; i++) { var worldPosition = curvedMesh.Vertices[i].Transform((Matrix4X4)matrix); var angleToRotate = ((worldPosition.X - rotationCenter.X) / circumference) * MathHelper.Tau - MathHelper.Tau / 4; var distanceFromCenter = rotationCenter.Y - worldPosition.Y; var rotatePosition = new Vector3Float(Math.Cos(angleToRotate), Math.Sin(angleToRotate), 0) * distanceFromCenter; rotatePosition.Z = worldPosition.Z; var worldWithBend = rotatePosition + new Vector3Float(rotationCenter.X, radius + aabb.MaxXYZ.Y, 0); curvedMesh.Vertices[i] = worldWithBend.Transform(matrixInv); } curvedMesh.MarkAsChanged(); curvedMesh.CalculateNormals(); } if (!BendCcw) { // fix the stored center so we draw correctly rotationCenter = new Vector2(rotationCenter.X, aabb.MinXYZ.Y - radius); } } // set the matrix back Matrix = currentMatrix; } Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Mesh)); if (valuesChanged) { Invalidate(InvalidateType.DisplayValues); } return(Task.CompletedTask); }
override public Task Rebuild() { using (RebuildLock()) { using (new CenterAndHeightMantainer(this)) { this.Children.Modify(list => { list.Clear(); }); var brailleText = TextToEncode; if (UseGrade2) { brailleText = BrailleGrade2.ConvertString(brailleText); } double pointSize = 18.5; double pointsToMm = 0.352778; IObject3D textObject = new Object3D(); var offest = 0.0; TypeFacePrinter textPrinter; if (RenderAsBraille) { textPrinter = new TypeFacePrinter(brailleText, new StyledTypeFace(typeFace, pointSize)); } else { textPrinter = new TypeFacePrinter(brailleText, new StyledTypeFace(ApplicationController.GetTypeFace(NamedTypeFace.Liberation_Mono), pointSize)); } foreach (var letter in brailleText.ToCharArray()) { IObject3D letterObject; TypeFacePrinter letterPrinter; if (RenderAsBraille) { letterPrinter = new TypeFacePrinter(letter.ToString(), new StyledTypeFace(typeFace, pointSize)); var scalledLetterPrinter = new VertexSourceApplyTransform(letterPrinter, Affine.NewScaling(pointsToMm)); // add all the spheres to letterObject letterObject = new Object3D(); var vertexCount = 0; var positionSum = Vector2.Zero; var lastPosition = Vector2.Zero; // find each dot outline and get it's center and place a sphere there foreach (var vertex in scalledLetterPrinter.Vertices()) { switch (vertex.command) { case Agg.ShapePath.FlagsAndCommand.Stop: case Agg.ShapePath.FlagsAndCommand.EndPoly: case Agg.ShapePath.FlagsAndCommand.FlagClose: case Agg.ShapePath.FlagsAndCommand.MoveTo: if (vertexCount > 0) { var center = positionSum / vertexCount; double radius = 1.44 / 2; // (center - lastPosition).Length; var sphere = new HalfSphereObject3D(radius * 2, 15) { Color = Color.LightBlue }; sphere.Translate(center.X, center.Y); letterObject.Children.Add(sphere); } vertexCount = 0; positionSum = Vector2.Zero; break; case Agg.ShapePath.FlagsAndCommand.Curve3: case Agg.ShapePath.FlagsAndCommand.Curve4: case Agg.ShapePath.FlagsAndCommand.LineTo: vertexCount++; lastPosition = vertex.position; positionSum += lastPosition; break; } } } else { letterPrinter = new TypeFacePrinter(letter.ToString(), new StyledTypeFace(ApplicationController.GetTypeFace(NamedTypeFace.Liberation_Mono), pointSize)); var scalledLetterPrinter = new VertexSourceApplyTransform(letterPrinter, Affine.NewScaling(pointsToMm)); letterObject = new Object3D() { Mesh = VertexSourceToMesh.Extrude(scalledLetterPrinter, 1), Color = Color.LightBlue }; } letterObject.Matrix = Matrix4X4.CreateTranslation(offest, 0, 0); textObject.Children.Add(letterObject); offest += letterPrinter.GetSize(letter.ToString()).X *pointsToMm; } // add a plate under the dots var padding = .9 * pointSize * pointsToMm / 2; var size = textPrinter.LocalBounds * pointsToMm; // make the base var basePath = new VertexStorage(); basePath.MoveTo(0, 0); basePath.LineTo(size.Width + padding, 0); basePath.LineTo(size.Width + padding, size.Height + padding); basePath.LineTo(padding, size.Height + padding); basePath.LineTo(0, size.Height); IObject3D basePlate = new Object3D() { Mesh = VertexSourceToMesh.Extrude(basePath, BaseHeight) }; basePlate = new AlignObject3D(basePlate, FaceAlign.Top, textObject, FaceAlign.Bottom, 0, 0, .01); basePlate = new AlignObject3D(basePlate, FaceAlign.Left | FaceAlign.Front, size.Left - padding / 2, size.Bottom - padding / 2); this.Children.Add(basePlate); basePlate.Matrix *= Matrix4X4.CreateRotationX(MathHelper.Tau / 4); // add an optional chain hook if (AddHook) { // x 10 to make it smoother double edgeWidth = 3; double height = basePlate.ZSize(); IVertexSource leftSideObject = new RoundedRect(0, 0, height / 2, height, 0) { ResolutionScale = 10 }; IVertexSource cicleObject = new Ellipse(0, 0, height / 2, height / 2) { ResolutionScale = 10 }; cicleObject = new Align2D(cicleObject, Side2D.Left | Side2D.Bottom, leftSideObject, Side2D.Left | Side2D.Bottom, -.01); IVertexSource holeObject = new Ellipse(0, 0, height / 2 - edgeWidth, height / 2 - edgeWidth) { ResolutionScale = 10 }; holeObject = new SetCenter2D(holeObject, cicleObject.GetBounds().Center); IVertexSource hookPath = leftSideObject.Plus(cicleObject); hookPath = hookPath.Minus(holeObject); IObject3D chainHook = new Object3D() { Mesh = VertexSourceToMesh.Extrude(hookPath, BaseHeight), Matrix = Matrix4X4.CreateRotationX(MathHelper.Tau / 4) }; chainHook = new AlignObject3D(chainHook, FaceAlign.Left | FaceAlign.Bottom | FaceAlign.Back, basePlate, FaceAlign.Right | FaceAlign.Bottom | FaceAlign.Back, -.01); this.Children.Add(chainHook); } // add the object that is the dots this.Children.Add(textObject); textObject.Matrix *= Matrix4X4.CreateRotationX(MathHelper.Tau / 4); } } Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children)); return(Task.CompletedTask); }
private static World CreateWorld() { var floor = new Plane { Material = new Material { Pattern = new CheckersPattern(Color.White, Color.Black), Color = Color.White, Specular = 0, } }; var backWall = new Plane { TransformMatrix = new Transform().RotateX(Math.PI / 2) .RotateY(-Math.PI / 2) .Translate(1.5, 0, 0) .GetTransformationMatrix(), Material = new Material { Pattern = new StripePattern(new Color(0, 0.5, 0.5), new Color(1, 0, 0)) { TransformMatrix = Matrix4X4.CreateRotationY(Math.PI / 4) }, Specular = 0, } }; var middleSphere = new Sphere(Matrix4X4.CreateTranslation(-0.5, 1, 0.5)) { Material = new Material { Pattern = new RingPattern(new Color(1, 0, 0), new Color(0, 1, 0)) { TransformMatrix = Matrix4X4.CreateRotationX(Math.PI / -3) * Matrix4X4.CreateScale(0.25, 0.25, 0.25) }, Diffuse = 0.7, Specular = 0.3, } }; var rightSphere = new Sphere(Matrix4X4.CreateTranslation(1.5, 0.5, -0.5) * Matrix4X4.CreateScale(0.5, 0.5, 0.5)) { Material = new Material { Color = new Color(0.5, 1, 0.1), Diffuse = 0.7, Specular = 0.3, } }; var leftSphere = new Sphere(Matrix4X4.CreateTranslation(-1.5, 0.33, -0.75) * Matrix4X4.CreateScale(0.33, 0.33, 0.33)) { Material = new Material { Pattern = new StripePattern(new Color(0, 0, 1), new Color(0, 1, 0)) { TransformMatrix = Matrix4X4.CreateScale(0.25, 0.25, 0.25) }, Diffuse = 0.7, Specular = 0.3, } }; var light = new PointLight(new Point(-10, 10, -10), new Color(1, 1, 1)); return(new World { Objects = { middleSphere, rightSphere, leftSphere, floor, backWall }, PointLights = { light }, }); }
public override Task Rebuild() { // Point Size 10 // Height 1 // Font Fredoka // Align // X: Right Right -11 // Y: Front -.3 // Z: Bottom .8 this.DebugDepth("Rebuild"); bool valuesChanged = false; using (RebuildLock()) { MaxTemperature = agg_basics.Clamp(MaxTemperature, 140, 400, ref valuesChanged); Sections = agg_basics.Clamp(Sections, 2, 20, ref valuesChanged); ChangeAmount = agg_basics.Clamp(ChangeAmount, 1, 30, ref valuesChanged); using (new CenterAndHeightMaintainer(this)) { Children.Modify(async(children) => { children.Clear(); // add the base var towerBase = new Object3D() { Mesh = new RoundedRect(-25, -15, 25, 15, 3) { ResolutionScale = 10 }.Extrude(BaseHeight), Name = "Base" }; children.Add(towerBase); // Add each section for (int i = 0; i < Sections; i++) { var temp = MaxTemperature - i * ChangeAmount; var section = new Object3D() { Matrix = Matrix4X4.CreateTranslation(0, 0, BaseHeight + i * SectionHeight), Name = $"{temp:0.##}" }; children.Add(section); // Add base mesh section.Children.Add(new Object3D() { Mesh = shape, Name = "CC - gaaZolee - AS" }); // Add temp changer section.Children.Add(new SetTemperatureObject3D() { Temperature = temp, Name = $"Set to {temp:0.##}", Matrix = Matrix4X4.CreateScale(.2, .1, 1) }); // Add temperature text var text = new TextObject3D() { Font = NamedTypeFace.Fredoka, Height = 1, Name = $"{temp:0.##}", PointSize = 10, NameToWrite = $"{temp:0.##}", Matrix = Matrix4X4.CreateRotationX(MathHelper.Tau / 4) * Matrix4X4.CreateTranslation(0, -4.3, .8), }; text.Rebuild().Wait(); var textBounds = text.GetAxisAlignedBoundingBox(); text.Matrix *= Matrix4X4.CreateTranslation(11 - textBounds.MaxXYZ.X, 0, 0); section.Children.Add(text); } }); } } Invalidate(InvalidateType.DisplayValues); Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Mesh)); return(Task.CompletedTask); }