Browse Source

Added thick shape and dilation

flabbet 5 years ago
parent
commit
36f769a558

+ 109 - 0
PixiEditor/Models/ImageManipulation/Morphology.cs

@@ -0,0 +1,109 @@
+using PixiEditor.Models.Position;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+
+namespace PixiEditor.Models.ImageManipulation
+{
+    public class Morphology
+    {
+
+        public static Coordinates[] ApplyDilation(Coordinates[] points, int kernelSize, int[,] mask)
+        {
+            int kernelDim = kernelSize;
+
+            //This is the offset of center pixel from border of the kernel
+            int kernelOffset = (kernelDim - 1) / 2;
+            int margin = kernelDim;
+
+            byte[,] byteImg = GetByteArrayForPoints(points, margin);
+            byte[,] outputArray = byteImg.Clone() as byte[,];
+            Coordinates offset = new Coordinates(points.Min(x => x.X) - margin, points.Min(x => x.Y) - margin);
+
+            int width = byteImg.GetLength(0);
+            int height = byteImg.GetLength(1);
+            for (int y = kernelOffset; y < height - kernelOffset; y++)
+            {
+                for (int x = kernelOffset; x < width - kernelOffset; x++)
+                {
+                    byte value = 0;
+
+                    //Apply dilation
+                    for (int ykernel = -kernelOffset; ykernel <= kernelOffset; ykernel++)
+                    {
+                        for (int xkernel = -kernelOffset; xkernel <= kernelOffset; xkernel++)
+                        {
+                            if (mask[xkernel + kernelOffset, ykernel + kernelOffset] == 1)
+                            {
+                                value = Math.Max(value, byteImg[x + xkernel, y + ykernel]);
+                            }
+                            else
+                            {
+                                continue;
+                            }
+                        }
+                    }
+                    //Write processed data into the second array
+                    outputArray[x, y] = value;
+                }
+            }
+            return ToCoordinates(outputArray, offset).Distinct().ToArray();
+        }
+
+        private static Coordinates[] ToCoordinates(byte[,] byteArray, Coordinates offset)
+        {
+            List<Coordinates> output = new List<Coordinates>();
+            int width = byteArray.GetLength(0);
+
+            for (int y = 0; y < byteArray.GetLength(1); y++)
+            {
+                for (int x = 0; x < width; x++)
+                {
+                    if(byteArray[x,y] == 1)
+                    {
+                        output.Add(new Coordinates(x + offset.X, y + offset.Y));
+                    }
+
+                }
+            }
+            return output.ToArray();
+        }
+
+        private static byte[,] GetByteArrayForPoints(Coordinates[] points, int margin)
+        {
+            Tuple<int, int> dimensions = GetDimensionsForPoints(points);
+            int minX = points.Min(x => x.X);
+            int minY = points.Min(x => x.Y);
+            byte[,] array = new byte[dimensions.Item1 + margin * 2, dimensions.Item2 + margin * 2];
+            //Debug.Write("----------\n");
+
+            for (int y = 0; y < dimensions.Item2 + margin; y++)
+            {
+                for (int x = 0; x < dimensions.Item1 + margin; x++)
+                {
+                    Coordinates cords = new Coordinates(x + minX, y + minY);
+                    array[x + margin,y + margin] = points.Contains(cords) ? (byte)1 : (byte)0;
+                }
+            }
+
+            //for (int y = 0; y < array.GetLength(1); y++)
+            //{
+            //    for (int x = 0; x < array.GetLength(0); x++)
+            //    {
+            //        Debug.Write($"{array[x, y]} ");
+            //    }
+            //    Debug.Write("\n");
+            //}
+
+            return array;
+        }
+
+        private static Tuple<int, int> GetDimensionsForPoints(Coordinates[] points)
+        {
+            int width = points.Max(x=> x.X) - points.Min(x => x.X);
+            int height = points.Max(x=> x.Y) - points.Min(x => x.Y);
+            return new Tuple<int, int>(width + 1, height + 1);
+        }
+    }
+}

+ 2 - 5
PixiEditor/Models/Position/CoordinatesCalculator.cs

@@ -34,11 +34,8 @@ namespace PixiEditor.Models.Position
 
         public static Coordinates GetCenterPoint(Coordinates startingPoint, Coordinates endPoint)
         {
-            double width = endPoint.X - startingPoint.X + 1;
-            double height = endPoint.Y - startingPoint.Y + 1;
-
-            int x = startingPoint.X + (int)Math.Floor(width / 2);
-            int y = startingPoint.Y + (int)Math.Floor(height / 2);
+            int x = (int)Math.Truncate((startingPoint.X + endPoint.X) / 2f);
+            int y = (int)Math.Truncate((startingPoint.Y + endPoint.Y) / 2f);
             return new Coordinates(x, y);
         }
 

+ 8 - 80
PixiEditor/Models/Tools/ShapeTool.cs

@@ -1,7 +1,9 @@
 using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
+using PixiEditor.Models.Tools.Tools;
 using System;
 using System.Collections.Generic;
+using System.Linq;
 using System.Windows.Input;
 using System.Windows.Media;
 
@@ -19,90 +21,16 @@ namespace PixiEditor.Models.Tools
             Cursor = Cursors.Cross;
         }
 
-        protected Coordinates[] BresenhamLine(int x1, int y1, int x2, int y2)
+        protected Coordinates[] GetThickShape(Coordinates[] shape, int thickness)
         {
-            List<Coordinates> coordinates = new List<Coordinates>();
-            if(x1 == x2 && y1 == y2)
+            List<Coordinates> output = new List<Coordinates>();
+            for (int i = 0; i < shape.Length; i++)
             {
-                return new Coordinates[] { new Coordinates(x1, y1) };
+                output.AddRange(CoordinatesCalculator.RectangleToCoordinates(CoordinatesCalculator.CalculateThicknessCenter(shape[i], thickness)));
             }
-
-            int d, dx, dy, ai, bi, xi, yi;
-            int x = x1, y = y1;
-
-            if (x1 < x2)
-            {
-                xi = 1;
-                dx = x2 - x1;
-            }
-            else
-            {
-                xi = -1;
-                dx = x1 - x2;
-            }
-
-            if (y1 < y2)
-            {
-                yi = 1;
-                dy = y2 - y1;
-            }
-            else
-            {
-                yi = -1;
-                dy = y1 - y2;
-            }
-            coordinates.Add(new Coordinates(x, y));
-
-            if (dx > dy)
-            {
-                ai = (dy - dx) * 2;
-                bi = dy * 2;
-                d = bi - dx;
-                
-                while (x != x2)
-                {
-                    
-                    if (d >= 0)
-                    {
-                        x += xi;
-                        y += yi;
-                        d += ai;
-                    }
-                    else
-                    {
-                        d += bi;
-                        x += xi;
-                    }
-                    coordinates.Add(new Coordinates(x, y));
-                }
-            }
-            else
-            {
-                ai = (dx - dy) * 2;
-                bi = dx * 2;
-                d = bi - dy;
-                
-                while (y != y2)
-                {
-                    
-                    if (d >= 0)
-                    {
-                        x += xi;
-                        y += yi;
-                        d += ai;
-                    }
-                    else
-                    {
-                        d += bi;
-                        y += yi;
-                    }
-                    coordinates.Add(new Coordinates(x, y));
-                }
-            }
-
-            return coordinates.ToArray();
-
+            return output.Distinct().ToArray();
         }
+     
 
         protected DoubleCords CalculateCoordinatesForShapeRotation(Coordinates startingCords, Coordinates secondCoordinates)
         {

+ 21 - 26
PixiEditor/Models/Tools/Tools/CircleTool.cs

@@ -1,4 +1,5 @@
-using PixiEditor.Models.Layers;
+using PixiEditor.Models.ImageManipulation;
+using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
 using System;
 using System.Collections.Generic;
@@ -20,20 +21,30 @@ namespace PixiEditor.Models.Tools.Tools
         public override BitmapPixelChanges Use(Layer layer, Coordinates[] coordinates, Color color, int toolSize)
         {
             DoubleCords fixedCoordinates = CalculateCoordinatesForShapeRotation(coordinates[^1], coordinates[0]);
-            return BitmapPixelChanges.FromSingleColoredArray(CreateEllipse(fixedCoordinates.Coords1, fixedCoordinates.Coords2, false), color);
+            return BitmapPixelChanges.FromSingleColoredArray(CreateEllipse(fixedCoordinates.Coords1, fixedCoordinates.Coords2, false, toolSize), color);
         }
 
-        public Coordinates[] CreateEllipse(Coordinates startCoordinates, Coordinates endCoordinates, bool filled)
-        {            
+        public Coordinates[] CreateEllipse(Coordinates startCoordinates, Coordinates endCoordinates, bool filled, int thickness)
+        {
             Coordinates centerCoordinates = CoordinatesCalculator.GetCenterPoint(startCoordinates, endCoordinates);
             int radiusX = endCoordinates.X - centerCoordinates.X;
             int radiusY = endCoordinates.Y - centerCoordinates.Y;
+            List<Coordinates> output = new List<Coordinates>();
             Coordinates[] ellipse = MidpointEllipse(radiusX, radiusY, centerCoordinates.X, centerCoordinates.Y);
+            if (thickness == 1)
+            {
+                output.AddRange(ellipse);
+            }
+            else
+            {
+                output.AddRange(GetThickShape(ellipse, thickness));
+            }
+
             if (filled)
             {
-                ellipse = ellipse.Concat(CalculateFillForEllipse(ellipse)).Distinct().ToArray();
+                output.AddRange(CalculateFillForEllipse(ellipse));
             }
-            return ellipse;
+            return output.Distinct().ToArray();
         }
 
         public Coordinates[] MidpointEllipse(double rx, double ry, double xc, double yc)
@@ -66,14 +77,14 @@ namespace PixiEditor.Models.Tools.Tools
                 }
             }
 
-            //Yeah, it scares me too
-            d2 = (ry * ry * ((x + 0.5f) * (x + 0.5f))) + (rx * rx * ((y - 1) * (y - 1))) - (rx * rx * ry * ry);
+            //Decision parameter of region 2
+            d2 = ((ry * ry) * ((x + 0.5f) * (x + 0.5f))) + ((rx * rx) * ((y - 1) * (y - 1))) - (rx * rx * ry * ry);
 
-            while(y >= 0)
+            while (y >= 0)
             {
                 outputCoordinates.AddRange(GetRegionPoints(x, xc, y, yc));
 
-                if(d2 > 0)
+                if (d2 > 0)
                 {
                     y--;
                     dy -= (2 * rx * rx);
@@ -119,22 +130,6 @@ namespace PixiEditor.Models.Tools.Tools
             outputCoordinates[2] = (new Coordinates((int)x + (int)xc, (int)-y + (int)yc));
             outputCoordinates[3] = (new Coordinates((int)-x + (int)xc, (int)-y + (int)yc));
             return outputCoordinates;
-        }
-       
-
-        private Coordinates[] GetPixelsForOctant(int xc, int yc, int x, int y)
-        {
-            Coordinates[] outputCords = new Coordinates[8];
-            outputCords[0] = new Coordinates(x + xc, y + yc);
-            outputCords[1] = new Coordinates(x + xc, -y + yc);
-            outputCords[2] = new Coordinates(-x + xc, -y + yc);
-            outputCords[3] = new Coordinates(-x + xc, y + yc);
-            outputCords[4] = new Coordinates(y + xc, x + yc);
-            outputCords[5] = new Coordinates(y + xc, -x + yc);
-            outputCords[6] = new Coordinates(-y + xc, -x + yc);
-            outputCords[7] = new Coordinates(-y + xc, x + yc);
-            return outputCords;
         }
-
     }
 }

+ 109 - 9
PixiEditor/Models/Tools/Tools/LineTool.cs

@@ -1,4 +1,5 @@
-using PixiEditor.Models.Layers;
+using PixiEditor.Models.ImageManipulation;
+using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
 using System;
 using System.Collections.Generic;
@@ -26,19 +27,118 @@ namespace PixiEditor.Models.Tools.Tools
         {
             Coordinates startingCoordinates = coordinates[^1];
             Coordinates latestCoordinates = coordinates[0];
-            return BresenhamLine(startingCoordinates.X, startingCoordinates.Y, latestCoordinates.X, latestCoordinates.Y);
+            if(thickness == 1)
+            {
+                return BresenhamLine(startingCoordinates.X, startingCoordinates.Y, latestCoordinates.X, latestCoordinates.Y);
+            }
+            return GetThickShape(BresenhamLine(startingCoordinates.X, startingCoordinates.Y, latestCoordinates.X, latestCoordinates.Y), thickness);
         }
-        
 
-        public Coordinates[] ThickLine(Coordinates start, Coordinates end, int thickness)
+        private Coordinates[] BresenhamLine(int x1, int y1, int x2, int y2)
         {
-            List<Coordinates> points = new List<Coordinates>();
+            List<Coordinates> coordinates = new List<Coordinates>();
+            if (x1 == x2 && y1 == y2)
+            {
+                return new Coordinates[] { new Coordinates(x1, y1) };
+            }
 
-            Coordinates[] linePoints = BresenhamLine(start.X, start.Y, end.X, end.Y);
+            int d, dx, dy, ai, bi, xi, yi;
+            int x = x1, y = y1;
 
-            
+            if (x1 < x2)
+            {
+                xi = 1;
+                dx = x2 - x1;
+            }
+            else
+            {
+                xi = -1;
+                dx = x1 - x2;
+            }
 
-            return points.Distinct().ToArray();
-		}       
+            if (y1 < y2)
+            {
+                yi = 1;
+                dy = y2 - y1;
+            }
+            else
+            {
+                yi = -1;
+                dy = y1 - y2;
+            }
+            coordinates.Add(new Coordinates(x, y));
+
+            if (dx > dy)
+            {
+                ai = (dy - dx) * 2;
+                bi = dy * 2;
+                d = bi - dx;
+
+                while (x != x2)
+                {
+
+                    if (d >= 0)
+                    {
+                        x += xi;
+                        y += yi;
+                        d += ai;
+                    }
+                    else
+                    {
+                        d += bi;
+                        x += xi;
+                    }
+                    coordinates.Add(new Coordinates(x, y));
+                }
+            }
+            else
+            {
+                ai = (dx - dy) * 2;
+                bi = dx * 2;
+                d = bi - dy;
+
+                while (y != y2)
+                {
+
+                    if (d >= 0)
+                    {
+                        x += xi;
+                        y += yi;
+                        d += ai;
+                    }
+                    else
+                    {
+                        d += bi;
+                        y += yi;
+                    }
+                    coordinates.Add(new Coordinates(x, y));
+                }
+            }
+
+            return coordinates.ToArray();
+
+        }
+
+        private int[,] GetMaskForThickness(int thickness)
+        {
+            if(thickness == 2)
+            {
+                return new int[,] {
+                {0,0,0 },
+                {0,1,1 },
+                {0,1,1 }
+                };
+            }
+            int[,] mask = new int[thickness,thickness];
+
+            for (int i = 0; i < thickness; i++)
+            {
+                for (int j = 0; j < thickness; j++)
+                {
+                    mask[i, j] = 1;
+                }
+            }
+            return mask;
+        }    
 	}
 }

+ 5 - 3
PixiEditor/Views/MainWindow.xaml

@@ -78,9 +78,6 @@
                         <i:EventTrigger EventName="MouseMove">
                             <i:InvokeCommandAction Command="{Binding MouseMoveCommand}"/>
                         </i:EventTrigger>
-                        <i:EventTrigger EventName="MouseDown">
-                            <i:InvokeCommandAction Command="{Binding MouseDownCommand}"/>
-                        </i:EventTrigger>
                         <i:EventTrigger EventName="MouseUp">
                             <i:InvokeCommandAction Command="{Binding MouseUpCommand}"/>
                         </i:EventTrigger>
@@ -90,6 +87,11 @@
                     </i:Interaction.Behaviors>
                     <vws:MainDrawingPanel.Item>
                         <Canvas Width="{Binding BitmapUtility.ActiveLayer.Width}" Height="{Binding BitmapUtility.ActiveLayer.Height}" VerticalAlignment="Center" HorizontalAlignment="Center">
+                            <i:Interaction.Triggers>
+                                <i:EventTrigger EventName="MouseDown">
+                                    <i:InvokeCommandAction Command="{Binding MouseDownCommand}"/>
+                                </i:EventTrigger>
+                            </i:Interaction.Triggers>
                             <Image Source="/Images/transparentbg.png" Height="{Binding BitmapUtility.ActiveLayer.Height}" Width="{Binding BitmapUtility.ActiveLayer.Width}" Opacity="0.9" Stretch="UniformToFill"/>
                             <Image Source="{Binding BitmapUtility.PreviewLayer.LayerBitmap}" Panel.ZIndex="2" RenderOptions.BitmapScalingMode="NearestNeighbor" Stretch="Uniform" Width="{Binding BitmapUtility.PreviewLayer.Width}" Height="{Binding BitmapUtility.PreviewLayer.Height}"/>
                             <ItemsControl ItemsSource="{Binding BitmapUtility.Layers}">