void OnCurveGUI(Rect rect, SerializedProperty curve, CurveState state) { // Discard invisible curves if (!state.visible) return; var animCurve = curve.animationCurveValue; var keys = animCurve.keys; var length = keys.Length; // Curve drawing // Slightly dim non-editable curves var color = state.color; if (!state.editable) color.a *= 0.5f; Handles.color = color; var bounds = settings.bounds; if (length == 0) { var p1 = CurveToCanvas(new Vector3(bounds.xMin, state.zeroKeyConstantValue)); var p2 = CurveToCanvas(new Vector3(bounds.xMax, state.zeroKeyConstantValue)); Handles.DrawAAPolyLine(state.width, p1, p2); } else if (length == 1) { var p1 = CurveToCanvas(new Vector3(bounds.xMin, keys[0].value)); var p2 = CurveToCanvas(new Vector3(bounds.xMax, keys[0].value)); Handles.DrawAAPolyLine(state.width, p1, p2); } else { var prevKey = keys[0]; for (int k = 1; k < length; k++) { var key = keys[k]; var pts = BezierSegment(prevKey, key); if (float.IsInfinity(prevKey.outTangent) || float.IsInfinity(key.inTangent)) { var s = HardSegment(prevKey, key); Handles.DrawAAPolyLine(state.width, s[0], s[1], s[2]); } else Handles.DrawBezier(pts[0], pts[3], pts[1], pts[2], color, null, state.width); prevKey = key; } // Curve extents & loops if (keys[0].time > bounds.xMin) { if (state.loopInBounds) { var p1 = keys[length - 1]; p1.time -= settings.bounds.width; var p2 = keys[0]; var pts = BezierSegment(p1, p2); if (float.IsInfinity(p1.outTangent) || float.IsInfinity(p2.inTangent)) { var s = HardSegment(p1, p2); Handles.DrawAAPolyLine(state.width, s[0], s[1], s[2]); } else Handles.DrawBezier(pts[0], pts[3], pts[1], pts[2], color, null, state.width); } else { var p1 = CurveToCanvas(new Vector3(bounds.xMin, keys[0].value)); var p2 = CurveToCanvas(keys[0]); Handles.DrawAAPolyLine(state.width, p1, p2); } } if (keys[length - 1].time < bounds.xMax) { if (state.loopInBounds) { var p1 = keys[length - 1]; var p2 = keys[0]; p2.time += settings.bounds.width; var pts = BezierSegment(p1, p2); if (float.IsInfinity(p1.outTangent) || float.IsInfinity(p2.inTangent)) { var s = HardSegment(p1, p2); Handles.DrawAAPolyLine(state.width, s[0], s[1], s[2]); } else Handles.DrawBezier(pts[0], pts[3], pts[1], pts[2], color, null, state.width); } else { var p1 = CurveToCanvas(keys[length - 1]); var p2 = CurveToCanvas(new Vector3(bounds.xMax, keys[length - 1].value)); Handles.DrawAAPolyLine(state.width, p1, p2); } } } // Make sure selection is correct (undo can break it) bool isCurrentlySelectedCurve = curve == m_SelectedCurve; if (isCurrentlySelectedCurve && m_SelectedKeyframeIndex >= length) m_SelectedKeyframeIndex = -1; // Handles & keys for (int k = 0; k < length; k++) { bool isCurrentlySelectedKeyframe = k == m_SelectedKeyframeIndex; var e = Event.current; var pos = CurveToCanvas(keys[k]); var hitRect = new Rect(pos.x - 8f, pos.y - 8f, 16f, 16f); var offset = isCurrentlySelectedCurve ? new RectOffset(5, 5, 5, 5) : new RectOffset(6, 6, 6, 6); var outTangent = pos + CurveTangentToCanvas(keys[k].outTangent).normalized * 40f; var inTangent = pos - CurveTangentToCanvas(keys[k].inTangent).normalized * 40f; var inTangentHitRect = new Rect(inTangent.x - 7f, inTangent.y - 7f, 14f, 14f); var outTangentHitrect = new Rect(outTangent.x - 7f, outTangent.y - 7f, 14f, 14f); // Draw if (state.showNonEditableHandles) { if (e.type == EventType.repaint) { var selectedColor = (isCurrentlySelectedCurve && isCurrentlySelectedKeyframe) ? settings.selectionColor : state.color; // Keyframe EditorGUI.DrawRect(offset.Remove(hitRect), selectedColor); // Tangents if (isCurrentlySelectedCurve && (!state.onlyShowHandlesOnSelection || (state.onlyShowHandlesOnSelection && isCurrentlySelectedKeyframe))) { Handles.color = selectedColor; if (k > 0 || state.loopInBounds) { Handles.DrawAAPolyLine(state.handleWidth, pos, inTangent); EditorGUI.DrawRect(offset.Remove(inTangentHitRect), selectedColor); } if (k < length - 1 || state.loopInBounds) { Handles.DrawAAPolyLine(state.handleWidth, pos, outTangent); EditorGUI.DrawRect(offset.Remove(outTangentHitrect), selectedColor); } } } } // Events if (state.editable) { // Keyframe move if (m_EditMode == EditMode.Moving && e.type == EventType.MouseDrag && isCurrentlySelectedCurve && isCurrentlySelectedKeyframe) { EditMoveKeyframe(animCurve, keys, k); } // Tangent editing if (m_EditMode == EditMode.TangentEdit && e.type == EventType.MouseDrag && isCurrentlySelectedCurve && isCurrentlySelectedKeyframe) { bool alreadyBroken = !(Mathf.Approximately(keys[k].inTangent, keys[k].outTangent) || (float.IsInfinity(keys[k].inTangent) && float.IsInfinity(keys[k].outTangent))); EditMoveTangent(animCurve, keys, k, m_TangentEditMode, e.shift || !(alreadyBroken || e.control)); } // Keyframe selection if (e.type == EventType.mouseDown && rect.Contains(e.mousePosition)) { if (hitRect.Contains(e.mousePosition)) { SelectKeyframe(curve, k); m_EditMode = EditMode.Moving; e.Use(); } } // Tangent selection & edit mode if (e.type == EventType.mouseDown && rect.Contains(e.mousePosition)) { if (inTangentHitRect.Contains(e.mousePosition) && (k > 0 || state.loopInBounds)) { SelectKeyframe(curve, k); m_EditMode = EditMode.TangentEdit; m_TangentEditMode = Tangent.In; e.Use(); } else if (outTangentHitrect.Contains(e.mousePosition) && (k < length - 1 || state.loopInBounds)) { SelectKeyframe(curve, k); m_EditMode = EditMode.TangentEdit; m_TangentEditMode = Tangent.Out; e.Use(); } } // Mouse up - clean up states if (e.rawType == EventType.MouseUp && m_EditMode != EditMode.None) { m_EditMode = EditMode.None; } // Set cursors { EditorGUIUtility.AddCursorRect(hitRect, MouseCursor.MoveArrow); if (k > 0 || state.loopInBounds) EditorGUIUtility.AddCursorRect(inTangentHitRect, MouseCursor.RotateArrow); if (k < length - 1 || state.loopInBounds) EditorGUIUtility.AddCursorRect(outTangentHitrect, MouseCursor.RotateArrow); } } } Handles.color = Color.white; SaveCurve(curve, animCurve); }
void EditMoveTangent(AnimationCurve curve, Keyframe[] keys, int keyframeIndex, Tangent targetTangent, bool linkTangents) { var pos = CanvasToCurve(Event.current.mousePosition); float time = keys[keyframeIndex].time; float value = keys[keyframeIndex].value; pos -= new Vector3(time, value); if (targetTangent == Tangent.In && pos.x > 0f) pos.x = 0f; if (targetTangent == Tangent.Out && pos.x < 0f) pos.x = 0f; float tangent; if (Mathf.Approximately(pos.x, 0f)) tangent = pos.y < 0f ? float.PositiveInfinity : float.NegativeInfinity; else tangent = pos.y / pos.x; float inTangent = keys[keyframeIndex].inTangent; float outTangent = keys[keyframeIndex].outTangent; if (targetTangent == Tangent.In || linkTangents) inTangent = tangent; if (targetTangent == Tangent.Out || linkTangents) outTangent = tangent; SetKeyframe(curve, keyframeIndex, new Keyframe(time, value, inTangent, outTangent)); }
public HomePageViewModel(IRegionManager regionManager) { _regionManager = regionManager; Data = new ObservableCollection <ObservablePoint>(); _axialData = new HashSet <ObservablePoint>(); _axialDataPlot = new LineSeries { Title = "Axial", Fill = Brushes.Transparent, Stroke = Brushes.Black, LineSmoothness = 0, StrokeDashArray = new DoubleCollection { 2 }, Values = new ChartValues <ObservablePoint>(), DataLabels = true }; _radialData = new HashSet <ObservablePoint>(); _radialDataPlot = new LineSeries { Title = "Radial Data", Fill = Brushes.Transparent, Stroke = Brushes.Orange, LineSmoothness = 0, StrokeDashArray = new DoubleCollection { 2 }, Values = new ChartValues <ObservablePoint>() }; _radialCurvePlot = new LineSeries { Title = "Radial Curve" }; _axialCurvePlot = new LineSeries { Title = "Axial", Fill = Brushes.Transparent, Stroke = Brushes.Red, LineSmoothness = 0.2, Values = new ChartValues <ObservablePoint>() }; _tgPlot = new LineSeries { Title = "Tg", Fill = Brushes.Transparent, Stroke = Brushes.Green, Values = new ChartValues <ObservablePoint>() }; _generatedCurveDataPlot = new LineSeries { Title = "Generated Data", Fill = Brushes.Transparent, Stroke = Brushes.Magenta, PointGeometrySize = 0.1, Values = new ChartValues <ObservablePoint>() }; StressStrainCurveSeries = new SeriesCollection(); StressStrainCurveSeries.Add(_axialDataPlot); StressStrainCurveSeries.Add(_radialDataPlot); StressStrainCurveSeries.Add(_axialCurvePlot); StressStrainCurveSeries.Add(_tgPlot); StressStrainCurveSeries.Add(_generatedCurveDataPlot); //Commands StressStrainCurveModeCommand = new DelegateCommand(() => { _regionManager.RequestNavigate(Configurations.Regions.ChartRegion, nameof(StressStrainCurveChartPage)); }); PoissonsRatioStressCurveModeCommand = new DelegateCommand(() => { _regionManager.RequestNavigate(Configurations.Regions.ChartRegion, nameof(PoissonsRatioStressCurveChartPage)); }); ModulusStressCurveModeCommand = new DelegateCommand(() => { _regionManager.RequestNavigate(Configurations.Regions.ChartRegion, nameof(ModulusStressCurveChartPage)); }); AddDataCommand = new DelegateCommand(() => AddData(_inputMicrostrain, _inputStress)); EditDataCommand = new DelegateCommand <ChartPoint>(p => { EditMicrostrain = p.X; EditStress = p.Y; }); MouseDoubleClickCommand = new DelegateCommand(() => { AddData(_currentXData, _currentYData); }); SmoothDataCommand = new DelegateCommand(async() => await SmoothData()); ResetCommand = new DelegateCommand(() => { Data.Clear(); _axialData.Clear(); _axialDataPlot.Values.Clear(); _axialCurvePlot.Values.Clear(); _tgPlot.Values.Clear(); _generatedCurveDataPlot.Values.Clear(); _radialData.Clear(); _radialDataPlot.Values.Clear(); }); DrawTangentCommand = new DelegateCommand <bool?>(v => { _tgPlot.Values.Clear(); _tgPlot.Visibility = (bool)v ? Visibility.Visible : Visibility.Hidden; if ((bool)v) { var x = _axialData.OrderBy(d => d.X).Select(d => d.X).ToArray(); var y = _axialData.OrderBy(d => d.X).Select(d => d.Y).ToArray(); var t = PolynomialRegression.LeastSquartPolynonial(x, y, PolynomDegree); var tgY = Tangent.Y(t, _axialData.OrderBy(p => p.X).Last().X); _tgPlot.Values.Add(new ObservablePoint { X = 0, Y = 0 }); _tgPlot.Values.Add(new ObservablePoint { X = _axialData.OrderBy(p => p.X).Last().X, Y = tgY }); } }); GenerateDataCommand = new DelegateCommand(() => { _generatedCurveDataPlot.Values.Clear(); var x = _axialData.OrderBy(d => d.X).Select(d => d.X).ToArray(); var y = _axialData.OrderBy(d => d.X).Select(d => d.Y).ToArray(); var t = PolynomialRegression.LeastSquartPolynonial(x, y, PolynomDegree); Task.Run(() => { var generatedData = PolynomialRegression.Generate(t, 50, _axialData.OrderBy(d => d.X).Last().X, GeneratedDataNoise); var strain = generatedData.Item1; var stress = generatedData.Item2; for (int i = 0; i < strain.Length; i++) { _generatedCurveDataPlot.Values.Add(new ObservablePoint { X = strain[i], Y = stress[i] }); } }); }); }
protected virtual void EvaluateTangent(Tangent tangentExpression) { }
public void Visit(Tangent tangentExpression) => EvaluateTangent(tangentExpression);
/// <summary> /// The matricies can only be calculated if the mesh has all positions, indices and uv coordinates initialized. /// Thus call this after initializing the mesh. /// </summary> private void CalcTangentsAndBitangents() { float maxId = IDs.Max(); if (maxId > TexCoord.Count) { throw new ArgumentException("Not all TexCoords are set, tangents and bitangents can not be calculated."); } //Calculate TBN for every triangle in the mesh List <Vector3> tangentPerTriangle = new List <Vector3>(); List <Vector3> bitangentPerTriangle = new List <Vector3>(); for (int i = 0; i < IDs.Count; i += 3) { int id0 = (int)IDs[i + 0]; int id1 = (int)IDs[i + 1]; int id2 = (int)IDs[i + 2]; Vector3 p0 = Position[id0]; Vector3 p1 = Position[id1]; Vector3 p2 = Position[id2]; Vector3 q1 = p1 - p0; Vector3 q2 = p2 - p0; float u0 = TexCoord[id0].X; float u1 = TexCoord[id1].X; float u2 = TexCoord[id2].X; float v0 = TexCoord[id0].Y; float v1 = TexCoord[id1].Y; float v2 = TexCoord[id2].Y; Vector2 s = new Vector2(u1 - u0, u2 - u0); Vector2 t = new Vector2(v1 - v0, v2 - v0); var leftSide = Mat2x2(t.Y, -t.X, -s.Y, s.X); var rightSide = VecToMat(q1, q2); var det = (1.0f / (s.X * t.Y - s.Y * t.X)); Matrix4x4 tb = Matrix4x4.Multiply(Matrix4x4.Multiply(leftSide, det), rightSide); Vector3 tan = new Vector3(tb.M11, tb.M12, tb.M13); Vector3 bitan = new Vector3(tb.M21, tb.M22, tb.M23); tangentPerTriangle.Add(Vector3.Normalize(tan)); bitangentPerTriangle.Add(Vector3.Normalize(bitan)); } //Average TBN on every vertex for (int i = 0; i < Position.Count; i++) { int countOfPointMatches = 0; Vector3 resultingTangent = Vector3.Zero; Vector3 resultingBitangent = Vector3.Zero; for (int k = 0; k < IDs.Count; k += 3) { int id0 = (int)IDs[k + 0]; int id1 = (int)IDs[k + 1]; int id2 = (int)IDs[k + 2]; if (id0 == i || id1 == i || id2 == i) { countOfPointMatches++; resultingTangent += tangentPerTriangle[(k - k % 3) / 3]; resultingBitangent += bitangentPerTriangle[(k - k % 3) / 3]; } } if (countOfPointMatches != 0) { resultingTangent = resultingTangent / countOfPointMatches; resultingBitangent = resultingBitangent / countOfPointMatches; } Tangent.Add(resultingTangent); Bitangent.Add(resultingBitangent); } }
public static void TangentHasCorrectType() { var tangent = new Tangent(One); Assert.AreEqual(SymbolType.Tangent, tangent.Type); }