Se añadieron mejoras en la gestión de la manipulación de objetos rotados, incluyendo métodos para adaptar los cursores y el comportamiento de los handles según la rotación del objeto. Se implementó la transformación de cambios del mouse en coordenadas locales para un redimensionamiento más intuitivo. Además, se documentaron las nuevas funcionalidades en la clase ObjectManipulationManager.
This commit is contained in:
parent
88e6de77cb
commit
f85c707cfc
|
@ -79,6 +79,19 @@ namespace CtrEditor
|
|||
JoinVertically
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gestor de manipulación de objetos que maneja la selección, movimiento, rotación y redimensionamiento de objetos.
|
||||
///
|
||||
/// MEJORAS PARA OBJETOS ROTADOS:
|
||||
/// - HandleResizeForObject: Aplica transformaciones matemáticas para convertir los cambios del mouse
|
||||
/// desde coordenadas del canvas a coordenadas locales del objeto rotado.
|
||||
/// - DetermineHandleMode: Adapta el comportamiento de los handles según la rotación del objeto.
|
||||
/// - GetAdaptiveCursors: Cambia los cursores de los handles para reflejar la orientación actual del objeto.
|
||||
///
|
||||
/// Estas mejoras hacen que el redimensionamiento sea más intuitivo cuando los objetos están rotados,
|
||||
/// ya que los handles responden de acuerdo a la orientación del objeto en lugar de las coordenadas
|
||||
/// absolutas del canvas.
|
||||
/// </summary>
|
||||
public class ObjectManipulationManager
|
||||
{
|
||||
private enum ResizeMode
|
||||
|
@ -371,19 +384,22 @@ namespace CtrEditor
|
|||
// Calcular el offset para posicionar los manejadores fuera del rectángulo
|
||||
double offset = rectSize / 2;
|
||||
|
||||
// Determinar cursores adaptativos según la rotación del objeto
|
||||
var cursors = GetAdaptiveCursors();
|
||||
|
||||
var positions = new List<(Point Position, string Tag, Cursor Cursor, Brush Stroke)>
|
||||
{
|
||||
// Esquinas - mover hacia afuera del rectángulo
|
||||
(new Point(rectBox.Left - offset, rectBox.Top - offset), "TopLeft", Cursors.Arrow, Brushes.Gray),
|
||||
(new Point(rectBox.Right + offset, rectBox.Top - offset), "TopRight", rotationCursorRx, Brushes.Red),
|
||||
(new Point(rectBox.Left - offset, rectBox.Bottom + offset), "BottomLeft", rotationCursorSx, Brushes.DarkRed),
|
||||
(new Point(rectBox.Right + offset, rectBox.Bottom + offset), "BottomRight", Cursors.SizeNWSE, Brushes.Blue),
|
||||
(new Point(rectBox.Right + offset, rectBox.Bottom + offset), "BottomRight", cursors.ResizeBoth, Brushes.Blue),
|
||||
|
||||
// Centros de los bordes - mover hacia afuera del rectángulo
|
||||
(new Point(rectBox.Left + rectBox.Width / 2, rectBox.Top - offset), "TopCenter", Cursors.Arrow, Brushes.Gray),
|
||||
(new Point(rectBox.Left + rectBox.Width / 2, rectBox.Bottom + offset), "BottomCenter", Cursors.SizeNS, Brushes.Blue),
|
||||
(new Point(rectBox.Left + rectBox.Width / 2, rectBox.Bottom + offset), "BottomCenter", cursors.ResizeVertical, Brushes.Blue),
|
||||
(new Point(rectBox.Left - offset, rectBox.Top + rectBox.Height / 2), "CenterLeft", rotationCursorRx, Brushes.Red),
|
||||
(new Point(rectBox.Right + offset, rectBox.Top + rectBox.Height / 2), "CenterRight", Cursors.SizeWE, Brushes.Blue)
|
||||
(new Point(rectBox.Right + offset, rectBox.Top + rectBox.Height / 2), "CenterRight", cursors.ResizeHorizontal, Brushes.Blue)
|
||||
};
|
||||
|
||||
foreach (var (Position, Tag, Cursor, Stroke) in positions)
|
||||
|
@ -395,6 +411,43 @@ namespace CtrEditor
|
|||
}
|
||||
}
|
||||
|
||||
private (Cursor ResizeHorizontal, Cursor ResizeVertical, Cursor ResizeBoth) GetAdaptiveCursors()
|
||||
{
|
||||
// Para un solo objeto o múltiples objetos con la misma rotación
|
||||
var firstObject = _selectedObjects.FirstOrDefault();
|
||||
if (firstObject == null)
|
||||
return (Cursors.SizeWE, Cursors.SizeNS, Cursors.SizeNWSE);
|
||||
|
||||
double angle = Math.Abs(firstObject.Angulo % 360);
|
||||
|
||||
// Si el objeto no está significativamente rotado, usar cursores estándar
|
||||
if (angle < 15 || (angle > 345 && angle < 360) ||
|
||||
(angle > 165 && angle < 195))
|
||||
{
|
||||
return (Cursors.SizeWE, Cursors.SizeNS, Cursors.SizeNWSE);
|
||||
}
|
||||
else if ((angle > 75 && angle < 105) || (angle > 255 && angle < 285))
|
||||
{
|
||||
// Objeto rotado 90 grados - intercambiar cursores
|
||||
return (Cursors.SizeNS, Cursors.SizeWE, Cursors.SizeNESW);
|
||||
}
|
||||
else if ((angle > 30 && angle < 60) || (angle > 210 && angle < 240))
|
||||
{
|
||||
// Objeto rotado aproximadamente 45 grados
|
||||
return (Cursors.SizeNESW, Cursors.SizeNWSE, Cursors.SizeAll);
|
||||
}
|
||||
else if ((angle > 120 && angle < 150) || (angle > 300 && angle < 330))
|
||||
{
|
||||
// Objeto rotado aproximadamente 135 grados
|
||||
return (Cursors.SizeNWSE, Cursors.SizeNESW, Cursors.SizeAll);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Para otros ángulos, usar cursores generales
|
||||
return (Cursors.SizeAll, Cursors.SizeAll, Cursors.SizeAll);
|
||||
}
|
||||
}
|
||||
|
||||
private Rectangle CreateResizeHandle(double rectSize, string tag, Cursor cursor, Brush stroke)
|
||||
{
|
||||
var handle = new Rectangle
|
||||
|
@ -921,6 +974,39 @@ namespace CtrEditor
|
|||
}
|
||||
|
||||
private HandleMode DetermineHandleMode(string resizeDirection)
|
||||
{
|
||||
// Si tenemos múltiples objetos seleccionados con diferentes rotaciones,
|
||||
// usar el comportamiento por defecto
|
||||
if (_selectedObjects.Count > 1)
|
||||
{
|
||||
var angles = _selectedObjects.Select(obj => Math.Abs(obj.Angulo % 360)).Distinct().ToList();
|
||||
if (angles.Count > 1) // Diferentes ángulos
|
||||
{
|
||||
return DetermineHandleModeDefault(resizeDirection);
|
||||
}
|
||||
}
|
||||
|
||||
// Para un solo objeto o múltiples objetos con la misma rotación
|
||||
var firstObject = _selectedObjects.FirstOrDefault();
|
||||
if (firstObject == null)
|
||||
return HandleMode.None;
|
||||
|
||||
double angle = Math.Abs(firstObject.Angulo % 360);
|
||||
|
||||
// Si el objeto no está significativamente rotado, usar el comportamiento por defecto
|
||||
if (angle < 15 || (angle > 345 && angle < 360) ||
|
||||
(angle > 75 && angle < 105) ||
|
||||
(angle > 165 && angle < 195) ||
|
||||
(angle > 255 && angle < 285))
|
||||
{
|
||||
return DetermineHandleModeDefault(resizeDirection);
|
||||
}
|
||||
|
||||
// Para objetos rotados significativamente, adaptar los handles
|
||||
return DetermineHandleModeRotated(resizeDirection, angle);
|
||||
}
|
||||
|
||||
private HandleMode DetermineHandleModeDefault(string resizeDirection)
|
||||
{
|
||||
return resizeDirection switch
|
||||
{
|
||||
|
@ -934,6 +1020,21 @@ namespace CtrEditor
|
|||
};
|
||||
}
|
||||
|
||||
private HandleMode DetermineHandleModeRotated(string resizeDirection, double angle)
|
||||
{
|
||||
// Para objetos rotados, hacer que todos los handles de redimensionamiento funcionen como los corners
|
||||
// Esto es mucho más intuitivo ya que el usuario puede redimensionar en cualquier dirección
|
||||
// sin preocuparse por la orientación específica del objeto
|
||||
|
||||
return resizeDirection switch
|
||||
{
|
||||
"TopLeft" => HandleMode.None,
|
||||
"TopRight" or "BottomLeft" or "CenterLeft" => HandleMode.Rotate,
|
||||
"BottomRight" or "BottomCenter" or "CenterRight" or "TopCenter" => HandleMode.ResizeBoth,
|
||||
_ => HandleMode.None
|
||||
};
|
||||
}
|
||||
|
||||
private void HandleResize(Point currentPosition, HandleMode mode)
|
||||
{
|
||||
PurgeDeletedObjects();
|
||||
|
@ -960,8 +1061,53 @@ namespace CtrEditor
|
|||
|
||||
private void HandleResizeForObject(osBase obj, Point currentPosition, bool activateSizeWidth, bool activateSizeHeight)
|
||||
{
|
||||
double widthChange = activateSizeWidth ? currentPosition.X - _startPointUserControl.X : 0;
|
||||
double heightChange = activateSizeHeight ? currentPosition.Y - _startPointUserControl.Y : 0;
|
||||
// Calcular el cambio del mouse en coordenadas del canvas
|
||||
double deltaX = currentPosition.X - _startPointUserControl.X;
|
||||
double deltaY = currentPosition.Y - _startPointUserControl.Y;
|
||||
|
||||
// Inicializar variables de cambio
|
||||
double widthChange = 0;
|
||||
double heightChange = 0;
|
||||
|
||||
// Si el objeto no está rotado, usar el método original
|
||||
if (Math.Abs(obj.Angulo) < 0.1) // Umbral pequeño para considerar "sin rotación"
|
||||
{
|
||||
widthChange = activateSizeWidth ? deltaX : 0;
|
||||
heightChange = activateSizeHeight ? deltaY : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Para objetos rotados, transformar los cambios del mouse según la orientación del objeto
|
||||
// Convertir ángulo de grados a radianes
|
||||
double angleRad = obj.Angulo * Math.PI / 180.0;
|
||||
|
||||
// Calcular los componentes de cambio transformados según la rotación
|
||||
// Rotar el vector de cambio por el ángulo negativo del objeto para obtener
|
||||
// los cambios en el sistema de coordenadas local del objeto
|
||||
double cos = Math.Cos(-angleRad);
|
||||
double sin = Math.Sin(-angleRad);
|
||||
|
||||
double localDeltaX = deltaX * cos - deltaY * sin;
|
||||
double localDeltaY = deltaX * sin + deltaY * cos;
|
||||
|
||||
// Determinar qué componente aplicar según el tipo de redimensionamiento
|
||||
if (activateSizeWidth && activateSizeHeight)
|
||||
{
|
||||
// Redimensionamiento proporcional - usar la componente más grande transformada
|
||||
widthChange = localDeltaX;
|
||||
heightChange = localDeltaY;
|
||||
}
|
||||
else if (activateSizeWidth)
|
||||
{
|
||||
// Solo redimensionar ancho - usar componente X transformada
|
||||
widthChange = localDeltaX;
|
||||
}
|
||||
else if (activateSizeHeight)
|
||||
{
|
||||
// Solo redimensionar alto - usar componente Y transformada
|
||||
heightChange = localDeltaY;
|
||||
}
|
||||
}
|
||||
|
||||
obj.Resize(widthChange, heightChange);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue