Skip to content

Instantly share code, notes, and snippets.

@felipebaltazar
Created June 15, 2018 19:36
Show Gist options
  • Save felipebaltazar/8a67fb25aebc0fa7c6f6c5e1366996a2 to your computer and use it in GitHub Desktop.
Save felipebaltazar/8a67fb25aebc0fa7c6f6c5e1366996a2 to your computer and use it in GitHub Desktop.
using Draw.Application.Aplication;
using Draw.Application.Helpers;
using Draw.Application.Helpers.Managers.Commands;
using Draw.Application.Ressources.Languages;
using Draw.Core.Extensions;
using Draw.Core.Helpers;
using Draw.Math.Helpers;
using Draw.Math.Models;
using Draw.Models.DraftModels;
using Draw.Models.WallModels;
using SkiaSharp;
using SkiaSharp.Views.Forms;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Xamarin.Forms;
namespace Draw.Application.DrawSpace
{
public class BluePrint : Ambient2D
{
#region Bindable Properties
public static readonly BindableProperty SnapModeProperty = BindableProperty.Create(
propertyName: nameof(SnapMode),
returnType: typeof(bool),
declaringType: typeof(BluePrint),
defaultValue: true,
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: OnSnapModeChanged);
public static readonly BindableProperty QuotasOnProperty = BindableProperty.Create(
propertyName: nameof(QuotasOn),
returnType: typeof(bool),
declaringType: typeof(BluePrint),
defaultValue: true,
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: OnQuotasOnChanged);
public static readonly BindableProperty ChildsOnProperty = BindableProperty.Create(
propertyName: nameof(ChildsOn),
returnType: typeof(bool),
declaringType: typeof(BluePrint),
defaultValue: true,
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: OnChildsOnChanged);
public static readonly BindableProperty VertsOnProperty = BindableProperty.Create(
propertyName: nameof(VertsOn),
returnType: typeof(bool),
declaringType: typeof(BluePrint),
defaultValue: true,
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: OnVertsOnChanged);
public static readonly BindableProperty IsDrawingProperty = BindableProperty.Create(
propertyName: nameof(IsDrawing),
returnType: typeof(bool),
declaringType: typeof(BluePrint),
defaultValue: false,
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: OnIsDrawingChanged);
public static readonly BindableProperty SelectedWallProperty = BindableProperty.Create(
propertyName: nameof(SelectedWall),
returnType: typeof(WallProperty),
declaringType: typeof(BluePrint),
defaultValue: null,
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: OnSelectedWallChanged);
#endregion
#region Bindable Events
private static void OnSelectedWallChanged(BindableObject bindable, object oldValue, object newValue)
{
if(bindable is BluePrint control)
{
if(newValue is WallProperty selectedWall)
{
control.SelectedWall = selectedWall;
}
}
}
private static void OnIsDrawingChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is BluePrint control)
{
if (newValue is bool isDrawing)
control.IsDrawing = isDrawing;
}
}
private static void OnQuotasOnChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is BluePrint control)
{
if (newValue is bool quotasOn)
control.QuotasOn = quotasOn;
}
}
private static void OnVertsOnChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is BluePrint control)
{
if (newValue is bool vertsOn)
control.VertsOn = vertsOn;
}
}
private static void OnSnapModeChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is BluePrint control)
{
if (newValue is bool snapMode)
control.SnapMode = snapMode;
}
}
private static void OnChildsOnChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is BluePrint control)
{
if (newValue is bool childsOn)
control.ChildsOn = childsOn;
}
}
#endregion
#region Private values
private int _gridStep = 50;
private int _rulerSize = 150;
private int _wallHeight = 2600;
private int _rulerFontSize = 35;
private int _quotaFontSize = 35;
private int _quotaDistance = 300;
private int _gridDivisions = 250;
private int _wallThickness = 150;
private bool _drawSingleVertice;
private bool _snapMode = true;
private bool _childsOn = true;
private bool _quotasOn = true;
private bool _vertsOn = true;
private Vector2D _selectedVertice;
private WallProperty _selectedWall;
private BluePrintCommands _commands;
private Vector2D _previousVertPosition = new Vector2D();
#endregion
#region Public properties
public ObservableRangeCollection<WallProperty> DraftWalls { get; set; }
public Vector2D SelectedWallIntersect { get; set; }
public Alignment Alignment { get; set; }
public BluePrintCommands Commands
{
get { return _commands; }
set
{
if (value == _commands)
return;
_commands = value;
OnPropertyChanged();
}
}
public WallProperty SelectedWall
{
get => _selectedWall;
set
{
if (_selectedWall != value)
{
if (value == null)
SelectedWallIntersect = null;
else
{
if(TouchLocation != null)
SelectedWallIntersect = new Vector2D(
TouchLocation.X, TouchLocation.Y);
}
_selectedWall = value;
MessagingCenter.Send(this, MessagingDictionary.SELECTEDWALL_CHANGED, value);
}
}
}
public Vector2D SelectedVertice
{
get => _selectedVertice;
set
{
if (value == _selectedVertice)
return;
if (value == null)
{
PreviousPosition.X = 0;
PreviousPosition.Y = 0;
}
_selectedVertice = value;
}
}
public int QuotaFontSize
{
get => _quotaFontSize;
set
{
if(_quotaDistance == value)
return;
_quotaFontSize = value;
CanvasView?.InvalidateSurface();
}
}
public int QuotaDistance
{
get => _quotaDistance;
set
{
if(_quotaDistance == value)
return;
_quotaDistance = value;
CanvasView?.InvalidateSurface();
}
}
public int WallThickness
{
get { return _wallThickness; }
set
{
if (value == _wallThickness)
return;
_wallThickness = value;
OnPropertyChanged();
}
}
public int WallHeight
{
get { return _wallHeight; }
set
{
if (_wallHeight == value)
return;
_wallHeight = value;
OnPropertyChanged();
}
}
public bool SnapMode
{
get { return _snapMode; }
set
{
if (_snapMode == value)
return;
_snapMode = value;
OnPropertyChanged();
}
}
public bool QuotasOn
{
get => _quotasOn;
set
{
if(value == _quotasOn)
return;
_quotasOn = value;
OnPropertyChanged();
CanvasView?.InvalidateSurface();
}
}
public bool ChildsOn
{
get => _childsOn;
set
{
if(value == _childsOn)
return;
_childsOn = value;
OnPropertyChanged();
CanvasView?.InvalidateSurface();
}
}
public bool VertsOn
{
get => _vertsOn;
set
{
if(value == _vertsOn)
return;
_vertsOn = value;
OnPropertyChanged();
CanvasView?.InvalidateSurface();
}
}
#endregion
#region Constructors
public BluePrint() : base()
{
if(DraftWalls == null)
DraftWalls = new ObservableRangeCollection<WallProperty>();
Commands = new BluePrintCommands(this);
_gridDivisions = AppConfig.SettingsDao?.List?
.LastOrDefault()?.GridDivisions?.ToInt32() ?? _gridDivisions;
}
#endregion
#region Override Methods
internal override void OnCanvasViewPaintSurface(object sender,
SKPaintSurfaceEventArgs args)
{
if (!KeepSelection)
{
SelectedVertice = null;
SelectedWall = null;
}
else
{
KeepSelection = false;
}
var info = args.Info;
var surface = args.Surface;
var canvas = surface.Canvas;
base.OnCanvasViewPaintSurface(sender, args);
canvas.Clear();
DrawGrid(info, surface, canvas);
if(_drawSingleVertice && IsDrawing)
{
canvas.Save();
canvas.Translate(LastTouch.X, LastTouch.Y);
using (var rectPaint = new SKPaint())
{
rectPaint.Style = SKPaintStyle.Fill;
rectPaint.Color = Color.Blue.ToSKColor();
var vertPoint = new SKRect()
{
Location = new SKPoint(-50, -50),
Size = new SKSize(100, 100)
};
canvas.DrawRect(vertPoint, rectPaint);
}
canvas.Restore();
}
DrawDraft(info, surface, canvas);
DrawMoveArrows(info, surface, canvas);
DrawRuler(info, surface, canvas);
}
internal override void SingleTapGestureTapped(object sender)
{
base.SingleTapGestureTapped(sender);
if (LastTouch != null && TouchLocation != null && LastTouch != TouchLocation)
{
var wallStart = new Vector2D();
var wallEnd = new Vector2D();
if (CheckAnyCollision())
return;
Commands.InsertUndo();
DraftWalls.Add(new WallProperty
{
WallName = Guid.NewGuid().ToString(),
WallStartX = LastTouch.X,
WallStartY = LastTouch.Y,
WallEndX = TouchLocation.X,
WallEndY = TouchLocation.Y,
Wallthickness = WallThickness,
StartHeight = WallHeight,
EndHeight = WallHeight
});
LastTouch.X = TouchLocation.X;
LastTouch.Y = TouchLocation.Y;
_drawSingleVertice = false;
CanvasView?.InvalidateSurface();
}
else
{
LastTouch = new Vector2D(TouchLocation.X, TouchLocation.Y);
_drawSingleVertice = true;
CanvasView?.InvalidateSurface();
}
}
internal override void PanGesturePanUpdated(object sender, PanUpdatedEventArgs e)
{
if (e.StatusType == GestureStatus.Running)
{
if (SelectedVertice != null)
{
MoveSelectedVertice(e);
return;
}
}
base.PanGesturePanUpdated(sender, e);
}
internal override void CenterDraw()
{
if (!(DraftWalls?.Count > 0))
{
ResetLocation();
return;
}
var (max, min) = Math2D.GetDrawLimits(DraftWalls);
var center = Math2D.Center(min, max);
var centerXScreen = WidthScreen > 0 ? WidthScreen / 2 : 0;
var centerYScreen = HeightScreen > 0 ? HeightScreen / 2 : 0;
CanvasPosition = new Vector2D(centerXScreen - center.X,
centerYScreen - center.Y);
CanvasView?.InvalidateSurface();
}
#endregion
#region Private Methods
private void DrawMoveArrows(SKImageInfo info,
SKSurface surface, SKCanvas canvas)
{
if (SelectedVertice == null)
return;
canvas.Save();
canvas.Translate(SelectedVertice.X, SelectedVertice.Y);
var arrowSize = 100 / CanvasScale;
var assembly = Assembly.GetExecutingAssembly();
using (var resource = assembly.GetManifestResourceStream("Draw.Application.Ressources.ToolBox.move.png"))
using (var stream = new SKManagedStream(resource))
using (var source = SKBitmap.Decode(stream))
{
var rec = new SKRect(0, 0, arrowSize, arrowSize)
{
Location = new SKPoint(-arrowSize / 2, -arrowSize / 2)
};
canvas.DrawImage(SKImage.FromBitmap(source), rec);
}
canvas.Restore();
}
private void DrawGrid(SKImageInfo info, SKSurface surface, SKCanvas canvas)
{
WidthScreen = canvas.LocalClipBounds.Size.Width;
HeightScreen = canvas.LocalClipBounds.Size.Height;
var divisionsParameter = GetDivisionsParameter();
var largeDivisionParameter = divisionsParameter * 4;
var xRepetitions = (System.Math.Round(WidthScreen / largeDivisionParameter) + 1).ToInt32();
var yRepetitions = (System.Math.Round(HeightScreen / largeDivisionParameter) + 1).ToInt32();
var largeDisplacementX = (System.Math.Round(canvas.LocalClipBounds.Location.X / largeDivisionParameter)).ToInt32();
var largeDisplacementY = (System.Math.Round(canvas.LocalClipBounds.Location.Y / largeDivisionParameter)).ToInt32();
var skinnyDisplacementX = (System.Math.Round(canvas.LocalClipBounds.Location.X / divisionsParameter)).ToInt32();
var skinnyDisplacementY = (System.Math.Round(canvas.LocalClipBounds.Location.Y / divisionsParameter)).ToInt32();
var paint = new SKPaint
{
Style = SKPaintStyle.Fill,
Color = BackgroundColor.ToSKColor(),
StrokeWidth = 2 / CanvasScale,
IsAntialias = HasAntialias(),
};
if(IsZooning || IsPanning)
{
using(var backgroundPath = new SKPath())
{
backgroundPath.MoveTo(
canvas.LocalClipBounds.Location.X, canvas.LocalClipBounds.Location.Y);
backgroundPath.LineTo(
canvas.LocalClipBounds.Location.X + canvas.LocalClipBounds.Size.Width,
canvas.LocalClipBounds.Location.Y);
backgroundPath.LineTo(
canvas.LocalClipBounds.Location.X + canvas.LocalClipBounds.Size.Width,
canvas.LocalClipBounds.Location.Y + canvas.LocalClipBounds.Size.Height);
backgroundPath.LineTo(
canvas.LocalClipBounds.Location.X,
canvas.LocalClipBounds.Location.Y + canvas.LocalClipBounds.Size.Height);
backgroundPath.Close();
canvas.DrawPath(backgroundPath,paint);
}
}
paint.Color = Color.LightGray.ToSKColor();
paint.Style = SKPaintStyle.Stroke;
paint.IsStroke = true;
#region grid 0,250 m²
xRepetitions = xRepetitions * 4;
yRepetitions = yRepetitions * 4;
for (int i = 0; i <= xRepetitions; i++)
{
using (var skinnyLinesPath = new SKPath())
{
skinnyLinesPath.MoveTo((i * divisionsParameter) + (skinnyDisplacementX * divisionsParameter),
canvas.LocalClipBounds.Location.Y);
skinnyLinesPath.LineTo((i * divisionsParameter) + (skinnyDisplacementX * divisionsParameter),
(HeightScreen) + canvas.LocalClipBounds.Location.Y);
canvas.DrawPath(skinnyLinesPath, paint);
}
}
for (int i = 0; i <= yRepetitions; i++)
{
using (var skinnyLinesPath = new SKPath())
{
skinnyLinesPath.MoveTo(canvas.LocalClipBounds.Location.X,
(i * divisionsParameter) + (skinnyDisplacementY * divisionsParameter));
skinnyLinesPath.LineTo((WidthScreen) + canvas.LocalClipBounds.Location.X,
(i * divisionsParameter) + (skinnyDisplacementY * divisionsParameter));
canvas.DrawPath(skinnyLinesPath, paint);
}
}
#endregion
#region grid 1 m²
xRepetitions = xRepetitions / 4;
yRepetitions = yRepetitions / 4;
paint.StrokeWidth = 3 / CanvasScale;
paint.Color = Color.Gray.ToSKColor();
for (int i = 0; i <= xRepetitions; i++)
{
using (var largeLinesPath = new SKPath())
{
largeLinesPath.MoveTo((i * largeDivisionParameter) + (largeDisplacementX * largeDivisionParameter),
canvas.LocalClipBounds.Location.Y);
largeLinesPath.LineTo((i * largeDivisionParameter) + (largeDisplacementX * largeDivisionParameter),
HeightScreen + canvas.LocalClipBounds.Location.Y);
canvas.DrawPath(largeLinesPath, paint);
}
}
for (int i = 0; i <= yRepetitions; i++)
{
using (var largeLinesPath = new SKPath())
{
largeLinesPath.MoveTo(canvas.LocalClipBounds.Location.X,
(i * largeDivisionParameter) + (largeDisplacementY * largeDivisionParameter));
largeLinesPath.LineTo(WidthScreen + canvas.LocalClipBounds.Location.X,
(i * largeDivisionParameter) + (largeDisplacementY * largeDivisionParameter));
canvas.DrawPath(largeLinesPath, paint);
}
}
#endregion
}
private void DrawDraft(SKImageInfo info,
SKSurface surface, SKCanvas canvas)
{
DrawFloor(info, surface, canvas);
DrawWalls(info, surface, canvas);
}
private void DrawFloor(SKImageInfo info,
SKSurface surface, SKCanvas canvas)
{
var paint = new SKPaint
{
Style = SKPaintStyle.Fill,
Color = Color.WhiteSmoke.ToSKColor(),
StrokeWidth = 3 / CanvasScale,
TextSize = 3,
IsAntialias = HasAntialias()
};
using (var floorPath = new SKPath())
{
foreach (var wall in DraftWalls)
{
var previousWall = Math2D.GetPreviousWall(wall, DraftWalls);
if(previousWall == null)
floorPath.MoveTo(wall.WallStartX, wall.WallStartY);
floorPath.LineTo(wall.WallEndX, wall.WallEndY);
var nexWall = Math2D.GetNextWall(wall, DraftWalls);
if (nexWall == null)
{
if (previousWall != null)
{
floorPath.Close();
canvas.DrawPath(floorPath, paint);
floorPath.Reset();
}
}
}
floorPath.Close();
canvas.DrawPath(floorPath, paint);
}
}
private void DrawWalls(SKImageInfo info,
SKSurface surface, SKCanvas canvas)
{
var paint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = Color.Black.ToSKColor(),
StrokeWidth = 3 / CanvasScale,
TextSize = 3,
IsAntialias = HasAntialias()
};
foreach (var wall in DraftWalls)
{
paint.Style = SKPaintStyle.Fill;
paint.Color = Color.LightGray.ToSKColor();
using (var wallsPath = new SKPath())
{
var previousWall = Math2D.GetPreviousWall(wall, DraftWalls);
var nextWall = Math2D.GetNextWall(wall, DraftWalls);
var startPoint = new Vector2D(wall.WallStartX, wall.WallStartY);
var endPoint = new Vector2D(wall.WallEndX, wall.WallEndY);
var wallAngle = Math2D.AngleByTwoPoints(
startPoint,
endPoint);
var width = Math2D.CalculeWidthByTwoPoints(
startPoint,
endPoint);
double previousConnection = 0;
double nextConnection = 0;
if(previousWall != null)
{
var angleBetweenWalls = Math2D.AngleByThreePoints(previousWall,startPoint,endPoint);
angleBetweenWalls = (180 - angleBetweenWalls) ;
previousConnection = Math2D.GetConnection(angleBetweenWalls, wall.Wallthickness);
}
if(nextWall != null)
{
var angleBetweenWalls = Math2D.AngleByThreePoints(startPoint, endPoint, nextWall);
angleBetweenWalls = (180 - angleBetweenWalls);
nextConnection = Math2D.GetConnection(angleBetweenWalls, wall.Wallthickness);
}
if (SelectedWall == wall ||
(!IsDrawing && !IsPanning && !IsZooning && SelectedWall == null
&& SelectedVertice == null && IsTouched(startPoint, endPoint, TouchLocation)))
{
paint.Color = Color.Red.ToSKColor();
SelectedWall = wall;
}
canvas.Save();
canvas.Translate(wall.WallStartX, wall.WallStartY);
canvas.RotateDegrees(wallAngle.ToSingle());
wallsPath.MoveTo(0,0);
wallsPath.LineTo(width,0);
wallsPath.LineTo(width + nextConnection.ToSingle(), -wall.Wallthickness);
wallsPath.LineTo(0 - previousConnection.ToSingle(), -wall.Wallthickness);
wallsPath.Close();
canvas.DrawPath(wallsPath, paint);
var assembly = Assembly.GetExecutingAssembly();
using (var resource = assembly.GetManifestResourceStream("Draw.Application.Ressources.Identity.hatch.png"))
using (var stream = new SKManagedStream(resource))
using (var source = SKBitmap.Decode(stream))
{
var matrix = SKMatrix.MakeRotation(30.0f);
matrix.ScaleX = 0.7f / CanvasScale;
matrix.ScaleY = 0.7f / CanvasScale;
using (var shader = SKShader.CreateBitmap(source, SKShaderTileMode.Repeat, SKShaderTileMode.Repeat, matrix))
using (var hatchPaint = new SKPaint())
{
hatchPaint.Style = SKPaintStyle.Fill;
hatchPaint.StrokeWidth = 6 / CanvasScale;
hatchPaint.TextSize = 3;
hatchPaint.IsAntialias = HasAntialias();
hatchPaint.Shader = shader;
canvas.DrawPath(wallsPath, hatchPaint);
};
}
paint.Color = Color.Black.ToSKColor();
paint.Style = SKPaintStyle.Stroke;
canvas.DrawPath(wallsPath, paint);
if (VertsOn)
DrawVertices(canvas, width, startPoint, endPoint);
if (ChildsOn)
DrawWallChilds(canvas, width, wall.Wallthickness, wall.Children.ToArray());
if (QuotasOn)
DrawQuotas(canvas, width, wallAngle.ToSingle());
canvas.Restore();
}
}
paint.Dispose();
}
private void DrawRuler(SKImageInfo info, SKSurface surface, SKCanvas canvas)
{
var divisionsParameter = GetDivisionsParameter();
var scaledRulerSize = _rulerSize / CanvasScale;
using (var paint = new SKPaint()
{
Style = SKPaintStyle.Fill,
Color = Color.White.ToSKColor(),
StrokeWidth = 2 / CanvasScale,
IsAntialias = HasAntialias(),
TextSize = _rulerFontSize / CanvasScale,
TextAlign = SKTextAlign.Center
})
{
using (var ruler = new SKPath())
{
ruler.MoveTo(canvas.LocalClipBounds.Location.X, canvas.LocalClipBounds.Location.Y);
ruler.LineTo(canvas.LocalClipBounds.Location.X + canvas.LocalClipBounds.Size.Width,
canvas.LocalClipBounds.Location.Y);
ruler.LineTo(canvas.LocalClipBounds.Location.X + canvas.LocalClipBounds.Size.Width,
canvas.LocalClipBounds.Location.Y + scaledRulerSize);
ruler.LineTo(canvas.LocalClipBounds.Location.X + scaledRulerSize,
canvas.LocalClipBounds.Location.Y + scaledRulerSize);
ruler.LineTo(canvas.LocalClipBounds.Location.X + scaledRulerSize,
canvas.LocalClipBounds.Location.Y + canvas.LocalClipBounds.Size.Height);
ruler.LineTo(canvas.LocalClipBounds.Location.X,
canvas.LocalClipBounds.Location.Y + canvas.LocalClipBounds.Size.Height);
ruler.Close();
canvas.DrawPath(ruler, paint);
paint.Color = Color.Black.ToSKColor();
paint.Style = SKPaintStyle.Stroke;
canvas.DrawPath(ruler, paint);
}
var largeDivisionParameter = divisionsParameter * 4;
var xRepetitions = ((WidthScreen / largeDivisionParameter).Round() + 1).ToInt32();
var yRepetitions = ((HeightScreen / largeDivisionParameter).Round() + 1).ToInt32();
var largeDisplacementX = ((canvas.LocalClipBounds.Location.X / largeDivisionParameter).Round()).ToInt32();
var largeDisplacementY = ((canvas.LocalClipBounds.Location.Y / largeDivisionParameter).Round()).ToInt32();
var skinnyDisplacementX = ((canvas.LocalClipBounds.Location.X / divisionsParameter).Round()).ToInt32();
var skinnyDisplacementY = ((canvas.LocalClipBounds.Location.Y / divisionsParameter).Round()).ToInt32();
paint.Style = SKPaintStyle.Stroke;
paint.StrokeWidth = 4 / CanvasScale;
paint.Color = Color.Black.ToSKColor();
paint.IsAntialias = HasAntialias();
paint.IsStroke = true;
var largeXPositions = new List<float>();
var largeYPositions = new List<float>();
#region grid 1 m²
for (int i = 0; i <= xRepetitions; i++)
{
using (var largeLinesPath = new SKPath())
{
var xPosition = (i * largeDivisionParameter) + (largeDisplacementX * largeDivisionParameter);
var yEndPosition = (scaledRulerSize - (scaledRulerSize / 1.3f)) + canvas.LocalClipBounds.Location.Y;
largeXPositions.Add(xPosition);
largeLinesPath.MoveTo(xPosition, canvas.LocalClipBounds.Location.Y + scaledRulerSize);
largeLinesPath.LineTo(xPosition, yEndPosition);
canvas.DrawPath(largeLinesPath, paint);
paint.Style = SKPaintStyle.Fill;
canvas.DrawText($"{xPosition} mm",
xPosition,
yEndPosition,
paint);
paint.Style = SKPaintStyle.Stroke;
}
}
for (int i = 0; i <= yRepetitions; i++)
{
using (var largeLinesPath = new SKPath())
{
var xEndPosition = (scaledRulerSize - (scaledRulerSize / 1.3f)) + canvas.LocalClipBounds.Location.X;
var yPosition = (i * largeDivisionParameter) + (largeDisplacementY * largeDivisionParameter);
largeYPositions.Add(yPosition);
largeLinesPath.MoveTo(canvas.LocalClipBounds.Location.X + scaledRulerSize, yPosition);
largeLinesPath.LineTo(xEndPosition, yPosition);
canvas.DrawPath(largeLinesPath, paint);
paint.Style = SKPaintStyle.Fill;
canvas.Save();
canvas.Translate(xEndPosition, yPosition);
canvas.RotateDegrees(-90);
canvas.DrawText($"{yPosition} mm", 0, 0, paint);
canvas.Restore();
paint.Style = SKPaintStyle.Stroke;
}
}
#endregion
#region grid 0,250 m²
paint.Color = Color.DarkGray.ToSKColor();
paint.StrokeWidth = 3 / CanvasScale;
xRepetitions = xRepetitions * 4;
yRepetitions = yRepetitions * 4;
for (int i = 0; i <= xRepetitions; i++)
{
using (var skinnyLinesPath = new SKPath())
{
var xPosition = (i * divisionsParameter) + (skinnyDisplacementX * divisionsParameter);
if (largeXPositions.Any(l => l == xPosition))
continue;
var xLargePosition = (i * largeDivisionParameter) + (largeDisplacementX * largeDivisionParameter);
var yEndPosition = (scaledRulerSize - (scaledRulerSize / 2)) + canvas.LocalClipBounds.Location.Y;
skinnyLinesPath.MoveTo(xPosition,
canvas.LocalClipBounds.Location.Y + scaledRulerSize);
skinnyLinesPath.LineTo(xPosition, yEndPosition);
canvas.DrawPath(skinnyLinesPath, paint);
paint.Style = SKPaintStyle.Fill;
canvas.DrawText($"{xPosition} mm",
xPosition,
yEndPosition,
paint);
paint.Style = SKPaintStyle.Stroke;
}
}
for (int i = 0; i <= yRepetitions; i++)
{
using (var skinnyLinesPath = new SKPath())
{
var yPosition = (i * divisionsParameter) + (skinnyDisplacementY * divisionsParameter);
if (largeYPositions.Any(l => l == yPosition))
continue;
var xEndPosition = (scaledRulerSize - (scaledRulerSize / 2)) + canvas.LocalClipBounds.Location.X;
var yLargePosition = (i * largeDivisionParameter) + (largeDisplacementY * largeDivisionParameter);
skinnyLinesPath.MoveTo(
canvas.LocalClipBounds.Location.X + scaledRulerSize,
yPosition);
skinnyLinesPath.LineTo(xEndPosition, yPosition);
canvas.DrawPath(skinnyLinesPath, paint);
paint.Style = SKPaintStyle.Fill;
canvas.Save();
canvas.Translate(xEndPosition, yPosition);
canvas.RotateDegrees(-90);
canvas.DrawText($"{yPosition} mm", 0, 0, paint);
canvas.Restore();
paint.Style = SKPaintStyle.Stroke;
}
}
#endregion
using (var ruler = new SKPath())
{
paint.Color = Color.LightGray.ToSKColor();
paint.Style = SKPaintStyle.Fill;
var xPosition = canvas.LocalClipBounds.Location.X + scaledRulerSize;
var yPosition = canvas.LocalClipBounds.Location.Y + scaledRulerSize;
ruler.MoveTo(canvas.LocalClipBounds.Location.X, canvas.LocalClipBounds.Location.Y);
ruler.LineTo(xPosition, canvas.LocalClipBounds.Location.Y);
ruler.LineTo(xPosition, yPosition);
ruler.LineTo(canvas.LocalClipBounds.Location.X, yPosition);
ruler.Close();
canvas.DrawPath(ruler, paint);
paint.Color = Color.Black.ToSKColor();
paint.Style = SKPaintStyle.Stroke;
canvas.DrawPath(ruler, paint);
paint.Style = SKPaintStyle.Fill;
paint.TextSize = 50 / CanvasScale;
canvas.DrawText($"{System.Math.Round(CanvasScale, 2)}/1",
canvas.LocalClipBounds.Location.X + scaledRulerSize / 2,
canvas.LocalClipBounds.Location.Y + scaledRulerSize / 2 + paint.TextSize / 2,
paint);
}
};
}
private bool IsTouched(Vector2D startPoint, Vector2D endPoint, Vector2D touchLocation)
{
if (touchLocation == null)
return false;
var parameter = 300;
var touchedStart1 = new Vector2D(touchLocation.X + parameter, touchLocation.Y + parameter);
var touchedEnd1 = new Vector2D(touchLocation.X - parameter, touchLocation.Y - parameter);
var touchedStart2 = new Vector2D(touchLocation.X + parameter, touchLocation.Y - parameter);
var touchedEnd2 = new Vector2D(touchLocation.X - parameter, touchLocation.Y + parameter);
return (Math2D.IsIntersecting(startPoint, endPoint, touchedStart1, touchedEnd1) ||
Math2D.IsIntersecting(startPoint, endPoint, touchedStart2, touchedEnd2)) &&
!(Math2D.InDistance(touchLocation, endPoint, 300) ||
Math2D.InDistance(touchLocation, startPoint, 300));
}
private bool CheckAnyCollision(float? startX = null, float? startY = null,
float? endX = null, float? endY = null)
{
var startPositionX = startX ?? LastTouch.X;
var startPositionY = startY ?? LastTouch.Y;
var endPositionX = endX ?? TouchLocation.X;
var endPositionY = endY ?? TouchLocation.Y;
return DraftWalls.Any(w =>
!(w.WallEndX == startPositionX && w.WallEndY == startPositionY)
&& !(w.WallStartX == endPositionX && w.WallStartY == endPositionY)
&& !(w.WallStartX == startPositionX && w.WallStartY == startPositionY)
&& !(w.WallEndX == endPositionX && w.WallEndY == endPositionY)
&& Math2D.IsIntersecting(w.WallStartX, w.WallStartY, w.WallEndX, w.WallEndY,
startPositionX, startPositionY, endPositionX, endPositionY));
}
private float GetDivisionsParameter() =>
((((_gridDivisions / CanvasScale).Round() / _gridStep).Round()) * _gridStep).ToSingle();
private void MoveSelectedVertice(PanUpdatedEventArgs e)
{
var newPosition = new Vector2D();
if (e.TotalX == 0 && e.TotalY == 0)
{
_previousVertPosition.X = 0;
_previousVertPosition.Y = 0;
}
foreach (var w in DraftWalls)
{
if (w.WallEndX == SelectedVertice.X
&& w.WallEndY == SelectedVertice.Y)
{
var newX = w.WallEndX + ((e.TotalX - _previousVertPosition.X)
/ CanvasScale * TouchSensibility).ToSingle();
var newY = w.WallEndY + ((e.TotalY - _previousVertPosition.Y)
/ CanvasScale * TouchSensibility).ToSingle();
var next = Math2D.GetNextWall(w, DraftWalls);
var previous = Math2D.GetPreviousWall(w, DraftWalls);
if (CheckAnyCollision(w.WallStartX, w.WallStartY, newX, newY)
|| (next != null && CheckAnyCollision(w.WallStartX, w.WallStartY, next.X, next.Y))
|| (previous != null && CheckAnyCollision(previous.X, previous.Y, w.WallStartX, w.WallStartY)))
{
break;
}
w.WallEndX = newX;
w.WallEndY = newY;
newPosition.X = w.WallEndX;
newPosition.Y = w.WallEndY;
}
else if (w.WallStartX == SelectedVertice.X
&& w.WallStartY == SelectedVertice.Y)
{
var newX = w.WallStartX + ((e.TotalX - _previousVertPosition.X)
/ CanvasScale * TouchSensibility).ToSingle();
var newY = w.WallStartY + ((e.TotalY - _previousVertPosition.Y)
/ CanvasScale * TouchSensibility).ToSingle();
var next = Math2D.GetNextWall(w, DraftWalls);
var previous = Math2D.GetPreviousWall(w, DraftWalls);
if (CheckAnyCollision(newX, newY, w.WallEndX, w.WallEndY)
|| (next != null && CheckAnyCollision(w.WallStartX, w.WallStartY, next.X, next.Y))
|| (previous != null && CheckAnyCollision(previous.X, previous.Y, w.WallStartX, w.WallStartY)))
{
break;
}
w.WallStartX = newX;
w.WallStartY = newY;
newPosition.X = w.WallStartX;
newPosition.Y = w.WallStartY;
}
}
_previousVertPosition.X = e.TotalX.ToSingle();
_previousVertPosition.Y = e.TotalY.ToSingle();
SelectedVertice.X = newPosition.X;
SelectedVertice.Y = newPosition.Y;
StopCanvasActions();
KeepSelection = true;
CanvasView.InvalidateSurface();
}
private void DrawWallChilds(SKCanvas canvas, float width, int wallThickness, params WallChildren[] children)
{
foreach (var child in children)
{
switch (child.Type)
{
case "Window":
DrawWindow(canvas, width, wallThickness, child);
break;
case "HydraulicPoint":
case "EletricPoint":
DrawPoint(canvas, width, wallThickness, child);
break;
default:
case "Door":
DrawDoor(canvas, width, wallThickness, child);
break;
}
}
}
private void DrawDoor(SKCanvas canvas, float width, int wallThickness, WallChildren child)
{
using (var doorPaint = new SKPaint())
using (var doorPath = new SKPath())
{
var doorThickness = 60;
doorPaint.Color = Color.White.ToSKColor();
doorPaint.Style = SKPaintStyle.Fill;
doorPaint.IsAntialias = HasAntialias();
doorPaint.StrokeWidth = 2 / CanvasScale;
doorPaint.TextSize = QuotaFontSize / CanvasScale;
doorPaint.TextAlign = SKTextAlign.Center;
var zeroPointX = width - child.LeftSpace;
doorPath.MoveTo(zeroPointX, 0);
doorPath.LineTo(zeroPointX - child.Width, 0);
doorPath.LineTo(zeroPointX - child.Width, -wallThickness);
doorPath.LineTo(zeroPointX, -wallThickness);
doorPath.Close();
canvas.DrawPath(doorPath, doorPaint);
doorPaint.Color = Color.Black.ToSKColor();
doorPaint.Style = SKPaintStyle.Stroke;
canvas.DrawPath(doorPath, doorPaint);
doorPath.Reset();
var doorPivoX = child.Inverted ? zeroPointX : zeroPointX - child.Width;
var rect = new SKRect(
doorPivoX - child.Width,
-child.Width,
doorPivoX + child.Width,
child.Width);
doorPaint.Style = SKPaintStyle.Fill;
doorPaint.Color = Color.LightGray.ToSKColor();
doorPath.MoveTo(doorPivoX, 0);
doorPath.LineTo(doorPivoX + (child.Inverted ? -child.Width : child.Width), 0);
doorPath.LineTo(doorPivoX, child.Width);
doorPath.Close();
canvas.DrawPath(doorPath, doorPaint);
doorPath.Reset();
doorPath.AddArc(rect, (child.Inverted ? 90 : 0), 90);
canvas.DrawPath(doorPath, doorPaint);
doorPath.Reset();
doorPaint.Color = Color.Black.ToSKColor();
doorPath.MoveTo(doorPivoX, 0);
doorPath.LineTo(doorPivoX, child.Width);
doorPath.LineTo(doorPivoX + (child.Inverted ? -doorThickness : doorThickness), child.Width);
doorPath.LineTo(doorPivoX + (child.Inverted ? -doorThickness : doorThickness), 0);
doorPaint.Style = SKPaintStyle.Fill;
canvas.DrawPath(doorPath, doorPaint);
doorPath.Reset();
doorPaint.StrokeWidth = 15;
doorPaint.Style = SKPaintStyle.Stroke;
doorPath.MoveTo(doorPivoX, child.Width - doorThickness);
doorPath.LineTo(doorPivoX + (child.Inverted ? 30 : -30), child.Width - doorThickness);
doorPath.LineTo(doorPivoX + (child.Inverted ? 30 : -30), child.Width - doorThickness -60);
doorPath.MoveTo(doorPivoX + (child.Inverted ? -doorThickness : doorThickness), child.Width - doorThickness);
doorPath.LineTo(doorPivoX + (child.Inverted ? -doorThickness : doorThickness) + (child.Inverted ? -30 : 30), child.Width - doorThickness);
doorPath.LineTo(doorPivoX + (child.Inverted ? -doorThickness : doorThickness) + (child.Inverted ? -30 : 30), child.Width - doorThickness -60);
canvas.DrawPath(doorPath, doorPaint);
};
}
private void DrawPoint(SKCanvas canvas, float width, int wallThickness, WallChildren child)
{
using (var pointPaint = new SKPaint())
using (var pointPath = new SKPath())
{
pointPaint.Color = Color.Black.ToSKColor();
pointPaint.Style = SKPaintStyle.Fill;
pointPaint.IsAntialias = HasAntialias();
pointPaint.StrokeWidth = 6;
pointPaint.TextSize = QuotaFontSize / CanvasScale;
pointPaint.TextAlign = SKTextAlign.Center;
var zeroPointX = width - child.LeftSpace;
pointPath.MoveTo(zeroPointX - 2, 0);
pointPath.LineTo(zeroPointX, QuotaDistance + 60);
pointPath.LineTo(zeroPointX + 60, QuotaDistance + 60);
pointPath.LineTo(zeroPointX, QuotaDistance + 120);
pointPath.LineTo(zeroPointX - 60, QuotaDistance + 60);
pointPath.LineTo(zeroPointX + 2, QuotaDistance + 60);
pointPath.Close();
canvas.DrawPath(pointPath, pointPaint);
canvas.DrawText(
child.Type == "HydraulicPoint" ? "H" : "E",
zeroPointX,
QuotaDistance + 140 + (pointPaint.TextSize /2),
pointPaint);
};
}
private void DrawWindow(SKCanvas canvas, float width, int wallThickness, WallChildren child)
{
using (var windowPaint = new SKPaint())
using (var windowPath = new SKPath())
{
windowPaint.Color = Color.White.ToSKColor();
windowPaint.Style = SKPaintStyle.Fill;
windowPaint.IsAntialias = HasAntialias();
windowPaint.StrokeWidth = 2 / CanvasScale;
windowPaint.TextSize = QuotaFontSize / CanvasScale;
windowPaint.TextAlign = SKTextAlign.Center;
var zeroPointX = width - child.LeftSpace;
windowPath.MoveTo(zeroPointX, 0);
windowPath.LineTo(zeroPointX - child.Width, 0);
windowPath.LineTo(zeroPointX - child.Width, - wallThickness);
windowPath.LineTo(zeroPointX, - wallThickness);
windowPath.Close();
canvas.DrawPath(windowPath, windowPaint);
windowPaint.Color = Color.Black.ToSKColor();
windowPaint.Style = SKPaintStyle.Stroke;
canvas.DrawPath(windowPath, windowPaint);
windowPath.Reset();
windowPaint.StrokeWidth = wallThickness / 3;
windowPath.MoveTo(zeroPointX, -wallThickness / 3);
windowPath.LineTo(zeroPointX - child.Width /2, -wallThickness / 3);
windowPath.MoveTo(zeroPointX - child.Width / 2, -(wallThickness / 3) * 2);
windowPath.LineTo(zeroPointX - child.Width, -(wallThickness / 3) * 2);
canvas.DrawPath(windowPath, windowPaint);
};
}
private void DrawQuotas(SKCanvas canvas, float width, float angle)
{
using (var paint = new SKPaint())
using (var path = new SKPath())
{
paint.Color = Color.Blue.ToSKColor();
paint.Style = SKPaintStyle.Stroke;
paint.IsAntialias = HasAntialias();
paint.StrokeWidth = 2 / CanvasScale;
paint.TextSize = QuotaFontSize / CanvasScale;
paint.TextAlign = SKTextAlign.Center;
path.MoveTo(0, 0);
path.LineTo(0, _quotaDistance);
path.MoveTo(0, _quotaDistance / 2);
path.LineTo(width, _quotaDistance / 2);
path.MoveTo(width, 0);
path.LineTo(width, _quotaDistance);
canvas.DrawPath(path, paint);
paint.Color = Color.Black.ToSKColor();
if (angle > 90 || angle < -90)
{
canvas.Translate(width / 2, 0);
canvas.RotateDegrees(180);
canvas.DrawText(width.ToString(), 0, -(_quotaDistance), paint);
canvas.RotateDegrees(180);
canvas.Translate(-width / 2, 0);
}
else
{
canvas.DrawText(width.ToString(), width / 2, _quotaDistance + paint.TextSize/2, paint);
}
paint.Color = Color.Blue.ToSKColor();
paint.Style = SKPaintStyle.Fill;
var arrowDepth = 130;
var arrowHeight = 60;
using (var rightArrowPath = new SKPath())
{
rightArrowPath.MoveTo(0, _quotaDistance / 2);
rightArrowPath.LineTo(arrowDepth, _quotaDistance / 2 + arrowHeight / 2);
rightArrowPath.LineTo(arrowDepth, _quotaDistance / 2 - arrowHeight / 2);
rightArrowPath.Close();
canvas.DrawPath(rightArrowPath, paint);
}
using (var leftArrowPath = new SKPath())
{
leftArrowPath.MoveTo(width, _quotaDistance / 2);
leftArrowPath.LineTo(width - arrowDepth, _quotaDistance / 2 + arrowHeight / 2);
leftArrowPath.LineTo(width - arrowDepth, _quotaDistance / 2 - arrowHeight / 2);
leftArrowPath.Close();
canvas.DrawPath(leftArrowPath, paint);
}
}
}
private void DrawVertices(SKCanvas canvas, float width, Vector2D startPoint, Vector2D endPoint)
{
using (var rectPaint = new SKPaint())
{
var sizeParam = 100;
var locationParam = 50;
rectPaint.Style = SKPaintStyle.Fill;
rectPaint.Color = Color.Blue.ToSKColor();
if ((TouchLocation != null && Math2D.InDistance(TouchLocation, startPoint, 300) && SelectedVertice == null
&& !IsDrawing && !IsPanning && !IsZooning) || SelectedVertice == startPoint)
{
SelectedWall = null;
SelectedVertice = startPoint;
rectPaint.Color = Color.Red.ToSKColor();
sizeParam = 250;
locationParam = 125;
}
var vertPoint = new SKRect()
{
Location = new SKPoint(-locationParam, -locationParam),
Size = new SKSize(sizeParam, sizeParam)
};
canvas.DrawRect(vertPoint, rectPaint);
rectPaint.Color = Color.Blue.ToSKColor();
sizeParam = 100;
locationParam = 50;
if ((TouchLocation != null && Math2D.InDistance(TouchLocation, endPoint, 300) && SelectedVertice == null
&& !IsDrawing && !IsPanning && !IsZooning && SelectedWall == null) || SelectedVertice == endPoint)
{
SelectedWall = null;
SelectedVertice = endPoint;
rectPaint.Color = Color.Red.ToSKColor();
sizeParam = 250;
locationParam = 125;
}
vertPoint.Location = new SKPoint(width - locationParam, -locationParam);
canvas.DrawRect(vertPoint, rectPaint);
}
}
#endregion
#region Public Methods
public void SubscribeEvents()
{
MessagingCenter.Subscribe<DrawPageViewModel>(
this, MessagingDictionary.VERTICE_ADD, (sender) =>
{
if (!Commands.VerticeAddCommand())
{
App.Current.MainPage.DisplayAlert(
AppResources.VerticeAddlbl,
AppResources.VerticeAddErrorMsg,
AppResources.AlertWarningOk);
}
});
MessagingCenter.Subscribe<DrawPageViewModel>(
this, MessagingDictionary.VERTICE_REMOVE, (sender) =>
{
if (!Commands.VerticeRemoveCommand())
{
App.Current.MainPage.DisplayAlert(
AppResources.VerticeRemovelbl,
AppResources.VerticeRemoveErrorMsg,
AppResources.AlertWarningOk);
}
});
MessagingCenter.Subscribe<DrawPageViewModel>(
this, MessagingDictionary.UNDO, (sender) =>
{
if (!Commands.UndoCommand())
{
App.Current.MainPage.DisplayAlert(
AppResources.Undolbl,
AppResources.UndoErrorMsg,
AppResources.AlertWarningOk);
}
});
MessagingCenter.Subscribe<DrawPageViewModel>(
this, MessagingDictionary.REDO, (sender) =>
{
if (!Commands.RedoCommand())
{
App.Current.MainPage.DisplayAlert(
AppResources.Redolbl,
AppResources.RedoErrorMsg,
AppResources.AlertWarningOk);
}
});
MessagingCenter.Subscribe<DrawPageViewModel>(
this, MessagingDictionary.ALIGNAMENT_MODE, (sender) =>
Commands.AlignamentCommand());
MessagingCenter.Subscribe<DrawPageViewModel>(
this, MessagingDictionary.CANVAS_NEED_REFRESH, (sender) =>
CanvasView?.InvalidateSurface());
}
public void UnsubscribeEvents()
{
MessagingCenter.Unsubscribe<DrawPageViewModel>(
this, MessagingDictionary.VERTICE_REMOVE);
MessagingCenter.Unsubscribe<DrawPageViewModel>(
this, MessagingDictionary.VERTICE_ADD);
MessagingCenter.Unsubscribe<DrawPageViewModel>(
this, MessagingDictionary.UNDO);
MessagingCenter.Unsubscribe<DrawPageViewModel>(
this, MessagingDictionary.REDO);
MessagingCenter.Unsubscribe<DrawPageViewModel>(
this, MessagingDictionary.ALIGNAMENT_MODE);
MessagingCenter.Unsubscribe<DrawPageViewModel>(
this, MessagingDictionary.CANVAS_NEED_REFRESH);
}
#endregion
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment