Control Desgine - Sigmoid Kurve

  • C#
  • .NET 4.5

Es gibt 5 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Control Desgine - Sigmoid Kurve

    Hallo Zusammen :D



    Ich bin grade an dem Problem, das ich eine Sigmoid-Funktion habe, die von Oben bzw. Unten nach Unten bzw. Oben läuft.
    Verlauf von Unten nach Oben
    Verlauf von Oben nach Unten



    Dies Funktion habe ich so angepasst, das ich
    die Y-Achse und die X-Achse einstellen kann so
    das das Funktion an dem Punkt P(5,5) zb. ausläuft.



    Das ganze mach ich mit einer Funktion die 4 Parameter brauch,

    C#-Quellcode

    1. /// <summary>
    2. /// draw sigmoid
    3. /// </summary>
    4. /// <param name="x">X-Achsen Position</param>
    5. /// <param name="width">Defintions-Bereich</param>
    6. /// <param name="height">Werte-Bereich</param>
    7. /// <param name="direction">Abfallen oder Steigend</param>
    8. /// <returns></returns>
    9. [MethodImpl(MethodImplOptions.AggressiveInlining)]
    10. private float Sigmoid(float x, float width, float height, DrawDirection direction)
    11. => (float)(height / (1 + Math.Pow(Math.E, (int) direction * ((6 / (width - (height / 10)) * x))))) - (height * .5f);



    *Unten ist die Methode mit der ich Zeichne
    Nun würde ich gern die Funtion wie den Tangens laufen lassen, Also von Rechts btw. Links nach Links bzw. Rechts
    *Die Bilder sind manuell gedreht
    Links nach Rechts
    Rechts nach Links




    Mein gedanken gang war nun: "Drehen wir einfach X und Y um", gemacht getan sah es nun so auf

    C#-Quellcode

    1. private void UpdatePath() {
    2. //[...]
    3. if (gamma > 1) {
    4. sigmodY = (x, w, h, d) => Sigmoid(x, w, h, d); //orginal
    5. vectorP = (x, y) => new PointF(y + wh, x + hh);
    6. }
    7. //[..]
    8. }



    Hier kann man erkennen, das die Funktion schon richtig verläuft aber nicht richtig auf die breite angepasst ist so tauschte ich die Breite mit der höhe,

    C#-Quellcode

    1. private void UpdatePath() {
    2. //[...]
    3. if (gamma > 1) {
    4. sigmodY = (x, w, h, d) => Sigmoid(x, h, w, d); //Tausch
    5. vectorP = (x, y) => new PointF(y + wh, x + hh);
    6. }
    7. //[..]
    8. }



    was da raus kam, war nicht so wie ich es wollte, nun hab ich ein wenig rum gespielt mit den werten

    C#-Quellcode

    1. private void UpdatePath() {
    2. //[...]
    3. if (gamma > 1) {
    4. sigmodY = (x, w, h, d) => Sigmoid(x, w, w, d); //Tausch
    5. vectorP = (x, y) => new PointF(y + wh, x + hh);
    6. }
    7. //[..]
    8. }


    C#-Quellcode

    1. private void UpdatePath() {
    2. //[...]
    3. if (gamma > 1) {
    4. sigmodY = (x, w, h, d) => Sigmoid(x, h, h, d); //Tausch
    5. vectorP = (x, y) => new PointF(y + wh, x + hh);
    6. }
    7. //[..]
    8. }



    Jetzt zu meiner Frage :D
    Hat jm eine idee wie ich die Parameter anpassen müsste so das die Kurve in den Ecken endet des Controls,
    bzw. hat jm. eine idee wie ich die funktion mittels Tangens hinbekomme oder wie ich die Punkte der Kurve so drehe das
    mein gewünschtes ziel rauskommt ?

    *Methode

    C#-Quellcode

    1. private void UpdatePath() {
    2. int segments = 32; //Eine linie besteht aus vielen Punkten die verbunden werden (32 Punkte hier)
    3. float wh = Width * .5f; //Halbe höhe um die Funktion zu verschieben *Bild drunter [a1]
    4. float hh = Height * .5f;
    5. float steps = wh / segments; //Einteilung der Abstände der Punkte
    6. PointF[] vertex = new PointF[segments + segments]; //Das array für die Punkte (Doppelt so viele, denn Links und rechts von der Y-Achse
    7. //L = Links, R = Rechts, B = Bottom, T = Top
    8. float gamma = (float)Math.Atan2(Height, Width); // zu erkenne ob ich [TB|BT] oder [LR|RL] Zeichnen muss
    9. //ISt der Winkel von (0,0) zu (Breite, Höhe) größer als 45° so soll die Funktion von RL oder LR laufen
    10. //default [TB|BT]
    11. Func<float, float, float, DrawDirection, float> sigmodY = (x, w, h, d) => Sigmoid(x, w, h, d);
    12. Func<float, float, PointF> vectorP = (x, y) => new PointF(x + wh, y + hh);
    13. //ende default
    14. if (gamma > 1) { //[RL|LR]
    15. sigmodY = (x, w, h, d) => Sigmoid(x, h, w, d);
    16. vectorP = (x, y) => new PointF(y + wh, x + hh);
    17. }
    18. for (int i = -segments; i < segments; i++) {
    19. float x = i * steps;
    20. float y = sigmodY(x, Width, Height, Direction);
    21. vertex[i + segments] = vectorP(x, y);
    22. //Console.WriteLine($"x: {x} y: {y}");
    23. }
    24. GraphicsPath path = new GraphicsPath();
    25. path.AddLines(vertex);
    26. WirePath = path;
    27. }

    [a1]



    *Voller code
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.ComponentModel;
    3. using System.Drawing;
    4. using System.Drawing.Drawing2D;
    5. using System.Runtime.CompilerServices;
    6. using System.Windows.Forms;
    7. namespace Block {
    8. public class Wire : Control {
    9. private const float PI = 3.14159f;
    10. private GraphicsPath WirePath;
    11. private Color _WireColor = Color.Gray;
    12. [Category("Wire")]
    13. public Color WireColor {
    14. get => _WireColor;
    15. set {
    16. if (_WireColor == value)
    17. return;
    18. _WireColor = value;
    19. Invalidate();
    20. }
    21. }
    22. private int _StrokeWidth = 5;
    23. [Category("Wire")]
    24. public int StrokeWidth {
    25. get => _StrokeWidth;
    26. set {
    27. if (_StrokeWidth == value)
    28. return;
    29. _StrokeWidth = value;
    30. Invalidate();
    31. }
    32. }
    33. private DrawDirection _DrawDirection = DrawDirection.BottomToTop;
    34. public DrawDirection Direction {
    35. get => _DrawDirection;
    36. set {
    37. if (_DrawDirection == value)
    38. return;
    39. _DrawDirection = value;
    40. Invalidate();
    41. }
    42. }
    43. public Wire() {
    44. InitializeStyle();
    45. InitializeValues();
    46. InitializeEvents();
    47. }
    48. private void InitializeStyle() {
    49. ControlStyles styles = ControlStyles.OptimizedDoubleBuffer
    50. | ControlStyles.SupportsTransparentBackColor
    51. | ControlStyles.UserPaint
    52. | ControlStyles.ResizeRedraw;
    53. SetStyle(styles, true);
    54. }
    55. private void InitializeValues() {
    56. BackColor = Color.Transparent;
    57. }
    58. private void InitializeEvents() {
    59. Invalidated += Wire_Invalidated;
    60. Paint += Wire_Paint;
    61. void Wire_Paint(object sender, PaintEventArgs e) {
    62. ///Setting
    63. ///
    64. Graphics graphics = e.Graphics;
    65. graphics = e.Graphics;
    66. graphics.SmoothingMode = SmoothingMode.AntiAlias;
    67. graphics.CompositingQuality = CompositingQuality.HighQuality;
    68. graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
    69. graphics.InterpolationMode = InterpolationMode.HighQualityBilinear;
    70. if (WirePath != null)
    71. graphics.DrawPath(new Pen(_WireColor, _StrokeWidth), WirePath);
    72. }
    73. }
    74. private void Wire_Invalidated(object sender, InvalidateEventArgs e) => UpdatePath();
    75. private void UpdatePath() {
    76. int segments = 32;
    77. float wh = Width * .5f;
    78. float hh = Height * .5f;
    79. float steps = wh / segments;
    80. PointF[] vertex = new PointF[segments + segments];
    81. float gamma = (float)Math.Atan2(Height, Width);
    82. //default
    83. Func<float, float, float, DrawDirection, float> sigmodY = (x, w, h, d) => Sigmoid(x, w, h, d);
    84. Func<float, float, PointF> vectorP = (x, y) => new PointF(x + wh, y + hh);
    85. if (gamma > 1) {
    86. sigmodY = (x, w, h, d) => Sigmoid(x, w, w, d);
    87. vectorP = (x, y) => new PointF(y + wh, x + hh);
    88. }
    89. //end default
    90. for (int i = -segments; i < segments; i++) {
    91. float x = i * steps;
    92. float y = sigmodY(x, Width, Height, Direction);
    93. vertex[i + segments] = vectorP(x, y);
    94. //Console.WriteLine($"x: {x} y: {y}");
    95. }
    96. GraphicsPath path = new GraphicsPath();
    97. path.AddLines(vertex);
    98. WirePath = path;
    99. }
    100. /// <summary>
    101. /// draw sigmoid
    102. /// </summary>
    103. /// <param name="x">X-Achsen Position</param>
    104. /// <param name="width">Defintions-Bereich</param>
    105. /// <param name="height">Werte-Bereich</param>
    106. /// <param name="direction">Abfallen oder Steigend</param>
    107. /// <returns></returns>
    108. [MethodImpl(MethodImplOptions.AggressiveInlining)]
    109. private float Sigmoid(float x, float width, float height, DrawDirection direction)
    110. => (float)(height / (1 + Math.Pow(Math.E, (int) direction * ((6 / (width - (height / 10)) * x))))) - (height * .5f);
    111. public enum DrawDirection : int {
    112. TopToBottom = -1,
    113. BottomToTop = 1,
    114. LeftToRight = -1,
    115. RightToLeft = 1
    116. }
    117. }
    118. }

    Dieser Beitrag wurde bereits 8 mal editiert, zuletzt von „Facebamm“ ()

    @Facebamm Kann es sein, dass die Werte Deines enum DrawDirection falsch (weil Paarweise gleich) sind?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    VB-Fragen über PN / Konversation werden ignoriert!
    hier probier ma dieses Control:

    VB.NET-Quellcode

    1. Imports System.Windows.Forms
    2. Imports System.Drawing
    3. Imports System.Drawing.Drawing2D
    4. Public Class Bezier1 : Inherits Control
    5. Private Shared _GP As New GraphicsPath
    6. Private Shared _rctNorm As New Rectangle(0, 0, 10, 10)
    7. Shared Sub New()
    8. With _rctNorm
    9. #If True Then
    10. _GP.AddBezier(.Location, New Point(.Right \ 2, .Top), New Point(.Right \ 2, .Bottom), New Point(.Right, .Bottom))
    11. #ElseIf True Then
    12. _GP.AddBezier(.Location, New Point(.Right, .Top), New Point(.Left, .Bottom), New Point(.Right, .Bottom))
    13. #ElseIf True Then
    14. #End If
    15. End With
    16. End Sub
    17. Protected Overrides Sub OnPaint(e As PaintEventArgs)
    18. MyBase.OnPaint(e)
    19. With Me.ClientRectangle
    20. Using gp = _GP.CloneX, mtr As New Matrix(_rctNorm, {.Location, New Point(.Right, 0), New Point(0, .Bottom)})
    21. gp.Transform(mtr)
    22. e.Graphics.DrawPath(Pens.Peru, gp)
    23. End Using
    24. End With
    25. End Sub
    26. End Class