The question is a little vague, so I will have some fun with this. You can make normals by switching tangents. For example, if the tangent t = {t1, t2} then the normal will be n = {-t2, t1}. With this in mind, we can make a roads generator with left and right using the following function:
makeRoad[ centerPointsList_, width_, id_] :=
Module[ { numberOfPoints, pairs, tangents, normals, leftBorder,
rightBorder, pointLocatorOnRoad, normalLocatorOnRoad},
numberOfPoints = Length[ centerPointsList ];
pairs =
With[ {p = Partition[ centerPointsList, 2, 1 ]},
Append[ p, Last[ p ] ] ];
tangents = Normalize[ #[[2]] - #[[1]] ] & /@ pairs;
normals = {-#[[2]], #[[1]]} & /@ tangents;
leftBorder =
Table[ centerPointsList[[i]] + normals[[i]] * width /2, {i, 1,
Length[ normals]}];
rightBorder =
Table[ centerPointsList[[i]] - normals[[i]] * width /2, {i, 1,
Length[ normals]}];
pointLocatorOnRoad =
With[ {localPointMap =
Thread[ {Range[ 0, 1, 1/(numberOfPoints - 1) ],
centerPointsList} ]},
Interpolation[ localPointMap, InterpolationOrder -> 1 ] ];
normalLocatorOnRoad =
With[ {localPointMap =
Thread[ {Range[ 0, 1, 1/(numberOfPoints - 1) ], normals} ]},
Interpolation[ localPointMap, InterpolationOrder -> 01 ] ];
$roadDatabase[id, "road" ] = {Line[ leftBorder ],
Line[ rightBorder ], Dashed, Line[ centerPointsList ]};
$roadDatabase[ id, "locate", s_ ] := pointLocatorOnRoad[ s ];
$roadDatabase[ id, "pointMid", s_ ] := {
Disk[ pointLocatorOnRoad[ s ], width / 4 ]};
$roadDatabase[ id, "pointLeft", s_ ] := {
Disk[ pointLocatorOnRoad[ s ] +
normalLocatorOnRoad[ s ] * width / 4 , width / 4 ]};
$roadDatabase[ id, "pointRight", s_ ] := {
Disk[ pointLocatorOnRoad[ s ] -
normalLocatorOnRoad[ s ] * width / 4 , width / 4 ]};
Graphics[ $roadDatabase[id, "road" ] ]
]
Evaluate above then, let's test it:
makeRoad[ Table[ {i, i^2}, {i, 0, 2, 0.2} ], 0.2, 1 ];
makeRoad[
Table[ {3, 2} + 2 {Cos[\[Theta]], Sin[\[Theta]]}, {\[Theta], 0,
2 \[Pi], 2 \[Pi] / 64} ], 0.2, 2 ];
Manipulate[
Graphics[ {$roadDatabase[1, "road" ], $roadDatabase[2, "road" ],
Red, $roadDatabase[ 1, "pointLeft", i ],
Blue, $roadDatabase[ 1, "pointRight", 1 - i ],
Red, $roadDatabase[ 2, "pointLeft", i ],
Blue, $roadDatabase[ 2, "pointRight", 1 - i ]} ],
{{i, 0}, 0, 1} ]
Above can be cleaned up to have $roadDatabase hidden and only accessed through some interface. You can also add other graphic primitives to put on your roads (as many as you want with each road being independent). It would be fun having objects for cars too and so on ... but fun is over. Hope this helps.