/// <summary> /// Creates a rectangle that includes all the provided points. /// </summary> /// <param name="points">The points that the rectangle should include.</param> /// <returns>The rectangle that includes all the provided points.</returns> /// <exception cref="System.ArgumentException">Enumeration is empty!</exception> public static RectangleD2D NewRectangleIncludingAllPoints(IEnumerable <PointD2D> points) { var en = points.GetEnumerator(); if (!en.MoveNext()) { throw new ArgumentException("Enumeration is empty!", nameof(points)); } var result = new RectangleD2D(en.Current, PointD2D.Empty); while (en.MoveNext()) { result.ExpandToInclude(en.Current); } return(result); }
/// <summary> /// Calculates the dimensions of the greatest (by area) rectangle included in an outer rectangle, where the inner rectangle is rotated/sheared/scaled. /// </summary> /// <param name="outerRectangle">The outer rectangle.</param> /// <param name="sx">SX component of the transformation matrix that is applied to the inner rectangle.</param> /// <param name="rx">RX component of the transformation matrix that is applied to the inner rectangle.</param> /// <param name="ry">RY component of the transformation matrix that is applied to the inner rectangle.</param> /// <param name="sy">SY component of the transformation matrix that is applied to the inner rectangle.</param> /// <returns>The inner rectangle with the greatest area that fits (when transformed with the transformation elements) into the outer rectangle. /// The position of the returned rectangle is calculated so that it centers into the outer rectangle.</returns> /// <exception cref="System.ArgumentOutOfRangeException"> /// X-Size of outer rectangle must be > 0 /// or /// Y-Size of outer rectangle must be > 0 /// </exception> public static RectangleD2D GetIncludedTransformedRectangle(this RectangleD2D outerRectangle, double sx, double rx, double ry, double sy) { PointD2D outerRectangleSize = outerRectangle.Size; if (!(outerRectangleSize.X > 0)) throw new ArgumentOutOfRangeException("X-Size of outer rectangle must be > 0"); if (!(outerRectangleSize.Y > 0)) throw new ArgumentOutOfRangeException("Y-Size of outer rectangle must be > 0"); double a = Math.Abs(sx); double b = Math.Abs(rx); double c = Math.Abs(ry); double d = Math.Abs(sy); double maxArea = 0; double sizeX = 0, sizeY = 0; double x, y, area; { // solution 1, which touches all walls double bcMad = b * c - a * d; if (bcMad != 0) { x = (b * outerRectangleSize.Y - d * outerRectangleSize.X) / bcMad; y = (c * outerRectangleSize.X - a * outerRectangleSize.Y) / bcMad; area = x * y; if (maxArea < area) { maxArea = area; sizeX = x; sizeY = y; } } } { // solution2 (which does not touch the left and right walls of the outer retangle var eps2 = outerRectangleSize.X - outerRectangleSize.Y * (b * c + a * d) / (2 * c * d); if (eps2 >= 0 && eps2 < outerRectangleSize.X) { area = outerRectangleSize.Y * outerRectangleSize.Y / (4 * c * d); x = outerRectangleSize.Y / (2 * c); y = outerRectangleSize.Y / (2 * d); if (maxArea < area) { maxArea = area; sizeX = x; sizeY = y; } } } { // solution3 (which does not touch the top and bottom walls of the outer rectangle var eps3 = outerRectangleSize.Y - outerRectangleSize.X * (b * c + a * d) / (2 * a * b); if (eps3 >= 0 && eps3 < outerRectangleSize.Y) { area = outerRectangleSize.X * outerRectangleSize.X / (4 * a * b); x = outerRectangleSize.X / (2 * a); y = outerRectangleSize.X / (2 * b); if (maxArea < area) { maxArea = area; sizeX = x; sizeY = y; } } } RectangleD2D innerRect = new RectangleD2D(); innerRect.ExpandToInclude(new PointD2D(sx * sizeX + rx * sizeY, ry * sizeX + sy * sizeY)); innerRect.ExpandToInclude(new PointD2D(sx * sizeX, ry * sizeX)); innerRect.ExpandToInclude(new PointD2D(rx * sizeY, sy * sizeY)); var outerMiddle = outerRectangle.CenterCenter; var innerMiddle = innerRect.CenterCenter; return new RectangleD2D((outerMiddle.X - innerMiddle.X), (outerMiddle.Y - innerMiddle.Y), sizeX, sizeY); }
/// <summary> /// Creates a rectangle that includes all the provided points. /// </summary> /// <param name="points">The points that the rectangle should include.</param> /// <returns>The rectangle that includes all the provided points.</returns> /// <exception cref="System.ArgumentException">Enumeration is empty!</exception> public static RectangleD2D NewRectangleIncludingAllPoints(IEnumerable<PointD2D> points) { var en = points.GetEnumerator(); if (!en.MoveNext()) throw new ArgumentException("Enumeration is empty!", nameof(points)); var result = new RectangleD2D(en.Current, PointD2D.Empty); while (en.MoveNext()) { result.ExpandToInclude(en.Current); } return result; }
/// <summary> /// Calculates the dimensions of the greatest (by area) rectangle included in an outer rectangle, where the inner rectangle is rotated/sheared/scaled. /// </summary> /// <param name="outerRectangle">The outer rectangle.</param> /// <param name="sx">SX component of the transformation matrix that is applied to the inner rectangle.</param> /// <param name="rx">RX component of the transformation matrix that is applied to the inner rectangle.</param> /// <param name="ry">RY component of the transformation matrix that is applied to the inner rectangle.</param> /// <param name="sy">SY component of the transformation matrix that is applied to the inner rectangle.</param> /// <returns>The inner rectangle with the greatest area that fits (when transformed with the transformation elements) into the outer rectangle. /// The position of the returned rectangle is calculated so that it centers into the outer rectangle.</returns> /// <exception cref="System.ArgumentOutOfRangeException"> /// X-Size of outer rectangle must be > 0 /// or /// Y-Size of outer rectangle must be > 0 /// </exception> public static RectangleD2D GetIncludedTransformedRectangle(this RectangleD2D outerRectangle, double sx, double rx, double ry, double sy) { PointD2D outerRectangleSize = outerRectangle.Size; if (!(outerRectangleSize.X > 0)) { throw new ArgumentOutOfRangeException("X-Size of outer rectangle must be > 0"); } if (!(outerRectangleSize.Y > 0)) { throw new ArgumentOutOfRangeException("Y-Size of outer rectangle must be > 0"); } double a = Math.Abs(sx); double b = Math.Abs(rx); double c = Math.Abs(ry); double d = Math.Abs(sy); double maxArea = 0; double sizeX = 0, sizeY = 0; double x, y, area; { // solution 1, which touches all walls double bcMad = b * c - a * d; if (bcMad != 0) { x = (b * outerRectangleSize.Y - d * outerRectangleSize.X) / bcMad; y = (c * outerRectangleSize.X - a * outerRectangleSize.Y) / bcMad; area = x * y; if (maxArea < area) { maxArea = area; sizeX = x; sizeY = y; } } } { // solution2 (which does not touch the left and right walls of the outer retangle var eps2 = outerRectangleSize.X - outerRectangleSize.Y * (b * c + a * d) / (2 * c * d); if (eps2 >= 0 && eps2 < outerRectangleSize.X) { area = outerRectangleSize.Y * outerRectangleSize.Y / (4 * c * d); x = outerRectangleSize.Y / (2 * c); y = outerRectangleSize.Y / (2 * d); if (maxArea < area) { maxArea = area; sizeX = x; sizeY = y; } } } { // solution3 (which does not touch the top and bottom walls of the outer rectangle var eps3 = outerRectangleSize.Y - outerRectangleSize.X * (b * c + a * d) / (2 * a * b); if (eps3 >= 0 && eps3 < outerRectangleSize.Y) { area = outerRectangleSize.X * outerRectangleSize.X / (4 * a * b); x = outerRectangleSize.X / (2 * a); y = outerRectangleSize.X / (2 * b); if (maxArea < area) { maxArea = area; sizeX = x; sizeY = y; } } } var innerRect = new RectangleD2D(); innerRect.ExpandToInclude(new PointD2D(sx * sizeX + rx * sizeY, ry * sizeX + sy * sizeY)); innerRect.ExpandToInclude(new PointD2D(sx * sizeX, ry * sizeX)); innerRect.ExpandToInclude(new PointD2D(rx * sizeY, sy * sizeY)); var outerMiddle = outerRectangle.CenterCenter; var innerMiddle = innerRect.CenterCenter; return(new RectangleD2D((outerMiddle.X - innerMiddle.X), (outerMiddle.Y - innerMiddle.Y), sizeX, sizeY)); }
/// <summary> /// Handles the mouse move event. /// </summary> /// <param name="position">Mouse position.</param> /// <param name="e">MouseEventArgs as provided by the view.</param> /// <returns>The next mouse state handler that should handle mouse events.</returns> public override void OnMouseMove(PointD2D position, MouseEventArgs e) { base.OnMouseMove(position, e); if (null != ActiveGrip) { PointD2D graphCoord = _grac.ConvertMouseToRootLayerCoordinates(position); ActiveGrip.MoveGrip(graphCoord); _wereObjectsMoved = true; _grac.RenderOverlay(); } else if (e.LeftButton == MouseButtonState.Pressed) { var diffPos = position - _positionLastMouseDownInMouseCoordinates; var oldRect = _rectangleSelectionArea_GraphCoordinates; if (null != _rectangleSelectionArea_GraphCoordinates || Math.Abs(diffPos.X) >= System.Windows.SystemParameters.MinimumHorizontalDragDistance || Math.Abs(diffPos.Y) >= System.Windows.SystemParameters.MinimumHorizontalDragDistance) { if (null == _rectangleSelectionArea_GraphCoordinates) { _grac.CaptureMouse(); } var pt1 = _grac.ConvertMouseToRootLayerCoordinates(_positionLastMouseDownInMouseCoordinates); var rect = new RectangleD2D(pt1, PointD2D.Empty); rect.ExpandToInclude(_grac.ConvertMouseToRootLayerCoordinates(position)); _rectangleSelectionArea_GraphCoordinates = rect; } if (null != _rectangleSelectionArea_GraphCoordinates) _grac.RenderOverlay(); } }
/// <summary> /// Gets the absolute enclosing rectangle, taking into account ScaleX, ScaleY, Rotation and Shear (SSRS). /// </summary> /// <returns>The enclosing rectangle in absolute values.</returns> public RectangleD2D GetAbsoluteEnclosingRectangle() { MatrixD2D m = new MatrixD2D(); m.SetTranslationRotationShearxScale(AbsolutePivotPositionX, AbsolutePivotPositionY, -Rotation, ShearX, ScaleX, ScaleY); m.TranslatePrepend(AbsoluteVectorPivotToLeftUpper.X, AbsoluteVectorPivotToLeftUpper.Y); var s = this.AbsoluteSize; var p1 = m.TransformPoint(new PointD2D(0, 0)); var p2 = m.TransformPoint(new PointD2D(s.X, 0)); var p3 = m.TransformPoint(new PointD2D(0, s.Y)); var p4 = m.TransformPoint(new PointD2D(s.X, s.Y)); var r = new RectangleD2D(p1, PointD2D.Empty); r.ExpandToInclude(p2); r.ExpandToInclude(p3); r.ExpandToInclude(p4); return r; }