public void Update(GameTime gameTime) { if (State == AnimationState.Playing) { var currentTime = gameTime.TotalGameTime.Ticks; // Initialize the star time if necessary. if (_startTime < 0) { _startTime = currentTime; _endTime = _startTime + Duration.Ticks; AnimationStarted(); OnStarted(); } // Calculate the current progress. Position = MathHelper.Clamp(1.0f - 1.0f / (_endTime - _startTime) * (_endTime - currentTime), 0.0f, 1.0f); OnProgress(Position); // Calculate the easing. var easing = Easing != null?Easing.Calculate(Position) : Position; DoAnimation(Position, easing); // Check if the animation has been finished. if (currentTime >= _endTime) { State = AnimationState.Finished; AnimationFinished(); OnFinished(); } } }
public void StaticFunctionTests() { void InverseWorking(Easing.EaseType easeType, Easing.EaseOption easeOption, double k) { var output = Easing.Calculate(easeType, easeOption, k); var input = Easing.CalculateInverse(easeType, easeOption, output); Assert.AreEqual(k, input, .001); } void RangeTest(Easing.EaseType easeType) { for (double i = 0; i <= 1; i += .05) { InverseWorking(easeType, Easing.EaseOption.In, i); InverseWorking(easeType, Easing.EaseOption.InOut, i); InverseWorking(easeType, Easing.EaseOption.Out, i); } } RangeTest(Easing.EaseType.Linear); RangeTest(Easing.EaseType.Cubic); RangeTest(Easing.EaseType.Quadratic); }
public override Task Rebuild() { this.DebugDepth("Rebuild"); bool valuesChanged = false; if (Angle < 1 || Angle > 100000) { Angle = Math.Min(100000, Math.Max(1, Angle)); valuesChanged = true; } if (RotationDistance < 0 || RotationDistance > 100000) { RotationDistance = Math.Min(100000, Math.Max(0, RotationDistance)); valuesChanged = true; } if (RotationSlices < 3 || RotationSlices > 300) { RotationSlices = Math.Min(300, Math.Max(3, RotationSlices)); valuesChanged = true; } if (EndHeightPercent < 1 || EndHeightPercent > 100) { EndHeightPercent = Math.Min(100, Math.Max(1, EndHeightPercent)); valuesChanged = true; } if (StartHeightPercent < 0 || StartHeightPercent > EndHeightPercent - 1) { StartHeightPercent = Math.Min(EndHeightPercent - 1, Math.Max(0, StartHeightPercent)); valuesChanged = true; } if (OverrideRadius < .01) { OverrideRadius = Math.Max(this.GetAxisAlignedBoundingBox().XSize, this.GetAxisAlignedBoundingBox().YSize); valuesChanged = true; } var rebuildLocks = this.RebuilLockAll(); return(ApplicationController.Instance.Tasks.Execute( "Twist".Localize(), null, (reporter, cancellationToken) => { var sourceAabb = this.SourceContainer.GetAxisAlignedBoundingBox(); var bottom = sourceAabb.MinXYZ.Z; var top = sourceAabb.ZSize * EndHeightPercent / 100.0; var size = sourceAabb.ZSize; if (Advanced) { bottom += sourceAabb.ZSize * StartHeightPercent / 100.0; size = top - bottom; } double numberOfCuts = RotationSlices; double cutSize = size / numberOfCuts; var cuts = new List <double>(); for (int i = 0; i < numberOfCuts + 1; i++) { var ratio = i / numberOfCuts; if (Advanced) { var goal = ratio; var current = .5; var next = .25; // look for an x value that equals the goal for (int j = 0; j < 64; j++) { var xAtY = Easing.Calculate(EasingType, EasingOption, current); if (xAtY < goal) { current += next; } else if (xAtY > goal) { current -= next; } next *= .5; } ratio = current; } cuts.Add(bottom - cutSize + (size * ratio)); } // get the rotation from the center of the circumscribed circle of the convex hull var enclosingCircle = SourceContainer.GetSmallestEnclosingCircleAlongZ(); var rotationCenter = enclosingCircle.Center + RotationOffset; var twistedChildren = new List <IObject3D>(); var status = new ProgressStatus(); foreach (var sourceItem in SourceContainer.VisibleMeshes()) { var originalMesh = sourceItem.Mesh; status.Status = "Copy Mesh".Localize(); reporter.Report(status); var transformedMesh = originalMesh.Copy(CancellationToken.None); var itemMatrix = sourceItem.WorldMatrix(SourceContainer); // transform into this space transformedMesh.Transform(itemMatrix); status.Status = "Split Mesh".Localize(); reporter.Report(status); // split the mesh along the z axis transformedMesh.SplitOnPlanes(Vector3.UnitZ, cuts, cutSize / 8); for (int i = 0; i < transformedMesh.Vertices.Count; i++) { var position = transformedMesh.Vertices[i]; var ratio = (position.Z - bottom) / size; if (Advanced) { if (position.Z < bottom) { ratio = 0; } else if (position.Z > top) { ratio = 1; } else { ratio = (position.Z - bottom) / size; ratio = Easing.Calculate(EasingType, EasingOption, ratio); } } var angleToRotate = ratio * Angle / 360.0 * MathHelper.Tau; if (RotationType == RotationTypes.Distance) { IRadiusProvider radiusProvider = RadiusProvider; // start off with assuming we want to set the radius var radius = this.OverrideRadius; if (radiusProvider != null && !this.EditRadius) { // have a radius provider and not wanting to edit radius = radiusProvider.Radius; } else if (!this.EditRadius) { // not wanting to edit radius = enclosingCircle.Radius; } if (this.PreferedRadius != radius) { this.PreferedRadius = radius; this.OverrideRadius = radius; UiThread.RunOnIdle(() => Invalidate(InvalidateType.DisplayValues)); } angleToRotate = ratio * (RotationDistance / radius); } if (!TwistCw) { angleToRotate = -angleToRotate; } var positionXy = new Vector2(position) - rotationCenter; positionXy.Rotate(angleToRotate); positionXy += rotationCenter; transformedMesh.Vertices[i] = new Vector3Float(positionXy.X, positionXy.Y, position.Z); } // transform back into item local space transformedMesh.Transform(itemMatrix.Inverted); //transformedMesh.MergeVertices(.1); transformedMesh.CalculateNormals(); var twistedChild = new Object3D() { Mesh = transformedMesh }; twistedChild.CopyWorldProperties(sourceItem, SourceContainer, Object3DPropertyFlags.All, false); twistedChild.Visible = true; twistedChildren.Add(twistedChild); } RemoveAllButSource(); this.SourceContainer.Visible = false; this.Children.Modify((list) => { list.AddRange(twistedChildren); }); if (valuesChanged) { Invalidate(InvalidateType.DisplayValues); } UiThread.RunOnIdle(() => { rebuildLocks.Dispose(); Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children)); }); return Task.CompletedTask; })); }
public static GuiWidget GetFieldContentWithSlider(EditableProperty property, PPEContext context, UIField field, UndoBuffer undoBuffer, Func <string, object> valueFromString, ThemeConfig theme) { var sliderAttribute = property.PropertyInfo.GetCustomAttributes(true).OfType <SliderAttribute>().FirstOrDefault(); if (sliderAttribute != null) { var min = sliderAttribute.Min; var max = sliderAttribute.Max; var delta = max - min; // the slider values go from 0 to 1 and are then mapped during translation to the field var slider = new Slider(new Vector2(0, 0), 80 * GuiWidget.DeviceScale, 0, 1) { VAnchor = VAnchor.Center, }; slider.View.TrackColor = theme.TextColor; slider.View.ThumbColor = theme.PrimaryAccentColor; slider.View.TrackHeight = 1 * GuiWidget.DeviceScale; Func <double> getFieldValue = null; double GetSlider0To1FromField() { return(GetSlider0To1FromValue(getFieldValue())); } double GetSlider0To1FromValue(double value) { var mapped0To1 = Math.Max(0, Math.Min(1, (value - min) / delta)); return(Easing.CalculateInverse(sliderAttribute.EasingType, sliderAttribute.EaseOption, mapped0To1)); } double GetFieldFromSlider0To1() { var fieldValue = Easing.Calculate(sliderAttribute.EasingType, sliderAttribute.EaseOption, slider.Value) * delta + min; var snapGridDistance = sliderAttribute.SnapDistance; if (sliderAttribute.UseSnappingGrid) { snapGridDistance = SnapGridDistance(); } if (snapGridDistance > 0) { // snap this position to the grid // snap this position to the grid fieldValue = ((int)((fieldValue / snapGridDistance) + .5)) * snapGridDistance; } return(fieldValue); } double SnapGridDistance() { var view3DWidget = slider.Parents <View3DWidget>().FirstOrDefault(); if (view3DWidget != null) { var object3DControlLayer = view3DWidget.Descendants <Object3DControlsLayer>().FirstOrDefault(); if (object3DControlLayer != null) { return(object3DControlLayer.SnapGridDistance); } } return(0); } var changeDueToSlider = false; var changeDueToField = false; slider.ValueChanged += (s, e) => { if (!changeDueToField) { changeDueToSlider = true; SetValue(property, context, valueFromString, GetFieldFromSlider0To1()); changeDueToSlider = false; } }; double sliderDownValue = 0; slider.SliderGrabed += (s, e) => { sliderDownValue = getFieldValue(); }; slider.SliderReleased += (s, e) => { var currentValue = GetFieldFromSlider0To1(); changeDueToSlider = true; SetValue(property, context, valueFromString, currentValue); changeDueToSlider = false; // save the undo information undoBuffer.Add(new UndoRedoActions(() => { SetValue(property, context, valueFromString, sliderDownValue); }, () => { SetValue(property, context, valueFromString, currentValue); })); }; GuiWidget content = null; var sliderRightMargin = 11; if (field is DoubleField doubleField) { getFieldValue = () => doubleField.DoubleValue; doubleField.ValueChanged += (s, e) => { changeDueToField = true; slider.Value = GetSlider0To1FromField(); changeDueToField = false; }; content = new FlowLayoutWidget(); content.AddChild(slider); content.AddChild(new GuiWidget() { Width = sliderRightMargin * GuiWidget.DeviceScale, Height = 3 }); content.AddChild(field.Content); } else if (field is ExpressionField expressionField) { getFieldValue = () => { if (double.TryParse(expressionField.Value, out double value)) { return(value); } return(0); }; expressionField.ValueChanged += (s, e) => { if (!changeDueToSlider) { changeDueToField = true; slider.Value = GetSlider0To1FromField(); changeDueToField = false; } }; expressionField.Content.Descendants <TextWidget>().First().TextChanged += (s, e) => { if (!changeDueToSlider) { changeDueToField = true; var textWidget = expressionField.Content.Descendants <TextWidget>().First(); double.TryParse(textWidget.Text, out double textWidgetValue); slider.Value = GetSlider0To1FromValue(textWidgetValue); changeDueToField = false; } }; var leftHold = new FlowLayoutWidget() { HAnchor = HAnchor.Stretch, Margin = new BorderDouble(0, 0, 66 / GuiWidget.DeviceScale + sliderRightMargin, 0) }; leftHold.AddChild(new HorizontalSpacer()); leftHold.AddChild(slider); field.Content.AddChild(leftHold, 0); content = field.Content; } // set the initial value of the slider changeDueToField = true; slider.Value = GetSlider0To1FromField(); changeDueToField = false; return(content); } return(field.Content); }