Beispiel #1
0
        private void scaleSlider(Slider slider, Vector2 scale)
        {
            referencePathTypes ??= slider.Path.ControlPoints.Select(p => p.Type).ToList();

            Quad sliderQuad = GetSurroundingQuad(slider.Path.ControlPoints.Select(p => p.Position));

            // Limit minimum distance between control points after scaling to almost 0. Less than 0 causes the slider to flip, exactly 0 causes a crash through division by 0.
            scale = Vector2Extensions.ComponentMax(new Vector2(Precision.FLOAT_EPSILON), sliderQuad.Size + scale) - sliderQuad.Size;

            Vector2 pathRelativeDeltaScale = new Vector2(
                sliderQuad.Width == 0 ? 0 : 1 + scale.X / sliderQuad.Width,
                sliderQuad.Height == 0 ? 0 : 1 + scale.Y / sliderQuad.Height);

            Queue <Vector2> oldControlPoints = new Queue <Vector2>();

            foreach (var point in slider.Path.ControlPoints)
            {
                oldControlPoints.Enqueue(point.Position);
                point.Position *= pathRelativeDeltaScale;
            }

            // Maintain the path types in case they were defaulted to bezier at some point during scaling
            for (int i = 0; i < slider.Path.ControlPoints.Count; ++i)
            {
                slider.Path.ControlPoints[i].Type = referencePathTypes[i];
            }

            //if sliderhead or sliderend end up outside playfield, revert scaling.
            Quad scaledQuad = getSurroundingQuad(new OsuHitObject[] { slider });

            (bool xInBounds, bool yInBounds) = isQuadInBounds(scaledQuad);

            if (xInBounds && yInBounds && slider.Path.HasValidLength)
            {
                return;
            }

            foreach (var point in slider.Path.ControlPoints)
            {
                point.Position = oldControlPoints.Dequeue();
            }
        }
Beispiel #2
0
        /// <summary>
        /// Clamp scale for multi-object-scaling where selection does not exceed playfield bounds or flip.
        /// </summary>
        /// <param name="hitObjects">The hitobjects to be scaled</param>
        /// <param name="reference">The anchor from which the scale operation is performed</param>
        /// <param name="scale">The scale to be clamped</param>
        /// <returns>The clamped scale vector</returns>
        private Vector2 getClampedScale(OsuHitObject[] hitObjects, Anchor reference, Vector2 scale)
        {
            float xOffset = ((reference & Anchor.x0) > 0) ? -scale.X : 0;
            float yOffset = ((reference & Anchor.y0) > 0) ? -scale.Y : 0;

            Quad selectionQuad = getSurroundingQuad(hitObjects);

            //todo: this is not always correct for selections involving sliders. This approximation assumes each point is scaled independently, but sliderends move with the sliderhead.
            Quad scaledQuad = new Quad(selectionQuad.TopLeft.X + xOffset, selectionQuad.TopLeft.Y + yOffset, selectionQuad.Width + scale.X, selectionQuad.Height + scale.Y);

            //max Size -> playfield bounds
            if (scaledQuad.TopLeft.X < 0)
            {
                scale.X += scaledQuad.TopLeft.X;
            }
            if (scaledQuad.TopLeft.Y < 0)
            {
                scale.Y += scaledQuad.TopLeft.Y;
            }

            if (scaledQuad.BottomRight.X > DrawWidth)
            {
                scale.X -= scaledQuad.BottomRight.X - DrawWidth;
            }
            if (scaledQuad.BottomRight.Y > DrawHeight)
            {
                scale.Y -= scaledQuad.BottomRight.Y - DrawHeight;
            }

            //min Size -> almost 0. Less than 0 causes the quad to flip, exactly 0 causes scaling to get stuck at minimum scale.
            Vector2 scaledSize = selectionQuad.Size + scale;
            Vector2 minSize    = new Vector2(Precision.FLOAT_EPSILON);

            scale = Vector2Extensions.ComponentMax(minSize, scaledSize) - selectionQuad.Size;

            return(scale);
        }