Virtueller Graph

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Danke Euch.
    Marco und MCDan

    Das Ergebnis ist definitiv besser.
    Siehe Bild. Der Rest sollte jetzt per Backgroundimage umgesetzt werden können.
    Ohne Titel 2.png

    Noch mal zu dem NSBezierPath:
    Wenn ich die Doku richtig verstanden habe, handelt es sich bei diesen Grafischen Elementen wirklich um Vectoren. Sprich Objekte, welche auch nachträglich verändert werden können.
    Gäbe es dann nicht auch die Möglichkeit einen transparenten NSBezierPath zu zeichnen und irgendwie alle 2 Pixel eine Linie bis zu den Schnittpunkt YPosition / NSBezierPath zu ziehen?
    Warum ich frage? Damit ich jene Linien animieren kann. Denn das ist eigentlich das Ziel.
  • Das habe ich befürchtet. Tiefstes Mittelalter! ;)

    Bei einem Shape-Layer brauchst Du nur den Start- und den Endpfad anzugeben. CoreAnimation interpoliert dann die Zwischenschritte, berechnet Beschleunigungen und Abbremsungen aus, kannst die Animation pausieren oder rückwärts laufen lassen usw.

    Mit CoreAnimation sind das 5 bis 10 Zeilen für die Animation
    „Meine Komplikation hatte eine Komplikation.“
  • mogiohh schrieb:


    Hi Markus. Leider funktioniert, dass was du vorhast so nicht. Denn Ich habe nur 5 Werte. Dein Weg würde voraussetzen, dass man pro Linie einen Wert hat. Das ist nicht der Fall. Ich könnte den Durchschnitt errechnen... nur wären jene dann nicht mehr "Weich" sonder "liniar".


    Beim Berechnen eine Splines erhältst Du auch nur einen neuen Datensatz mit Koordnaten, der die Kurve darstellt. Das Auslesen deines Y-Wertes zu einem X-Wert sollte kein Hindernis darstellen.

    NSBezierPath erzeugt intern genau so einen Datensatz. Da die Klasse aber zur Darstellung dient, kommt man an diesen Datensatz nicht ran. Ich weis zumindest nicht wie. Vielleicht hat einer der erfahreneren Entwickler dieses Wissen. Würde mich auch interessieren.

    Du kannst ja als Übung deine eigene Spline-Funktion implementieren. Macht Spass und man kann diese öfter nutzen als man denkt. :D
    goto fail;
  • MarkusM schrieb:

    NSBezierPath erzeugt intern genau so einen Datensatz. Da die Klasse aber zur Darstellung dient, kommt man an diesen Datensatz nicht ran. Ich weis zumindest nicht wie. Vielleicht hat einer der erfahreneren Entwickler dieses Wissen. Würde mich auch interessieren.

    NSBezierPath speichert erstmal nur die Pfadsegmente so, wie man sie ihm gegeben hat. An die kommt man mit -elementCount und -elementAtIndex:associatedPoints: heran, bringt aber nicht viel, weil es eben nur die Daten sind, die man eh schon hatte. NSBezierPath berechnet auch nie alle Werte genau, sondern ersetzt zum Zeichnen jedes Kurvensegment durch mehrere kleinere Liniensegmente, die klein genug sind, dass die Kurve weich aussieht (flattening). Man kann aus dem Originalpath per -bezierPathByFlatteningPath: einen flachen erzeugen, mit den oben genannten Methoden die Linienstücke auslesen und im Ergebnis den Schnittpunkt mit einer Vertikalen suchen. Ist aber in diesem Fall viel mehr Aufwand als sich seine eigenen Splines zu implementieren (auch weil es fummelig wird, einen NSBezierPath zu bauen, der "weich" genau durch die 5 Punkte verläuft).

    mogiohh schrieb:

    Ich könnte den Durchschnitt errechnen... nur wären jene dann nicht mehr "Weich" sonder "liniar".

    Wenn du linear interpolierst, kommt natürlich etwas Lineares raus. Wenn du etwas Weiches haben willst, musst du eine Interpolation verwenden, die etwas Weiches erzeugen kann - quadratisch, kubisch oder sonstwas. Ich glaube, dass es sehr hilfreich für dich wäre, dich mit den Konzepten von Interpolation und Splines zu beschäftigen. Die Mathematik dahinter ist weniger kompliziert als es am Anfang aussieht. Und wie MarkusM schon sagte: Macht Spass und man kann diese öfter nutzen als man denkt.
    Multigrad - 360°-Produktfotografie für den Mac
  • Ok zurück zu meinem Problem.

    Ich kann den NSBezierPath in IOS nicht verwenden. Ergo muss es über "CGContextRef" funktionieren.

    Laut MCDan kann ich per Funktion "CGPathAddCurveToPoint" kurven hintereinanderweg so zeichnen ohne das scharfe Ecken entstehen.

    Leider ist mir absolut nicht ersichtlich, wie jenes mac hen soll. Meine Kurven bekommen immer Ecken. Siehe Bild


    Bildschirmfoto 2014-07-28 um 12.13.38.png


    anbei der Code:

    Quellcode

    1. - (void)drawRect:(CGRect)rect{
    2. // Drawing code
    3. CGContextRef context = UIGraphicsGetCurrentContext();
    4. CGPathMoveToPoint(_plot, nil, 0, STAGE_H - (10 * VALUE_START));
    5. CGPathAddCurveToPoint(_plot,
    6. nil,
    7. .33 * valueDevider,
    8. STAGE_H - (10 * 2),
    9. .66 * valueDevider,
    10. STAGE_H - (10 * 4),
    11. 1 * valueDevider,
    12. STAGE_H - (10 * 6)
    13. );
    14. CGPathAddCurveToPoint(_plot,
    15. nil,
    16. 1.33 * valueDevider ,
    17. STAGE_H - (10 * 2),
    18. 1.66 * valueDevider,
    19. STAGE_H - (10 * 4),
    20. 2 * valueDevider,
    21. STAGE_H - (10 * 6)
    22. );
    23. CGContextAddPath(context, _plot);
    24. CGContextStrokePath(context);
    25. }
    Alles anzeigen


    Es gibt keinen weichen Übergang zwischen Kurve 1 und 2.


    Somit stehe ich wieder ganz am Anfang.
    Irgendjemand, der vielleicht eine Idee hat? Es kann doch nicht sein dass ich mir erst eineigenes Kurvenpfad Framework bauen muss um einfache weiche Linien zu zeichen.



  • Das Problem liegt ja nicht an den mangelnden Fähigkeiten von Core Graphics, und auch ein eigenes Kurvenpfad-Framework (Was soll das überhaupt sein?) wird Dich nicht weiterbringen.

    Warum beschreibst Du nicht, wo Deine Kurven herkommen und was für Daten Du hast?
    „Meine Komplikation hatte eine Komplikation.“
  • mogiohh schrieb:


    Irgendjemand, der vielleicht eine Idee hat? Es kann doch nicht sein dass ich mir erst eineigenes Kurvenpfad Framework bauen muss um einfache weiche Linien zu zeichen.


    Um's mal generell zu beantworten: Ja, manchmal kommt es vor, dass man Sachen tatsächlich selber programmieren muss. :D

    Konkret zu Deinem Problem: Du musst halt stetige Übergänge hinbekommen. Bei Bezierkurven bekommt man das dadurch hin, dass der vorletzte Stützpunkt des vorherigen Beziersegments mit dem zweiten Stützpunkt des nächsten Segments auf einer Gerade liegen. Die beiden beschreiben sozusagen die tangentiale Richtung des Kurvenbeginns bzw. -ende.

    ciao

    gandhi
    P.S. Wenn Du ein eigenes Kurvenframework machen willst: Ich hab' hier irgendwo noch 68K-Assemblercode zum Berechnen von Bezierkurven rumfliegen. ;)
  • macmoonshine schrieb:

    Das Problem liegt ja nicht an den mangelnden Fähigkeiten von Core Graphics, und auch ein eigenes Kurvenpfad-Framework (Was soll das überhaupt sein?) wird Dich nicht weiterbringen.

    Warum beschreibst Du nicht, wo Deine Kurven herkommen und was für Daten Du hast?



    Na klar. es gibt 5 Werte.
    zwischen 1 und 10.
    Jene 5 Werte sollen durch weiche Kurven verbunden sein.

    - ohne Kanten zwischen 2 Kurven.

    Stelle dir Berge vor dessen Täler und Gipfel "weich" nicht "spitz" sind.

    Das ist alles.


    Kurvenpfad-Framework (Was soll das überhaupt sein?)

    Eine Library mit Physikalischen Berechnungen. Kenne sowas von Flash noch damals.


    tatsächlich selber programmieren muss.

    Lol. Davon bin ich zu Anfangs auch ausgegangen. Nur hätte ich mir beim besten Willen einfach nicht vorstellen können, dass jene simplen Berechnungen noch nicht existent sind.
    Zumindestens ansatzweise.
    Zudem wurde des Öfteren behauptet, dass man für jene Kurvengestaltung on board Funktionen verwenden kann. Jenes hat mich leicht abdriften lassen.
    "Simple" setzt ich mal in Anführungssätze, denn ich habe absolut keine Ahnung wie ich jene Kurven mathematisch berechnen soll. ich hatte mal eine C Datei mit knapp 80 Funktionen. Ich finde aber leider auch nicht jene Weiche Kurvenberechnungen dort. Anscheinend muss ich jetzt doch auf eine Plot Library zurückgreifen um einen weichen 5 kurvigen Pfad zu zeichnen.

    Wo das Problem liegt ist mir schon klar. Um eine Kurve weich zu formen, muss Startpunkt von Pfad 2 mit Endpunkt von Pfad 1 angeglichen werden. Super interessantes Feld. Wenn ich mal ein paar Tag Zeit hätte sicherlich toll physikalische Fomeln zu lernen. Nur grade gibt es nur Zeit um auf Bestehendes zurückzugreifen.






    Dieser Beitrag wurde bereits 8 mal editiert, zuletzt von mogiohh ()

  • mogiohh schrieb:

    Stelle dir Berge vor dessen Täler und Gipfel "weich" nicht "spitz" sind.

    Ja, das ist eine Interpolation mit zusätzlichen Bedingingungen (z. B. Differenzierbarkeit).

    mogiohh schrieb:

    Das ist alles.

    Diese Zusatzbedingungen lassen sich in der Regel auch mathematisch ausdrücken und in die Interpolation mit einbeziehen. Deine Weichheitsanforderung kann beispielsweise bedeuten, dass die Ableitungen von den Interpolationsfunktionen an den gemeinsamen Stützstellen gleich sein müssen. Kubische Bezierkurven kann man beispielsweise entsprechend über die mittleren Stützpunkte konfigurieren.
    „Meine Komplikation hatte eine Komplikation.“
  • Ich habe eine Lösung für Dein Problem. Der Code ist allerdings schlimm.
    Ich paste Dir den wichtigen Teil unten, aber erstmal eine Erklärung.

    Du hast (als Beispiel) 3 Punkte. p1, p2 und p3.
    Du musst jetzt die Kontrollpunkte so finden, dass die Steigung in allen Punkten der Steigung zwischen dem linken und rechten Nachbarn entspricht.

    Jeder Punkt hat ja 2 Kontrollpunkte c1 und c2, die gedachte Line durch diese Punkte ist die Steigung im Punkt p.
    Der Kontrollpunkt c1 liegt quasi "vor" p und c2 quasi dahinter.

    Egal, dass wird jetzt zu kompliziert.
    Hier ist der Code der Dir aus Punkten p1 .... pX jeweils ein Objekt mit 2 Punkten und 2 Kontrollpunkten erstellt.

    Die kannst Du direkt an CGContextAddCurveToPoint übergeben.

    Ich habe das hier von Hand gemacht.
    Mein Code enthält noch CALayer code und andere Sachen. Er sollte aber funktionieren.

    Quellcode

    1. @interface CurvePoint : NSObject
    2. @property CGPoint p1;
    3. @property CGPoint p2;
    4. @property CGPoint c1;
    5. @property CGPoint c2;
    6. @end
    7. static CGFloat slope(CGPoint p1, CGPoint p2)
    8. {
    9. return (p2.y - p1.y) / (p2.x - p1.x);
    10. }
    11. static CGPoint ctrlPointBefore(CGPoint p1, CGPoint p2, CGPoint p3)
    12. {
    13. CGPoint c;
    14. CGFloat s;
    15. s = slope(p1, p3);
    16. c.x = p2.x - (p2.x - p1.x) / 2.0f;
    17. c.y = p2.y - s * (p2.x - p1.x) / 2.0f;
    18. return c;
    19. }
    20. static CGPoint ctrlPointAfter(CGPoint p1, CGPoint p2, CGPoint p3)
    21. {
    22. CGPoint c;
    23. CGFloat s;
    24. s = slope(p1, p3);
    25. c.x = p2.x + (p3.x - p2.x) / 2.0f;
    26. c.y = p2.y + s * (p3.x - p2.x) / 2.0f;
    27. return c;
    28. }
    29. - (void)setupCurve
    30. {
    31. CurvePoint *cp;
    32. NSMutableArray *points = [[NSMutableArray alloc] init];
    33. CGPoint p1 = CGPointMake(100.0f, 100.0f);
    34. CGPoint p2 = CGPointMake(150.0f, 200.0f);
    35. CGPoint p3 = CGPointMake(200.0f, 100.0f);
    36. CGPoint p4 = CGPointMake(250.0f, 200.0f);
    37. CGPoint p5 = CGPointMake(300.0f, 100.0f);
    38. cp = [[CurvePoint alloc] init];
    39. cp.p1 = p1;
    40. cp.p2 = p2;
    41. cp.c1 = CGPointMake(p1.x + (p2.x - p1.x) / 2.0f, p1.y);
    42. cp.c2 = ctrlPointBefore(p1, p2, p3);
    43. [points addObject:cp];
    44. cp = [[CurvePoint alloc] init];
    45. cp.p1 = p2;
    46. cp.p2 = p3;
    47. cp.c1 = ctrlPointAfter(p1, p2, p3);
    48. cp.c2 = ctrlPointBefore(p2, p3, p4);
    49. [points addObject:cp];
    50. cp = [[CurvePoint alloc] init];
    51. cp.p1 = p3;
    52. cp.p2 = p4;
    53. cp.c1 = ctrlPointAfter(p2, p3, p4);
    54. cp.c2 = ctrlPointBefore(p3, p4, p5);
    55. [points addObject:cp];
    56. cp = [[CurvePoint alloc] init];
    57. cp.p1 = p4;
    58. cp.p2 = p5;
    59. cp.c1 = ctrlPointAfter(p3, p4, p5);
    60. cp.c2 = CGPointMake(p5.x - (p5.x - p4.x) / 2.0f, p5.y);
    61. [points addObject:cp];
    62. }
    63. /* So würde gemalt
    64. for (i = 0; i < points.count; i++) {
    65. cp = (CurvePoint *)[points objectAtIndex:i];
    66. CGContextMoveToPoint(ctx, cp.p1.x, cp.p1.y);
    67. CGContextAddCurveToPoint(ctx, cp.c1.x, cp.c1.y, cp.c2.x, cp.c2.y, cp.p2.x, cp.p2.y);
    68. }
    69. */
    Alles anzeigen
  • Ich weiss echt nicht wo dein problem liegt.
    deine "weichen" kurven kannst du ganz einfach mit UIBezierpath machen. siehe angehängtes bild und folgenden code....

    Quellcode

    1. ​//// Bezier Drawing
    2. UIBezierPath* bezierPath = UIBezierPath.bezierPath;
    3. [bezierPath moveToPoint: CGPointMake(55.5, 207.5)];
    4. [bezierPath addCurveToPoint: CGPointMake(261.5, 207.5) controlPoint1: CGPointMake(197.5, 155.5) controlPoint2: CGPointMake(218.5, 207.5)];
    5. [bezierPath addCurveToPoint: CGPointMake(410.5, 154.5) controlPoint1: CGPointMake(304.5, 207.5) controlPoint2: CGPointMake(340.5, 154.5)];
    6. [bezierPath addCurveToPoint: CGPointMake(501.5, 218.5) controlPoint1: CGPointMake(480.5, 154.5) controlPoint2: CGPointMake(477.75, 205.25)];
    7. [bezierPath addCurveToPoint: CGPointMake(632.5, 190.5) controlPoint1: CGPointMake(525.25, 231.75) controlPoint2: CGPointMake(594.5, 226.5)];
    8. [UIColor.blackColor setStroke];
    9. bezierPath.lineWidth = 1;
    10. [bezierPath stroke];
    Dateien