def compute_sag(pattern, opening): u, v = opening[0] if pattern.vertex_attribute(u, 'is_fixed'): a = pattern.vertex_attributes(u, 'xyz') aa = pattern.vertex_attributes(v, 'xyz') else: a = pattern.vertex_attributes(v, 'xyz') aa = pattern.vertex_attributes(u, 'xyz') u, v = opening[-1] if pattern.vertex_attribute(u, 'is_fixed'): b = pattern.vertex_attributes(u, 'xyz') bb = pattern.vertex_attributes(v, 'xyz') else: b = pattern.vertex_attributes(v, 'xyz') bb = pattern.vertex_attributes(u, 'xyz') span = distance_point_point_xy(a, b) apex = intersection_line_line_xy((a, aa), (b, bb)) if apex is None: rise = 0.0 else: midspan = midpoint_point_point_xy(a, b) rise = 0.5 * distance_point_point_xy(midspan, apex) sag = rise / span return sag
def parallelise_edges(xy, edges, targets, i_nbrs, ij_e, fixed=None, kmax=100, lmin=None, lmax=None, callback=None): """Parallelise the edges of a mesh to given target vectors. Parameters ---------- xy : list The XY coordinates of the vertices of the edges. edges : list The edges as pairs of indices in ``xy``. targets : list A target vector for every edge. i_nbrs : dict A list of neighbours per vertex. ij_e : dict An edge index per vertex pair. fixed : list, optional The fixed nodes of the mesh. Default is ``None``. kmax : int, optional Maximum number of iterations. Default is ``100``. lmin : list, optional Minimum length per edge. Default is ``None``. lmax : list, optional Maximum length per edge. Default is ``None``. callback : callable, optional A user-defined callback function to be executed after every iteration. Default is ``None``. Returns ------- None Examples -------- >>> """ if callback: if not callable(callback): raise Exception('The provided callback is not callable.') fixed = fixed or [] fixed = set(fixed) n = len(xy) for k in range(kmax): xy0 = [[x, y] for x, y in xy] uv = [[xy[j][0] - xy[i][0], xy[j][1] - xy[i][1]] for i, j in edges] lengths = [(dx**2 + dy**2)**0.5 for dx, dy in uv] if lmin: lengths[:] = [max(a, b) for a, b in zip(lengths, lmin)] if lmax: lengths[:] = [min(a, b) for a, b in zip(lengths, lmax)] for j in range(n): if j in fixed: continue nbrs = i_nbrs[j] x, y = 0.0, 0.0 for i in nbrs: ax, ay = xy0[i] if (i, j) in ij_e: e = ij_e[(i, j)] l = lengths[e] # noqa: E741 tx, ty = targets[e] x += ax + l * tx y += ay + l * ty else: e = ij_e[(j, i)] l = lengths[e] # noqa: E741 tx, ty = targets[e] x += ax - l * tx y += ay - l * ty xy[j][0] = x / len(nbrs) xy[j][1] = y / len(nbrs) for (i, j) in ij_e: e = ij_e[(i, j)] if lengths[e] == 0.0: c = midpoint_point_point_xy(xy[i], xy[j]) xy[i][:] = c[:][:2] xy[j][:] = c[:][:2] if callback: callback(k, xy, edges)
def parallelise_edges(xy, edges, i_nbrs, ij_e, target_vectors, target_lengths, fixed=None, line_constraints=None, kmax=100, callback=None): """Parallelise the edges of a mesh to given target vectors. Parameters ---------- xy : list The XY coordinates of the vertices of the edges. edges : list The edges as pairs of indices in ``xy``. i_nbrs : dict A list of neighbours per vertex. ij_e : dict An edge index per vertex pair. target_vectors : list A list with an entry for each edge representing the target vector or ``None``. target_lengths : list A list with an entry for each edge representing the target length or ``None``. fixed : list, optional The fixed nodes of the mesh. Default is ``None``. line_constraints : list, optional Line constraints applied to the free nodes. Default is an ``None`` in which case no line constraints are considered. kmax : int, optional Maximum number of iterations. Default is ``100``. callback : callable, optional A user-defined callback function to be executed after every iteration. Default is ``None``. Returns ------- None Notes ----- This implementation is based on the function ``compas_tna.equilibrium.parallelisation.parallelise_edges``. Examples -------- >>> """ if callback: if not callable(callback): raise Exception('The provided callback is not callable.') n = len(xy) for k in range(kmax): xy0 = [[x, y] for x, y in xy] uv = [[xy[j][0] - xy[i][0], xy[j][1] - xy[i][1]] for i, j in edges] lengths = [(dx**2 + dy**2)**0.5 for dx, dy in uv] for j in range(n): if j in fixed: continue nbrs = i_nbrs[j] x, y = 0.0, 0.0 len_nbrs = 0 for i in nbrs: if (i, j) in ij_e: e = ij_e[(i, j)] u, v = i, j signe = +1.0 else: e = ij_e[(j, i)] u, v = j, i signe = -1.0 if target_lengths[ e] is not None: # edges with constraint on length ... lij = target_lengths[e] if target_vectors[ e]: # edges with constraint on length + orientation tx, ty = target_vectors[e] else: # edges with constraint on length only if lengths[e] == 0.0: tx = ty = 0.0 else: tx = (xy0[v][0] - xy0[u][0]) / lengths[e] ty = (xy0[v][1] - xy0[u][1]) / lengths[ e] # check if xy0 is indeed better than xy else: if target_vectors[ e]: # edges with constraint on orientation only tx, ty = target_vectors[e] lij = lengths[e] else: continue # edges to discard ax, ay = xy0[i] x += ax + signe * lij * tx y += ay + signe * lij * ty len_nbrs += 1 if len_nbrs > 0: xy[j][0] = x / len_nbrs xy[j][1] = y / len_nbrs # check if line constraints are applied and project result if line_constraints: line = line_constraints[j] if line: pt_proj = project_point_line_xy(xy[j], line) xy[j][0] = pt_proj[0] xy[j][1] = pt_proj[1] for (i, j) in ij_e: e = ij_e[(i, j)] if lengths[e] == 0.0 or target_lengths[e] == 0.0: c = midpoint_point_point_xy(xy[i], xy[j]) xy[i][:] = c[:][:2] xy[j][:] = c[:][:2] if callback: callback(k, xy, edges)