Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 16 additions & 11 deletions doc/distrib/xml/en-US/DSCoreNodes.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

100 changes: 66 additions & 34 deletions src/Libraries/CoreNodeModels/CurveMapperNodeModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,28 @@ public class CurveMapperNodeModel : NodeModel
private double maxLimitX = 1;
private double minLimitY = 0;
private double maxLimitY = 1;
private int pointsCount = 10;
private List<Double> pointsCount = new List<double>() { 10.0 };

private List<double> outputValuesY;
private List<double> outputValuesX;
private List<double> renderValuesY;
private List<double> renderValuesX;

private const int minXDefaultValue = 0;
private const int maxXDefaultValue = 1;
private const int minYDefaultValue = 0;
private const int maxYDefaultValue = 1;

private const int pointCountDefaultValue = 10;
private static readonly int minXDefaultValue = 0;
private static readonly int maxXDefaultValue = 1;
private static readonly int minYDefaultValue = 0;
private static readonly int maxYDefaultValue = 1;
private static readonly double pointCountDefaultValue = 10.0;

private readonly IntNode minLimitXDefaultValue = new IntNode(minXDefaultValue);
private readonly IntNode maxLimitXDefaultValue = new IntNode(maxXDefaultValue);
private readonly IntNode minLimitYDefaultValue = new IntNode(minYDefaultValue);
private readonly IntNode maxLimitYDefaultValue = new IntNode(maxYDefaultValue);
private readonly IntNode pointsCountDefaultValue = new IntNode(pointCountDefaultValue);
private readonly AssociativeNode pointsCountDefaultValue =
AstFactory.BuildExprList(new List<AssociativeNode>
{
AstFactory.BuildDoubleNode(pointCountDefaultValue)
});

private const string gaussianCurveControlPointData2Tag = "GaussianCurveControlPointData2";
private const string gaussianCurveControlPointData3Tag = "GaussianCurveControlPointData3";
Expand Down Expand Up @@ -232,7 +235,7 @@ public double MaxLimitY

/// <summary> Gets or sets the number of points used to compute the curve. </summary>
[JsonProperty]
public int PointsCount
public List<double> PointsCount
{
get => pointsCount;
set
Expand Down Expand Up @@ -680,9 +683,16 @@ public void UpdateGaussianCurveControlPoints(double deltaX, string tag)

private bool IsValidInput()
{
return PointsCount >= 2
&& MinLimitX != MaxLimitX
&& MinLimitY != MaxLimitY;
if (pointsCount == null || pointsCount.Count == 0)
return false;

if (pointsCount.Count == 1 && pointsCount.FirstOrDefault() < 2)
return false;

if (MinLimitX == MaxLimitX || MinLimitY == MaxLimitY)
return false;

return true;
}

private bool IsValidCurve()
Expand Down Expand Up @@ -787,14 +797,31 @@ private void DataBridgeCallback(object data)
var maxValueX = double.TryParse(inputs[1]?.ToString(), out var maxX) ? maxX : MaxLimitX;
var minValueY = double.TryParse(inputs[2]?.ToString(), out var minY) ? minY : MinLimitY;
var maxValueY = double.TryParse(inputs[3]?.ToString(), out var maxY) ? maxY : MaxLimitY;
var listValue = int.TryParse(inputs[4]?.ToString(), out var parsedCount) ? parsedCount : PointsCount;
var parsedPointsCount = new List<double>();

if (inputs[4] is IList list)
{
foreach (var item in list)
{
if (double.TryParse(item?.ToString(), out var val))
parsedPointsCount.Add(val);
}
}
else if (double.TryParse(inputs[4]?.ToString(), out var singleVal))
{
parsedPointsCount.Add(singleVal);
}
else
{
parsedPointsCount = PointsCount;
}

// Check port connectivity
if (InPorts[0].IsConnected) MinLimitX = minValueX;
if (InPorts[1].IsConnected) MaxLimitX = maxValueX;
if (InPorts[2].IsConnected) MinLimitY = minValueY;
if (InPorts[3].IsConnected) MaxLimitY = maxValueY;
if (InPorts[4].IsConnected) PointsCount = listValue;
if (InPorts[4].IsConnected) PointsCount = parsedPointsCount;

// Notify property changes to update UI
foreach (var propertyName in new[] { nameof(MinLimitX), nameof(MaxLimitX), nameof(MinLimitY), nameof(MaxLimitY), nameof(PointsCount) })
Expand All @@ -810,8 +837,8 @@ private void DataBridgeCallback(object data)

public override IEnumerable<AssociativeNode> BuildOutputAst(List<AssociativeNode> inputAstNodes)
{
// Return null outputs if GraphType is Empty
if (SelectedGraphType == GraphTypes.Empty || !IsValidCurve())
// If input is missing or invalid, return nulls
if (inputAstNodes == null || inputAstNodes.Count < 5 || SelectedGraphType == GraphTypes.Empty || !IsValidCurve())
{
return new[]
{
Expand Down Expand Up @@ -868,15 +895,13 @@ public override IEnumerable<AssociativeNode> BuildOutputAst(List<AssociativeNode

// Build controlPointsList dynamically
var controlPointsList = AstFactory.BuildExprList(
controlPointMap[SelectedGraphType]
.SelectMany(cp => new AssociativeNode[]
{
controlPointMap[SelectedGraphType]
.SelectMany(cp => new AssociativeNode[]
{
AstFactory.BuildDoubleNode(cp.X),
AstFactory.BuildDoubleNode(DynamicCanvasSize - cp.Y)
})
.Cast<AssociativeNode>()
.ToList()
);
}).ToList()
);

// Handle input values with fall-back defaults
var inputValues = new List<AssociativeNode>
Expand All @@ -888,32 +913,39 @@ public override IEnumerable<AssociativeNode> BuildOutputAst(List<AssociativeNode
InPorts[4].IsConnected ? inputAstNodes[4] : pointsCountDefaultValue
};

var curveInputs = new List<AssociativeNode> {controlPointsList, AstFactory.BuildDoubleNode(DynamicCanvasSize)};
var curveInputs = new List<AssociativeNode> { controlPointsList, AstFactory.BuildDoubleNode(DynamicCanvasSize) };
curveInputs.AddRange(inputValues);
curveInputs.Add(AstFactory.BuildStringNode(SelectedGraphType.ToString()));

AssociativeNode buildResultNode =
AssociativeNode buildResultNodeX =
AstFactory.BuildFunctionCall(
new Func<List<double>, double, double, double, double, double, int, string, List<List<double>>>(
CurveMapperGenerator.CalculateValues),
new Func<List<double>, double, object, object, object, object, List<double>, string, List<double>>(
CurveMapperGenerator.CalculateValuesX),
curveInputs
);

// DataBridge call
var dataBridgeCall = AstFactory.BuildAssignment(
AstFactory.BuildIdentifier(AstIdentifierBase + "_dataBridge"),
VMDataBridge.DataBridge.GenerateBridgeDataAst(GUID.ToString(), AstFactory.BuildExprList(inputValues))
);
AssociativeNode buildResultNodeY =
AstFactory.BuildFunctionCall(
new Func<List<double>, double, object, object, object, object, List<double>, string, List<double>>(
CurveMapperGenerator.CalculateValuesY),
curveInputs
);

// Assign outputs
var xValuesAssignment = AstFactory.BuildAssignment(
GetAstIdentifierForOutputIndex(0),
AstFactory.BuildIndexExpression(buildResultNode, AstFactory.BuildIntNode(0))
buildResultNodeX
);

var yValuesAssignment = AstFactory.BuildAssignment(
GetAstIdentifierForOutputIndex(1),
AstFactory.BuildIndexExpression(buildResultNode, AstFactory.BuildIntNode(1))
buildResultNodeY
);

// DataBridge call
var dataBridgeCall = AstFactory.BuildAssignment(
AstFactory.BuildIdentifier(AstIdentifierBase + "_dataBridge"),
VMDataBridge.DataBridge.GenerateBridgeDataAst(GUID.ToString(), AstFactory.BuildExprList(inputValues))
);

return new[] { xValuesAssignment, yValuesAssignment, dataBridgeCall };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,6 @@ private void ResetButton_Click(object sender, RoutedEventArgs e)

// Dictionary to map UI control points to their corresponding data
var controlPointsResetMap = BuildControlPointsDictionary();

RecreateControlPoints(controlPointsResetMap);
RenderCurve();
}
Expand Down
38 changes: 30 additions & 8 deletions src/Libraries/CoreNodes/CurveMapper/BezierCurve.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,15 @@ private void GetValueAtT(double t, out double x, out double y)
/// <summary>
/// Gets interpolated Y values based on the assigned parameters and limits.
/// </summary>
protected override (List<double> XValues, List<double> YValues) GenerateCurve(int pointsCount, bool isRender)
protected override (List<double> XValues, List<double> YValues) GenerateCurve(List<double> pointsDomain, bool isRender)
{
var renderValuesX = new List<double>();
var renderValuesY = new List<double>();
var valuesX = new List<double>();
var valuesY = new List<double>();

var pointsCount = pointsDomain.Count == 1 ? pointsDomain[0] : pointsDomain.Count;

// Generate fine-grained samples to ensure better interpolation
int fineSteps = (int)(pointsCount * CanvasSize);

Expand All @@ -78,15 +80,35 @@ protected override (List<double> XValues, List<double> YValues) GenerateCurve(in
return (renderValuesX, renderValuesY);
}

// Collect output values
for (int i = 0; i < pointsCount; i++)
if (pointsDomain.Count == 1)
{
for (int i = 0; i < pointsCount; i++)
{
double targetX = (i / (double)(pointsCount - 1) * CanvasSize);
int closestIndex = renderValuesX.IndexOf(renderValuesX.OrderBy(x => Math.Abs(x - targetX)).First());
double y = renderValuesY[closestIndex];

valuesX.Add(targetX);
valuesY.Add(y);
}
}
else
{
double targetX = (i / (double)(pointsCount - 1) * CanvasSize);
int closestIndex = renderValuesX.IndexOf(renderValuesX.OrderBy(x => Math.Abs(x - targetX)).First());
double y = renderValuesY[closestIndex];
double minInput = pointsDomain.Min();
double maxInput = pointsDomain.Max();

// Normalize domain value & map to canvas X coordinate
foreach (double t in pointsDomain)
{
double normalizedT = (t - minInput) / (maxInput - minInput);
double targetX = normalizedT * CanvasSize;

int closestIndex = renderValuesX.IndexOf(renderValuesX.OrderBy(x => Math.Abs(x - targetX)).First());
double y = renderValuesY[closestIndex];

valuesX.Add(targetX);
valuesY.Add(y);
valuesX.Add(targetX);
valuesY.Add(y);
}
}

return (valuesX, valuesY);
Expand Down
2 changes: 1 addition & 1 deletion src/Libraries/CoreNodes/CurveMapper/ControlLine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public ControlLine(double cp1X, double cp1Y, double cp2X, double cp2Y, double ca
ControlPoint2X = cp2X;
ControlPoint2Y = cp2Y;
}
protected override (List<double> XValues, List<double> YValues) GenerateCurve(int pointsCount, bool isRender = false)
protected override (List<double> XValues, List<double> YValues) GenerateCurve(List<double> pointsCount, bool isRender = false)
{
return (new List<double> { ControlPoint1X, ControlPoint2X }, new List<double> { ControlPoint1Y, ControlPoint2Y });
}
Expand Down
Loading
Loading