/// <summary> /// Draws this object to the <see cref="IGraphics" /> provided. /// </summary> /// <param name="graphics">The graphics object to use to draw this object.</param> public override void Draw(IGraphics graphics) { base.Draw(graphics); float lineWidth = Controller.StyleManager.LineStyle.Width; graphics.LineStyle = SolidColourStyle.Black; graphics.LineWidth = lineWidth; SelectedLine currLine = _selectedLine ?? _hoverLine; if (currLine != null) { Matrix3x2 transform = currLine.EdgePart.GetLineTransform() * currLine.Tile.Transform; bool first = true; foreach (ILine line in currLine.EdgePart.Lines) { if (first) { first = false; graphics.DrawCircle(Vector2.Transform(line.Start, transform), lineWidth); } graphics.DrawCircle(Vector2.Transform(line.End, transform), lineWidth); } graphics.DrawLine(_splitLineStart, _splitLineEnd); } }
/// <summary> /// Initializes a new instance of the <see cref="SplitLineAction" /> class. /// </summary> /// <param name="line">The line.</param> /// <param name="point">The point.</param> /// <param name="tool">The tool.</param> public SplitLineAction(SelectedLine line, LinePoint point, [NotNull] SplitLineTool tool) { Debug.Assert(line != null, "line != null"); Debug.Assert(point != null, "point != null"); Debug.Assert(tool != null, "tool != null"); _line = line; _point = point; _tool = tool; }
/// <summary> /// Sets the location that the line will be split along, for drwaing the preview. /// </summary> /// <param name="line">The line.</param> /// <param name="point">The point.</param> private void SetSplitLineLoc(SelectedLine line, LinePoint point) { Vector2 tangent = Vector2.Normalize(line.Line.GetTangent(point.Distance, line.LineTransform)) * 3; Vector2 pos = Vector2.Transform(point.Position, Controller.View.InverseViewMatrix); _splitLineStart = pos + new Vector2(tangent.Y, -tangent.X); _splitLineEnd = pos + new Vector2(-tangent.Y, tangent.X); }
/// <summary> /// Starts the action associated with this tool at the location given. /// </summary> /// <param name="rawLocation"> /// The raw location to start the action. /// Should be transformed by the <see cref="IView.InverseViewMatrix" /> for the /// <see cref="Controller">Controllers</see> <see cref="EscherTiler.Controllers.Controller.View" /> to get the /// location in the tiling itself. /// </param> /// <returns> /// The action that was performed, or null if no action was performed. /// </returns> public override Action StartAction(Vector2 rawLocation) { Matrix3x2 viewMatrix = Controller.View.ViewMatrix; // If there is a line selected, see if one of the control points has been selected if (_selectedLine != null) { Matrix3x2 transform = _selectedLine.EdgePart.GetLineTransform() * _selectedLine.Tile.Transform * viewMatrix; // Gets the closest point to the location Tuple <LineVector, float> closest = _selectedLine.EdgePart.Lines.SelectMany(l => l.Points) .Where(p => !p.IsFixed) .Select(p => GetDist(p, transform, rawLocation)) .OrderBy(t => t.Item2) .FirstOrDefault(); // If the closest point is within the toelrance, select it if (closest != null && closest.Item2 < (_tolerance * _tolerance)) { Debug.Assert(closest.Item1 != null, "closest.Item1 != null"); // Need the inverse transform for updating the line from a raw location Matrix3x2 inverseTransform; if (!Matrix3x2.Invert(_selectedLine.Tile.Transform, out inverseTransform)) { throw new InvalidOperationException(); } inverseTransform = Controller.View.InverseViewMatrix * inverseTransform * _selectedLine.EdgePart.GetLineTransform(true); _selectedVector = closest.Item1; return(new EditPointAction(closest.Item1, inverseTransform, this)); } } _selectedVector = null; _selectedLine = Controller.GetSelected(rawLocation, _tolerance); if (_selectedLine == null) { RemoveOption(ChangeLineOption); return(null); } ChangeLineOption.Value = _selectedLine.Line.GetType(); AddOption(ChangeLineOption); return(InstantAction.PureInstance); }
/// <summary> /// Called when this tool is selected as the current tool. /// </summary> public override void Selected() { base.Selected(); if (_selectedLine != null) { if (!_selectedLine.EdgePart.Lines.Contains(_selectedLine.Line)) { _selectedLine = null; } } }
/// <summary> /// Starts the action associated with this tool at the location given. /// </summary> /// <param name="rawLocation"> /// The raw location to start the action. /// Should be transformed by the <see cref="IView.InverseViewMatrix" /> for the /// <see cref="Controller">Controllers</see> <see cref="EscherTiler.Controllers.Controller.View" /> to get the /// location in the tiling itself. /// </param> /// <returns> /// The action that was performed, or null if no action was performed. /// </returns> public override Action StartAction(Vector2 rawLocation) { LinePoint loc; _selectedLine = Controller.GetSelected(rawLocation, _tolerance, out loc); if (_selectedLine == null) { return(null); } return(new SplitLineAction(_selectedLine, loc, this)); }
private void btnSend_Click(object sender, RoutedEventArgs e) { if (SelectedLine == null) { return; } SelectedLine.SendOutofDialogInstantMessage(Recipient, InstantMessage); string msgSender = string.Format("{0}@{1}", SelectedLine.SIPAccount.UserName, SelectedLine.SIPAccount.GetSIPHostPort(SelectedLine.TransportType)); Model.AddInstantMessage(msgSender, InstantMessage); InstantMessage = ""; }
/// <summary> /// Removes a penalty sets on a croissant. /// </summary> private void RemovePenalty() { if (SelectedLine != null && SelectedLine.SelectedCroissant != null) { SelectedLine.RemovePenalty(SelectedLine.SelectedCroissant.Date.Value); } else { InformationMessage = "Impossible de supprimer une pénalité inexistante."; } // Check the commands: they state can change due to the added penalty. CheckCommands(); }
/// <summary> /// Activates a croissant that is deactivated. /// </summary> private void ActivateCroissant() { if (SelectedLine != null && SelectedLine.SelectedCroissant != null) { // A deactivated croissant doesn't have a date of deactivation, // so we simply ask the line to reactivate one of its croissant. SelectedLine.ReactivatedCroissant(); } else { InformationMessage = "Impossible de gérer une pénalité inexistante."; } // Check the commands: they state can change due to the activated croissant. CheckCommands(); }
/// <summary> /// Called when this tool is selected as the current tool. /// </summary> public override void Selected() { base.Selected(); if (_selectedLine != null) { if (!_selectedLine.EdgePart.Lines.Contains(_selectedLine.Line)) _selectedLine = null; } }
/// <summary> /// Called when the highlighted location (ie the cursor location) changes. /// </summary> /// <param name="rawLocation"> /// The raw location. /// Should be transformed by the <see cref="IView.InverseViewMatrix" /> for the /// <see cref="Controller">Controllers</see> <see cref="EscherTiler.Controllers.Controller.View" /> to get the /// location in the tiling itself. /// </param> public override void UpdateLocation(Vector2 rawLocation) { base.UpdateLocation(rawLocation); _hoverLine = Controller.GetSelected(rawLocation, _tolerance); }
/// <summary> /// Draws this object to the <see cref="IGraphics" /> provided. /// </summary> /// <param name="graphics">The graphics object to use to draw this object.</param> public override void Draw(IGraphics graphics) { base.Draw(graphics); graphics.LineWidth = Controller.StyleManager.LineStyle.Width; SelectedLine selectedLine = _selectedLine; SelectedLine hoverLine = _hoverLine; if (hoverLine != null) { graphics.LineStyle = SolidColourStyle.CornflowerBlue; hoverLine.Line.Draw( graphics, hoverLine.EdgePart.GetLineTransform() * hoverLine.Tile.Transform); } if (selectedLine != null) { float radius = Controller.StyleManager.LineStyle.Width * 2; Matrix3x2 transform = selectedLine.EdgePart.GetLineTransform() * selectedLine.Tile.Transform; graphics.LineStyle = SolidColourStyle.CornflowerBlue; selectedLine.Line.Draw(graphics, transform); graphics.LineStyle = SolidColourStyle.Black; foreach (ILine line in selectedLine.EdgePart.Lines) { QuadraticBezierCurve quadCurve; CubicBezierCurve cubicCurve; if ((quadCurve = line as QuadraticBezierCurve) != null) { graphics.LineStyle = TransparentBlue; graphics.DrawLines( Vector2.Transform(quadCurve.Start, transform), Vector2.Transform(quadCurve.ControlPoint, transform), Vector2.Transform(quadCurve.End, transform)); graphics.LineStyle = SolidColourStyle.Black; } else if ((cubicCurve = line as CubicBezierCurve) != null) { graphics.LineStyle = TransparentBlue; graphics.DrawLines( Vector2.Transform(cubicCurve.Start, transform), Vector2.Transform(cubicCurve.ControlPointA, transform), Vector2.Transform(cubicCurve.ControlPointB, transform), Vector2.Transform(cubicCurve.End, transform)); graphics.LineStyle = SolidColourStyle.Black; } foreach (LineVector point in line.Points) { if (point.IsFixed) { graphics.FillStyle = SolidColourStyle.Gray; } else if (point == _selectedVector) { graphics.FillStyle = SolidColourStyle.CornflowerBlue; } else { graphics.FillStyle = SolidColourStyle.White; } DrawControl(graphics, Vector2.Transform(point, transform), radius); } } } }
/// <summary> /// Changes the type of the selected line. /// </summary> /// <param name="value">The value.</param> private void ChangeLineType(object value) { Type type = value as Type; if (type == null) throw new ArgumentException(); SelectedLine selectedLine = _selectedLine; if (selectedLine == null) return; ILine currLine = selectedLine.Line; Type currLineType = currLine.GetType(); if (type == currLineType) return; ILine newLine; if (type == typeof(Line)) newLine = new Line(currLine.Start, currLine.End); else if (type == typeof(QuadraticBezierCurve)) { if (currLineType == typeof(Line)) { newLine = new QuadraticBezierCurve( currLine.Start, new LineVector((currLine.Start.Vector + currLine.End.Vector) / 2), currLine.End); } else if (currLineType == typeof(CubicBezierCurve)) { CubicBezierCurve cubic = (CubicBezierCurve) currLine; Vector2 vec = currLine.Start.Vector + (currLine.End.Vector - currLine.Start.Vector) / 2; newLine = new QuadraticBezierCurve( cubic.Start, new LineVector(vec), cubic.End); } else { throw new NotSupportedException( $"Cannot change a line of type '{currLineType.FullName}' to a line of type '{type.FullName}'."); } } else if (type == typeof(CubicBezierCurve)) { if (currLineType == typeof(Line)) { Vector2 vec = (currLine.End.Vector - currLine.Start.Vector) / 3; newLine = new CubicBezierCurve( currLine.Start, new LineVector(currLine.Start.Vector + vec), new LineVector(currLine.Start.Vector + vec + vec), currLine.End); } else if (currLineType == typeof(QuadraticBezierCurve)) { QuadraticBezierCurve quad = (QuadraticBezierCurve) currLine; Vector2 start = quad.Start.Vector; Vector2 end = quad.End.Vector; Vector2 control = quad.ControlPoint.Vector; newLine = new CubicBezierCurve( quad.Start, new LineVector(start + (2f / 3f * (control - start))), new LineVector(end + (2f / 3f * (control - end))), quad.End); } else { throw new NotSupportedException( $"Cannot change a line of type '{currLineType.FullName}' to a line of type '{type.FullName}'."); } } else { throw new NotSupportedException( $"Cannot change a line of type '{currLineType.FullName}' to a line of type '{type.FullName}'."); } Debug.Assert(newLine.GetType() == type, "newLine.GetType() == type"); selectedLine.EdgePart.Lines.Replace(currLine, newLine); _selectedLine = new SelectedLine( selectedLine.Tile, selectedLine.EdgePart, newLine, selectedLine.LineTransform); }
/// <summary> /// Changes the type of the selected line. /// </summary> /// <param name="value">The value.</param> private void ChangeLineType(object value) { Type type = value as Type; if (type == null) { throw new ArgumentException(); } SelectedLine selectedLine = _selectedLine; if (selectedLine == null) { return; } ILine currLine = selectedLine.Line; Type currLineType = currLine.GetType(); if (type == currLineType) { return; } ILine newLine; if (type == typeof(Line)) { newLine = new Line(currLine.Start, currLine.End); } else if (type == typeof(QuadraticBezierCurve)) { if (currLineType == typeof(Line)) { newLine = new QuadraticBezierCurve( currLine.Start, new LineVector((currLine.Start.Vector + currLine.End.Vector) / 2), currLine.End); } else if (currLineType == typeof(CubicBezierCurve)) { CubicBezierCurve cubic = (CubicBezierCurve)currLine; Vector2 vec = currLine.Start.Vector + (currLine.End.Vector - currLine.Start.Vector) / 2; newLine = new QuadraticBezierCurve( cubic.Start, new LineVector(vec), cubic.End); } else { throw new NotSupportedException( $"Cannot change a line of type '{currLineType.FullName}' to a line of type '{type.FullName}'."); } } else if (type == typeof(CubicBezierCurve)) { if (currLineType == typeof(Line)) { Vector2 vec = (currLine.End.Vector - currLine.Start.Vector) / 3; newLine = new CubicBezierCurve( currLine.Start, new LineVector(currLine.Start.Vector + vec), new LineVector(currLine.Start.Vector + vec + vec), currLine.End); } else if (currLineType == typeof(QuadraticBezierCurve)) { QuadraticBezierCurve quad = (QuadraticBezierCurve)currLine; Vector2 start = quad.Start.Vector; Vector2 end = quad.End.Vector; Vector2 control = quad.ControlPoint.Vector; newLine = new CubicBezierCurve( quad.Start, new LineVector(start + (2f / 3f * (control - start))), new LineVector(end + (2f / 3f * (control - end))), quad.End); } else { throw new NotSupportedException( $"Cannot change a line of type '{currLineType.FullName}' to a line of type '{type.FullName}'."); } } else { throw new NotSupportedException( $"Cannot change a line of type '{currLineType.FullName}' to a line of type '{type.FullName}'."); } Debug.Assert(newLine.GetType() == type, "newLine.GetType() == type"); selectedLine.EdgePart.Lines.Replace(currLine, newLine); _selectedLine = new SelectedLine( selectedLine.Tile, selectedLine.EdgePart, newLine, selectedLine.LineTransform); }
/// <summary> /// Starts the action associated with this tool at the location given. /// </summary> /// <param name="rawLocation"> /// The raw location to start the action. /// Should be transformed by the <see cref="IView.InverseViewMatrix" /> for the /// <see cref="Controller">Controllers</see> <see cref="EscherTiler.Controllers.Controller.View" /> to get the /// location in the tiling itself. /// </param> /// <returns> /// The action that was performed, or null if no action was performed. /// </returns> public override Action StartAction(Vector2 rawLocation) { Matrix3x2 viewMatrix = Controller.View.ViewMatrix; // If there is a line selected, see if one of the control points has been selected if (_selectedLine != null) { Matrix3x2 transform = _selectedLine.EdgePart.GetLineTransform() * _selectedLine.Tile.Transform * viewMatrix; // Gets the closest point to the location Tuple<LineVector, float> closest = _selectedLine.EdgePart.Lines.SelectMany(l => l.Points) .Where(p => !p.IsFixed) .Select(p => GetDist(p, transform, rawLocation)) .OrderBy(t => t.Item2) .FirstOrDefault(); // If the closest point is within the toelrance, select it if (closest != null && closest.Item2 < (_tolerance * _tolerance)) { Debug.Assert(closest.Item1 != null, "closest.Item1 != null"); // Need the inverse transform for updating the line from a raw location Matrix3x2 inverseTransform; if (!Matrix3x2.Invert(_selectedLine.Tile.Transform, out inverseTransform)) throw new InvalidOperationException(); inverseTransform = Controller.View.InverseViewMatrix * inverseTransform * _selectedLine.EdgePart.GetLineTransform(true); _selectedVector = closest.Item1; return new EditPointAction(closest.Item1, inverseTransform, this); } } _selectedVector = null; _selectedLine = Controller.GetSelected(rawLocation, _tolerance); if (_selectedLine == null) { RemoveOption(ChangeLineOption); return null; } ChangeLineOption.Value = _selectedLine.Line.GetType(); AddOption(ChangeLineOption); return InstantAction.PureInstance; }
/// <summary> /// Gets the line selected at the locaiton given. /// </summary> private SelectedLine GetSelected(Vector2 rawLocation, float tolerance, out LinePoint loc) { Matrix3x2 viewMatrix = View.ViewMatrix; bool checkNext = false; SelectedLine last = null; LinePoint lastHit = null; // Check each line for each edge part for each tile foreach (TileBase tile in Tiles) { foreach (EdgePartShape partShape in tile.PartShapes) { Matrix3x2 transform = partShape.GetLineTransform() * tile.Transform * viewMatrix; foreach (ILine line in partShape.Lines) { LinePoint hit = line.HitTest(rawLocation, tolerance, transform); if (hit != null) { if (checkNext) { if (hit.Distance > 0) { loc = hit; return(new SelectedLine(tile, partShape, line, transform)); } loc = lastHit; return(last); } // If the hit was just at/past the end of the line, check to see if it was in the next line if (hit.Distance >= 1) { lastHit = hit; last = new SelectedLine(tile, partShape, line, transform); checkNext = true; continue; } loc = hit; return(new SelectedLine(tile, partShape, line, transform)); } if (checkNext) { loc = lastHit; return(last); } } } } if (checkNext) { loc = lastHit; return(last); } loc = null; return(null); }
/// <summary> /// Starts the action associated with this tool at the location given. /// </summary> /// <param name="rawLocation"> /// The raw location to start the action. /// Should be transformed by the <see cref="IView.InverseViewMatrix" /> for the /// <see cref="Controller">Controllers</see> <see cref="EscherTiler.Controllers.Controller.View" /> to get the /// location in the tiling itself. /// </param> /// <returns> /// The action that was performed, or null if no action was performed. /// </returns> public override Action StartAction(Vector2 rawLocation) { LinePoint loc; _selectedLine = Controller.GetSelected(rawLocation, _tolerance, out loc); if (_selectedLine == null) return null; return new SplitLineAction(_selectedLine, loc, this); }
/// <summary> /// Gets the line selected at the locaiton given. /// </summary> private SelectedLine GetSelected(Vector2 rawLocation, float tolerance, out LinePoint loc) { Matrix3x2 viewMatrix = View.ViewMatrix; bool checkNext = false; SelectedLine last = null; LinePoint lastHit = null; // Check each line for each edge part for each tile foreach (TileBase tile in Tiles) { foreach (EdgePartShape partShape in tile.PartShapes) { Matrix3x2 transform = partShape.GetLineTransform() * tile.Transform * viewMatrix; foreach (ILine line in partShape.Lines) { LinePoint hit = line.HitTest(rawLocation, tolerance, transform); if (hit != null) { if (checkNext) { if (hit.Distance > 0) { loc = hit; return new SelectedLine(tile, partShape, line, transform); } loc = lastHit; return last; } // If the hit was just at/past the end of the line, check to see if it was in the next line if (hit.Distance >= 1) { lastHit = hit; last = new SelectedLine(tile, partShape, line, transform); checkNext = true; continue; } loc = hit; return new SelectedLine(tile, partShape, line, transform); } if (checkNext) { loc = lastHit; return last; } } } } if (checkNext) { loc = lastHit; return last; } loc = null; return null; }