public static void ApplyTransformationToWidgetsGroupObb(IList <Widget> widgetsInParentSpace, Vector2d?overridePivotInParentSpace, bool obbInFirstWidgetSpace, Vector2d currentMousePosInParentSpace, Vector2d previousMousePosInParentSpace, bool convertScaleToSize, CalculateTransformationDelegate onCalculateTransformation) { if (widgetsInParentSpace.Count == 0) { return; } // Importent. Try to correct the pivot point to the closest pivot of one of widgets. if (overridePivotInParentSpace != null) { foreach (Widget widget in widgetsInParentSpace) { double length = ((Vector2d)widget.Position - overridePivotInParentSpace.Value).Length; if (length <= 1e-3) { overridePivotInParentSpace = (Vector2d)widget.Position; break; } } } Matrix32d originalObbToParentSpace; if (!obbInFirstWidgetSpace) { originalObbToParentSpace = Matrix32d.Translation(overridePivotInParentSpace ?? (Vector2d)widgetsInParentSpace[0].Position); } else { Widget widgetFirst = widgetsInParentSpace[0]; WidgetZeroScalePreserver zeroScalePreserver = new WidgetZeroScalePreserver(widgetFirst); zeroScalePreserver.Store(); // Nullify Pivot and Scale, to simplify transformation matrix from M = mT' * mR * mS * mT, to M = mR * mT, // to be able to use it with complex transformation by user (U = uT' uR * uS * uT), as // dM = U * M, instead of we must make dM = mT' * uR * mR * uS * mS * uT * mT, // and now if mT' = 1 and mS = 1 and uT = 1 it is reduced to dM = uT' * uS * uR * mR * mT = U * M. Matrix32d firstWidgetToParentSpace; Vector2 savedPivot = widgetFirst.Pivot; Vector2 savedScale = widgetFirst.Scale; widgetFirst.Pivot = Vector2.Zero; widgetFirst.Scale = Vector2.One; try { firstWidgetToParentSpace = widgetFirst.CalcLocalToParentTransformDouble(); if (overridePivotInParentSpace != null) { firstWidgetToParentSpace.T = overridePivotInParentSpace.Value; } } finally { widgetFirst.Pivot = savedPivot; widgetFirst.Scale = savedScale; zeroScalePreserver.Restore(); } originalObbToParentSpace = firstWidgetToParentSpace; } ApplyTransformationToWidgetsGroupObb( widgetsInParentSpace, originalObbToParentSpace, currentMousePosInParentSpace, previousMousePosInParentSpace, convertScaleToSize, onCalculateTransformation); }
public static void ApplyTransformationToWidgetsGroupObb(IEnumerable <Widget> widgetsInParentSpace, Matrix32d obbInParentSpace, Transform2d obbTransformation, bool convertScaleToSize) { Matrix32d originalObbToParentSpace = obbInParentSpace; if (Math.Abs(originalObbToParentSpace.CalcDeterminant()) < Mathf.ZeroTolerance) { return; } Matrix32d obbTransformationMatrix = obbTransformation.ToMatrix32(); foreach (Widget widget in widgetsInParentSpace) { WidgetZeroScalePreserver zeroScalePreserver = new WidgetZeroScalePreserver(widget); zeroScalePreserver.Store(); try { Matrix32d widgetToParentSpace = widget.CalcLocalToParentTransformDouble(); Matrix32d widgetToOriginalObbSpace = widgetToParentSpace * originalObbToParentSpace.CalcInversed(); // Calculate the new obb transformation in the parent space. Matrix32d deformedObbToParentSpace = obbTransformationMatrix * originalObbToParentSpace; Matrix32d deformedWidgetToParentSpace = widgetToOriginalObbSpace * deformedObbToParentSpace; Transform2d widgetResultTransform = widget.ExtractTransform2Double(deformedWidgetToParentSpace, widget.Rotation + obbTransformation.Rotation); // Correct a rotation delta, to prevent wrong values if a new angle 0 and previous is 359, // then rotationDelta must be 1. double rotationDelta = Mathd.Wrap180(widgetResultTransform.Rotation - widget.Rotation); // Reduce an influence of small transformations (Scale, Position, Rotation). bool needChangeScaleX = IsSignificantChangeOfValue(widget.Scale.X, widgetResultTransform.Scale.X); bool needChangeScaleY = IsSignificantChangeOfValue(widget.Scale.Y, widgetResultTransform.Scale.Y); if (needChangeScaleX || needChangeScaleY) { Vector2 useScale = new Vector2( (float)(!needChangeScaleX ? widget.Scale.X : widgetResultTransform.Scale.X), (float)(!needChangeScaleY ? widget.Scale.Y : widgetResultTransform.Scale.Y) ); useScale = zeroScalePreserver.AdjustToScale(useScale); zeroScalePreserver.Restore(); if (!convertScaleToSize) { SetAnimableProperty.Perform(widget, nameof(Widget.Scale), useScale, CoreUserPreferences.Instance.AutoKeyframes); } else { Vector2 useSize = new Vector2( Math.Abs(widget.Scale.X) < FloatSignificantDelta ? widget.Size.X : widget.Size.X * Math.Abs(useScale.X / widget.Scale.X), Math.Abs(widget.Scale.Y) < FloatSignificantDelta ? widget.Size.Y : widget.Size.Y * Math.Abs(useScale.Y / widget.Scale.Y) ); SetAnimableProperty.Perform(widget, nameof(Widget.Size), useSize, CoreUserPreferences.Instance.AutoKeyframes); } } bool needChangePositionX = IsSignificantChangeOfValue(widget.Position.X, widgetResultTransform.Translation.X); bool needChangePositionY = IsSignificantChangeOfValue(widget.Position.Y, widgetResultTransform.Translation.Y); if (needChangePositionX || needChangePositionY) { SetAnimableProperty.Perform(widget, nameof(Widget.Position), new Vector2( (float)(!needChangePositionX ? widget.Position.X : widgetResultTransform.Translation.X), (float)(!needChangePositionY ? widget.Position.Y : widgetResultTransform.Translation.Y) ), CoreUserPreferences.Instance.AutoKeyframes); } if (IsSignificantChangeByDelta(widget.Rotation, rotationDelta)) { SetAnimableProperty.Perform(widget, nameof(Widget.Rotation), (float)(widget.Rotation + rotationDelta), CoreUserPreferences.Instance.AutoKeyframes); } } finally { zeroScalePreserver.Restore(); } } }