Jump to content

Draw a polygon along a path

Recommended Posts



Firstly apologies if this question has been asked before but I cant find a solution anywhere...


I am trying to create a a 2D plan of a fairly simple road network for a temporary event. I have a base map showing the positions of the buildings, I have added perpendicular lines in between the buildings to get the centre points of the road and I can then draw a polyline through those points to give me a line going down the center of the road. 


I know that, centred on that line, I need enough space for a 2.5m path for vehicles and 1.5m path for pedestrians, so a 4m wide area in total.


What I would like to be able to do is something similar to "Extrude along path" but for a polygon? So I can create 2 polygons, one 2.5m wide and another 1.5m wide, next to each other on the center line I have drawn. 


I know I can achieve something similar with the "Double Line Polygon Tool" (draw a 4m wide polygon along the centre line, then a 2.5m wide polygon along one edge and then a 1.5m wide polygon along the other edge and delete the original 4m wide polygon leaving the remaining 2.5m and 1.5m polygons) but I was hoping for a way of firstly, drawing both polygons at once, and secondly, being able to edit the path of the resulting polygons as you can when extruding an object along a path? instead of having to move the individual points that make up the resulting polygon. That way I can easily tweek the polygon while maintaining the width?


I think what I'm looking for would be something like "Extend along Path"? But I cant see anything like it? 


I'm using VW2019

Share this post

Link to post

Hi Pat, thanks a lot.


I ended up creating my own "profiles" using lines (1x line 2.5m + 1x line 1.5m) next to each other, then extruding them along the path of the center line I created, converting the "extrude along path" object to a NURBS group and then each NURBS inside the group back into a polygon and using add surface...


Converting them to a NURBS first (rather that straight to polygons) meant that I could go into the group and select each "path way" and "road way" and individually to add the areas in one go rather than having to try and select all the associated polygons in one area.

Share this post

Link to post
Posted (edited)

@shodkin sounds like lots of work to go in and out of 3d.


Would the 2d Offset tool work for this? offset the ctr line 1.5m to one side, then offset ctr line 2.5m to other side. In the offset tool prefs, choose whether to close the shapes ( yes, if center line should show on the drawing and so that colorfill can be added). In the tool mode choose whether to keep the source (probably yes for 1st offset, no for 2nd. or keep both but may want to delete after so no polys lurking under the road). intersections will likely need separate objects. 



Edited by Benson Shaw
out on limb
  • Like 1

Share this post

Link to post

or if the center line is actual center rather than boundary btw the 2 uses,  offset 2m either side to establish one road edge, then offset back 2.5, then offset the new one 1.5 to establish the opposite road edge.  


or if boundary not needed, offset ctr line twice, 2m each side.



Share this post

Link to post

Hi Benson,

Thanks for this, its a lot closer to the elegant solution I was looking for.


Many thanks

Share this post

Link to post
Posted (edited)



Thanks for all the responses. Sorry it's taken a while to get around to this but I thought I'd post the solution I came up with incase it is useful to anyone else...


I ended up creating a VectorScript to do this, it had the advantage of allowing a lot more control over what is created and how!  Plus it can be created to work on multiple lines in one go, rather than having to be manually repeated over and over as well as adding class info to each object automatically as it is created.


In addition, the section at the beginning which reads in the path info (number of paths, width of each path etc) can also be read in from a symbol, which avoids having to enter all the information every time...


procedure CreatePaths;
	counter 										:integer;
	pathWidths										:Dynarray[] of real;
	totalNumPaths									:integer;
	pathBoundaries									:Dynarray[] of handle;
	paths											:Dynarray[] of handle;
	pathsCenterline									:Dynarray[] of handle;
	lineAStart, lineAEnd, lineBStart, lineBEnd		:vector;
	totalNumPathBoundaries							:integer;
	pathNumber										:integer;
	default, result									:string;
	tempPathA, tempPathB							:handle;
	tempInteger 									:integer;
	tempReal										:real;
	temp											:handle;
	currentCenterline 								:handle;
	highwayCenterlines 								:Dynarray of handle;
	totalCenterLines, activeCenterline 				:integer;
	{Check to see if at least one HIGHWAY centerline has been selected}
	if (FSActLayer <> Nil) then
		{Centerlines of selected HIGHWAYS are counted and array populated to hold them}
		Allocate highwayCenterlines[1..totalCenterlines];
		{HIGHWAYS are added to array}
		while (activeCenterline <= totalCenterlines) do
				highwayCenterlines[activeCenterline]:= FSActLayer;
				SetName(highwayCenterlines[activeCenterline], Concat('Highway-Centerline-',Num2StrF(activeCenterline)));
				activeCenterline := activeCenterline + 1;
		{all HIGHWAY centerlines are now stored in "highwayCenterlines[]"}
		{Ask user for total number of PATHS to be created along the HIGHWAY}
		default	:='';
		result	:= StrDialog('Enter Number of Paths...', default);
		totalNumPaths := Str2Num(result);
		counter	:=1;
		{Define an array to store the pathWidths as reals, total highway width is calculated and stored in
			last element (totalNumPaths+1)}
		Allocate pathWidths[1..totalNumPaths+1];
		Allocate paths[1..totalNumPaths];
		Allocate pathsCenterline[1..totalNumPaths];
		{Asks the user to input the widths of the PATHS and stores them from left to right in
			the direction of the highway path}
		while (counter <= totalNumPaths) do
				{Input path width is stored in pathsWidth array}
				result := StrDialog(Concat('Enter width of Path ', Num2StrF(counter)), default);
				pathWidths[counter] := Str2Num(result);	
				{total Highway width is updated and stored at end of array}
				pathWidths[totalNumPaths+1] := pathWidths[totalNumPaths+1] + pathWidths[counter];
				counter	:= counter + 1;			

		{all path widths are now stored in the pathWidths array with the total highway width stored at the
			end of array in element "totalNumPaths+1"}

			{populates the path boundaries with the centerline and outer boundaries}
				{NOTES: element 1 = HIGHWAY centerLine
						Element 2 = HIGHWAY righthand boundary
						Element 3 = HIGHWAY lefthand Boundary
						Element 4 = Final PATH boundary}
			while (activeCenterline <= totalCenterlines) do
				{Create an array to hold the PATH boundary lines, the 4 additional elements are required to
					store the final path boundaries and to store the centerline and boundaries for the HIGHWAY}
				totalNumPathBoundaries	:= totalNumPaths + 4;
				Allocate pathBoundaries[1..totalNumPathBoundaries];
				{Creates the HIGHWAY centerline}
				pathBoundaries[1] := highwayCenterlines[activeCenterline];
				SetClass(pathBoundaries[1], 'Highway-Centerline');
				{creates the HIGHWAY top boundary and sets its name and class information}
				pathBoundaries[2]		:= OffsetPolyN(pathBoundaries[1],   pathWidths[totalNumPaths+1]/2, false);
				SetClass(pathBoundaries[2], 'Highway-Boundary');
				{creates the HIGHWAY bottom boundary and sets its name and class information}
				pathBoundaries[3]		:= OffsetPolyN(pathBoundaries[1],  -pathWidths[totalNumPaths+1]/2, false);
				SetClass(pathBoundaries[3], 'Highway-Boundary');	
				{creates the final PATH boundary and sets its name and class information}
				pathBoundaries[4]		:= CreateDuplicateObject(pathBoundaries[3], NIL);
				SetClass(pathBoundaries[4], 'Path-Boundary');
				{increases the counter to the number of the next PATH to be created and
					begins creating the remaining PATHS}
				counter	:= 5;
				pathNumber :=1;
				while (counter <= totalNumPathBoundaries) do
					{Tempory PATH boundires are created to allow composed objects to be created
						later while retaining the original PATH boundaries}
					tempPathA := CreateDuplicateObject(pathBoundaries[counter-1], NIL);
					pathBoundaries[counter]:= OffsetPolyN(pathBoundaries[counter-1], pathWidths[pathNumber], false);
					{Classes and names are set for the PATH boundaries}
					SetClass(pathBoundaries[counter], 'Path-Boundary');
					tempPathB := CreateDuplicateObject(pathBoundaries[counter], NIL);
					SetName(tempPathB, 'TempB');
					{Retrieves the start and end points of the 2 temporary boundary paths and stores
						them in "lineStart" }
					GetPolylineVertex(tempPathA, 1, lineAStart.x, lineAStart.y, tempInteger, tempReal);
					GetPolylineVertex(tempPathA, getVertNum(tempPathA), lineAEnd.x, lineAEnd.y, tempInteger, tempReal);
					GetPolylineVertex(tempPathB, 1, lineBStart.x, lineBStart.y, tempInteger, tempReal);
					GetPolylineVertex(tempPathB, getVertNum(tempPathB), lineBEnd.x, lineBEnd.y, tempInteger, tempReal);
					{Deselects all objects on in the Vectorworks document}
					{Draws 2 lines which links the 2 PATH boundaries to create 4 connected lines
						and makes sure they are selected in the document}
					moveTo(lineAStart.x, lineAStart.y);
					lineTo(lineBStart.x, lineBStart.y);
					moveTo(lineBEnd.x, lineBEnd.y);
					lineTo(lineAEnd.x, lineAEnd.y);
					{selects the 2 PATH boundaries so that both PATH boundaries and
						the 2 end lines are now selected in the document}
					{Composes the selected lines, which should be the 2 boundary lines and 
						the 2 end lines, into a single polygon}
					{Assigns the newly created polygon to the "Path-Section" class}
					temp := LNewObj;
					SetClass(FSActLayer, 'Path-Section');
					paths[pathNumber] := FSActLayer;
					{Creates a new centerline for the PATH section and adds it to the 
						centerline array}
					pathsCenterline[pathNumber]		:= OffsetPolyN(tempPathA, (pathWidths[pathNumber]/2), false);
					SetClass(pathsCenterline[pathNumber], 'Path-Centerline');
					counter						:= counter +1;
					pathNumber					:= pathNumber + 1;
				activeCenterline := activeCenterline +1;
	else {Script had been run with no objects selected}
		AlrtDialog('Please select a centerline!');

{Run the program}

Hope its of use to someone, and if anyone ends up making it a bit shorter/simpler... please repost!


Many thanks

Edited by shodkin
  • Like 1

Share this post

Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


7150 Riverwood Drive, Columbia, Maryland 21046, USA   |   Contact Us:   410-290-5114


© 2018 Vectorworks, Inc. All Rights Reserved. Vectorworks, Inc. is part of the Nemetschek Group.

  • Create New...