Added spiro control point knot support
This commit is contained in:
Родитель
a7e481619c
Коммит
c1aabc7775
|
@ -252,9 +252,9 @@ namespace SpiroNet.Editor
|
|||
}
|
||||
}
|
||||
|
||||
public void MarkKnot(int knotIndex)
|
||||
public void MarkKnot(int index, double theta, double x, double y, SpiroPointType type)
|
||||
{
|
||||
_state.knot_idx = knotIndex;
|
||||
_state.knot_idx = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|||
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
|
@ -34,6 +36,7 @@ namespace SpiroNet.Editor
|
|||
{
|
||||
private bool _needToClose = false;
|
||||
private StringBuilder _sb = new StringBuilder();
|
||||
private IList<SpiroKnot> _knots = new List<SpiroKnot>();
|
||||
|
||||
/// <summary>
|
||||
/// Format double value using en-GB culture info.
|
||||
|
@ -59,6 +62,15 @@ namespace SpiroNet.Editor
|
|||
return _sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get output spiro control point knots for current Path segment.
|
||||
/// </summary>
|
||||
/// <returns>The spiro control point knots for current Path segment.</returns>
|
||||
public IList<SpiroKnot> GetKnots()
|
||||
{
|
||||
return _knots;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get output Path data string format.
|
||||
/// </summary>
|
||||
|
@ -126,11 +138,24 @@ namespace SpiroNet.Editor
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mark current control point knot. Currenlty not implemented, may be usefull for marking generated curves to original spiro code points.
|
||||
/// Mark current control point knot.
|
||||
/// Currenlty not implemented, may be usefull for marking generated curves to original spiro code points.
|
||||
/// </summary>
|
||||
/// <param name="knotIndex">The current spiros control point knot index.</param>
|
||||
public void MarkKnot(int knotIndex)
|
||||
/// <param name="index">The spiros control point knot index.</param>
|
||||
/// <param name="theta">The spiros control point knot theta angle.</param>
|
||||
/// <param name="x">The spiros control point X location.</param>
|
||||
/// <param name="y">The spiros control point Y location.</param>
|
||||
/// <param name="type">The spiros control point type.</param>
|
||||
public void MarkKnot(int index, double theta, double x, double y, SpiroPointType type)
|
||||
{
|
||||
_knots.Add(new SpiroKnot()
|
||||
{
|
||||
Index = index,
|
||||
Theta = theta * 180 / Math.PI,
|
||||
X = x,
|
||||
Y = y,
|
||||
Type = type
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,7 +117,7 @@ namespace SpiroNet.Editor
|
|||
_state.y = y3;
|
||||
}
|
||||
|
||||
public void MarkKnot(int knotIndex)
|
||||
public void MarkKnot(int index, double theta, double x, double y, SpiroPointType type)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ namespace SpiroNet.Editor
|
|||
private Action _invalidate = null;
|
||||
private PathDrawing _drawing = null;
|
||||
private IDictionary<PathShape, string> _data = null;
|
||||
private IDictionary<PathShape, IList<SpiroKnot>> _knots = null;
|
||||
|
||||
public SpirtoEditorState State
|
||||
{
|
||||
|
@ -65,6 +66,12 @@ namespace SpiroNet.Editor
|
|||
set { Update(ref _data, value); }
|
||||
}
|
||||
|
||||
public IDictionary<PathShape, IList<SpiroKnot>> Knots
|
||||
{
|
||||
get { return _knots; }
|
||||
set { Update(ref _knots, value); }
|
||||
}
|
||||
|
||||
public void ToggleIsStroked()
|
||||
{
|
||||
_state.IsStroked = !_state.IsStroked;
|
||||
|
@ -189,9 +196,15 @@ namespace SpiroNet.Editor
|
|||
var bc = new PathBezierContext();
|
||||
var result = TryGetData(shape, bc);
|
||||
if (_data.ContainsKey(shape))
|
||||
{
|
||||
_data[shape] = result ? bc.ToString() : null;
|
||||
_knots[shape] = result ? bc.GetKnots() : null;
|
||||
}
|
||||
else
|
||||
{
|
||||
_data.Add(shape, result ? bc.ToString() : null);
|
||||
_knots.Add(shape, result ? bc.GetKnots() : null);
|
||||
}
|
||||
}
|
||||
|
||||
private static double DistanceSquared(double x0, double y0, double x1, double y1)
|
||||
|
@ -367,6 +380,7 @@ namespace SpiroNet.Editor
|
|||
// Delete shape.
|
||||
_drawing.Shapes.Remove(hitShape);
|
||||
_data.Remove(hitShape);
|
||||
_knots.Remove(hitShape);
|
||||
_invalidate();
|
||||
}
|
||||
else
|
||||
|
@ -384,6 +398,7 @@ namespace SpiroNet.Editor
|
|||
// Delete shape.
|
||||
_drawing.Shapes.Remove(hitShape);
|
||||
_data.Remove(hitShape);
|
||||
_knots.Remove(hitShape);
|
||||
_invalidate();
|
||||
return;
|
||||
}
|
||||
|
@ -471,6 +486,7 @@ namespace SpiroNet.Editor
|
|||
{
|
||||
Drawing = drawing;
|
||||
Data = new Dictionary<PathShape, string>();
|
||||
Knots = new Dictionary<PathShape, IList<SpiroKnot>>();
|
||||
|
||||
foreach (var shape in _drawing.Shapes)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
SpiroNet.Editor
|
||||
Copyright (C) 2015 Wiesław Šoltés
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 3
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301, USA.
|
||||
|
||||
*/
|
||||
using System;
|
||||
|
||||
namespace SpiroNet.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// Spiro control point knot.
|
||||
/// </summary>
|
||||
public struct SpiroKnot
|
||||
{
|
||||
/// <summary>
|
||||
/// The spiros control point knot index.
|
||||
/// </summary>
|
||||
public int Index;
|
||||
|
||||
/// <summary>
|
||||
/// The spiros control point knot theta angle.
|
||||
/// </summary>
|
||||
public double Theta;
|
||||
|
||||
/// <summary>
|
||||
/// The spiros control point X location.
|
||||
/// </summary>
|
||||
public double X;
|
||||
|
||||
/// <summary>
|
||||
/// The spiros control point Y location.
|
||||
/// </summary>
|
||||
public double Y;
|
||||
|
||||
/// <summary>
|
||||
/// The spiros control point type.
|
||||
/// </summary>
|
||||
public SpiroPointType Type;
|
||||
}
|
||||
}
|
|
@ -47,6 +47,7 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="Contexts\PsBezierContext.cs" />
|
||||
<Compile Include="Editor\SpiroEditor.cs" />
|
||||
<Compile Include="Editor\SpiroKnot.cs" />
|
||||
<Compile Include="Editor\SpirtoEditorCommands.cs" />
|
||||
<Compile Include="Editor\SpirtoEditorMode.cs" />
|
||||
<Compile Include="Editor\SpirtoEditorState.cs" />
|
||||
|
|
|
@ -73,7 +73,11 @@ namespace SpiroNet
|
|||
/// <summary>
|
||||
/// Called by spiro to mark current control point knot.
|
||||
/// </summary>
|
||||
/// <param name="knotIndex">The current spiros control point knot index.</param>
|
||||
void MarkKnot(int knotIndex);
|
||||
/// <param name="index">The spiros control point knot index.</param>
|
||||
/// <param name="theta">The spiros control point knot theta angle.</param>
|
||||
/// <param name="x">The spiros control point X location.</param>
|
||||
/// <param name="y">The spiros control point Y location.</param>
|
||||
/// <param name="type">The spiros control point type.</param>
|
||||
void MarkKnot(int index, double theta, double x, double y, SpiroPointType type);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -769,9 +769,12 @@ namespace SpiroNet
|
|||
if (i == 0)
|
||||
bc.MoveTo(x0, y0, s[0].Type == SpiroPointType.OpenContour ? true : false);
|
||||
|
||||
bc.MarkKnot(i);
|
||||
bc.MarkKnot(i, get_knot_th(s, i), s[i].X, s[i].Y, s[i].Type);
|
||||
spiro_seg_to_bpath(s[i].ks, x0, y0, x1, y1, bc, 0);
|
||||
}
|
||||
|
||||
if (nsegs == n - 1)
|
||||
bc.MarkKnot(n - 1, get_knot_th(s, n - 1), s[n - 1].X, s[n - 1].Y, s[n - 1].Type);
|
||||
}
|
||||
|
||||
public static double get_knot_th(SpiroSegment[] s, int i)
|
||||
|
|
|
@ -32,6 +32,12 @@ namespace SpiroNet.Wpf
|
|||
{
|
||||
public class SpiroCanvas : Canvas
|
||||
{
|
||||
private static Geometry LeftKnot = Geometry.Parse("M0,-4 A 4,4 0 0 0 0,4");
|
||||
private static Geometry RightKnot = Geometry.Parse("M0,-4 A 4,4 0 0 1 0,4");
|
||||
private static Geometry EndKnot = Geometry.Parse("M-3.5,-3.5 L3.5,3.5 M-3.5,3.5 L3.5,-3.5");
|
||||
private static Geometry EndOpenContourKnot = Geometry.Parse("M-3.5,-3.5 L0,0 -3.5,3.5");
|
||||
private static Geometry OpenContourKnot = Geometry.Parse("M3.5,-3.5 L0,0 3.5,3.5");
|
||||
|
||||
private Brush _geometryBrush;
|
||||
private Brush _geometryPenBrush;
|
||||
private Pen _geometryPen;
|
||||
|
@ -39,7 +45,9 @@ namespace SpiroNet.Wpf
|
|||
private Brush _hitGeometryPenBrush;
|
||||
private Pen _hitGeometryPen;
|
||||
private Brush _pointBrush;
|
||||
private Pen _pointPen;
|
||||
private Brush _hitPointBrush;
|
||||
private Pen _hitPointPen;
|
||||
|
||||
public SpiroEditor Editor
|
||||
{
|
||||
|
@ -77,9 +85,13 @@ namespace SpiroNet.Wpf
|
|||
|
||||
_pointBrush = new SolidColorBrush(Color.FromArgb(192, 0, 0, 255));
|
||||
_pointBrush.Freeze();
|
||||
_pointPen = new Pen(_pointBrush, 2.0);
|
||||
_pointPen.Freeze();
|
||||
|
||||
_hitPointBrush = new SolidColorBrush(Color.FromArgb(192, 255, 0, 0));
|
||||
_hitPointBrush.Freeze();
|
||||
_hitPointPen = new Pen(_hitPointBrush, 2.0);
|
||||
_hitPointPen.Freeze();
|
||||
}
|
||||
|
||||
protected override void OnRender(DrawingContext dc)
|
||||
|
@ -102,14 +114,15 @@ namespace SpiroNet.Wpf
|
|||
|
||||
private void DrawShape(DrawingContext dc, PathShape shape)
|
||||
{
|
||||
if (shape == null || Editor == null || Editor.Data == null)
|
||||
if (shape == null || Editor == null)
|
||||
return;
|
||||
|
||||
var hitShape = Editor.State.HitShape;
|
||||
var hitShapePointIndex = Editor.State.HitShapePointIndex;
|
||||
|
||||
// draw shapes
|
||||
string data;
|
||||
if (Editor.Data.TryGetValue(shape, out data) && !string.IsNullOrEmpty(data))
|
||||
if (Editor.Data != null && Editor.Data.TryGetValue(shape, out data) && !string.IsNullOrEmpty(data))
|
||||
{
|
||||
var geometry = Geometry.Parse(data);
|
||||
if (shape == hitShape && hitShapePointIndex == -1)
|
||||
|
@ -128,12 +141,76 @@ namespace SpiroNet.Wpf
|
|||
}
|
||||
}
|
||||
|
||||
if (shape.Points != null)
|
||||
// draw shape knots
|
||||
IList<SpiroKnot> knots;
|
||||
Editor.Knots.TryGetValue(shape, out knots);
|
||||
if (knots != null)
|
||||
{
|
||||
for (int i = 0; i < knots.Count; i++)
|
||||
{
|
||||
var knot = knots[i];
|
||||
var brush = shape == hitShape && i == hitShapePointIndex ? _hitPointBrush : _pointBrush;
|
||||
var pen = shape == hitShape && i == hitShapePointIndex ? _hitPointPen : _pointPen;
|
||||
|
||||
switch (knot.Type)
|
||||
{
|
||||
case SpiroPointType.Corner:
|
||||
dc.DrawRectangle(brush, null, new Rect(knot.X - 3.5, knot.Y - 3.5, 7, 7));
|
||||
break;
|
||||
case SpiroPointType.G4:
|
||||
dc.DrawEllipse(brush, null, new Point(knot.X, knot.Y), 3.5, 3.5);
|
||||
break;
|
||||
case SpiroPointType.G2:
|
||||
dc.PushTransform(new RotateTransform(knot.Theta, knot.X, knot.Y));
|
||||
dc.DrawRectangle(brush, null, new Rect(knot.X - 1.5, knot.Y - 3.5, 3, 7));
|
||||
dc.Pop();
|
||||
break;
|
||||
case SpiroPointType.Left:
|
||||
dc.PushTransform(new RotateTransform(knot.Theta, knot.X, knot.Y));
|
||||
dc.PushTransform(new TranslateTransform(knot.X, knot.Y));
|
||||
dc.DrawGeometry(brush, null, LeftKnot);
|
||||
dc.Pop();
|
||||
dc.Pop();
|
||||
break;
|
||||
case SpiroPointType.Right:
|
||||
dc.PushTransform(new RotateTransform(knot.Theta, knot.X, knot.Y));
|
||||
dc.PushTransform(new TranslateTransform(knot.X, knot.Y));
|
||||
dc.DrawGeometry(brush, null, RightKnot);
|
||||
dc.Pop();
|
||||
dc.Pop();
|
||||
break;
|
||||
case SpiroPointType.End:
|
||||
dc.PushTransform(new RotateTransform(knot.Theta, knot.X, knot.Y));
|
||||
dc.PushTransform(new TranslateTransform(knot.X, knot.Y));
|
||||
dc.DrawGeometry(null, pen, EndKnot);
|
||||
dc.Pop();
|
||||
dc.Pop();
|
||||
break;
|
||||
case SpiroPointType.OpenContour:
|
||||
dc.PushTransform(new RotateTransform(knot.Theta, knot.X, knot.Y));
|
||||
dc.PushTransform(new TranslateTransform(knot.X, knot.Y));
|
||||
dc.DrawGeometry(null, pen, OpenContourKnot);
|
||||
dc.Pop();
|
||||
dc.Pop();
|
||||
break;
|
||||
case SpiroPointType.EndOpenContour:
|
||||
dc.PushTransform(new RotateTransform(knot.Theta, knot.X, knot.Y));
|
||||
dc.PushTransform(new TranslateTransform(knot.X, knot.Y));
|
||||
dc.DrawGeometry(null, pen, EndOpenContourKnot);
|
||||
dc.Pop();
|
||||
dc.Pop();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// draw shape points if knots do not exist
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < shape.Points.Count; i++)
|
||||
{
|
||||
var point = shape.Points[i];
|
||||
var brush = shape == hitShape && i == hitShapePointIndex ? _hitPointBrush : _pointBrush;
|
||||
var pen = shape == hitShape && i == hitShapePointIndex ? _hitPointPen : _pointPen;
|
||||
|
||||
switch (point.Type)
|
||||
{
|
||||
|
@ -141,25 +218,15 @@ namespace SpiroNet.Wpf
|
|||
dc.DrawRectangle(brush, null, new Rect(point.X - 3.5, point.Y - 3.5, 7, 7));
|
||||
break;
|
||||
case SpiroPointType.G4:
|
||||
dc.DrawEllipse(brush, null, new Point(point.X, point.Y), 3.5, 3.5);
|
||||
break;
|
||||
case SpiroPointType.G2:
|
||||
dc.DrawEllipse(brush, null, new Point(point.X, point.Y), 3.5, 3.5);
|
||||
break;
|
||||
case SpiroPointType.Left:
|
||||
dc.DrawRectangle(brush, null, new Rect(point.X - 3.5, point.Y - 3.5, 7, 7));
|
||||
break;
|
||||
case SpiroPointType.Right:
|
||||
dc.DrawRectangle(brush, null, new Rect(point.X - 3.5, point.Y - 3.5, 7, 7));
|
||||
break;
|
||||
case SpiroPointType.End:
|
||||
dc.DrawRectangle(brush, null, new Rect(point.X - 3.5, point.Y - 3.5, 7, 7));
|
||||
break;
|
||||
case SpiroPointType.OpenContour:
|
||||
dc.DrawRectangle(brush, null, new Rect(point.X - 3.5, point.Y - 3.5, 7, 7));
|
||||
break;
|
||||
case SpiroPointType.EndOpenContour:
|
||||
dc.DrawRectangle(brush, null, new Rect(point.X - 3.5, point.Y - 3.5, 7, 7));
|
||||
dc.PushTransform(new TranslateTransform(point.X, point.Y));
|
||||
dc.DrawGeometry(null, pen, EndKnot);
|
||||
dc.Pop();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,7 +62,8 @@ namespace SpiroNet.Wpf
|
|||
Height = 600,
|
||||
Shapes = new ObservableCollection<PathShape>()
|
||||
},
|
||||
Data = new Dictionary<PathShape, string>()
|
||||
Data = new Dictionary<PathShape, string>(),
|
||||
Knots = new Dictionary<PathShape, IList<SpiroKnot>>()
|
||||
};
|
||||
|
||||
_editor.Commands.NewCommand = Command.Create(_editor.New);
|
||||
|
|
Загрузка…
Ссылка в новой задаче