More selection stuff. Do we really want to select tangent lines this way?
This commit is contained in:
parent
8618442bba
commit
55cb7af2ac
@ -48,9 +48,6 @@ public class ColumnTable : Graphable
|
||||
return items;
|
||||
}
|
||||
|
||||
public override bool ShouldSelectGraphable(in GraphForm graph, Float2 graphMousePos, double factor) => false;
|
||||
public override Float2 GetSelectedPoint(in GraphForm graph, Float2 graphMousePos) => default;
|
||||
|
||||
// Nothing to preload, everything is already cached.
|
||||
public override void Preload(Float2 xRange, Float2 yRange, double step) { }
|
||||
}
|
||||
|
||||
@ -74,9 +74,46 @@ public class SlopeField : Graphable
|
||||
|
||||
public override void EraseCache() => cache.Clear();
|
||||
public override long GetCacheBytes() => cache.Count * 48;
|
||||
|
||||
public override bool ShouldSelectGraphable(in GraphForm graph, Float2 graphMousePos, double factor)
|
||||
{
|
||||
Float2 nearestPos = new(Math.Round(graphMousePos.x * detail) / detail,
|
||||
Math.Round(graphMousePos.y * detail) / detail);
|
||||
|
||||
public override bool ShouldSelectGraphable(in GraphForm graph, Float2 graphMousePos, double factor) => false;
|
||||
public override Float2 GetSelectedPoint(in GraphForm graph, Float2 graphMousePos) => default;
|
||||
double epsilon = 1 / (detail * 2.0);
|
||||
GraphLine line = GetFromCache(epsilon, nearestPos.x, nearestPos.y);
|
||||
double slope = (line.b.y - line.a.y) / (line.b.x - line.a.x);
|
||||
|
||||
if (graphMousePos.x < Math.Min(line.a.x, line.b.x) ||
|
||||
graphMousePos.x > Math.Max(line.a.x, line.b.x)) return false;
|
||||
|
||||
double allowedDist = factor * graph.DpiFloat * 10 / 192;
|
||||
|
||||
double lineX = graphMousePos.x,
|
||||
lineY = slope * (lineX - nearestPos.x) + nearestPos.y;
|
||||
|
||||
Int2 pointScreen = graph.GraphSpaceToScreenSpace(new Float2(lineX, lineY));
|
||||
Int2 mouseScreen = graph.GraphSpaceToScreenSpace(graphMousePos);
|
||||
Int2 dist = new(pointScreen.x - mouseScreen.x,
|
||||
pointScreen.y - mouseScreen.y);
|
||||
double totalDist = Math.Sqrt(dist.x * dist.x + dist.y * dist.y);
|
||||
return totalDist <= allowedDist;
|
||||
}
|
||||
public override Float2 GetSelectedPoint(in GraphForm graph, Float2 graphMousePos)
|
||||
{
|
||||
Float2 nearestPos = new(Math.Round(graphMousePos.x * detail) / detail,
|
||||
Math.Round(graphMousePos.y * detail) / detail);
|
||||
|
||||
double epsilon = 1 / (detail * 2.0);
|
||||
GraphLine line = GetFromCache(epsilon, nearestPos.x, nearestPos.y);
|
||||
double slope = (line.b.y - line.a.y) / (line.b.x - line.a.x);
|
||||
|
||||
double lineX = graphMousePos.x,
|
||||
lineY = slope * (lineX - nearestPos.x) + nearestPos.y;
|
||||
Float2 point = new(lineX, lineY);
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
public override void Preload(Float2 xRange, Float2 yRange, double step)
|
||||
{
|
||||
|
||||
@ -21,10 +21,12 @@ public class TangentLine : Graphable
|
||||
|
||||
protected readonly double length;
|
||||
|
||||
protected double currentSlope;
|
||||
// X is slope, Y is height.
|
||||
protected Float2 currentSlope;
|
||||
|
||||
// No binary search for this, I want it to be exact.
|
||||
protected Dictionary<double, double> slopeCache;
|
||||
// Value: X is slope, Y is height.
|
||||
protected Dictionary<double, Float2> slopeCache;
|
||||
|
||||
public TangentLine(double length, double position, Equation parent)
|
||||
{
|
||||
@ -39,27 +41,28 @@ public class TangentLine : Graphable
|
||||
|
||||
public override IEnumerable<IGraphPart> GetItemsToRender(in GraphForm graph)
|
||||
{
|
||||
Float2 point = new(Position, parentEqu(Position));
|
||||
return [MakeSlopeLine(point, currentSlope),
|
||||
new GraphUiCircle(point, 8)];
|
||||
Float2 point = new(Position, currentSlope.y);
|
||||
return [MakeSlopeLine(), new GraphUiCircle(point, 8)];
|
||||
}
|
||||
protected GraphLine MakeSlopeLine(Float2 position, double slope)
|
||||
protected GraphLine MakeSlopeLine()
|
||||
{
|
||||
double dirX = length, dirY = slope * length;
|
||||
double dirX = length, dirY = currentSlope.x * length;
|
||||
double magnitude = Math.Sqrt(dirX * dirX + dirY * dirY);
|
||||
|
||||
dirX /= magnitude * 2 / length;
|
||||
dirY /= magnitude * 2 / length;
|
||||
|
||||
return new(new(position.x + dirX, position.y + dirY), new(position.x - dirX, position.y - dirY));
|
||||
return new(new(Position + dirX, currentSlope.y + dirY), new(Position - dirX, currentSlope.y - dirY));
|
||||
}
|
||||
protected double DerivativeAtPoint(double x)
|
||||
protected Float2 DerivativeAtPoint(double x)
|
||||
{
|
||||
// If value is already computed, return it.
|
||||
if (slopeCache.TryGetValue(x, out double y)) return y;
|
||||
if (slopeCache.TryGetValue(x, out Float2 val)) return val;
|
||||
|
||||
const double step = 1e-3;
|
||||
double result = (parentEqu(x + step) - parentEqu(x)) / step;
|
||||
|
||||
double initial = parentEqu(x);
|
||||
Float2 result = new((parentEqu(x + step) - initial) / step, initial);
|
||||
slopeCache.Add(x, result);
|
||||
return result;
|
||||
}
|
||||
@ -67,10 +70,37 @@ public class TangentLine : Graphable
|
||||
public override Graphable DeepCopy() => new TangentLine(length, Position, parent);
|
||||
|
||||
public override void EraseCache() => slopeCache.Clear();
|
||||
public override long GetCacheBytes() => slopeCache.Count * 16;
|
||||
public override long GetCacheBytes() => slopeCache.Count * 24;
|
||||
|
||||
public override bool ShouldSelectGraphable(in GraphForm graph, Float2 graphMousePos, double factor) => false;
|
||||
public override Float2 GetSelectedPoint(in GraphForm graph, Float2 graphMousePos) => default;
|
||||
public override bool ShouldSelectGraphable(in GraphForm graph, Float2 graphMousePos, double factor)
|
||||
{
|
||||
GraphLine line = MakeSlopeLine();
|
||||
|
||||
if (graphMousePos.x < Math.Min(line.a.x - 0.25, line.b.x - 0.25) ||
|
||||
graphMousePos.x > Math.Max(line.a.x + 0.25, line.b.x + 0.25)) return false;
|
||||
|
||||
double allowedDist = factor * graph.DpiFloat * 80 / 192;
|
||||
|
||||
double lineX = graphMousePos.x,
|
||||
lineY = currentSlope.x * (lineX - Position) + currentSlope.y;
|
||||
|
||||
Int2 pointScreen = graph.GraphSpaceToScreenSpace(new Float2(lineX, lineY));
|
||||
Int2 mouseScreen = graph.GraphSpaceToScreenSpace(graphMousePos);
|
||||
Int2 dist = new(pointScreen.x - mouseScreen.x,
|
||||
pointScreen.y - mouseScreen.y);
|
||||
double totalDist = Math.Sqrt(dist.x * dist.x + dist.y * dist.y);
|
||||
return totalDist <= allowedDist;
|
||||
}
|
||||
public override Float2 GetSelectedPoint(in GraphForm graph, Float2 graphMousePos)
|
||||
{
|
||||
GraphLine line = MakeSlopeLine();
|
||||
|
||||
double lineX = Math.Clamp(graphMousePos.x,
|
||||
Math.Min(line.a.x, line.b.x),
|
||||
Math.Max(line.a.x, line.b.x)),
|
||||
lineY = currentSlope.x * (lineX - Position) + currentSlope.y;
|
||||
return new Float2(lineX, lineY);
|
||||
}
|
||||
|
||||
public override void Preload(Float2 xRange, Float2 yRange, double step)
|
||||
{
|
||||
|
||||
@ -14,8 +14,8 @@ internal static class Program
|
||||
|
||||
GraphForm graph = new("One Of The Graphing Calculators Of All Time");
|
||||
|
||||
Equation possibleA = new(x => Math.Sin(x));
|
||||
SlopeField sf = new(2, (x, y) => Math.Cos(x));
|
||||
Equation possibleA = new(x => x * x * x);
|
||||
SlopeField sf = new(2, (x, y) => 1 / x);
|
||||
TangentLine tl = new(2, 2, possibleA);
|
||||
graph.Graph(possibleA, sf, tl);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user