Home Forums Nazca Bent Taper Reply To: Bent Taper

#5258
Douglas
Participant

And here comes a big code…
I managed to reuse your polyline2polygon in a brute force way.
Solved my problem for some cases, but not for all.
On my code I see some spurious points in the beginning of the bent taper.
Would you know why, and mainly, how to solve that?

Thanks

import nazca as nd
import nazca.generic_bend as gb
import nazca.util as util

def polyline2polygonTapered(xy, widthIn=0.49, widthOut=0.49, miter=0.5):
    """Return a polygon that contains the outline points of a tapered polyline

    Since we have to specify the outline of two or more segments that make
    an angle, we have to know what to do with the gap between those
    segments at the outside of the corner. In order to determine which
    points are on the outside of the corner we use the following algorithm:
    Given a line segment between P0 (x0,y0) and P1 (x1,y1), another point P
    (x,y) has the following relationship to the line segment. Compute
    (y - y0) (x1 - x0) - (x - x0) (y1 - y0). If it is less than 0 then P is
    to the right of the line segment, if greater than 0 it is to the left,
    if equal to 0 then it lies on the line segment.
    The routine fills an array from the start with the anticlockwise points
    and from the end with the clockwise points.

    Args:
        xy (list): list of (x,y) points that hold the polygon
        width (float): width of the polyline (default 2)
        miter (float): maximum fraction of the width before an extra point
            is added in outside corners (default 0.5)

    Returns:
        list of (float, float): the polygon
    """

    # the fraction of the width of the line segments that is used to
    # determine if a single point is sufficient to describe the outline, or
    # that two points are needed (miter limit).
    dsqrmax = (miter * widthIn)**2
    n = len(xy)
    if n < 2:
        raise ValueError("Polyline2polygon: need at least 2 points for polyline.")
    # Compute array of widths
    widths = []
    for i in range(len(xy)):
        widths.append(widthIn+(widthOut-widthIn)/(len(xy)+1)*(i+1))
    # Start with the first two points
    dxy1 = util.pointdxdy(xy, 0, widths[0])
    cxy1 = util.corner(xy, 0, dxy1)
    xy_start = [cxy1[0]]
    xy_end = [cxy1[1]]
    for i in range(1, n-1): # loop over the points in the polyline
        dxy0 = dxy1
        # Shift corner points from next to current segment.
        cxy0 = cxy1
        # Get corner points for next segment.
        dxy1 = util.pointdxdy(xy, i, widths[i+1])
        cxy1 = util.corner(xy, i, dxy1)
        # left or right turn
        lrt = (xy[i+1][1]-xy[i-1][1]) * (xy[i][0]-xy[i-1][0]) -\
              (xy[i+1][0]-xy[i-1][0]) * (xy[i][1]-xy[i-1][1])
        # Distance (squared) between the two points at the kink (2->4 == 3->5)
        dsqr = (cxy1[0][0] - cxy0[2][0])**2 + (cxy1[0][1] - cxy0[2][1])**2
        # the inside corner point is on the intersection of the two inside
        # lines.
        if lrt > 0: # Left turn
            # Outside corner: use two points, unless these points are close.
            if dsqr < dsqrmax:
                xy_start.append(util.intersect(cxy0[0], cxy0[2], cxy1[0], cxy1[2]))
            else:
                xy_start.append((xy[i][0]+dxy0[0], xy[i][1]+dxy0[1]))
                xy_start.append((xy[i][0]+dxy1[0], xy[i][1]+dxy1[1]))
            # Inside corner: always intersect.
            xy_end.append(util.intersect(cxy0[1], cxy0[3], cxy1[1], cxy1[3]))
        elif lrt < 0: # Right turn
            # Outside corner: use two points, unless these points are close.
            if dsqr < dsqrmax:
                xy_end.append(util.intersect(cxy0[1], cxy0[3], cxy1[1], cxy1[3]))
            else:
                xy_end.append((xy[i][0]-dxy0[0], xy[i][1]-dxy0[1]))
                xy_end.append((xy[i][0]-dxy1[0], xy[i][1]-dxy1[1]))
            # Inside corner: always intersect.
            xy_start.append(util.intersect(cxy0[0], cxy0[2], cxy1[0], cxy1[2]))
        else:
            continue # No turn: goto next point
    # Last two points.
    xy_start.append(cxy1[2])
    xy_end.append(cxy1[3])
    return xy_start + list(reversed(xy_end))

########
# Actual testing code
########
# Define interconnect
nd.add_layer2xsection(xsection='WgXS', layer=10, accuracy=0.001)
myIC = nd.interconnects.Interconnect(radius=10, width=0.49, xs='WgXS')

# TESTING THE TAPERED BEND - From bend to str
# Defining bends
InBend = myIC.bend(angle=-50,radius=8.5,width=0.450).put(0,0)
OutStr = myIC.strt(length=10).put(70,0)

xya = nd.diff(InBend.pin['b0'],OutStr.pin['a0'].rot(180))        
A, B, L ,Rmin = gb.gb_coefficients(xya,Rin=30, Rout=-30) # Curve parameters
xy = gb.curve2polyline(gb.gb_point, 
                               xya, 
                               0.001, (A, B, L)) # Curve points
xy = polyline2polygonTapered(xy,widthIn=0.45,widthOut=0.49)
nd.Polygon(layer=10, points=xy).put(InBend.pin['b0'])
        

# TESTING THE TAPERED BEND  - From bend to str with initial radius not as desired
# Defining bends
InStr = myIC.strt(length=10).put(0,18)
OutBend = myIC.bend(angle=-50,radius=8.5,width=0.450).put(70,15,50)

xya = nd.diff(InStr.pin['b0'],OutBend.pin['a0'].rot(180))        
A, B, L ,Rmin = gb.gb_coefficients(xya,Rin=30,Rout=30) # Curve parameters
xy = gb.curve2polyline(gb.gb_point, 
                               xya, 
                               0.001, (A, B, L)) # Curve points
xy = polyline2polygonTapered(xy,widthIn=0.49,widthOut=0.45)
nd.Polygon(layer=10, points=xy).put(InStr.pin['b0'])

# TESTING THE TAPERED BEND  - From bend to str - with desired initial radius
# Defining bends
InStr = myIC.strt(length=10).put(0,36)
OutBend = myIC.bend(angle=-50,radius=8.5,width=0.450).put(70,33,50)

xya = nd.diff(InStr.pin['b0'],OutBend.pin['a0'].rot(180))        
A, B, L ,Rmin = gb.gb_coefficients(xya,Rin=-30,Rout=30) # Curve parameters
xy = gb.curve2polyline(gb.gb_point, 
                               xya, 
                               0.001, (A, B, L)) # Curve points
xy = polyline2polygonTapered(xy,widthIn=0.49,widthOut=0.45)
nd.Polygon(layer=10, points=xy).put(InStr.pin['b0'])

nd.export_gds(filename='issue3.gds')