public static void ThrowIfNaN(this Vector2 vector, string exceptionString) { if (vector.IsNaN()) { throw new ArithmeticException(exceptionString); } }
/// <summary> /// Calculates the dimension offset from a point along the dimension line. /// </summary> /// <param name="point">Point along the dimension line.</param> public void SetDimensionLinePosition(Vector2 point) { Vector2 dirRef1 = this.endFirstLine - this.startFirstLine; Vector2 dirRef2 = this.endSecondLine - this.startSecondLine; Vector2 center = MathHelper.FindIntersection(this.startFirstLine, dirRef1, this.startSecondLine, dirRef2); if (Vector2.IsNaN(center)) { throw new ArgumentException("The two lines that define the dimension are parallel."); } Vector2 dirOffset = point - center; this.offset = Vector2.Distance(center, point); double cross = Vector2.CrossProduct(dirRef1, dirRef2); if (cross < 0) { Vector2 tmp = this.startFirstLine; this.startFirstLine = this.endFirstLine; this.endFirstLine = tmp; tmp = this.startSecondLine; this.startSecondLine = this.endSecondLine; this.endSecondLine = tmp; } double crossStart = Vector2.CrossProduct(dirRef1, dirOffset); double crossEnd = Vector2.CrossProduct(dirRef2, dirOffset); if (crossStart >= 0 && crossEnd < 0) { } if (crossStart >= 0 && crossEnd >= 0) { Vector2 tmp = this.startFirstLine; this.startFirstLine = this.endFirstLine; this.endFirstLine = tmp; } if (crossStart < 0 && crossEnd >= 0) { Vector2 tmp = this.startFirstLine; this.startFirstLine = this.endFirstLine; this.endFirstLine = tmp; tmp = this.startSecondLine; this.startSecondLine = this.endSecondLine; this.endSecondLine = tmp; } if (crossStart < 0 && crossEnd < 0) { Vector2 tmp = this.startSecondLine; this.startSecondLine = this.endSecondLine; this.endSecondLine = tmp; } }
public void Vector2_IsNaN_Test() { var a = new Vector2(float.NaN, 10); var b = new Vector2(10, float.NaN); var c = new Vector2(float.NaN, float.NaN); var d = new Vector2(10, 10); Assert.IsTrue(a.IsNaN()); Assert.IsTrue(b.IsNaN()); Assert.IsTrue(c.IsNaN()); Assert.IsFalse(d.IsNaN()); }
/// <summary> /// Calculate the dimension reference points. /// </summary> protected override void CalculteReferencePoints() { DimensionStyleOverride styleOverride; double measure = this.Measurement * MathHelper.DegToRad; Vector2 center = this.CenterPoint; if (Vector2.IsNaN(center)) { throw new ArgumentException("The two lines that define the dimension are parallel."); } double startAngle = Vector2.Angle(center, this.endFirstLine); double midRot = startAngle + measure * 0.5; Vector2 midDim = Vector2.Polar(center, this.offset, midRot); this.defPoint = this.endSecondLine; this.arcDefinitionPoint = midDim; if (this.TextPositionManuallySet) { DimensionStyleFitTextMove moveText = this.Style.FitTextMove; if (this.StyleOverrides.TryGetValue(DimensionStyleOverrideType.FitTextMove, out styleOverride)) { moveText = (DimensionStyleFitTextMove)styleOverride.Value; } if (moveText == DimensionStyleFitTextMove.BesideDimLine) { this.SetDimensionLinePosition(this.textRefPoint, false); } } else { double textGap = this.Style.TextOffset; if (this.StyleOverrides.TryGetValue(DimensionStyleOverrideType.TextOffset, out styleOverride)) { textGap = (double)styleOverride.Value; } double scale = this.Style.DimScaleOverall; if (this.StyleOverrides.TryGetValue(DimensionStyleOverrideType.DimScaleOverall, out styleOverride)) { scale = (double)styleOverride.Value; } double gap = textGap * scale; this.textRefPoint = midDim + gap * Vector2.Normalize(midDim - center); } }
protected override void Manipulate() { Vector3 center = (FirstGrabbingHand.transform.position + SecondGrabbingHand.transform.position) / 2f; Vector3 offset = TargetTransform.position - center; float currentDistance = Vector3.Distance(FirstGrabbingHand.transform.position, SecondGrabbingHand.transform.position); float multiplier = currentDistance / _priorDistance; multiplier = Mathf.Clamp(multiplier, .5f, 1.5f); if (_exponentialScaling) { multiplier = Mathf.Pow(multiplier, _gammaScalePower); } RectTransform rectTransform = TargetTransform as RectTransform; if (rectTransform != null && _scaleSizeDelta) { Vector2 newSize = rectTransform.sizeDelta * multiplier; if (newSize.IsNaN()) { return; } if (newSize.x < _maxSize.x && newSize.y < _maxSize.y && newSize.x > _minSize.x && newSize.y > _minSize.y) { rectTransform.sizeDelta = newSize; OnScaleChanged(newSize); Move(center + (offset * multiplier)); } } else { Vector3 newScale = TargetTransform.localScale * multiplier; if (newScale.IsNaN()) { return; } if (newScale.x < _maxSize.x && newScale.y < _maxSize.y && newScale.x > _minSize.x && newScale.y > _minSize.y) { TargetTransform.localScale = newScale; OnScaleChanged(newScale); Move(center + (offset * multiplier)); } } _priorDistance = currentDistance; }
/// <summary> /// Clamps the camera to a specified range. If the ClampToMap field is set, the range will be dimensions of the active map. /// Otherwise, it will use the Vector2 CameraClampRange. If CameraClampRange is not set, it will be unbounded. /// </summary> public Vector2 CameraClamp(Vector2 position) { // If the clamp variables aren't set, literally have the clamp value be unbounded. var cameraMax = new Vector2(Int32.MaxValue, Int32.MaxValue); if (_clampToMap) { cameraMax = new Vector2(scene.Map.Width - (_viewportWidth / Zoom / 2), scene.Map.Height - (_viewportHeight / Zoom / 2)); } if (!_clampToMap && !_clampRange.IsNaN()) { cameraMax = new Vector2(_clampRange.X / Zoom / 2, _clampRange.Y / Zoom / 2); } return(Vector2.Clamp(position, new Vector2(_viewportWidth / Zoom / 2, _viewportHeight / Zoom / 2), cameraMax)); }
public override Vector3 PickPosition(bool local = false) { // Get the appropriate bounding rect values, local or not Bounds bounds = collider2D.bounds; if (local) { bounds.min = transform.InverseTransformPoint(bounds.min); bounds.max = transform.InverseTransformPoint(bounds.max); } Vector2 pos = MathUtils.NaNVector2; // Pick a position in the bounding rect, check if it's in the area // If it's not, keep trying until it is while (pos.IsNaN()) { Vector2 posAttempt = new Vector2(Random.Range(bounds.min.x, bounds.max.x), Random.Range(bounds.min.y, bounds.max.y)); if (IsInArea(posAttempt, local)) { pos = posAttempt; } } return(pos); }
private void SetDimensionLinePosition(Vector2 point, bool updateRefs) { Vector2 center = this.CenterPoint; if (Vector2.IsNaN(center)) { throw new ArgumentException("The two lines that define the dimension are parallel."); } if (updateRefs) { double cross = Vector2.CrossProduct(this.EndFirstLine - this.StartFirstLine, this.EndSecondLine - this.StartSecondLine); if (cross < 0) { Vector2 temp1 = this.startFirstLine; Vector2 temp2 = this.endFirstLine; this.startFirstLine = this.startSecondLine; this.endFirstLine = this.endSecondLine; this.startSecondLine = temp1; this.endSecondLine = temp2; } Vector2 ref1Start = this.StartFirstLine; Vector2 ref1End = this.EndFirstLine; Vector2 ref2Start = this.StartSecondLine; Vector2 ref2End = this.EndSecondLine; Vector2 dirRef1 = ref1End - ref1Start; Vector2 dirRef2 = ref2End - ref2Start; Vector2 dirOffset = point - center; double crossStart = Vector2.CrossProduct(dirRef1, dirOffset); double crossEnd = Vector2.CrossProduct(dirRef2, dirOffset); if (crossStart >= 0 && crossEnd >= 0) { this.StartFirstLine = ref2Start; this.EndFirstLine = ref2End; this.StartSecondLine = ref1End; this.EndSecondLine = ref1Start; } else if (crossStart < 0 && crossEnd >= 0) { this.StartFirstLine = ref1End; this.EndFirstLine = ref1Start; this.StartSecondLine = ref2End; this.EndSecondLine = ref2Start; } else if (crossStart < 0 && crossEnd < 0) { this.StartFirstLine = ref2End; this.EndFirstLine = ref2Start; this.StartSecondLine = ref1Start; this.EndSecondLine = ref1End; } } this.offset = Vector2.Distance(center, point); this.defPoint = this.endSecondLine; double measure = this.Measurement * MathHelper.DegToRad; double startAngle = Vector2.Angle(center, this.endFirstLine); double midRot = startAngle + measure * 0.5; Vector2 midDim = Vector2.Polar(center, this.offset, midRot); this.arcDefinitionPoint = midDim; if (!this.TextPositionManuallySet) { DimensionStyleOverride styleOverride; double textGap = this.Style.TextOffset; if (this.StyleOverrides.TryGetValue(DimensionStyleOverrideType.TextOffset, out styleOverride)) { textGap = (double)styleOverride.Value; } double scale = this.Style.DimScaleOverall; if (this.StyleOverrides.TryGetValue(DimensionStyleOverrideType.DimScaleOverall, out styleOverride)) { scale = (double)styleOverride.Value; } double gap = textGap * scale; this.textRefPoint = midDim + gap * Vector2.Normalize(midDim - center); } }
public virtual bool Intersects(Line2D line) { Vector2 point = IntersectionPoint(line); return !point.IsNaN() && !point.IsInfinity(); }
public virtual bool Intersects(Segment2D segment) { Vector2 point = IntersectionPoint(segment); return !point.IsNaN() && !point.IsInfinity() && Contains(point) && segment.Contains(point); }
/// <summary> /// Moves, scales, and/or rotates the current entity given a 3x3 transformation matrix and a translation vector. /// </summary> /// <param name="transformation">Transformation matrix.</param> /// <param name="translation">Translation vector.</param> /// <remarks>Matrix3 adopts the convention of using column vectors to represent a transformation matrix.</remarks> public override void TransformBy(Matrix3 transformation, Vector3 translation) { // NOTE: this is a generic implementation of the ellipse transformation, // for non rotated ellipses and/or uniform scaling the code can be simplified // rectangle that circumscribe the ellipse double semiMajorAxis = this.MajorAxis * 0.5; double semiMinorAxis = this.MinorAxis * 0.5; Vector2 p1 = new Vector2(-semiMajorAxis, semiMinorAxis); Vector2 p2 = new Vector2(semiMajorAxis, semiMinorAxis); Vector2 p3 = new Vector2(-semiMajorAxis, -semiMinorAxis); Vector2 p4 = new Vector2(semiMajorAxis, -semiMinorAxis); List <Vector2> ocsPoints = MathHelper.Transform(new[] { p1, p2, p3, p4 }, this.Rotation * MathHelper.DegToRad, CoordinateSystem.Object, CoordinateSystem.World); Vector3 p1Prime = new Vector3(ocsPoints[0].X, ocsPoints[0].Y, 0.0); Vector3 p2Prime = new Vector3(ocsPoints[1].X, ocsPoints[1].Y, 0.0); Vector3 p3Prime = new Vector3(ocsPoints[2].X, ocsPoints[2].Y, 0.0); Vector3 p4Prime = new Vector3(ocsPoints[3].X, ocsPoints[3].Y, 0.0); List <Vector3> wcsPoints = MathHelper.Transform(new[] { p1Prime, p2Prime, p3Prime, p4Prime }, this.Normal, CoordinateSystem.Object, CoordinateSystem.World); for (int i = 0; i < wcsPoints.Count; i++) { wcsPoints[i] += this.Center; wcsPoints[i] = transformation * wcsPoints[i]; wcsPoints[i] += translation; } Vector3 newNormal = transformation * this.Normal; if (Vector3.Equals(Vector3.Zero, newNormal)) { newNormal = this.Normal; } List <Vector3> rectPoints = MathHelper.Transform(wcsPoints, newNormal, CoordinateSystem.World, CoordinateSystem.Object); // corners of the transformed rectangle that circumscribe the new ellipse Vector2 pointA = new Vector2(rectPoints[0].X, rectPoints[0].Y); Vector2 pointB = new Vector2(rectPoints[1].X, rectPoints[1].Y); Vector2 pointC = new Vector2(rectPoints[2].X, rectPoints[2].Y); Vector2 pointD = new Vector2(rectPoints[3].X, rectPoints[3].Y); // the new ellipse is tangent at the mid points Vector2 pointM = Vector2.MidPoint(pointA, pointB); Vector2 pointN = Vector2.MidPoint(pointC, pointD); Vector2 pointH = Vector2.MidPoint(pointA, pointC); Vector2 pointK = Vector2.MidPoint(pointB, pointD); // we need to find a fifth point Vector2 origin = Vector2.MidPoint(pointH, pointK); Vector2 pointX = Vector2.MidPoint(pointH, origin); // a point along the OH segment // intersection line AC and line parallel to BC through pointX Vector2 pointY = MathHelper.FindIntersection(pointA, pointC - pointA, pointX, pointC - pointB); if (Vector2.IsNaN(pointY)) { Debug.Assert(false, "The transformation cannot be applied."); return; } // find the fifth point in the ellipse Vector2 pointZ = MathHelper.FindIntersection(pointM, pointX - pointM, pointN, pointY - pointN); if (Vector2.IsNaN(pointZ)) { Debug.Assert(false, "The transformation cannot be applied."); return; } Vector3 oldNormal = this.Normal; double oldRotation = this.Rotation * MathHelper.DegToRad; if (ConicThroughFivePoints.EllipseProperties(pointM, pointN, pointH, pointK, pointZ, out Vector2 _, out double newSemiMajorAxis, out double newSemiMinorAxis, out double newRotation)) { double axis1 = 2 * newSemiMajorAxis; axis1 = MathHelper.IsZero(axis1) ? MathHelper.Epsilon : axis1; double axis2 = 2 * newSemiMinorAxis; axis2 = MathHelper.IsZero(axis2) ? MathHelper.Epsilon : axis2; this.Center = transformation * this.Center + translation; this.MajorAxis = axis1; this.MinorAxis = axis2; this.Rotation = newRotation * MathHelper.RadToDeg; this.Normal = newNormal; }
/// <summary> /// Moves, scales, and/or rotates the current entity given a 3x3 transformation matrix and a translation vector. /// </summary> /// <param name="transformation">Transformation matrix.</param> /// <param name="translation">Translation vector.</param> /// <remarks>Matrix3 adopts the convention of using column vectors to represent a transformation matrix.</remarks> public override void TransformBy(Matrix3 transformation, Vector3 translation) { // NOTE: this is a generic implementation of the ellipse transformation, // for non rotated ellipses and/or uniform scaling the code can be simplified // rectangle that circumscribe the ellipse double semiMajorAxis = this.MajorAxis * 0.5; double semiMinorAxis = this.MinorAxis * 0.5; Vector2 p1 = new Vector2(-semiMajorAxis, semiMinorAxis); Vector2 p2 = new Vector2(semiMajorAxis, semiMinorAxis); Vector2 p3 = new Vector2(-semiMajorAxis, -semiMinorAxis); Vector2 p4 = new Vector2(semiMajorAxis, -semiMinorAxis); List <Vector2> ocsPoints = MathHelper.Transform(new[] { p1, p2, p3, p4 }, this.Rotation * MathHelper.DegToRad, CoordinateSystem.Object, CoordinateSystem.World); Vector3 p1Prime = new Vector3(ocsPoints[0].X, ocsPoints[0].Y, 0.0); Vector3 p2Prime = new Vector3(ocsPoints[1].X, ocsPoints[1].Y, 0.0); Vector3 p3Prime = new Vector3(ocsPoints[2].X, ocsPoints[2].Y, 0.0); Vector3 p4Prime = new Vector3(ocsPoints[3].X, ocsPoints[3].Y, 0.0); List <Vector3> wcsPoints = MathHelper.Transform(new[] { p1Prime, p2Prime, p3Prime, p4Prime }, this.Normal, CoordinateSystem.Object, CoordinateSystem.World); for (int i = 0; i < wcsPoints.Count; i++) { wcsPoints[i] += this.Center; wcsPoints[i] = transformation * wcsPoints[i]; wcsPoints[i] += translation; } Vector3 newNormal = transformation * this.Normal; if (Vector3.Equals(Vector3.Zero, newNormal)) { newNormal = this.Normal; } List <Vector3> rectPoints = MathHelper.Transform(wcsPoints, newNormal, CoordinateSystem.World, CoordinateSystem.Object); // corners of the transformed rectangle that circumscribe the new ellipse Vector2 pointA = new Vector2(rectPoints[0].X, rectPoints[0].Y); Vector2 pointB = new Vector2(rectPoints[1].X, rectPoints[1].Y); Vector2 pointC = new Vector2(rectPoints[2].X, rectPoints[2].Y); Vector2 pointD = new Vector2(rectPoints[3].X, rectPoints[3].Y); // the new ellipse is tangent at the mid points Vector2 pointM = Vector2.MidPoint(pointA, pointB); Vector2 pointN = Vector2.MidPoint(pointC, pointD); Vector2 pointH = Vector2.MidPoint(pointA, pointC); Vector2 pointK = Vector2.MidPoint(pointB, pointD); // we need to find a fifth point Vector2 origin = Vector2.MidPoint(pointH, pointK); Vector2 pointX = Vector2.MidPoint(pointH, origin); // a point along the OH segment // intersection line AC and line parallel to BC through pointX Vector2 pointY = MathHelper.FindIntersection(pointA, pointC - pointA, pointX, pointC - pointB); if (Vector2.IsNaN(pointY)) { Debug.Assert(false, "The transformation cannot be applied."); return; } // find the fifth point in the ellipse Vector2 pointZ = MathHelper.FindIntersection(pointM, pointX - pointM, pointN, pointY - pointN); if (Vector2.IsNaN(pointZ)) { Debug.Assert(false, "The transformation cannot be applied."); return; } Vector3 oldNormal = this.Normal; double oldRotation = this.Rotation; Vector2 newCenter; double newSemiMajorAxis; double newSemiMinorAxis; double newRotation; if (ConicThroughFivePoints.EllipseProperties(pointM, pointN, pointH, pointK, pointZ, out newCenter, out newSemiMajorAxis, out newSemiMinorAxis, out newRotation)) { double axis1 = 2 * newSemiMajorAxis; axis1 = MathHelper.IsZero(axis1) ? MathHelper.Epsilon : axis1; double axis2 = 2 * newSemiMinorAxis; axis2 = MathHelper.IsZero(axis2) ? MathHelper.Epsilon : axis2; this.Center = transformation * this.Center + translation; this.MajorAxis = axis1; this.MinorAxis = axis2; this.Rotation = newRotation * MathHelper.RadToDeg; this.Normal = newNormal; } else { Debug.Assert(false, "The transformation cannot be applied."); return; } if (this.IsFullEllipse) { return; } //if not full ellipse calculate start and end angles Vector2 start = this.PolarCoordinateRelativeToCenter(this.StartAngle); Vector2 end = this.PolarCoordinateRelativeToCenter(this.EndAngle); if (!MathHelper.IsZero(oldRotation)) { double beta = oldRotation * MathHelper.DegToRad; double sinBeta = Math.Sin(beta); double cosBeta = Math.Cos(beta); start = new Vector2(start.X * cosBeta - start.Y * sinBeta, start.X * sinBeta + start.Y * cosBeta); end = new Vector2(end.X * cosBeta - end.Y * sinBeta, end.X * sinBeta + end.Y * cosBeta); } Vector3 pStart = new Vector3(start.X, start.Y, 0.0); Vector3 pEnd = new Vector3(end.X, end.Y, 0.0); List <Vector3> wcsAnglePoints = MathHelper.Transform(new[] { pStart, pEnd }, oldNormal, CoordinateSystem.Object, CoordinateSystem.World); for (int i = 0; i < wcsAnglePoints.Count; i++) { wcsPoints[i] += this.Center; wcsAnglePoints[i] = transformation * wcsAnglePoints[i]; wcsPoints[i] += translation; } List <Vector3> ocsAnglePoints = MathHelper.Transform(wcsAnglePoints, newNormal, CoordinateSystem.World, CoordinateSystem.Object); Vector2 newStart = new Vector2(ocsAnglePoints[0].X, ocsAnglePoints[0].Y); Vector2 newEnd = new Vector2(ocsAnglePoints[1].X, ocsAnglePoints[1].Y); double invert = Math.Sign(transformation.M11 * transformation.M22 * transformation.M33) < 0 ? 180.0 : 0.0; this.StartAngle = invert + Vector2.Angle(newStart) * MathHelper.RadToDeg - this.Rotation; this.EndAngle = invert + Vector2.Angle(newEnd) * MathHelper.RadToDeg - this.Rotation; }
/// <summary> /// Returns the distance to move a given rectangle in order to properly /// resolve a collision. /// </summary> /// <param name="intersect"> /// The intersection depth for the other rectangle. /// </param> /// <returns> /// A value that can be applied to the position of the rectangle to /// move it the minimum distance such that it won't be intersecting /// this one. /// </returns> public Vector2 GetCollisionResolution(Vector2 intersect) { if (intersect.IsNaN()) { return new Vector2(float.NaN, float.NaN); } else if (Math.Abs(intersect.X) < Math.Abs(intersect.Y)) { return new Vector2(intersect.X, 0f); } else { return new Vector2(0f, intersect.Y); } }
/// <summary> /// Check to see if the current Vector is usable /// </summary> /// <param name="vector">The vector being checked</param> /// <returns>Returns true if the none of the axis of this vector are NaN or infinite</returns> public static bool IsUsable(this Vector2 vector) { return(!vector.IsNaN() && !vector.IsInfinite()); }