def calc_bezier_round_points(apos, avec, bpos, bvec, radius): _, alen, blen = vec2.find_intersection(apos, avec, bpos, bvec) debug = False if alen <= radius: print('BezierRound: alen < radius, {} < {}, at {}'.format( alen, radius, apos)) debug = True if blen <= radius: print('BezierRound: blen < radius, {} < {}, at {}'.format( blen, radius, bpos)) debug = True amid = vec2.scale(alen - radius, avec, apos) bmid = vec2.scale(blen - radius, bvec, bpos) #add_line( apos, amid, layer, width ) #add_line( bpos, bmid, layer, width ) angle = vec2.angle(avec, bvec) if angle < 0: #angle += 360 angle *= -1 ndivs = int(round(angle / 4.5)) #print( 'BezierRound: angle = {}, ndivs = {}'.format( angle, ndivs ) ) coeff = (math.sqrt(0.5) - 0.5) / 3 * 8 #print( 'coeff = {}'.format( coeff ) ) actrl = vec2.scale(alen + (coeff - 1) * radius, avec, apos) bctrl = vec2.scale(blen + (coeff - 1) * radius, bvec, bpos) pnts = [amid, actrl, bctrl, bmid] curv = [apos] for pos in calc_bezier_points(pnts, ndivs, debug): curv.append(pos) curv.append(bpos) return curv
def calc_spline_points(apos, avec, bpos, bvec, num_divs, vec_scale): curv = [apos] for i in range(1, num_divs): t = float(i) / num_divs pos = vec2.add(vec2.scale(h0(t), apos), vec2.scale(h1(t), bpos)) vec = vec2.add(vec2.scale(g0(t), (avec[1], -avec[0])), vec2.scale(g1(t), (bvec[1], -bvec[0]))) pos = vec2.scale(vec_scale, vec, pos) curv.append(pos) curv.append(bpos) return curv
def add_wire_offsets_straight(prms_a, prms_b, net, layer, width, radius): pos_a, offsets_a = prms_a pos_b, offsets_b = prms_b pnts_a = [pos_a] pnts_b = [pos_b] for off_len_a, off_angle_a in offsets_a: pos_a = vec2.scale(off_len_a, vec2.rotate(-off_angle_a), pos_a) pnts_a.append(pos_a) for off_len_b, off_angle_b in offsets_b: pos_b = vec2.scale(off_len_b, vec2.rotate(-off_angle_b), pos_b) pnts_b.append(pos_b) pnts = pnts_a for pnt_b in reversed(pnts_b): pnts.append(pnt_b) add_wire_straight(pnts, net, layer, width, radius)
def calc_bezier_corner_points(apos, avec, bpos, bvec, pitch=1, ratio=0.7): _, alen, blen = vec2.find_intersection(apos, avec, bpos, bvec) debug = False if alen <= 0: print('BezierCorner: alen = {} < 0, at {}'.format(alen, apos)) debug = True if blen <= 0: print('BezierCorner: blen = {} < 0, at {}'.format(blen, bpos)) debug = True # if debug: # return [] actrl = vec2.scale(alen * ratio, avec, apos) bctrl = vec2.scale(blen * ratio, bvec, bpos) ndivs = int(round((alen + blen) / pitch)) pnts = [apos, actrl, bctrl, bpos] curv = calc_bezier_points(pnts, ndivs, debug) return curv
def calc_bezier_points(pnts, num_divs, debug=False): num_pnts = len(pnts) tmp = [(0, 0) for n in range(num_pnts)] curv = [pnts[0]] for i in range(1, num_divs): t = float(i) / num_divs s = 1 - t for n in range(num_pnts): tmp[n] = pnts[n] for L in range(num_pnts - 1, 0, -1): for n in range(L): tmp[n] = vec2.scale(s, tmp[n], vec2.scale(t, tmp[n + 1])) curv.append(tmp[0]) curv.append(pnts[-1]) #add_lines( curv, layer, width ) if debug: # debug for pnt in pnts: add_arc(pnt, vec2.add(pnt, (20, 0)), 360, 'F.Fab', 4) return curv
def add_wire_offsets_directed(prms_a, prms_b, net, layer, width, radius): pos_a, offsets_a, angle_a = prms_a pos_b, offsets_b, angle_b = prms_b pnts_a = [pos_a] pnts_b = [pos_b] for off_len_a, off_angle_a in offsets_a: pos_a = vec2.scale(off_len_a, vec2.rotate(-off_angle_a), pos_a) pnts_a.append(pos_a) for off_len_b, off_angle_b in offsets_b: pos_b = vec2.scale(off_len_b, vec2.rotate(-off_angle_b), pos_b) pnts_b.append(pos_b) apos = pnts_a[-1] bpos = pnts_b[-1] dir_a = vec2.rotate(-angle_a) dir_b = vec2.rotate(-angle_b) xpos, _, _ = vec2.find_intersection(apos, dir_a, bpos, dir_b) pnts = pnts_a pnts.append(xpos) for pnt_b in reversed(pnts_b): pnts.append(pnt_b) add_wire_straight(pnts, net, layer, width, radius)
def add_wire_straight(pnts, net, layer, width, radius=0): rpnts = [] for idx, curr in enumerate(pnts): if idx == 0 or idx + 1 == len(pnts): # first or last rpnts.append(curr) continue prev = pnts[idx - 1] next = pnts[idx + 1] vec_a = vec2.sub(prev, curr) vec_b = vec2.sub(next, curr) len_a = vec2.length(vec_a) len_b = vec2.length(vec_b) length = min(abs(radius), len_a / 2 if idx - 1 > 0 else len_a, len_b / 2 if idx + 1 < len(pnts) - 1 else len_b) if length < 10**(-PointDigits): rpnts.append(curr) else: if radius < 0: # and abs( vec2.dot( vec_a, vec_b ) ) < len_a * len_b * 0.001: # bezier circle num_divs = 15 cef = (math.sqrt(0.5) - 0.5) / 3 * 8 bpnts = [] bpnts.append(vec2.scale(length / len_a, vec_a, curr)) bpnts.append(vec2.scale(length / len_a * cef, vec_a, curr)) bpnts.append(vec2.scale(length / len_b * cef, vec_b, curr)) bpnts.append(vec2.scale(length / len_b, vec_b, curr)) num_pnts = len(bpnts) tmp = [(0, 0) for n in range(num_pnts)] rpnts.append(bpnts[0]) for i in range(1, num_divs): t = float(i) / num_divs s = 1 - t for n in range(num_pnts): tmp[n] = bpnts[n] for L in range(num_pnts - 1, 0, -1): for n in range(L): tmp[n] = vec2.scale(s, tmp[n], vec2.scale(t, tmp[n + 1])) rpnts.append(tmp[0]) rpnts.append(bpnts[-1]) else: rpnts.append(vec2.scale(length / len_a, vec_a, curr)) rpnts.append(vec2.scale(length / len_b, vec_b, curr)) for idx, curr in enumerate(rpnts): if idx == 0: continue prev = rpnts[idx - 1] if vec2.distance(prev, curr) > 0.01: add_track(prev, curr, net, layer, width)
def add_wire_zigzag(pos_a, pos_b, angle, delta_angle, net, layer, width, radius): mid_pos = vec2.scale(0.5, vec2.add(pos_a, pos_b)) dir = vec2.rotate(-angle) mid_dir1 = vec2.rotate(-angle + delta_angle) mid_dir2 = vec2.rotate(-angle - delta_angle) _, ka1, _ = vec2.find_intersection(pos_a, dir, mid_pos, mid_dir1) _, ka2, _ = vec2.find_intersection(pos_a, dir, mid_pos, mid_dir2) mid_angle = (angle - delta_angle) if abs(ka1) < abs(ka2) else (angle + delta_angle) add_wire_directed((pos_a, angle), (mid_pos, mid_angle), net, layer, width, radius) add_wire_directed((pos_b, angle), (mid_pos, mid_angle), net, layer, width, radius)
def drawRect(pnts, layer, R=75, width=2): if R > 0: arcs = [] for idx, a in enumerate(pnts): b = pnts[idx - 1] vec = vec2.sub(b, a) length = vec2.length(vec) delta = vec2.scale(R / length, vec) na = vec2.add(a, delta) nb = vec2.sub(b, delta) ctr = vec2.add(nb, (delta[1], -delta[0])) arcs.append((ctr, na, nb)) add_line(na, nb, layer, width) for idx, (ctr, na, nb) in enumerate(arcs): arc = add_arc2(ctr, nb, arcs[idx - 1][1], -90, layer, width) # print( "na ", pnt.mils2unit( vec2.round( na ) ) ) # print( "start", arc.GetArcStart() ) # print( "nb ", pnt.mils2unit( vec2.round( nb ) ) ) # print( "end ", arc.GetArcEnd() ) else: for idx, a in enumerate(pnts): b = pnts[idx - 1] add_line(a, b, layer, width)
def draw_corner(cnr_type, a, cnr_data, b, layer, width, dump=False): apos, aangle = a bpos, bangle = b avec = vec2.rotate(aangle) bvec = vec2.rotate(bangle + 180) curv = None if cnr_type != Bezier and abs(vec2.dot(avec, bvec)) > 0.999: cnr_type = Line #print( avec, bvec ) if cnr_type == Line: add_line(apos, bpos, layer, width) elif cnr_type == Linear: xpos, alen, blen = vec2.find_intersection(apos, avec, bpos, bvec) if cnr_data == None: add_line(apos, xpos, layer, width) add_line(bpos, xpos, layer, width) else: delta = cnr_data[0] #print( delta, alen, xpos ) amid = vec2.scale(alen - delta, avec, apos) bmid = vec2.scale(blen - delta, bvec, bpos) add_line(apos, amid, layer, width) add_line(bpos, bmid, layer, width) add_line(amid, bmid, layer, width) elif cnr_type == Bezier: num_data = len(cnr_data) alen = cnr_data[0] blen = cnr_data[-2] ndivs = cnr_data[-1] apos2 = vec2.scale(alen, avec, apos) bpos2 = vec2.scale(blen, bvec, bpos) pnts = [apos, apos2] if num_data > 3: for pt in cnr_data[1:num_data - 2]: pnts.append(pt) pnts.append(bpos2) pnts.append(bpos) curv = calc_bezier_points(pnts, ndivs) add_lines(curv, layer, width) elif cnr_type == BezierRound: radius = cnr_data[0] # _, alen, blen = vec2.find_intersection( apos, avec, bpos, bvec ) # debug = False # if alen <= radius: # print( 'BezierRound: alen < radius, {} < {}, at {}'.format( alen, radius, apos ) ) # debug = True # if blen <= radius: # print( 'BezierRound: alen < radius, {} < {}, at {}'.format( blen, radius, bpos ) ) # debug = True # amid = vec2.scale( alen - radius, avec, apos ) # bmid = vec2.scale( blen - radius, bvec, bpos ) # add_line( apos, amid, layer, width ) # add_line( bpos, bmid, layer, width ) # angle = vec2.angle( avec, bvec ) # if angle < 0: # #angle += 360 # angle *= -1 # ndivs = int( round( angle / 4.5 ) ) # #print( 'BezierRound: angle = {}, ndivs = {}'.format( angle, ndivs ) ) # coeff = (math.sqrt( 0.5 ) - 0.5) / 3 * 8 # #print( 'coeff = {}'.format( coeff ) ) # actrl = vec2.scale( alen + (coeff - 1) * radius, avec, apos ) # bctrl = vec2.scale( blen + (coeff - 1) * radius, bvec, bpos ) # pnts = [amid, actrl, bctrl, bmid] curv = calc_bezier_round_points(apos, avec, bpos, bvec, radius) add_lines(curv, layer, width) elif cnr_type == Round: radius = cnr_data[0] # print( 'Round: radius = {}'.format( radius ) ) # print( apos, avec, bpos, bvec ) xpos, alen, blen = vec2.find_intersection(apos, avec, bpos, bvec) # print( xpos, alen, blen ) debug = False if not is_supported_round_angle(aangle): pass #print( 'Round: warning aangle = {}'.format( aangle ) ) #debug = True if not is_supported_round_angle(bangle): pass #print( 'Round: warning bangle = {}'.format( bangle ) ) #debug = True if alen < radius: print('Round: alen < radius, {} < {}'.format(alen, radius)) debug = True if blen < radius: print('Round: blen < radius, {} < {}'.format(blen, radius)) debug = True if debug: add_arc(xpos, vec2.add(xpos, (10, 0)), 360, layer, width) return b, curv angle = vec2.angle(avec, bvec) angle = math.ceil(angle * 10) / 10 tangent = math.tan(abs(angle) / 2 / 180 * math.pi) side_len = radius / tangent # print( 'angle = {}, radius = {}, side_len = {}, tangent = {}'.format( angle, radius, side_len, tangent ) ) amid = vec2.scale(-side_len, avec, xpos) bmid = vec2.scale(-side_len, bvec, xpos) add_line(apos, amid, layer, width) add_line(bpos, bmid, layer, width) aperp = (-avec[1], avec[0]) if angle >= 0: ctr = vec2.scale(-radius, aperp, amid) add_arc2(ctr, bmid, amid, 180 - angle, layer, width) else: ctr = vec2.scale(+radius, aperp, amid) add_arc2(ctr, amid, bmid, 180 + angle, layer, width) elif cnr_type == Spline: vec_scale = cnr_data[0] ndivs = int(round(vec2.distance(apos, bpos) / 2.0)) avec = vec2.rotate(aangle + 90) bvec = vec2.rotate(bangle - 90) curv = calc_spline_points(apos, avec, bpos, bvec, ndivs, vec_scale) add_lines(curv, layer, width) return b, curv