2017-01-25 1 views
1

Comment créer un chemin d'onde sinusoïdale entre deux points?Onde sinusoïdale UIBezierPath entre deux points

Je suis capable de créer une trajectoire d'onde sinusoïdale à partir d'une origine, mais je ne suis pas sûr de savoir comment la direction peut être transformée de telle sorte que l'onde sinusoïdale se termine à un CGPoint cible.

Je voudrais animer un SKNode le long du chemin en utilisant SKAction.followPath

Répondre

3

La façon la plus simple de penser à ce sujet est de transformer le système de coordonnées, en rotation par l'angle entre les deux points, mise à l'échelle de la distance entre eux et traduire par le premier point (en supposant que le sinus commence à 0,0). L'OP a spécifié qu'il ne veut pas seulement dessiner la courbe (auquel cas il suffit d'appliquer la transformation au contexte graphique), mais plutôt d'utiliser la courbe dans un appel SpriteKit SKAction.followPath, la transformée doit donc être appliquée aux coordonnées du chemin, pas au contexte.

Voici une solution utilisant CGPath plutôt que UIBezierPath, mais ils sont équivalents, et vous pouvez obtenir la version de l'interface utilisateur simplement par let uip = UIBezierPath(cgPath: path). (Je préfère CoreGraphics car ils sont multi-plateforme).

Code Playground ...

class MyView: UIView { 

    override func draw(_ rect: CGRect) { 
     guard let context = UIGraphicsGetCurrentContext() else { return } 

     context.setFillColor(UIColor.red.cgColor) 
     context.fill(self.bounds) 

     // Calculate the transform 
     let p1 = CGPoint(x: 100, y: 100) 
     let p2 = CGPoint(x: 400, y: 400) 
     let dx = p2.x - p1.x 
     let dy = p2.y - p1.y 
     let d = sqrt(dx * dx + dy * dy) 
     let a = atan2(dy, dx) 
     let cosa = cos(a) // Calculate only once... 
     let sina = sin(a) // Ditto 

     // Initialise our path 
     let path = CGMutablePath() 
     path.move(to: p1) 

     // Plot a parametric function with 100 points 
     let nPoints = 100 
     for t in 0 ... nPoints { 
      // Calculate the un-transformed x,y 
      let tx = CGFloat(t)/CGFloat(nPoints) // 0 ... 1 
      let ty = 0.1 * sin(tx * 2 * CGFloat.pi) // 0 ... 2π, arbitrary amplitude 
      // Apply the transform 
      let x = p1.x + d * (tx * cosa - ty * sina) 
      let y = p1.y + d * (tx * sina + ty * cosa) 
      // Add the transformed point to the path 
      path.addLine(to: CGPoint(x: x, y: y)) 
     } 

     // Draw the path 
     context.setStrokeColor(UIColor.blue.cgColor) 
     context.addPath(path) 
     context.strokePath() 
    } 
} 

let v = MyView(frame: CGRect(origin: CGPoint(x: 0, y:0), size: CGSize(width: 500, height: 500))) 

Playground output...

+0

Merci pour cela! Je voulais créer un chemin au lieu de dessiner, donc les traductions sont sur le contexte. Je me demandais si mathématiquement, à l'intérieur de la boucle de génération, l'onde sinusoïdale peut être ajustée vers le point cible. La raison en est que je veux utiliser le chemin dans un appel SKAction.followPath – jarryd

+0

Cela fonctionne parfaitement, merci beaucoup! – jarryd

+1

De rien! C'est génial pour les maths - ça marche! – Grimxn

1

Pas clair ce que vous voulez, mais voici une possibilité en supposant que vous voulez une courbe de péché basculée:

On suppose que le point de départ est (0, 0) et le point final est (x, y).

Soit L la distance entre l'origine et le point de: L = sqrt (x^2 + y^2)

écrire une boucle qui commence à 0 et se termine à L, avec incrément dL et somme courante l (qui finit par courir entre 0 et L). Cette boucle nous permettra de créer les points sur votre Bézier.

Ensuite, la coordonnée x de votre graphe de péché sera: x_P = l cos * (thêta), allant de 0 à L * cos (thêta) = x

Pour obtenir la coordonnée y, nous ajoutons une sin fonction avec la période correcte à la ligne de pente entre l'origine et votre point: y_P = l * sin (thêta) + sin (2 * PI * l/L)

noter que, à l = L, (x_P, y_P) = (x, y) qui est comme il se doit.

Était-ce ce que vous vouliez? Ce n'est pas une rotation et ne se comportera donc pas lorsque l'angle thêta est grand.