Offset of a Polyline

Previously I’ve needed to offset a polygon which I’ve been able to do with some assistance from TIG.

Now I’m trying to figure out how to offset a locus of points/edges for a polyline (in the X and Y directions only, the points are always in the Z plane), given the edges and the amount to offset.

I don’t think any methods exist in the API for doing this sort of thing so it’s going to have to be something from scratch.

If you have any hints or ideas please feel free to post. I will provide my progression of the algorithm development as I work my way through this.

Does the Array.offset method not do that?

Would the Offset command work, for what you want, if applied manually?

@john_mcclenahan don’t confuse the GUI Offset Tool with the SketchUp Ruby API Array#offset method. The latter is really an extension of Ruby’s Array so that an Array of three coordinates can be treated as a point/position without explicitly converting it to a Point3d. It offsets a single point by a vector to create an Array of the coordinates of a new point.

@medeek I can’t tell you an algorithm, but if you look at the history of bugs and quirks of the GUI Offset Tool you will come to realize that this problem is a lot more subtle than it might at first seem. There are a lot of funky corner cases that have to be handled. Especially for curves, there is a design issue of whether you want to offset parallel to the segments of the curve or along the local radius of the curve at each vertex.

2 Likes

Here is my solution to the problem:

            # Create Rebar Path

    		perp_transform = Geom::Transformation.new(origin, [0, 0, 1], 90.degrees)
    		perp_vector = dir_vector.transform(perp_transform)
    		perp_vector.length = perpoffset
    		pt0b = @pts_aligned[0].offset(perp_vector)

    		rebar_path = [pt0b]

    		for index in 1 ... (@pts_aligned.size - 1)
    			index2 = index + 1
    			index0 = index - 1
    			vec2 = @pts_aligned[index2] - @pts_aligned[index]
    			angle2 = atan2(vec2.y, vec2.x)
    			vec0 = @pts_aligned[index0] - @pts_aligned[index]
    			angle0 = atan2(vec0.y, vec0.x)
    			phi = (angle0 - angle2) * 0.5
    			transformi = Geom::Transformation.new(@pts_aligned[index], [0, 0, 1], phi)
    			vec2.length = perpoffset/(sin(phi))
    			vecr = vec2.transform(transformi)
    			ptib = @pts_aligned[index].offset(vecr)
    				
    			rebar_path << ptib	
    		end

    		end_dir_vector = @pts_aligned[-1] - @pts_aligned[-2]
    		perp_end_transform = Geom::Transformation.new(@pts_aligned[-1], [0, 0, 1], 90.degrees)
    		end_perp_vector = end_dir_vector.transform(perp_end_transform)
    		end_perp_vector.length = perpoffset
    		pt1b = @pts_aligned[-1].offset(end_perp_vector)
    		rebar_path << pt1b

This seems to work reasonably well, I’ve been unable to break it. There may be a more efficient way to do this but it does work.