2010-11-30 8 views
5

¿Cuál es una buena forma de dibujar una curva suave con el punto de inicio y finalización especificado y restringido para estar dentro de un tubo lineal por partes como el siguiente?Colocación de una curva suave dentro de un tubo

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

¿Aceptarías una solución que dibujara un tubo lineal por partes alrededor de una curva suave? –

+0

El objetivo es construir automáticamente diagramas como el primero aquí (es decir, las líneas curvas de color dentro del gráfico) - http://en.wikipedia.org/wiki/Tree_decomposition –

Respuesta

4

Tal vez algo como esto:

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

Usted puede obtener un mejor control sobre la ruta mediante la adición/eliminación de los puntos de control para la Bézier. Como recuerdo, "A Bspline está contenida en el casco convexo de sus puntos de control", por lo que puede agregar puntos de control dentro de sus líneas gruesas (arriba y abajo de los puntos medios en un conjunto de puntos real, por ejemplo) para atar al Bezier cada vez más.

Editar

El siguiente es un primer intento para limitar la curva. La mala programación, sólo para tener la sensación de lo que puede hacerse:

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

Editar 2

O quizás mejor aún:

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

alt text

esto en e escala bastante bien cuando se agranda la imagen (las anteriores no)

+0

Buenas tramas, me gustan las primeras porque me parece mejor las restricciones de dibujo de la vida real (si quieres dibujarlo lo más recto posible sin salir del tubo o tener esquinas agudas), la escala no es realmente un problema porque puedo cambiar AbsoluteThickness a "Espesor" –

+0

@Yaro ¿Funciona? problema sigue sin abordarse? –

+0

sí, parece lo que necesito, gracias –

Cuestiones relacionadas