Added spiro control point knot support

This commit is contained in:
Wiesław Šoltés 2015-08-06 21:18:55 +02:00
Родитель a7e481619c
Коммит c1aabc7775
10 изменённых файлов: 198 добавлений и 26 удалений

Просмотреть файл

@ -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);