2010-11-30 25 views
5

Quelle est la meilleure façon de tracer une courbe régulière avec un point de départ et un point de fin spécifiés et de rester à l'intérieur d'un tube linéaire par morceaux comme ci-dessous?Mettre une courbe lisse à l'intérieur d'un tube

http://yaroslavvb.com/upload/save/so-tubes.png

coords = {1 -> {0, 2}, 2 -> {1/3, 1}, 3 -> {0, 0}, 
    4 -> {(1/3 + 2)/2, 1}, 5 -> {2, 1}, 6 -> {2 + 1/3, 0}, 
    7 -> {2 + 1/3, 2}}; 
gp = GraphPlot[graph, VertexCoordinateRules -> coords]; 
pr = {{-1, 3 + 1/3}, {-1 - 1/6, 3 + 1/6}}; 
scale = 50; 
is = -scale*(Subtract @@@ pr); 
lineThickness = 2/3; 
graph = {1 -> 2, 3 -> 2, 2 -> 4, 4 -> 5, 5 -> 6, 5 -> 7}; 
path = {3, 2, 4, 5, 7}; 
lp = Graphics[{Blue, Opacity[.5], 
    AbsoluteThickness[lineThickness*scale], Line[path /. coords]}]; 
Show[lp, gp, PlotRange -> pr, ImageSize -> is] 
+0

Accepteriez-vous une solution qui a attiré un tube linéaire par morceaux autour d'une courbe lisse? –

+0

L'objectif est automatiquement construit des diagrammes comme le premier ici (c'est à dire, les lignes courbes colorées à l'intérieur du graphique) - http://en.wikipedia.org/wiki/Tree_decomposition –

Répondre

4

Peut-être quelque chose comme ceci:

coords = {2 -> {1/3, 1}, 1 -> {0, 0}, 3 -> {(1/3 + 2)/2, 1}, 
    4 -> {2, 1}, 5 -> {2 + 1/3, 2}}; 
pr = {{-1, 3 + 1/3}, {-1 - 1/6, 3 + 1/6}}; 
scale = 50; 
is = -scale*(Subtract @@@ pr); 
lineThickness = 2/3; 
graph = {1 -> 2, 2 -> 3, 3 -> 4, 4 -> 5}; 
gp = GraphPlot[graph, VertexCoordinateRules -> coords]; 
path = {1, 2, 3, 4, 5}; 

f = BezierFunction[ 
    SortBy[coords /. Rule[x_, List[a_, b_]] -> List[a, b], First]]; 
pp = ParametricPlot[f[t], {t, 0, 1}]; 

lp = Graphics[{Blue, Opacity[.5], 
    AbsoluteThickness[lineThickness*scale], Line[path /. coords]}]; 
Show[pp, lp, gp, PlotRange -> pr, ImageSize -> is] 

alt text

Vous pouvez gagner un meilleur contrôle sur le chemin par l'ajout/suppression des points de contrôle pour la Bézier. Comme je me souviens "Une Bspline est contenue dans la coque convexe de ses points de contrôle", ainsi vous pouvez ajouter des points de contrôle à l'intérieur de vos lignes épaisses (en haut et en bas des points intermédiaires, par exemple) pour relier le Bézier de plus en plus.

Modifier

Ce qui suit est une première tentative pour délimiter la courbe. Une mauvaise programmation, juste pour obtenir le sentiment de ce qui peut être fait:

coords = {2 -> {1/3, 1}, 1 -> {0, 0}, 3 -> {(1/3 + 2)/2, 1}, 
    4 -> {2, 1}, 5 -> {2 + 1/3, 2}}; 
pr = {{-1, 3 + 1/3}, {-1 - 1/6, 3 + 1/6}}; 
scale = 50; 
is = -scale*(Subtract @@@ pr); 
lineThickness = 2/3; 
graph = {1 -> 2, 2 -> 3, 3 -> 4, 4 -> 5}; 
gp = GraphPlot[graph, VertexCoordinateRules -> coords]; 
path = {1, 2, 3, 4, 5}; 

kk = SortBy[coords /. Rule[x_, List[y_, z_]] -> List[y, z], 
    First]; f = BezierFunction[kk]; 
pp = ParametricPlot[f[t], {t, 0, 1}, Axes -> False]; 

mp = Table[{a = (kk[[i + 1, 1]] - kk[[i, 1]])/2 + kk[[i, 1]], 
    Interpolation[{kk[[i]], kk[[i + 1]]}, InterpolationOrder -> 1][ 
     a] + lineThickness/2}, {i, 1, Length[kk] - 1}]; 
mp2 = mp /. {x_, y_} -> {x, y - lineThickness}; 
kk1 = SortBy[Union[kk, mp, mp2], First] 
g = BezierFunction[kk1]; 
pp2 = ParametricPlot[g[t], {t, 0, 1}, Axes -> False]; 

lp = Graphics[{Blue, Opacity[.5], 
    AbsoluteThickness[lineThickness*scale], Line[path /. coords]}]; 
Show[pp, pp2, lp, gp, PlotRange -> pr, ImageSize -> is] 

alt text

Edit 2

Ou peut-être mieux encore:

g1 = Graphics[BSplineCurve[kk1]]; 
Show[lp, g1, PlotRange -> pr, ImageSize -> is]  

alt text

Ceci sur e échelles très bien lorsque vous agrandissez l'image (les précédents ne le font pas)

+0

Belles parcelles, j'aime mieux les premiers parce qu'il se rapproche la vraie vie dessinant des contraintes (vous voulez le dessiner aussi droit que possible sans quitter le tube ou avoir des angles aigus), la mise à l'échelle n'est pas vraiment un problème car je peux changer AbsoluteThickness en "épaisseur" –

+0

@Yaro Est-ce que ça fonctionne? problème reste non résolu? –

+0

oui, ça ressemble à ce dont j'ai besoin, merci –