diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs index af76b73f3..be34834c3 100644 --- a/src/Artemis.Core/Models/Profile/Layer.cs +++ b/src/Artemis.Core/Models/Profile/Layer.cs @@ -179,8 +179,7 @@ namespace Artemis.Core.Models.Profile // Translation originates from the unscaled center of the shape and is tied to the anchor var x = position.X * AbsoluteRectangle.Width - LayerShape.RenderRectangle.Width / 2 - relativeAnchor.X; var y = position.Y * AbsoluteRectangle.Height - LayerShape.RenderRectangle.Height / 2 - relativeAnchor.Y; - - + canvas.RotateDegrees(rotation, anchor.X, anchor.Y); canvas.Scale(size.Width, size.Height, anchor.X, anchor.Y); canvas.Translate(x, y); diff --git a/src/Artemis.Core/Models/Profile/LayerShapes/Ellipse.cs b/src/Artemis.Core/Models/Profile/LayerShapes/Ellipse.cs index 2ddf66601..e5fb33544 100644 --- a/src/Artemis.Core/Models/Profile/LayerShapes/Ellipse.cs +++ b/src/Artemis.Core/Models/Profile/LayerShapes/Ellipse.cs @@ -15,14 +15,15 @@ namespace Artemis.Core.Models.Profile.LayerShapes public override void CalculateRenderProperties() { - RenderRectangle = GetUnscaledRectangle(); - + var unscaled = GetUnscaledRectangle(); + RenderRectangle = SKRect.Create(0,0 , unscaled.Width, unscaled.Height); + var path = new SKPath(); path.AddOval(RenderRectangle); RenderPath = path; } - public override void ApplyToEntity() + internal override void ApplyToEntity() { base.ApplyToEntity(); Layer.LayerEntity.ShapeEntity.Type = ShapeEntityType.Ellipse; diff --git a/src/Artemis.Core/Models/Profile/LayerShapes/Fill.cs b/src/Artemis.Core/Models/Profile/LayerShapes/Fill.cs index 86340bdaf..765a0ea3c 100644 --- a/src/Artemis.Core/Models/Profile/LayerShapes/Fill.cs +++ b/src/Artemis.Core/Models/Profile/LayerShapes/Fill.cs @@ -23,7 +23,7 @@ namespace Artemis.Core.Models.Profile.LayerShapes RenderPath = renderPath; } - public override void ApplyToEntity() + internal override void ApplyToEntity() { base.ApplyToEntity(); Layer.LayerEntity.ShapeEntity.Type = ShapeEntityType.Fill; diff --git a/src/Artemis.Core/Models/Profile/LayerShapes/LayerShape.cs b/src/Artemis.Core/Models/Profile/LayerShapes/LayerShape.cs index f24949591..6dda4b14b 100644 --- a/src/Artemis.Core/Models/Profile/LayerShapes/LayerShape.cs +++ b/src/Artemis.Core/Models/Profile/LayerShapes/LayerShape.cs @@ -1,6 +1,6 @@ -using System; -using System.Linq; +using System.Linq; using Artemis.Storage.Entities.Profile; +using RGB.NET.Core; using SkiaSharp; namespace Artemis.Core.Models.Profile.LayerShapes @@ -41,18 +41,27 @@ namespace Artemis.Core.Models.Profile.LayerShapes public abstract void CalculateRenderProperties(); - public virtual void ApplyToEntity() + /// + /// Updates Position and Size using the provided unscaled rectangle + /// + /// An unscaled rectangle where 1px = 1mm + public void SetFromUnscaledRectangle(SKRect rect) { - Layer.LayerEntity.ShapeEntity = new ShapeEntity + if (!Layer.Leds.Any()) { - X = ScaledRectangle.Left, - Y = ScaledRectangle.Top, - Width = ScaledRectangle.Width, - Height = ScaledRectangle.Height - }; + ScaledRectangle = SKRect.Empty; + return; + } + + ScaledRectangle = SKRect.Create( + 100f / Layer.AbsoluteRectangle.Width * (rect.Left - Layer.AbsoluteRectangle.Left) / 100f, + 100f / Layer.AbsoluteRectangle.Height * (rect.Top - Layer.AbsoluteRectangle.Top) / 100f, + 100f / Layer.AbsoluteRectangle.Width * rect.Width / 100f, + 100f / Layer.AbsoluteRectangle.Height * rect.Height / 100f + ); } - protected SKRect GetUnscaledRectangle() + public SKRect GetUnscaledRectangle() { if (!Layer.Leds.Any()) return SKRect.Empty; @@ -64,5 +73,16 @@ namespace Artemis.Core.Models.Profile.LayerShapes Layer.AbsoluteRectangle.Height * ScaledRectangle.Height ); } + + internal virtual void ApplyToEntity() + { + Layer.LayerEntity.ShapeEntity = new ShapeEntity + { + X = ScaledRectangle.Left, + Y = ScaledRectangle.Top, + Width = ScaledRectangle.Width, + Height = ScaledRectangle.Height + }; + } } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/LayerShapes/Polygon.cs b/src/Artemis.Core/Models/Profile/LayerShapes/Polygon.cs index f5248c80a..6a527f5e6 100644 --- a/src/Artemis.Core/Models/Profile/LayerShapes/Polygon.cs +++ b/src/Artemis.Core/Models/Profile/LayerShapes/Polygon.cs @@ -44,7 +44,7 @@ namespace Artemis.Core.Models.Profile.LayerShapes RenderRectangle = path.GetRect(); } - public override void ApplyToEntity() + internal override void ApplyToEntity() { base.ApplyToEntity(); Layer.LayerEntity.ShapeEntity.Type = ShapeEntityType.Polygon; diff --git a/src/Artemis.Core/Models/Profile/LayerShapes/Rectangle.cs b/src/Artemis.Core/Models/Profile/LayerShapes/Rectangle.cs index 17c18eca4..aab4432ca 100644 --- a/src/Artemis.Core/Models/Profile/LayerShapes/Rectangle.cs +++ b/src/Artemis.Core/Models/Profile/LayerShapes/Rectangle.cs @@ -22,7 +22,7 @@ namespace Artemis.Core.Models.Profile.LayerShapes RenderPath = path; } - public override void ApplyToEntity() + internal override void ApplyToEntity() { base.ApplyToEntity(); Layer.LayerEntity.ShapeEntity.Type = ShapeEntityType.Rectangle; diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerViewModel.cs index 7c0e4de71..ae374de77 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileLayerViewModel.cs @@ -105,7 +105,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization Execute.PostToUIThread(() => { - var rect = _layerEditorService.GetShapeRenderRect(Layer.LayerShape); + var rect = _layerEditorService.GetShapeUntransformedRect(Layer.LayerShape); var shapeGeometry = Geometry.Empty; switch (Layer.LayerShape) { diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/EditToolViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/EditToolViewModel.cs index f2cef267e..1fee2ce38 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/EditToolViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/EditToolViewModel.cs @@ -46,7 +46,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools ShapeAnchor = _layerEditorService.GetLayerAnchor(layer, true); Execute.PostToUIThread(() => { - var shapeGeometry = new RectangleGeometry(_layerEditorService.GetShapeRenderRect(layer.LayerShape)) + var shapeGeometry = new RectangleGeometry(_layerEditorService.GetShapeUntransformedRect(layer.LayerShape)) { Transform = _layerEditorService.GetLayerTransformGroup(layer) }; diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/EllipseToolViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/EllipseToolViewModel.cs index 00f3b707d..6379c8bb5 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/EllipseToolViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/EllipseToolViewModel.cs @@ -53,7 +53,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools layer.LayerShape = new Ellipse(layer); // Apply the drag rectangle - _layerEditorService.SetShapeRenderRect(layer.LayerShape, DragRectangle); + _layerEditorService.SetShapeBaseFromRectangle(layer.LayerShape, DragRectangle); ProfileEditorService.UpdateSelectedProfileElement(); } } diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/FillToolViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/FillToolViewModel.cs index f2e660324..b4cf601d3 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/FillToolViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/FillToolViewModel.cs @@ -42,7 +42,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools layer.LayerShape = new Fill(layer); // Apply the full layer rectangle - _layerEditorService.SetShapeRenderRect(layer.LayerShape, _layerEditorService.GetLayerRect(layer)); + _layerEditorService.SetShapeBaseFromRectangle(layer.LayerShape, _layerEditorService.GetLayerRect(layer)); ProfileEditorService.UpdateSelectedProfileElement(); } } diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/RectangleToolViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/RectangleToolViewModel.cs index fc5c43589..499278f44 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/RectangleToolViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/RectangleToolViewModel.cs @@ -52,7 +52,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools layer.LayerShape = new Rectangle(layer); // Apply the drag rectangle - _layerEditorService.SetShapeRenderRect(layer.LayerShape, DragRectangle); + _layerEditorService.SetShapeBaseFromRectangle(layer.LayerShape, DragRectangle); ProfileEditorService.UpdateSelectedProfileElement(); } } diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/SelectionRemoveToolViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/SelectionRemoveToolViewModel.cs index 83a65852a..c3ee49bc9 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/SelectionRemoveToolViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/SelectionRemoveToolViewModel.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Windows; @@ -9,6 +10,8 @@ using Artemis.UI.Extensions; using Artemis.UI.Properties; using Artemis.UI.Services; using Artemis.UI.Services.Interfaces; +using SkiaSharp; +using SkiaSharp.Views.WPF; namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools { @@ -52,18 +55,18 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools if (ProfileEditorService.SelectedProfileElement is Layer layer) { // If the layer has a shape, save it's size - var shapeSize = Rect.Empty; + var shapeSize = SKRect.Empty; if (layer.LayerShape != null) - shapeSize = _layerEditorService.GetShapeRenderRect(layer.LayerShape); + shapeSize = layer.LayerShape.GetUnscaledRectangle(); var remainingLeds = layer.Leds.Except(selectedLeds).ToList(); layer.ClearLeds(); layer.AddLeds(remainingLeds); - + // Restore the saved size if (layer.LayerShape != null) - _layerEditorService.SetShapeRenderRect(layer.LayerShape, shapeSize); - + layer.LayerShape.SetFromUnscaledRectangle(shapeSize); + ProfileEditorService.UpdateSelectedProfileElement(); } } diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/SelectionToolViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/SelectionToolViewModel.cs index 3bc206716..0652a9c50 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/SelectionToolViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/SelectionToolViewModel.cs @@ -53,9 +53,9 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools if (ProfileEditorService.SelectedProfileElement is Layer layer) { // If the layer has a shape, save it's size - var shapeSize = Rect.Empty; + var shapeSize = SKRect.Empty; if (layer.LayerShape != null) - shapeSize = _layerEditorService.GetShapeRenderRect(layer.LayerShape); + shapeSize = layer.LayerShape.GetUnscaledRectangle(); // If shift is held down, add to the selection instead of replacing it if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift)) @@ -68,7 +68,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools // Restore the saved size if (layer.LayerShape != null) - _layerEditorService.SetShapeRenderRect(layer.LayerShape, shapeSize); + layer.LayerShape.SetFromUnscaledRectangle(shapeSize); ProfileEditorService.UpdateSelectedProfileElement(); } diff --git a/src/Artemis.UI/Services/LayerShapeService.cs b/src/Artemis.UI/Services/LayerShapeService.cs index 419ba60be..d5d34f36c 100644 --- a/src/Artemis.UI/Services/LayerShapeService.cs +++ b/src/Artemis.UI/Services/LayerShapeService.cs @@ -49,7 +49,7 @@ namespace Artemis.UI.Services public SKPath GetLayerPath(Layer layer, bool includeTranslation, bool includeScale, bool includeRotation) { var layerRect = GetLayerRenderRect(layer).ToSKRect(); - var shapeRect = GetShapeRenderRect(layer.LayerShape).ToSKRect(); + var shapeRect = GetShapeUntransformedRect(layer.LayerShape).ToSKRect(); // Apply transformation like done by the core during layer rendering var anchor = GetLayerAnchor(layer, true); @@ -74,7 +74,7 @@ namespace Artemis.UI.Services public void ReverseLayerPath(Layer layer, SKPath path) { var layerRect = GetLayerRenderRect(layer).ToSKRect(); - var shapeRect = GetShapeRenderRect(layer.LayerShape).ToSKRect(); + var shapeRect = GetShapeUntransformedRect(layer.LayerShape).ToSKRect(); // Apply transformation like done by the core during layer rendering var anchor = GetLayerAnchor(layer, true); @@ -100,7 +100,7 @@ namespace Artemis.UI.Services var position = layer.PositionProperty.CurrentValue; position.X = (float) (position.X * layerRect.Width); position.Y = (float) (position.Y * layerRect.Height); - var shapeRect = GetShapeRenderRect(layer.LayerShape); + var shapeRect = GetShapeUntransformedRect(layer.LayerShape); return new SKPoint((float) (position.X + shapeRect.Left), (float) (position.Y + shapeRect.Top)); } @@ -115,7 +115,7 @@ namespace Artemis.UI.Services var layerRect = GetLayerRect(layer); if (absolute) { - var shapeRect = GetShapeRenderRect(layer.LayerShape); + var shapeRect = GetShapeUntransformedRect(layer.LayerShape); var position = new SKPoint((float) ((point.X - shapeRect.Left) / layerRect.Width), (float) ((point.Y - shapeRect.Top) / layerRect.Height)); layer.PositionProperty.SetCurrentValue(position, time); } @@ -128,7 +128,7 @@ namespace Artemis.UI.Services public TransformGroup GetLayerTransformGroup(Layer layer) { var layerRect = GetLayerRenderRect(layer).ToSKRect(); - var shapeRect = GetShapeRenderRect(layer.LayerShape).ToSKRect(); + var shapeRect = GetShapeUntransformedRect(layer.LayerShape).ToSKRect(); // Apply transformation like done by the core during layer rendering var anchor = GetLayerAnchor(layer, true); @@ -146,11 +146,11 @@ namespace Artemis.UI.Services } /// - public Rect GetShapeRenderRect(LayerShape layerShape) + public Rect GetShapeUntransformedRect(LayerShape layerShape) { if (layerShape == null) return Rect.Empty; - + // Adjust the render rectangle for the difference in render scale var renderScale = _settingsService.GetSetting("Core.RenderScale", 1.0).Value; return new Rect( @@ -162,13 +162,21 @@ namespace Artemis.UI.Services } /// - public void SetShapeRenderRect(LayerShape layerShape, Rect rect) + public Rect GetShapeTransformedRect(LayerShape layerShape) + { + var path = GetLayerPath(layerShape.Layer, true, true, false); + return path.Bounds.ToRect(); + } + + /// + public void SetShapeBaseFromRectangle(LayerShape layerShape, Rect rect) { if (!layerShape.Layer.Leds.Any()) { layerShape.ScaledRectangle = SKRect.Empty; return; } + var layerRect = GetLayerRenderRect(layerShape.Layer).ToSKRect(); // Compensate for the current value of the position transformation @@ -179,7 +187,7 @@ namespace Artemis.UI.Services rect.Y += rect.Height / 2; rect.Y -= layerRect.Height * layerShape.Layer.PositionProperty.CurrentValue.Y; rect.Y += layerRect.Height * layerShape.Layer.AnchorPointProperty.CurrentValue.Y * layerShape.Layer.SizeProperty.CurrentValue.Height; - + // Compensate for the current value of the size transformation rect.Height /= layerShape.Layer.SizeProperty.CurrentValue.Height; rect.Width /= layerShape.Layer.SizeProperty.CurrentValue.Width; @@ -201,15 +209,15 @@ namespace Artemis.UI.Services var renderScale = _settingsService.GetSetting("Core.RenderScale", 1.0).Value; if (absolute) { - return new SKPoint( + return new SKPoint( 100f / layer.AbsoluteRectangle.Width * ((float) (point.X * renderScale) - layer.AbsoluteRectangle.Left) / 100f, 100f / layer.AbsoluteRectangle.Height * ((float) (point.Y * renderScale) - layer.AbsoluteRectangle.Top) / 100f ); } return new SKPoint( - 100f / layer.AbsoluteRectangle.Width * (float)(point.X * renderScale) / 100f, - 100f / layer.AbsoluteRectangle.Height * (float)(point.Y * renderScale) / 100f + 100f / layer.AbsoluteRectangle.Width * (float) (point.X * renderScale) / 100f, + 100f / layer.AbsoluteRectangle.Height * (float) (point.Y * renderScale) / 100f ); } } @@ -249,7 +257,7 @@ namespace Artemis.UI.Services /// /// SKPoint GetLayerAnchor(Layer layer, bool absolute); - + void SetLayerAnchor(Layer layer, SKPoint point, bool absolute, TimeSpan? time); /// @@ -261,21 +269,29 @@ namespace Artemis.UI.Services TransformGroup GetLayerTransformGroup(Layer layer); /// - /// Returns an absolute and scaled rectangle for the given shape that is corrected for the current render scale. + /// Returns an absolute and scaled rectangle for the given shape that is corrected for the current render scale without + /// any transformations applied. /// /// - Rect GetShapeRenderRect(LayerShape layerShape); + Rect GetShapeUntransformedRect(LayerShape layerShape); /// - /// Sets the render rectangle of the given shape to match the provided unscaled rectangle. The rectangle is corrected - /// for the current render scale. + /// Returns an absolute and scaled rectangle for the given shape that is corrected for the current render scale with + /// translation and scale transformations applied. + /// + /// + Rect GetShapeTransformedRect(LayerShape layerShape); + + /// + /// Sets the base properties of the given shape to match the provided unscaled rectangle. The rectangle is corrected + /// for the current render scale, anchor property and size property. /// /// /// - void SetShapeRenderRect(LayerShape layerShape, Rect rect); + void SetShapeBaseFromRectangle(LayerShape layerShape, Rect rect); /// - /// Returns a new point scaled to the layer. + /// Returns a new point scaled to the layer. /// /// ///