public static double AngleRad(Vector v1, Vector v2) { Debug.Assert(v1.IsValid()); Debug.Assert(v2.IsValid()); double dot = Dot(v1, v2); double dotNormalize = dot / (v1.Length * v2.Length); double acos = Math.Acos(dotNormalize); return acos; }
public static double Dot(Vector v1, Vector v2) { Debug.Assert(v1.IsValid()); Debug.Assert(v2.IsValid()); return v1.X * v2.X + v1.Y * v2.Y; }
public static bool Animate( Point currentValue, Vector currentVelocity, Point targetValue, double attractionFator, double dampening, double terminalVelocity, double minValueDelta, double minVelocityDelta, out Point newValue, out Vector newVelocity) { Debug.Assert(currentValue.IsValid()); Debug.Assert(currentVelocity.IsValid()); Debug.Assert(targetValue.IsValid()); Debug.Assert(dampening.IsValid()); Debug.Assert(dampening > 0 && dampening < 1); Debug.Assert(attractionFator.IsValid()); Debug.Assert(attractionFator > 0); Debug.Assert(terminalVelocity > 0); Debug.Assert(minValueDelta > 0); Debug.Assert(minVelocityDelta > 0); Vector diff = targetValue.Subtract(currentValue); if (diff.Length > minValueDelta || currentVelocity.Length > minVelocityDelta) { newVelocity = currentVelocity * (1 - dampening); newVelocity += diff * attractionFator; if (currentVelocity.Length > terminalVelocity) { newVelocity *= terminalVelocity / currentVelocity.Length; } newValue = currentValue + newVelocity; return true; } else { newValue = targetValue; newVelocity = new Vector(); return false; } }
public bool TickData(Vector lastMouse, bool isFlipped) { bool somethingChanged = false; //active means nothing in the "flipped" mode bool isActiveItem = IsMouseOver && !isFlipped; bool goodMouse = lastMouse.IsValid(); #region rotation Quaternion rotationTarget = new Quaternion(new Vector3D(1, 0, 0), 0); //apply forces rotationTarget.Normalize(); m_rotationCurrent.Normalize(); double angle = 0; Vector3D axis = new Vector3D(0, 0, 1); if (lastMouse.IsValid() && !isFlipped) { Point3D mouse = new Point3D(lastMouse.X, lastMouse.Y, 1); Vector3D line = mouse - m_locationCurrent; Vector3D straight = new Vector3D(0, 0, 1); angle = Vector3D.AngleBetween(line, straight); axis = Vector3D.CrossProduct(line, straight); } Quaternion rotationForceTowardsMouse = new Quaternion(axis, -angle); Quaternion rotationForceToDesired = rotationTarget - m_rotationCurrent; Quaternion rotationForce = rotationForceToDesired + rotationForceTowardsMouse; m_rotationVelocity *= new Quaternion(rotationForce.Axis, rotationForce.Angle * .2); //dampenning m_rotationVelocity = new Quaternion(m_rotationVelocity.Axis, m_rotationVelocity.Angle * (m_weird - .3)); //apply terminal velocity m_rotationVelocity = new Quaternion(m_rotationVelocity.Axis, m_rotationVelocity.Angle); m_rotationVelocity.Normalize(); //apply to position m_rotationCurrent *= m_rotationVelocity; m_rotationCurrent.Normalize(); //see if there is any real difference between what we calculated and what actually exists if (AnyDiff(m_quaternionRotation3D.Quaternion.Axis, m_rotationCurrent.Axis, c_diff) || AnyDiff(m_quaternionRotation3D.Quaternion.Angle, m_rotationCurrent.Angle, c_diff)) { //if the angles are both ~0, the axis may be way off but the result is basically the same //check for this and forget animating in this case if (AnyDiff(m_quaternionRotation3D.Quaternion.Angle, 0, c_diff) || AnyDiff(m_rotationCurrent.Angle, 0, c_diff)) { m_quaternionRotation3D.Quaternion = m_rotationCurrent; somethingChanged = true; } } #endregion #region flip double verticalFlipTarget = isFlipped ? 180 : 0; double verticalFlipCurrent = m_verticalFlipRotation.Angle; //force double verticalFlipForce = verticalFlipTarget - verticalFlipCurrent; //velocity m_flipVerticalVelocity += .3 * verticalFlipForce; //dampening m_flipVerticalVelocity *= (m_weird - .3); //terminal velocity m_flipVerticalVelocity = limitDouble(m_flipVerticalVelocity, 10); //apply verticalFlipCurrent += m_flipVerticalVelocity; if (AnyDiff(verticalFlipCurrent, m_verticalFlipRotation.Angle, c_diff) && AnyDiff(m_flipVerticalVelocity, 0, c_diff)) { m_verticalFlipRotation.Angle = verticalFlipCurrent; } #endregion #region scale if (isActiveItem && !isFlipped) { this.m_scaleDesired = 2; } else { this.m_scaleDesired = 1; } double scaleForce = this.m_scaleDesired - this.m_scaleCurrent; this.m_scaleVelocity += .1 * scaleForce; //dampening this.m_scaleVelocity *= .8; //terminal velocity this.m_scaleVelocity = limitDouble(this.m_scaleVelocity, .05); this.m_scaleCurrent += this.m_scaleVelocity; if (AnyDiff(m_scaleTransform.ScaleX, m_scaleCurrent, c_diff) || AnyDiff(m_scaleTransform.ScaleY, m_scaleCurrent, c_diff)) { this.m_scaleTransform.ScaleX = this.m_scaleCurrent; this.m_scaleTransform.ScaleY = this.m_scaleCurrent; somethingChanged = true; } #endregion #region location Vector3D locationForce; //apply forces if (isActiveItem) { m_locationDesired.Z = .1; } else { m_locationDesired.Z = 0; } locationForce = m_locationDesired - m_locationCurrent; //only repel the non-active items if (!isActiveItem && goodMouse && !isFlipped) { locationForce += .025 * invertVector(this.CurrentLocationVector - new Vector3D(lastMouse.X, lastMouse.Y, 0)); } m_locationVelocity += .1 * locationForce; //apply dampenning m_locationVelocity *= (m_weird - .3); //apply terminal velocity m_locationVelocity = limitVector3D(m_locationVelocity, .3); //apply velocity to location m_locationCurrent += m_locationVelocity; if ((GetVector(m_translate) - (Vector3D)m_locationCurrent).Length > c_diff) { m_translate.OffsetX = m_locationCurrent.X; m_translate.OffsetY = m_locationCurrent.Y; m_translate.OffsetZ = m_locationCurrent.Z; somethingChanged = true; } #endregion return somethingChanged; }
private static Vector Normalize(Vector v) { v.Normalize(); Debug.Assert(v.IsValid()); return v; }
private static Vector GetSpringForce(Vector x) { Vector force = new Vector(); //negative is attraction force += GetAttractionForce(x); //positive is repulsion force += GetRepulsiveForce(x); Debug.Assert(force.IsValid()); return force; }
/// <summary/> protected override Vector GetCurrentValueCore(Vector baseFromValue, Vector baseToValue, AnimationClock animationClock) { var progress = animationClock.CurrentProgress; if (!progress.HasValue || Interpolator == null) { return base.GetCurrentValueCore(baseFromValue, baseToValue, animationClock); } var fromValue = new Vector(); var toValue = new Vector(); var offset = new Vector(); var isValid = true; if (From.HasValue) { fromValue = From.Value; if (To.HasValue) { // from ... to toValue = To.Value; if (IsAdditive) { offset = baseFromValue; isValid = offset.IsValid(); } } else if (By.HasValue) { // from ... from+by toValue = fromValue + By.Value; if (IsAdditive) { offset = baseFromValue; isValid = offset.IsValid(); } } else { // from ... base toValue = baseToValue; isValid = toValue.IsValid(); } } else if (To.HasValue) { // base ... to fromValue = baseFromValue; toValue = To.Value; isValid = fromValue.IsValid(); } else if (By.HasValue) { // base ... base+by toValue = By.Value; offset = baseFromValue; isValid = offset.IsValid(); } else { // base ... base fromValue = baseFromValue; toValue = baseToValue; isValid = fromValue.IsValid() && toValue.IsValid(); } if (!isValid) { throw new InvalidOperationException("GetCurrentValueCore"); } if (IsCumulative) { var iteration = animationClock.CurrentIteration; if (iteration.HasValue && iteration.Value > 1) { offset += (toValue - fromValue) * (iteration.Value - 1); } } var interpolator = Interpolator ?? Interpolators.Linear; return fromValue + (toValue - fromValue) * interpolator(progress.Value, 0.0, 1.0) + offset; }