Skip to content

Commit

Permalink
moved curve drawing to CurveComponent
Browse files Browse the repository at this point in the history
simplified, centralized and improved segmentation
fixed various off-by-one errors
fixed an off-by-one error causing wrong velocities in SVG export
fixed capturing-related crash
  • Loading branch information
julmb committed Jan 30, 2014
1 parent b9e72dc commit 022d79d
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 117 deletions.
21 changes: 17 additions & 4 deletions source/Kurve/Kurve.Curves/Curve.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
using System;
using System.Linq;
using System.Collections.Generic;
using Krach.Basics;
using Krach.Extensions;
using Wrappers.Casadi;

namespace Kurve.Curves
{
Expand All @@ -13,6 +9,23 @@ public abstract class Curve
public abstract double GetSpeed(double position);
public abstract double GetDirection(double position);
public abstract double GetCurvature(double position);

public Vector2Double GetDirectionVector(double position)
{
double direction = GetDirection(position);

return new Vector2Double(Scalars.Cosine(direction), Scalars.Sine(direction));
}
public Vector2Double GetNormalVector(double position)
{
Vector2Double directionVector = GetDirectionVector(position);

return new Vector2Double(directionVector.Y, -directionVector.X);
}
public Vector2Double GetVelocity(double position)
{
return GetSpeed(position) * GetDirectionVector(position);
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ abstract class PositionedControlComponent : LengthControlComponent

public BasicSpecification BasicSpecification { get { return curveComponent.BasicSpecification; } }
public Curve Curve { get { return curveComponent.Curve; } }
public int SegmentCount { get { return curveComponent.SegmentCount; } }
public abstract double Position { get; }
public bool IsSelected { get { return isSelected; } set { isSelected = value; } }
public bool IsDragging { get { return isDragging; } }
Expand Down
54 changes: 17 additions & 37 deletions source/Kurve/Kurve/Components/Controls/SegmentComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@ class SegmentComponent : PositionedControlComponent
readonly PositionedControlComponent rightComponent;

Orthotope2Double Bounds { get { return new Orthotope2Double(Point - 0.5 * size, Point + 0.5 * size); } }
int SegmentSegmentCount
{
get
{
double length = rightComponent.Position - leftComponent.Position;

if (length == 0) return 1;

return (int)(length * SegmentCount).Ceiling();
}
}

public override double Position { get { return (leftComponent.Position + rightComponent.Position) / 2; } }
public Vector2Double Point { get { return Curve == null ? Vector2Double.Origin : Curve.GetPoint(Position); } }
Expand All @@ -39,42 +50,12 @@ public SegmentComponent(Component parent, CurveComponent curveComponent, Positio

public override void Draw(Context context)
{
if (Curve == null) return;

foreach (Tuple<double, double> positions in Scalars.GetIntermediateValuesSymmetric(leftComponent.Position, rightComponent.Position, 250).GetRanges())
{
double stretchFactor = Curve.GetSpeed((positions.Item1 + positions.Item2) / 2) / BasicSpecification.CurveLength;

if (IsSelected) Drawing.DrawLine(context, Curve.GetPoint(positions.Item1), Curve.GetPoint(positions.Item2), 8, Colors.Green.ReplaceAlpha(0.3));

Krach.Graphics.Color color = StretchedColor(stretchFactor);
Drawing.DrawLine(context, Curve.GetPoint(positions.Item1), Curve.GetPoint(positions.Item2), 2, color);

Vector2Double point = 0.5 * (Curve.GetPoint(positions.Item1) + Curve.GetPoint(positions.Item2));
double direction = Curve.GetDirection((positions.Item1 + positions.Item2) / 2);
Vector2Double directionVector = new Vector2Double(Scalars.Cosine(direction), Scalars.Sine(direction));
Vector2Double angularDirection = new Vector2Double(directionVector.Y, -directionVector.X);
double curvature = Curve.GetCurvature((positions.Item1 + positions.Item2) / 2);
Vector2Double curvatureVector = 10000 * curvature * angularDirection;
Drawing.DrawLine(context, point, point + curvatureVector, 0.5, Colors.Green);
}
if (Curve != null && IsSelected)
foreach (Tuple<double, double> positions in Scalars.GetIntermediateValuesSymmetric(leftComponent.Position, rightComponent.Position, SegmentSegmentCount + 1).GetRanges())
Drawing.DrawLine(context, Curve.GetPoint(positions.Item1), Curve.GetPoint(positions.Item2), 8, Colors.Green.ReplaceAlpha(0.3));

base.Draw(context);
}
static Krach.Graphics.Color StretchedColor(double stretchFactor)
{
Krach.Graphics.Color baseColor = Krach.Graphics.Color.FromHsv(0, 0, 0);

OrderedRange<double> source = new OrderedRange<double>(0.75, 1.0);
OrderedRange<double> destination = new OrderedRange<double>(0.0, 1.0);

IMap<double, double> amplifier = new RangeMap(source, destination, Mappers.Linear);

if (stretchFactor < 1) return Krach.Graphics.Color.InterpolateRgb(Colors.Blue, baseColor, Scalars.InterpolateLinear, amplifier.Map((1.0 * stretchFactor).Clamp(source)));
if (stretchFactor > 1) return Krach.Graphics.Color.InterpolateRgb(Colors.Red, baseColor, Scalars.InterpolateLinear, amplifier.Map((1.0 / stretchFactor).Clamp(source)));

return baseColor;
}

public override bool Contains(Vector2Double position)
{
Expand All @@ -83,7 +64,7 @@ public override bool Contains(Vector2Double position)
if (leftComponent is SpecificationComponent && (Curve.GetPoint(leftComponent.Position) - position).Length < 15) return false;
if (rightComponent is SpecificationComponent && (Curve.GetPoint(rightComponent.Position) - position).Length < 15) return false;

foreach (double testedPosition in Scalars.GetIntermediateValuesSymmetric(leftComponent.Position, rightComponent.Position, 100))
foreach (double testedPosition in Scalars.GetIntermediateValuesSymmetric(leftComponent.Position, rightComponent.Position, SegmentSegmentCount + 1))
if ((Curve.GetPoint(testedPosition) - position).Length < 10)
return true;

Expand All @@ -102,14 +83,13 @@ public override void MouseMove(Vector2Double mousePosition)
OnSpecificationChanged();
}
}

public override void MouseUp(Vector2Double mousePosition, MouseButton mouseButton)
{
if (IsRightMouseDown)
{
double closestPosition =
(
from position in Scalars.GetIntermediateValuesSymmetric(leftComponent.Position, rightComponent.Position, 100)
from position in Scalars.GetIntermediateValuesSymmetric(leftComponent.Position, rightComponent.Position, SegmentSegmentCount + 1)
let distance = (Curve.GetPoint(position) - mousePosition).Length
orderby distance ascending
select position
Expand All @@ -119,7 +99,7 @@ select position
OnAddSpecification(closestPosition);
}

base.MouseUp(mousePosition,mouseButton);
base.MouseUp(mousePosition, mouseButton);
}

protected void OnSpecificationChanged()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ public Vector2Double Point
{
if (specifiesPoint) return point;
else if (Curve != null) return Curve.GetPoint(Position);
else return Vector2Double.Origin; }
else return Vector2Double.Origin;
}
set
{
if (specifiesPoint) point = value;
Expand Down Expand Up @@ -136,7 +137,7 @@ public override void MouseMove(Vector2Double mousePosition)
{
double closestPosition =
(
from position in Scalars.GetIntermediateValuesSymmetric(0, 1, 100)
from position in Scalars.GetIntermediateValuesSymmetric(0, 1, SegmentCount + 1)
let distance = (Curve.GetPoint(position) - mousePosition).Length
orderby distance ascending
select position
Expand Down
45 changes: 38 additions & 7 deletions source/Kurve/Kurve/Components/CurveComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ namespace Kurve.Component
class CurveComponent : Component
{
readonly CurveOptimizer curveOptimizer;

public CurveOptimizer CurveOptimizer { get { return curveOptimizer; } }

readonly List<SpecificationComponent> specificationComponents;
readonly List<SegmentComponent> segmentComponents;
readonly FixedPositionComponent curveStartComponent;
Expand Down Expand Up @@ -100,9 +97,11 @@ protected override IEnumerable<Component> SubComponents
}

public event Action RemoveCurve;


public CurveOptimizer CurveOptimizer { get { return curveOptimizer; } }
public BasicSpecification BasicSpecification { get { return basicSpecification; } }
public Curve Curve { get { return curve; } }
public int SegmentCount { get { return curveOptimizer.SegmentCount; } }
public Specification Specification { get { return curveOptimizer.Specification; } }

public CurveComponent(Component parent, OptimizationWorker optimizationWorker, Specification specification) : base(parent)
Expand All @@ -124,11 +123,13 @@ public CurveComponent(Component parent, OptimizationWorker optimizationWorker, S

curveOptimizer.Submit(nextSpecification);

IEnumerable<SpecificationComponent> specificationComponents =
IEnumerable<SpecificationComponent> specificationComponents =
(
from spec in nextSpecification.CurveSpecifications
orderby spec.Position ascending
group spec by spec.Position into specificationGroup
select new SpecificationComponent(this, this, specificationGroup.Key, specificationGroup);
select new SpecificationComponent(this, this, specificationGroup.Key, specificationGroup)
);

foreach (SpecificationComponent component in specificationComponents) AddSpecificationComponent(component);
}
Expand Down Expand Up @@ -306,7 +307,6 @@ void ChangePolynomialtemplateDegree(int newDegree)
}
}


void RebuildSegmentComponents()
{
IEnumerable<PositionedControlComponent> orderedSpecificationComponents =
Expand Down Expand Up @@ -350,6 +350,23 @@ public void SelectionChanged(PositionedControlComponent selectedComponent)
}
}

public override void Draw(Context context)
{
if (curve != null)
foreach (Tuple<double, double> positions in Scalars.GetIntermediateValuesSymmetric(0, 1, SegmentCount + 1).GetRanges())
{
double position = Enumerables.Average(positions.Item1, positions.Item2);

Vector2Double curvatureVector = CurveOptimizer.CurvatureMarkersFactor * curve.GetCurvature(position) * curve.GetNormalVector(position);

Krach.Graphics.Color lineColor = StretchColor(curve.GetSpeed(position) / basicSpecification.CurveLength);

Drawing.DrawLine(context, curve.GetPoint(position), curve.GetPoint(position) + curvatureVector, 0.5, Colors.Blue);
Drawing.DrawLine(context, curve.GetPoint(positions.Item1), curve.GetPoint(positions.Item2), 2, lineColor);
}

base.Draw(context);
}
public override void KeyDown(Key key)
{
if (key == Key.Shift) isShiftDown = true;
Expand Down Expand Up @@ -385,6 +402,20 @@ static double ShiftPosition(double position, double insertionPosition, double le

throw new InvalidOperationException();
}
static Krach.Graphics.Color StretchColor(double stretchFactor)
{
Krach.Graphics.Color baseColor = Krach.Graphics.Color.FromHsv(0, 0, 0);

OrderedRange<double> source = new OrderedRange<double>(0.75, 1.0);
OrderedRange<double> destination = new OrderedRange<double>(0.0, 1.0);

IMap<double, double> amplifier = new RangeMap(source, destination, Mappers.Linear);

if (stretchFactor < 1) return Krach.Graphics.Color.InterpolateRgb(Colors.Blue, baseColor, Scalars.InterpolateLinear, amplifier.Map((1.0 * stretchFactor).Clamp(source)));
if (stretchFactor > 1) return Krach.Graphics.Color.InterpolateRgb(Colors.Red, baseColor, Scalars.InterpolateLinear, amplifier.Map((1.0 / stretchFactor).Clamp(source)));

return baseColor;
}
}
}

36 changes: 16 additions & 20 deletions source/Kurve/Kurve/Components/RootComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Kurve.Interface;
using Gtk;
using System.Xml.Linq;
using Krach.Formats.Svg;

namespace Kurve.Component
{
Expand Down Expand Up @@ -142,25 +143,17 @@ select curveComponent.Specification.XElement

void DoExport(IEnumerable<CurveOptimizer> optimizers, String filename)
{
Console.WriteLine("exporting to "+filename);

XAttribute style = new XAttribute("style", "fill:none; stroke:black; stroke-width:2");
XAttribute curvatureStyle = new XAttribute("style", "fill:none; stroke:green; stroke-width:0.5");
XNamespace @namespace = "http://www.w3.org/2000/svg";
int width;
int height;
this.parentWindow.GetSize(out width, out height);
new XElement(
@namespace + "svg",
new XAttribute("viewBox", "0 0 "+width+" "+height),
int width, height;
parentWindow.GetSize(out width, out height);

new XElement
(
Svg.Namespace + "svg",
new XAttribute("viewBox", string.Format("{0} {1} {2} {3}", 0, 0, width, height)),
new XAttribute("version", "1.1"),
from optimizer in optimizers
from item in Enumerables.Create
(
new XElement(@namespace+"path", style, new XAttribute("d", optimizer.GetSvgAttributeString(100))),
new XElement(@namespace+"path", curvatureStyle, new XAttribute("d", optimizer.GetCurvatureIndicators(250)))
)
select item
from path in optimizer.GetSvgPaths()
select path
)
.Save(filename);
}
Expand All @@ -170,11 +163,14 @@ void Export()
{
if ((ResponseType)fileChooser.Run() == ResponseType.Accept)
{
IEnumerable<CurveOptimizer> optimizers =
IEnumerable<CurveOptimizer> optimizers =
(
from curveComponent in curveComponents
select curveComponent.CurveOptimizer;
select curveComponent.CurveOptimizer
);
string path = fileChooser.Filename;

this.optimizationWorker.SubmitTask(this, () => DoExport(optimizers, fileChooser.Filename));
this.optimizationWorker.SubmitTask(new CurveOptimizer(optimizationWorker, null), curveOptimizer => DoExport(optimizers, path));
}

fileChooser.Destroy();
Expand Down
Loading

0 comments on commit 022d79d

Please sign in to comment.