def an_envelop(width, height, spec):
    envelop_group, envelop_width, envelop_height = a_rectangle(width,
                                                               height,
                                                               spec=spec)

    # two lines from center to top left and top right to give it an envelop look
    center_point = Point(width / 2, height / 2)
    top_left_point = Point(0, 0)
    top_right_point = Point(width, 0)
    points = [top_left_point, center_point, top_right_point, top_left_point]

    # the lines' color is shapes stroke
    line_style = StyleBuilder(spec['style']).getStyle()
    line1_svg = Line(x1=0,
                     y1=0,
                     x2=width / 2,
                     y2=height / 2,
                     style=spec['style'])
    line2_svg = Line(x1=width / 2,
                     y1=height / 2,
                     x2=width,
                     y2=0,
                     style=spec['style'])
    line1_svg.set_style(line_style)
    line2_svg.set_style(line_style)
    envelop_group.addElement(line1_svg)
    envelop_group.addElement(line2_svg)

    return envelop_group, width, height
def a_lightning(width, height, spec):
    diagonal = math.sqrt(width * width + height * height)
    len_mb_mt = (diagonal / 2) * 0.3
    len_mt_tl = (diagonal / 2) * 0.4
    angle_bl_tr = math.atan(height / width)
    angle_mt_tl = math.pi / 2

    bottom_left = Point(0, height)
    mid_top = bottom_left.to_point(math.degrees(angle_bl_tr),
                                   diagonal / 2 + len_mb_mt / 2)
    mid_bottom = bottom_left.to_point(math.degrees(angle_bl_tr),
                                      diagonal / 2 - len_mb_mt / 2)
    top_left = mid_top.to_point(math.degrees(angle_mt_tl + angle_bl_tr),
                                len_mt_tl)

    top_right = Point(width, 0)
    bottom_right = mid_bottom.to_point(
        -math.degrees(angle_mt_tl - angle_bl_tr), len_mt_tl)

    lightning_points = [
        bottom_left, top_left, mid_top, top_right, bottom_right, mid_bottom
    ]
    # lightning_points = [bottom_left, top_left, mid_top]

    lightning_svg = Polygon(points=points_to_str(lightning_points))
    lightning_svg.set_style(StyleBuilder(spec['style']).getStyle())

    return lightning_svg, width, height
def a_gear(radius, spec):
    mark_length = radius * 0.3
    circle_radius = radius - mark_length
    gear_group_svg, _, _ = a_circle(radius=circle_radius, spec=spec)

    # the inner circle
    inner_circle_radius = radius * 0.1
    inner_circle_svg = Circle(cx=circle_radius,
                              cy=circle_radius,
                              r=inner_circle_radius)
    inner_circle_svg.set_style(StyleBuilder(spec['style']).getStyle())
    gear_group_svg.addElement(inner_circle_svg)

    # the hour marks
    center_point = Point(circle_radius, circle_radius)
    for mark in range(0, 9):
        point_on_circle = center_point.to_point(40 * mark, circle_radius)
        point_outside = center_point.to_point(40 * mark,
                                              circle_radius + mark_length)
        mark_svg = Line(x1=point_on_circle.x,
                        y1=point_on_circle.y,
                        x2=point_outside.x,
                        y2=point_outside.y)
        mark_svg.set_style(StyleBuilder(spec['style']).getStyle())
        gear_group_svg.addElement(mark_svg)

    # add to group
    return gear_group_svg, radius * 2, radius * 2
    def connect_southward(self, from_lane_number, point_from, to_lane_number, point_to):
        # see if there is one or more lanes between the from-lane and to-lane
        if to_lane_number > from_lane_number + 1:
            # yes we have lanes in between

            # we bypass the northmost (first) lane
            lane_number_to_bypass = from_lane_number + 1
            lane_to_bypass = self.pool_collection_list[lane_number_to_bypass]
            margin_spec = self.margin_spec(lane_number_to_bypass)
            points_to_bypass_the_lane = lane_to_bypass.bypass_vertically(coming_from=point_from, going_to=point_to, margin_spec=margin_spec)

            return [point_from] + points_to_bypass_the_lane + self.connect_southward(lane_number_to_bypass, points_to_bypass_the_lane[-1], to_lane_number, point_to)

        else:
            # there is no lane in between
            if point_from.y == point_to.y:
                # they are on the same horizontal line - inside a lane routing area
                return [point_from, Point(point_from.x, point_to.y), point_to]
            else:
                # they are not on a line, we need a connecting path, looks like one or both of them are at eastern/western boundary
                # the north (point_from) needs to come down to southern boundary
                point_from_next = Point(point_from.x, self.pool_collection_list[from_lane_number].element.xy.y + self.pool_collection_list[from_lane_number].element.height + self.margin_spec(to_lane_number)['bottom'])

                # the south (point_to) needs to move up to northern boundary
                point_to_next = Point(point_to.x, self.pool_collection_list[to_lane_number].element.xy.y - self.margin_spec(to_lane_number)['top'])

                return [point_from, point_from_next, point_to_next, point_to]
def an_upword_arrowhead(width, height, spec):
    mid_point = Point(width / 2, height / 2)
    top_point = Point(width / 2, 0)
    left_point = Point(0, height)
    right_point = Point(width, height)

    arrowhead_points = [mid_point, left_point, top_point, right_point]

    arrowhead_svg = Polygon(points=points_to_str(arrowhead_points))
    arrowhead_svg.set_style(StyleBuilder(spec['style']).getStyle())

    return arrowhead_svg, width, height
    def snap_points(self, width, height):
        snaps = super().snap_points(width, height)

        # add two more (slight left and slight right) for north-middle)
        snaps['north']['middle'].append(
            SnapPoint(point=Point(width * 0.40, self.snap_point_offset * -1)))
        snaps['north']['middle'].append(
            SnapPoint(point=Point(width * 0.60, self.snap_point_offset * -1)))

        # add two more (slight left and slight right) for south-middle)
        snaps['south']['middle'].append(
            SnapPoint(point=Point(width * 0.40, height +
                                  self.snap_point_offset * 1)))
        snaps['south']['middle'].append(
            SnapPoint(point=Point(width * 0.60, height +
                                  self.snap_point_offset * 1)))

        # add two more (slight up and slight down) for east-middle)
        snaps['east']['middle'].append(
            SnapPoint(point=Point(width + self.snap_point_offset * 1, height *
                                  0.40)))
        snaps['east']['middle'].append(
            SnapPoint(point=Point(width + self.snap_point_offset * 1, height *
                                  0.60)))

        # add two more (slight up and slight down) for west-middle)
        snaps['west']['middle'].append(
            SnapPoint(point=Point(self.snap_point_offset * -1, height * 0.40)))
        snaps['west']['middle'].append(
            SnapPoint(point=Point(self.snap_point_offset * -1, height * 0.60)))

        return snaps
    def assemble_labels(self):
        group_id = '{0}:{1}-pools-labels'.format(self.bpmn_id, self.lane_id)
        svg_group = G(id=group_id)

        group_width = 0
        transformer = TransformBuilder()
        for child_pool_class in self.child_pool_classes:
            child_label_element = child_pool_class.assemble_labels()
            if child_label_element is None:
                continue

            # the y position of this pool label in the group will be its corresponding swim-pool's y position
            child_label_xy = Point(0, child_pool_class.svg_element.xy.y)
            transformer.setTranslation(child_label_xy)
            child_label_element.svg.set_transform(transformer.getTransform())
            svg_group.addElement(child_label_element.svg)

            group_width = max(child_label_element.width, group_width)

        group_height = self.svg_element.height

        # wrap it in a svg element
        self.label_element = SvgElement(svg=svg_group,
                                        width=group_width,
                                        height=group_height)
        return self.label_element
    def assemble_elements(self):
        info('assembling lanes for [{0}] DONE'.format(self.bpmn_id))

        # wrap it in a svg group
        group_id = '{0}-lanes'.format(self.bpmn_id)
        svg_group = G(id=group_id)

        # height of the lane collection is sum of height of all lanes with gaps between lanes
        max_lane_width = self.theme['pad-spec']['left']
        current_y = self.theme['pad-spec']['top']
        transformer = TransformBuilder()
        for child_lane_class in self.child_lane_classes:
            swim_lane_element = child_lane_class.assemble_elements()
            current_x = self.theme['pad-spec']['left'] + float(child_lane_class.lane_data['styles'].get('move_x', 0))
            swim_lane_element.xy = Point(current_x, current_y)
            transformer.setTranslation(swim_lane_element.xy)
            swim_lane_element.svg.set_transform(transformer.getTransform())
            svg_group.addElement(swim_lane_element.svg)

            max_lane_width = max(max_lane_width, current_x + swim_lane_element.width)
            current_y = current_y + swim_lane_element.height + self.theme['dy-between-lanes']

        group_width = self.theme['pad-spec']['left'] + max_lane_width + self.theme['pad-spec']['right']
        group_height = current_y - self.theme['dy-between-lanes'] + self.theme['pad-spec']['bottom']

        # add the ractangle
        lane_collection_rect_svg = Rect(width=group_width, height=group_height)
        lane_collection_rect_svg.set_style(StyleBuilder(self.theme['style']).getStyle())
        svg_group.addElement(lane_collection_rect_svg)

        # wrap it in a svg element
        self.svg_element = SvgElement(svg=svg_group, width=group_width, height=group_height)
        self.lane_collection.element = self.svg_element
        info('assembling lanes for [{0}] DONE'.format(self.bpmn_id))
        return self.svg_element
def a_diamond(diagonal_x, diagonal_y, spec):
    svg_group = G()

    points = [
        Point(0, diagonal_y / 2),
        Point(diagonal_x / 2, 0),
        Point(diagonal_x, diagonal_y / 2),
        Point(diagonal_x / 2, diagonal_y),
        Point(0, diagonal_y / 2)
    ]
    diamond_svg = Polygon(points=points_to_str(points))
    diamond_svg.set_style(StyleBuilder(spec['style']).getStyle())

    # add to group
    svg_group.addElement(diamond_svg)
    return svg_group, diagonal_x, diagonal_y
def an_equilateral_triangle_inside_a_circular_shape(radius, inner_shape_spec):
    # in a trangle ABC, A is alwys the top vertex
    svg_group = G()

    pad = radius * 0.4
    center_to_vertex = radius - pad
    center_point = Point(radius, radius)
    point_a = center_point.to_point(90, center_to_vertex)
    point_b = center_point.to_point(210, center_to_vertex)
    point_c = center_point.to_point(330, center_to_vertex)
    points = [point_a, point_b, point_c, point_a]
    triangle_svg = Polygon(points=points_to_str(points))
    triangle_svg.set_style(StyleBuilder(inner_shape_spec['style']).getStyle())

    # add to group
    svg_group.addElement(triangle_svg)
    return svg_group, radius * 2, radius * 2
def an_equilateral_pentagon_inside_a_circular_shape(radius, inner_shape_spec):
    svg_group = G()

    pad = radius * 0.4
    center_to_vertex = radius - pad
    center_point = Point(radius, radius)
    point_a = center_point.to_point(90 - (72 * 0), center_to_vertex)
    point_b = center_point.to_point(90 - (72 * 1), center_to_vertex)
    point_c = center_point.to_point(90 - (72 * 2), center_to_vertex)
    point_d = center_point.to_point(90 - (72 * 3), center_to_vertex)
    point_e = center_point.to_point(90 - (72 * 4), center_to_vertex)
    points = [point_a, point_b, point_c, point_d, point_e, point_a]
    pentagon_svg = Polygon(points=points_to_str(points))
    pentagon_svg.set_style(StyleBuilder(inner_shape_spec['style']).getStyle())

    # add to group
    svg_group.addElement(pentagon_svg)
    return svg_group, radius * 2, radius * 2
def a_page(width, height, spec):
    rect_svg_group, _, _ = a_rectangle(width=width, height=height, spec=spec)

    left_edge = width * 0.1
    right_edge = width * 0.1
    num_lines = 4
    y_gap_between_lines = height / (num_lines + 1)
    for line in range(1, num_lines + 1):
        y_len = line * y_gap_between_lines
        left_point = Point(left_edge, y_len)
        right_point = Point(width - right_edge, y_len)
        line_svg = Line(x1=left_point.x,
                        y1=left_point.y,
                        x2=right_point.x,
                        y2=right_point.y)
        line_svg.set_style(StyleBuilder(spec['style']).getStyle())
        rect_svg_group.addElement(line_svg)

    return rect_svg_group, width, height
    def connect_southward(self, point_from, point_to):
        if point_from == point_to:
            return [point_from]

        # see if there is any channel (vertically or horizontally) between point_from and point_to
        channels_vertically_between, channels_horizontally_between = self.channels_blocking_southward(
            point_from, point_to)

        # first we bypass the channels which are obstructing the path vertically
        if len(channels_vertically_between) > 0:
            # we bypass the northmost (first) channel
            channel_to_bypass = channels_vertically_between[0]

            debug('bypassing vertically blocking channel [{0}:{1}]'.format(
                channel_to_bypass.number, channel_to_bypass.name))
            # self.mark_points([point_from], self.element.svg, 'red')
            # self.mark_points([point_to], self.element.svg, 'green')

            points_to_bypass_the_channel = channel_to_bypass.bypass_vertically(
                coming_from=point_from, going_to=point_to)
            # debug('[{0}] -> [{1}] channel [{2}:{3}] bypass points [{4}]'.format(point_from, point_to, channel_to_bypass.number, channel_to_bypass.name, points_to_bypass_the_channel))
            # self.mark_points(points_to_bypass_the_channel, self.element.svg, 'blue')

            points = [
                point_from
            ] + points_to_bypass_the_channel + self.connect_southward(
                points_to_bypass_the_channel[-1], point_to)
            # debug('[{0}] -> [{1}] connection points [{2}]'.format(point_from, point_to, points))
            return points

        # next we handle the channels which are obstructing the path horizontally only when we have no vertical obstruction
        elif len(channels_horizontally_between) > 0:
            # debug('...horizontally blocking channels')
            # for channel in channels_horizontally_between:
            #     debug('......[{0}]:[{1}]'.format(channel.number, channel.name))

            # there may be a number of such obstructing channels, our target is to, find the channel closest to point_to (the last channel)
            channel_to_bypass = channels_horizontally_between[-1]
            # debug('bypassing [{0}]:[{1}] from {2} towards {3}'.format(channel_to_bypass.number, channel_to_bypass.name, point_to, point_from))
            points_to_bypass_the_channel = channel_to_bypass.bypass_vertically(
                coming_from=point_to, going_to=point_from)
            points_to_bypass_the_channel.reverse()
            points = self.connect_southward(
                point_from, points_to_bypass_the_channel[0]
            ) + points_to_bypass_the_channel + [point_to]
            return points

        else:
            # there is no channel in between, we can just return the intersection point
            if point_from.x == point_to.x or point_from.y == point_to.y:
                return [point_from, point_to]
            else:
                return [point_from, Point(point_from.x, point_to.y), point_to]
def a_triangular_rewind(width, height, spec):
    svg_group = G()

    left_arrow_point_left = Point(0, height / 2)
    left_arrow_point_top = Point(width / 2, 0)
    left_arrow_point_bottom = Point(width / 2, height)

    right_arrow_point_left = Point(width / 2, height / 2)
    right_arrow_point_top = Point(width, 0)
    right_arrow_point_bottom = Point(width, height)

    left_arrow_points = [
        left_arrow_point_left, left_arrow_point_top, left_arrow_point_bottom
    ]
    right_arrow_points = [
        right_arrow_point_left, right_arrow_point_top, right_arrow_point_bottom
    ]

    left_arrow_svg = Polygon(points=points_to_str(left_arrow_points))
    left_arrow_svg.set_style(StyleBuilder(spec['style']).getStyle())

    right_arrow_svg = Polygon(points=points_to_str(right_arrow_points))
    right_arrow_svg.set_style(StyleBuilder(spec['style']).getStyle())

    svg_group.addElement(left_arrow_svg)
    svg_group.addElement(right_arrow_svg)

    return svg_group, width, height
def two_gears_inside_a_circular_shape(radius, inner_shape_spec):
    svg_group = G()

    gear_radius = radius * 0.7
    gear1_svg_group, _, _ = a_gear(radius=gear_radius, spec=inner_shape_spec)
    gear2_svg_group, _, _ = a_gear(radius=gear_radius, spec=inner_shape_spec)

    # gear1 is towards top left
    north_west_point_on_circle = Point(radius, radius).to_point(135, radius)
    gear1_center_point = north_west_point_on_circle.to_point(-45, gear_radius)
    gear1_svg_group_xy = '{0},{1}'.format(gear1_center_point.x - gear_radius,
                                          gear1_center_point.y - gear_radius)
    transformer = TransformBuilder()
    transformer.setTranslation(gear1_svg_group_xy)
    gear1_svg_group.set_transform(transformer.getTransform())
    svg_group.addElement(gear1_svg_group)

    # gear2 is towards bottom right
    south_east_point_on_circle = Point(radius, radius).to_point(-45, radius)
    gear2_center_point = south_east_point_on_circle.to_point(135, gear_radius)
    gear2_svg_group_xy = '{0},{1}'.format(gear2_center_point.x - gear_radius,
                                          gear2_center_point.y - gear_radius)
    transformer = TransformBuilder()
    transformer.setTranslation(gear2_svg_group_xy)
    gear2_svg_group.set_transform(transformer.getTransform())
    svg_group.addElement(gear2_svg_group)

    return svg_group, radius * 2, radius * 2
def a_clock(radius, spec):
    clock_group_svg, _, _ = a_circle(radius, spec)

    hour_mark_length = radius * 0.3
    minute_hand_length = radius * 0.6
    hour_hand_length = radius * 0.4

    minute_hand_svg = Line(x1=radius,
                           y1=radius,
                           x2=radius,
                           y2=(radius - minute_hand_length))
    minute_hand_svg.set_style(StyleBuilder(spec['style']).getStyle())
    hour_hand_svg = Line(x1=radius,
                         y1=radius,
                         x2=radius + hour_hand_length,
                         y2=radius)
    hour_hand_svg.set_style(StyleBuilder(spec['style']).getStyle())

    clock_group_svg.addElement(minute_hand_svg)
    clock_group_svg.addElement(hour_hand_svg)

    # the hour marks
    center_point = Point(radius, radius)
    for hour in range(0, 12):
        point_on_circle = center_point.to_point(30 * hour, radius)
        point_inside = center_point.to_point(30 * hour,
                                             radius - hour_mark_length)
        hour_mark_svg = Line(x1=point_on_circle.x,
                             y1=point_on_circle.y,
                             x2=point_inside.x,
                             y2=point_inside.y)
        hour_mark_svg.set_style(StyleBuilder(spec['style']).getStyle())
        clock_group_svg.addElement(hour_mark_svg)

    # add to group
    return clock_group_svg, radius * 2, radius * 2
def a_right_arrow(width, height, spec):
    arrow_height = height / 3

    top_left = Point(0, (height - arrow_height) / 2)
    mid_top = Point(width / 2, (height - arrow_height) / 2)
    top = Point(width / 2, 0)
    right = Point(width, height / 2)
    bottom = Point(width / 2, height)
    mid_bottom = Point(width / 2, (height + arrow_height) / 2)
    bottom_left = Point(0, (height + arrow_height) / 2)

    arrow_points = [
        top_left, mid_top, top, right, bottom, mid_bottom, bottom_left
    ]

    arrow_svg = Polygon(points=points_to_str(arrow_points))
    arrow_svg.set_style(StyleBuilder(spec['style']).getStyle())

    return arrow_svg, width, height
Пример #18
0
def main(argv=None):
    pygame.init()

    if len(argv) == 0:
        sys.exit(1)

    data_filename = argv[0]

    data = load_sense_data(data_filename)

    windowSize = grid.GRID_SIZE * CELL_PIX
    window = pygame.display.set_mode((windowSize, windowSize))

    board = grid.OccupancyGrid(grid.GRID_SIZE, grid.CELL_SIZE, Point(0, 0))
    sonarModel = nao_sonar_model()

    send_sense(data, board, window, sonarModel)

    #generate_random_board(board)
    render_grid(window, board)

    pygame.display.flip()
    wait_for_exit()
def a_folded_rectangle(width, height, spec):
    svg_group = G()

    top_left = Point(0, 0)
    mid_top = Point(width - spec['fold-length'], 0)
    mid_right = Point(width, spec['fold-length'])
    bottom_right = Point(width, height)
    bottom_left = Point(0, height)
    shape1_points = [
        top_left, mid_top, mid_right, bottom_right, bottom_left, top_left
    ]

    shape1_svg = Polygon(points=points_to_str(shape1_points))
    shape1_svg.set_style(StyleBuilder(spec['style']).getStyle())

    mid = Point(width - spec['fold-length'], spec['fold-length'])
    shape2_points = [mid_top, mid, mid_right]
    shape2_svg = Polygon(points=points_to_str(shape2_points))
    shape2_svg.set_style(StyleBuilder(spec['style']).getStyle())

    # add to group
    svg_group.addElement(shape1_svg)
    svg_group.addElement(shape2_svg)
    return svg_group, width, height
def a_cross(width, height, x_bar_height, y_bar_width, spec):
    svg_group = G()

    # make the X inside the group
    cross_points = [
        Point(0, (height + x_bar_height) / 2),
        Point(0, (height - x_bar_height) / 2),
        Point((width - y_bar_width) / 2, (height - x_bar_height) / 2),
        Point((width - y_bar_width) / 2, 0),
        Point((width + y_bar_width) / 2, 0),
        Point((width + y_bar_width) / 2, (height - x_bar_height) / 2),
        Point(width, (height - x_bar_height) / 2),
        Point(width, (height + x_bar_height) / 2),
        Point((width + y_bar_width) / 2, (height + x_bar_height) / 2),
        Point((width + y_bar_width) / 2, height),
        Point((width - y_bar_width) / 2, height),
        Point((width - y_bar_width) / 2, (height + x_bar_height) / 2)
    ]

    cross_svg = Polygon(points=points_to_str(cross_points))
    cross_svg.set_style(StyleBuilder(spec['style']).getStyle())

    # add to group
    svg_group.addElement(cross_svg)

    return svg_group, width, height
Пример #21
0
    def to_svg(self):
        info('......processing node [{0}:{1}:{2}:{3}]'.format(
            self.bpmn_id, self.lane_id, self.pool_id, self.node_id))

        # the label element
        label_group, label_group_width, label_group_height = text_inside_a_rectangle(
            text=self.node_data['label'],
            min_width=self.theme['rectangle']['min-width'],
            max_width=self.theme['rectangle']['max-width'],
            rect_spec=self.theme['rectangle'],
            text_spec=self.theme['text'])

        # the circle element
        if 'inner-circle' in self.theme:
            circle_group, circle_group_width, circle_group_height = two_concentric_circles(
                outer_radius=self.theme['circle']['radius'],
                inner_radius=self.theme['inner-circle']['radius'],
                outer_circle_spec=self.theme['circle'],
                inner_circle_spec=self.theme['inner-circle'])
        else:
            circle_group, circle_group_width, circle_group_height = a_circle(
                radius=self.theme['circle']['radius'],
                spec=self.theme['circle'])

        # get the inside element
        inside_element = self.get_inside_element()

        # if an inside element is to be placed inside the circle group, place it so that the inside object's center and the circle's center is same
        if inside_element is not None:
            inside_group, inside_group_width, inside_group_height = inside_element.svg, inside_element.width, inside_element.height
            inside_group_xy = Point(
                (circle_group_width - inside_group_width) / 2,
                (circle_group_height - inside_group_height) / 2)
            transformer = TransformBuilder()
            transformer.setTranslation(inside_group_xy)
            inside_group.set_transform(transformer.getTransform())
            circle_group.addElement(inside_group)

        # wrap it in a svg group
        svg_group = G(id=self.group_id)

        # the circle is vertically below the label, keep a gap of *snap_point_offset*
        circle_group_xy = Point((label_group_width - circle_group_width) / 2,
                                label_group_height + self.snap_point_offset)
        transformer = TransformBuilder()
        transformer.setTranslation(circle_group_xy)
        circle_group.set_transform(transformer.getTransform())

        # where the label will be positioned depends on the value of label_pos
        if self.label_pos == 'bottom':
            label_group_xy = Point(
                0, label_group_height + self.snap_point_offset +
                circle_group_height + self.snap_point_offset)
            transformer = TransformBuilder()
            transformer.setTranslation(label_group_xy)
            label_group.set_transform(transformer.getTransform())

        # place the label and circle
        svg_group.addElement(label_group)
        svg_group.addElement(circle_group)

        # extend the height so that a blank space of the same height as text is at the bottom so that the circle's left edge is at dead vertical center
        group_width = label_group_width
        group_height = label_group_height + self.snap_point_offset + circle_group_height + self.snap_point_offset + label_group_height

        # snap points
        snap_points = self.snap_points(group_width, group_height)
        self.snap_offset_x = (label_group_width -
                              circle_group_width) / 2 + self.snap_point_offset
        self.snap_offset_y = label_group_height + self.snap_point_offset * 2
        # self.draw_snaps(snap_points, svg_group, x_offset=self.snap_offset_x, y_offset=self.snap_offset_y)

        info('......processing node [{0}:{1}:{2}:{3}] DONE'.format(
            self.bpmn_id, self.lane_id, self.pool_id, self.node_id))
        self.svg_element = SvgElement(svg=svg_group,
                                      width=group_width,
                                      height=group_height,
                                      snap_points=snap_points,
                                      label_pos=self.label_pos)
        return self.svg_element
    def to_svg(self):
        info('......processing node [{0}:{1}:{2}:{3}]'.format(
            self.bpmn_id, self.lane_id, self.pool_id, self.node_id))

        # the label element
        label_group, label_group_width, label_group_height = text_inside_a_rectangle(
            text=self.node_data['label'],
            min_width=self.theme['rectangle']['min-width'],
            max_width=self.theme['rectangle']['max-width'],
            rect_spec=self.theme['rectangle'],
            text_spec=self.theme['text'])

        # the folded rectangle
        folded_rectangle_group, folded_rectangle_group_width, folded_rectangle_group_height = a_folded_rectangle(
            width=self.theme['folded-rectangle']['width'],
            height=self.theme['folded-rectangle']['height'],
            spec=self.theme['folded-rectangle'])

        # top left element inside -------------------------------------------------------
        top_left_element = self.get_top_left_element()
        # position properly inside the folder rectangle at top left
        if top_left_element is not None:
            top_left_group, top_left_group_width, top_left_group_height = top_left_element.svg, top_left_element.width, top_left_element.height
            top_left_group_xy = Point(
                self.theme['folded-rectangle']['pad-spec']['left'],
                self.theme['folded-rectangle']['pad-spec']['top'])
            transformer = TransformBuilder()
            transformer.setTranslation(top_left_group_xy)
            top_left_group.set_transform(transformer.getTransform())
            folded_rectangle_group.addElement(top_left_group)

        # bottom center element inside -------------------------------------------------------
        bottom_center_element = self.get_bottom_center_element()
        # position properly inside the folder rectangle at bottom center
        if bottom_center_element is not None:
            bottom_center_group, bottom_center_group_width, bottom_center_group_height = bottom_center_element.svg, bottom_center_element.width, bottom_center_element.height
            bottom_center_group_xy = '{0},{1}'.format(
                (folded_rectangle_group_width - bottom_center_group_width) / 2,
                folded_rectangle_group_height - bottom_center_group_height -
                self.theme['folded-rectangle']['pad-spec']['bottom'])
            transformer = TransformBuilder()
            transformer.setTranslation(bottom_center_group_xy)
            bottom_center_group.set_transform(transformer.getTransform())
            folded_rectangle_group.addElement(bottom_center_group)

        # wrap them in a svg group -----------------------------------------------------------------
        svg_group = G(id=self.group_id)

        # the folded rectangle is below an empty space of the same height of the label
        folded_rectangle_group_xy = Point(
            (label_group_width - folded_rectangle_group_width) / 2,
            label_group_height + self.snap_point_offset)
        transformer = TransformBuilder()
        transformer.setTranslation(folded_rectangle_group_xy)
        folded_rectangle_group.set_transform(transformer.getTransform())

        # where the label will be positioned depends on the value of label_pos
        if self.label_pos == 'bottom':
            label_group_xy = Point(
                0, label_group_height + self.snap_point_offset +
                folded_rectangle_group_height + self.snap_point_offset)
            transformer = TransformBuilder()
            transformer.setTranslation(label_group_xy)
            label_group.set_transform(transformer.getTransform())

        # place the elements
        svg_group.addElement(folded_rectangle_group)
        svg_group.addElement(label_group)

        # extend the height so that a blank space of the same height as text is at the bottom so that the circle's left edge is at dead vertical center
        group_width = label_group_width
        group_height = label_group_height + self.snap_point_offset + folded_rectangle_group_height + self.snap_point_offset + label_group_height

        # snap points
        snap_points = self.snap_points(group_width, group_height)
        self.snap_offset_x = (label_group_width - folded_rectangle_group_width
                              ) / 2 + self.snap_point_offset
        self.snap_offset_y = label_group_height + self.snap_point_offset * 2
        # self.draw_snaps(snap_points, svg_group, x_offset=self.snap_offset_x, y_offset=self.snap_offset_y)

        info('......processing node [{0}:{1}:{2}:{3}] DONE'.format(
            self.bpmn_id, self.lane_id, self.pool_id, self.node_id))
        self.svg_element = SvgElement(svg=svg_group,
                                      width=group_width,
                                      height=group_height,
                                      snap_points=snap_points,
                                      label_pos=self.label_pos)
        return self.svg_element
Пример #23
0
    def create_flow(self, from_node, to_node, label, label_style):
        from_node_channel, from_node_ordinal = self.channel_collection.channel_and_ordinal(
            from_node)
        to_node_channel, to_node_ordinal = self.channel_collection.channel_and_ordinal(
            to_node)

        if self.validate(from_node_channel, to_node_channel, from_node,
                         to_node) == False:
            return None

        # first we need the diection from from_node to to_node
        if from_node_channel.number < to_node_channel.number:
            direction = 'south'
        else:
            direction = 'north'

        # node-positions
        if from_node_ordinal == len(from_node_channel.nodes) - 1:
            from_node_position = 'east-most'
        else:
            from_node_position = '*'

        if to_node_ordinal == 0:
            to_node_position = 'west-most'
        else:
            to_node_position = '*'

        # now we know the rule to chose for snapping and routing for the *from* and *to* node
        from_node_spec = self.snap_rules[direction]['from-node'][
            from_node_position][from_node.category]
        to_node_spec = self.snap_rules[direction]['to-node'][to_node_position][
            to_node.category]

        from_node_points_in_pool_coordinate = self.channel_collection.points_to_pool_flow_area(
            boundary=from_node_spec['cross-through-boundary'],
            channel=from_node_channel,
            node=from_node,
            side=from_node_spec['side'],
            position=from_node_spec['position'],
            role='from',
            approach_snap_point_from=from_node_spec[
                'approach-snap-point-from'],
            peer=to_node,
            edge_type=self.edge_type)

        if from_node_points_in_pool_coordinate is None:
            warn('could not calculate snap points for from-node [{0}]'.format(
                from_node.id))
            return None

        to_node_points_in_pool_coordinate = self.channel_collection.points_to_pool_flow_area(
            boundary=to_node_spec['cross-through-boundary'],
            channel=to_node_channel,
            node=to_node,
            side=to_node_spec['side'],
            position=to_node_spec['position'],
            role='to',
            approach_snap_point_from=to_node_spec['approach-snap-point-from'],
            peer=from_node,
            edge_type=self.edge_type)

        if to_node_points_in_pool_coordinate is None:
            warn('could not calculate snap points for to-node [{0}]'.format(
                to_node.id))
            return None

        # we always connect from the north point to the south point
        # if the points are vertically close it means that they are inside the same pool-flow-area between same two channels, we just connect them by adjusting the to_point y positions
        from_node_end_point = from_node_points_in_pool_coordinate[-1]
        to_node_start_point = to_node_points_in_pool_coordinate[0]
        # TODO: this 48 is a hack, it shold be the sy-between-channels value
        if abs(from_node_end_point.y - to_node_start_point.y) <= 24:
            joining_points = [
                Point(to_node_start_point.x, from_node_end_point.y)
            ]

        else:
            # TODO: the connect_southward is problematic, no
            if from_node_points_in_pool_coordinate[-1].north_of(
                    to_node_points_in_pool_coordinate[0]):
                north_point = from_node_points_in_pool_coordinate[-1]
                south_point = to_node_points_in_pool_coordinate[0]
                joining_points = self.channel_collection.connect_southward(
                    point_from=north_point, point_to=south_point)
            else:
                # self.mark_points([from_node_points_in_pool_coordinate[-1]], self.channel_collection.element.svg, 'red')
                # self.mark_points([to_node_points_in_pool_coordinate[0]], self.channel_collection.element.svg, 'green')

                north_point = to_node_points_in_pool_coordinate[0]
                south_point = from_node_points_in_pool_coordinate[-1]
                joining_points = self.channel_collection.connect_southward(
                    point_from=north_point, point_to=south_point)
                joining_points.reverse()

                # self.mark_points(joining_points, self.channel_collection.element.svg, 'blue')

            # self.mark_points(from_node_points_in_pool_coordinate, self.channel_collection.element.svg, 'red')
            # self.mark_points(to_node_points_in_pool_coordinate, self.channel_collection.element.svg, 'green')

        # we have the points, now create and return the flow
        flow_points = from_node_points_in_pool_coordinate + joining_points + to_node_points_in_pool_coordinate

        # debug('[{0}] -> [{1}] point outside channel from node: {2}'.format(from_node.id, to_node.id, from_node_points_in_pool_coordinate[-1]))
        # debug('[{0}] -> [{1}] point outside channel to   node: {2}'.format(from_node.id, to_node.id, to_node_points_in_pool_coordinate[0]))
        # debug('[{0}] -> [{1}] joining points                 : {2}'.format(from_node.id, to_node.id, joining_points))

        flow_points = optimize_points(flow_points)

        # determine the placement of the label
        label_data = None
        if label is not None and label != '':
            label_data = {}
            label_data['text'] = label
            # get the first vertical line segment having a min-length
            point_from, point_to = first_vertical_line_segment_longer_than(
                flow_points, 30)
            # the main connecting line for ChannelFlow is a horizontal line
            label_data['line-points'] = {'from': point_from, 'to': point_to}
            label_data['line-direction'] = 'north-south'
            # the text should be placed on top of the line
            label_data['placement'] = label_style.get('placement', 'east')
            label_data['move-x'] = float(label_style.get('move_x', 0))
            label_data['move-y'] = float(label_style.get('move_y', 20))

        flow_svg, flow_width, flow_height = a_flow(flow_points, label_data,
                                                   self.theme, self.flow_scope)

        # debug('[{0}] -> [{1}] : {2}'.format(from_node.id, to_node.id, flow_points))

        return SvgElement(svg=flow_svg, width=flow_width, height=flow_height)
    def snap_points(self, width, height):
        snaps = super().snap_points(width, height)

        # add two more (slight left and slight right) for north-middle)
        snaps['north']['middle'].append(
            SnapPoint(point=Point(width * 0.45, self.snap_point_offset * -1)))
        snaps['north']['middle'].append(
            SnapPoint(point=Point(width * 0.55, self.snap_point_offset * -1)))

        # add two more (slight left and slight right) for south-middle)
        snaps['south']['middle'].append(
            SnapPoint(point=Point(width * 0.45, height +
                                  self.snap_point_offset * 1)))
        snaps['south']['middle'].append(
            SnapPoint(point=Point(width * 0.55, height +
                                  self.snap_point_offset * 1)))

        # add two more (slight up and slight down) for east-middle)
        snaps['east']['middle'].append(
            SnapPoint(point=Point(width + self.snap_point_offset * 1, height *
                                  0.40)))
        snaps['east']['middle'].append(
            SnapPoint(point=Point(width + self.snap_point_offset * 1, height *
                                  0.60)))

        # add two more (slight up and slight down) for west-middle)
        snaps['west']['middle'].append(
            SnapPoint(point=Point(self.snap_point_offset * -1, height * 0.40)))
        snaps['west']['middle'].append(
            SnapPoint(point=Point(self.snap_point_offset * -1, height * 0.60)))

        # activities have snap-points in north-left - one in mid-left and two more (slight left and slight right)
        snaps['north']['left'] = [
            SnapPoint(point=Point(width * 0.25, self.snap_point_offset * -1))
        ]
        snaps['north']['left'].append(
            SnapPoint(point=Point(width * 0.20, self.snap_point_offset * -1)))
        snaps['north']['left'].append(
            SnapPoint(point=Point(width * 0.30, self.snap_point_offset * -1)))

        # activities have snap-points in north-right - one in mid-right and two more (slight left and slight right)
        snaps['north']['right'] = [
            SnapPoint(point=Point(width * 0.75, self.snap_point_offset * -1))
        ]
        snaps['north']['right'].append(
            SnapPoint(point=Point(width * 0.70, self.snap_point_offset * -1)))
        snaps['north']['right'].append(
            SnapPoint(point=Point(width * 0.80, self.snap_point_offset * -1)))

        # activities have snap-points in south-left - one in mid-left and two more (slight left and slight right)
        snaps['south']['left'] = [
            SnapPoint(point=Point(width * 0.25, height +
                                  self.snap_point_offset * 1))
        ]
        snaps['south']['left'].append(
            SnapPoint(point=Point(width * 0.20, height +
                                  self.snap_point_offset * 1)))
        snaps['south']['left'].append(
            SnapPoint(point=Point(width * 0.30, height +
                                  self.snap_point_offset * 1)))

        # activities have snap-points in south-right - one in mid-right and two more (slight left and slight right)
        snaps['south']['right'] = [
            SnapPoint(point=Point(width * 0.75, height +
                                  self.snap_point_offset * 1))
        ]
        snaps['south']['right'].append(
            SnapPoint(point=Point(width * 0.70, height +
                                  self.snap_point_offset * 1)))
        snaps['south']['right'].append(
            SnapPoint(point=Point(width * 0.80, height +
                                  self.snap_point_offset * 1)))

        # activities have snap-points in east-top - one in mid-top and two more (slight up and slight down)
        snaps['east']['top'] = [
            SnapPoint(point=Point(width + self.snap_point_offset * 1, height *
                                  0.25))
        ]
        snaps['east']['top'].append(
            SnapPoint(point=Point(width + self.snap_point_offset * 1, height *
                                  0.15)))
        snaps['east']['top'].append(
            SnapPoint(point=Point(width + self.snap_point_offset * 1, height *
                                  0.35)))

        # activities have snap-points in east-bottom - one in mid-bottom and two more (slight up and slight down)
        snaps['east']['bottom'] = [
            SnapPoint(point=Point(width + self.snap_point_offset * 1, height *
                                  0.75))
        ]
        snaps['east']['bottom'].append(
            SnapPoint(point=Point(width + self.snap_point_offset * 1, height *
                                  0.65)))
        snaps['east']['bottom'].append(
            SnapPoint(point=Point(width + self.snap_point_offset * 1, height *
                                  0.85)))

        # activities have snap-points in west-top - one in mid-top and two more (slight up and slight down)
        snaps['west']['top'] = [
            SnapPoint(point=Point(self.snap_point_offset * -1, height * 0.25))
        ]
        snaps['west']['top'].append(
            SnapPoint(point=Point(self.snap_point_offset * -1, height * 0.15)))
        snaps['west']['top'].append(
            SnapPoint(point=Point(self.snap_point_offset * -1, height * 0.35)))

        # activities have snap-points in west-bottom - one in mid-bottom and two more (slight up and slight down)
        snaps['west']['bottom'] = [
            SnapPoint(point=Point(self.snap_point_offset * -1, height * 0.75))
        ]
        snaps['west']['bottom'].append(
            SnapPoint(point=Point(self.snap_point_offset * -1, height * 0.65)))
        snaps['west']['bottom'].append(
            SnapPoint(point=Point(self.snap_point_offset * -1, height * 0.85)))

        return snaps
Пример #25
0
def points_to_curved_path(points):
    new_points = optimize_points(points)

    # first we generate a new set of points for every three points so that if the three points make a turn we have actually 5 points
    path = 'M {0}'.format(new_points[0])
    # if we have only two points
    if len(points) == 2:
        path = '{0} L {1}'.format(path, points[1])
        return path

    default_offset = 5
    i = 0
    while i < (len(new_points) - 2):
        p1, p2, p3 = new_points[i], new_points[i+1], new_points[i+2]
        # we know that p1-p2 line is perpendicular to p2-p3 line
        if p1.x == p2.x:
            # line p1-p2 is vertical, so p2-p3 must be horizontal
            if p1.y < p2.y:
                # p1 is above p2
                # we just add a new point p2a just vertically (q_offset) above p2.
                # The default_offset may be greater than the vertical diff betwwen the points p1 and p2, we adjust it
                q_offset = min(abs(p2.y - p1.y)/2, default_offset)
                p2a = Point(p2.x, p2.y - q_offset)

                # The default_offset may be greater than the horizontal diff betwwen the points p2 and p3, we adjust it
                q_offset = min(abs(p3.x - p2.x)/2, default_offset)
                if p2.x < p3.x:
                    # p2 is left to p3
                    # and another new point p2b just horizontally (q_offset) after p2
                    p2b = Point(p2.x + q_offset, p2.y)
                else:
                    # p2 is right to p3
                    # and another new point p2b just horizontally (q_offset) before p2
                    p2b = Point(p2.x - q_offset, p2.y)
            else:
                # p1 is below p2
                # we just add a new point p2a just vertically (q_offset) below p2
                # The default_offset may be greater than the vertical diff betwwen the points p1 and p2, we adjust it
                q_offset = min((p1.y - p2.y)/2, default_offset)
                p2a = Point(p2.x, p2.y + q_offset)

                # The default_offset may be greater than the horizontal diff betwwen the points p2 and p3, we adjust it
                q_offset = min(abs(p3.x - p2.x)/2, default_offset)
                if p2.x < p3.x:
                    # p2 is left to p3
                    # and another new point p2b just horizontally (q_offset) after p2
                    p2b = Point(p2.x + q_offset, p2.y)
                else:
                    # p2 is right to p3
                    # and another new point p2b just horizontally (q_offset) before p2
                    p2b = Point(p2.x - q_offset, p2.y)

        if p1.y == p2.y:
            # line p1-p2 is horizontal, so p2-p3 must be vertical
            if p1.x < p2.x:
                # p1 is left to p2
                # we just add a new point p2a just horizontally (q_offset) before p2
                # The default_offset may be greater than the horizontal diff betwwen the points p1 and p2, we adjust it
                q_offset = min(abs(p2.x - p1.x)/2, default_offset)
                p2a = Point(p2.x - q_offset, p2.y)

                # The default_offset may be greater than the vertical diff betwwen the points p2 and p3, we adjust it
                q_offset = min(abs(p3.y - p2.y)/2, default_offset)
                if p2.y < p3.y:
                    # p2 is above to p3
                    # and another new point p2b just vertically (q_offset) after p2
                    p2b = Point(p2.x, p2.y + q_offset)
                else:
                    # p2 is below p3

                    # and another new point p2b just vertically (q_offset) before p2
                    p2b = Point(p2.x, p2.y - q_offset)
            else:
                # p1 is right to p2
                # we just add a new point p2a just horizontally (q_offset) after p2
                # The default_offset may be greater than the horizontal diff betwwen the points p1 and p2, we adjust it
                q_offset = min(abs(p2.x - p1.x)/2, default_offset)
                p2a = Point(p2.x + q_offset, p2.y)

                # The default_offset may be greater than the vertical diff betwwen the points p2 and p3, we adjust it
                q_offset = min(abs(p3.y - p2.y)/2, default_offset)
                if p2.y < p3.y:
                    # p2 is above p3
                    # and another new point p2b just vertically (q_offset) after p2
                    p2b = Point(p2.x, p2.y + q_offset)
                else:
                    # p2 is below p3
                    # and another new point p2b just vertically (q_offset) before p2
                    p2b = Point(p2.x, p2.y - q_offset)

        # the path is 5 point path with p2 now as the Q point
        # path = '{0} L {1} L {2} Q {3} {4} L {5}'.format(path, p1, p2a, p2, p2b, p3)
        path = '{0} L {1} Q {2} {3}'.format(path, p2a, p2, p2b)

        i = i + 1

    path = '{0} L {1}'.format(path, new_points[-1])

    return path
Пример #26
0
    def create_svg(self):
        info('assembling BPMN [{0}]'.format(self.bpmn_id))

        # wrap it in a svg group
        svg_group = G(id=self.bpmn_id)

        bpmn_width = self.theme['bpmn-rect']['pad-spec'][
            'left'] + self.label_element.width + self.body_element.width + self.theme[
                'bpmn-rect']['pad-spec']['right']

        # get the svg element for the label on top
        bpmn_label_svg, label_width, label_height = text_inside_a_rectangle(
            text=self.bpmn_data['label'],
            min_width=bpmn_width,
            max_width=bpmn_width,
            rect_spec=self.theme['rectangle'],
            text_spec=self.theme['text'],
            debug_enabled=False)

        bpmn_height = label_height + self.theme['bpmn-rect']['pad-spec'][
            'top'] + self.body_element.height + self.theme['bpmn-rect'][
                'pad-spec']['bottom']

        body_rect_svg = Rect(width=bpmn_width, height=bpmn_height)
        body_rect_svg.set_style(
            StyleBuilder(self.theme['bpmn-rect']['style']).getStyle())
        svg_group.addElement(body_rect_svg)

        # assemble bpmn text and bpmn body. text stacked on top of body
        # bpmn has a margin, so the outer group needs a transformation
        svg_group_xy = Point(self.theme['margin-spec']['left'],
                             self.theme['margin-spec']['top'])
        transformer = TransformBuilder()
        transformer.setTranslation(svg_group_xy)
        svg_group.set_transform(transformer.getTransform())

        if 'hide_labels' in self.bpmn_data['styles'] and self.bpmn_data[
                'styles']['hide_labels'] == 'true':
            # place the bpmn body group just below the text group right to label
            body_element_xy = Point(
                self.theme['bpmn-rect']['pad-spec']['left'],
                label_height + self.theme['bpmn-rect']['pad-spec']['top'])
            transformer = TransformBuilder()
            transformer.setTranslation(body_element_xy)
            self.body_element.svg.set_transform(transformer.getTransform())

            # place the bpmn label
            svg_group.addElement(bpmn_label_svg)
            svg_group.addElement(self.body_element.svg)
        else:
            # place the lane-pool label just below the text to the laft
            label_element_xy = Point(
                self.theme['bpmn-rect']['pad-spec']['left'],
                label_height + self.theme['bpmn-rect']['pad-spec']['top'])
            transformer = TransformBuilder()
            transformer.setTranslation(label_element_xy)
            self.label_element.svg.set_transform(transformer.getTransform())

            # place the bpmn body group just below the text group right to label
            body_element_xy = Point(
                self.theme['bpmn-rect']['pad-spec']['left'] +
                self.label_element.width,
                label_height + self.theme['bpmn-rect']['pad-spec']['top'])
            transformer = TransformBuilder()
            transformer.setTranslation(body_element_xy)
            self.body_element.svg.set_transform(transformer.getTransform())

            # place the bpmn label
            svg_group.addElement(bpmn_label_svg)
            svg_group.addElement(self.label_element.svg)
            svg_group.addElement(self.body_element.svg)

        # wrap in canvas
        canvas_width = self.theme['margin-spec'][
            'left'] + bpmn_width + self.theme['margin-spec']['right']
        canvas_height = self.theme['margin-spec'][
            'top'] + bpmn_height + self.theme['margin-spec']['bottom']
        svg = Svg(0, 0, width=canvas_width, height=canvas_height)
        svg.addElement(svg_group)

        info('assembling BPMN [{0}]'.format(self.bpmn_id))
        return svg
Пример #27
0
    def tune_labels(self):
        # get the width of the lane label having the maximum width
        max_lane_label_width = 0
        max_pool_label_width = 0
        for lane_group in self.label_element.svg.getAllElements():
            # the first child is a rect and the rect element's width is the width of lane-label
            lane_label_width = lane_group.getElementAt(0).getAttribute('width')
            # print('lane {0} width: {1}'.format(lane_group.getAttribute('id'), lane_label_width))
            max_lane_label_width = max(max_lane_label_width, lane_label_width)

            # the pool labels are in a group which is the third child
            for pool_group in lane_group.getElementAt(2).getAllElements():
                # the first child is a rect and the rect element's width is the width of pool-label
                pool_label_width = pool_group.getElementAt(0).getAttribute(
                    'width')
                # print('....pool {0} width: {1}'.format(pool_group.getAttribute('id'), pool_label_width))
                max_pool_label_width = max(max_pool_label_width,
                                           pool_label_width)

        # now we know the max width for lane and pool labels, we adjust them accordingly
        for lane_group in self.label_element.svg.getAllElements():
            # the first child is a rect and the rect element's width is the width of lane-label
            lane_label_width_diff = max_lane_label_width - lane_group.getElementAt(
                0).getAttribute('width')
            if lane_label_width_diff == 0:
                # we do nothing, this is already at the max width
                pass

            # change the rect's (first child) width
            lane_group.getElementAt(0).setAttribute('width',
                                                    max_lane_label_width)

            # second child is an svg whose width needs to be adjusted by diff
            lane_label_svg_width = lane_group.getElementAt(1).getAttribute(
                'width')
            lane_group.getElementAt(1).setAttribute(
                'width', lane_label_svg_width + lane_label_width_diff)

            # third child is the pool label group, whose transform's translation's x position needs to be adjusted by diff
            transform = lane_group.getElementAt(2).getAttribute('transform')
            m = re.match('translate\((?P<x>.+),(?P<y>.+)\)', transform,
                         re.IGNORECASE)
            if m and m.group('x') is not None and m.group('y') is not None:
                point = Point(
                    float(m.group('x')) + lane_label_width_diff,
                    float(m.group('y')))
                lane_group.getElementAt(2).setAttribute(
                    'transform', 'translate({0})'.format(point))

            # the pool labels are in a group which is the third child
            for pool_group in lane_group.getElementAt(2).getAllElements():
                # the first child is a rect and the rect element's width is the width of pool-label
                pool_label_width_diff = max_pool_label_width - pool_group.getElementAt(
                    0).getAttribute('width')
                if pool_label_width_diff == 0:
                    # we do nothing, this is already at the max width
                    pass

                # change the rect's (first child) width
                pool_group.getElementAt(0).setAttribute(
                    'width', max_pool_label_width)

                # second child is an svg whose width needs to be adjusted by diff
                pool_label_svg_width = pool_group.getElementAt(1).getAttribute(
                    'width')
                pool_group.getElementAt(1).setAttribute(
                    'width', pool_label_svg_width + pool_label_width_diff)
def a_path_with_label(points, label_data, spec, flow_scope):
    svg_group = G()

    path_data = points_to_curved_path(points)
    # path_data = points_to_path(points)
    # print(path_data)

    svg = Path(pathData=path_data)
    svg.set_style(StyleBuilder(spec['style'][flow_scope]).getStyle())

    if label_data is not None:
        # calculate max_width if line_direction is east-west
        # print(label_data)
        if label_data['line-direction'] == 'east-west':
            max_width = abs(label_data['line-points']['to'].x -
                            label_data['line-points']['from'].x)
        else:
            max_width = spec['label']['rectangle']['max-width']

        label_group, label_group_width, label_group_height = text_inside_a_rectangle(
            text=label_data['text'],
            min_width=min(spec['label']['rectangle']['min-width'], max_width),
            max_width=max_width,
            rect_spec=spec['label']['rectangle'],
            text_spec=spec['label']['text'])

        # for east-west (horizontal label line)
        if label_data['line-direction'] == 'east-west':
            if label_data['line-points']['to'].east_of(
                    label_data['line-points']['from']):
                label_pos_x = label_data['line-points']['from'].x + label_data[
                    'move-x']
            else:
                label_pos_x = label_data['line-points'][
                    'from'].x - label_group_width + label_data['move-x']

            if label_data['placement'] == 'north':
                label_pos_y = min(label_data['line-points']['from'].y,
                                  label_data['line-points']['to'].y
                                  ) - label_group_height + label_data['move-y']
            else:
                label_pos_y = min(
                    label_data['line-points']['from'].y,
                    label_data['line-points']['to'].y) + label_data['move-y']

        # for north-south (vertical label line)
        else:
            # label should be nearer to the from point
            if label_data['line-points']['to'].north_of(
                    label_data['line-points']['from']):
                label_pos_y = label_data['line-points'][
                    'from'].y - label_group_height - label_data['move-y']
            else:
                label_pos_y = label_data['line-points']['from'].y + label_data[
                    'move-y']

            if label_data['placement'] == 'east':
                label_pos_x = min(
                    label_data['line-points']['from'].x,
                    label_data['line-points']['to'].x) + label_data['move-x']
            else:
                label_pos_x = min(label_data['line-points']['from'].x,
                                  label_data['line-points']['to'].x
                                  ) - label_group_width + label_data['move-x']

        # print('x: {} y: {} w: {} h: {}'.format(label_pos_x, label_pos_y, label_group_width, label_group_height))

        # add label to group
        label_pos_xy = Point(label_pos_x, label_pos_y)
        transformer = TransformBuilder()
        transformer.setTranslation(label_pos_xy)
        label_group.set_transform(transformer.getTransform())
        svg_group.addElement(label_group)

    # add flow to group
    svg_group.addElement(svg)
    return svg_group, 0, 0
    def bypass_vertically(self, coming_from, going_to, margin_spec):
        # the coming_from point is north of going_to, so we have to reach a point south of the lane either through east or west or directly dpending on which direction we are going_to
        if coming_from.north_of(going_to):
            # if the coming_from point is already below the lane, we have no point
            if coming_from.y >= self.element.xy.y + self.element.height + margin_spec[
                    'bottom']:
                return []

            # if the coming_from point's x position is outside the lane, we can directly go south
            elif (self.element.xy.x -
                  margin_spec['left']) >= coming_from.x or coming_from.x >= (
                      self.element.xy.x + self.element.width +
                      margin_spec['right']):
                return [
                    Point(
                        coming_from.x, self.element.xy.y +
                        self.element.height + margin_spec['bottom'])
                ]

            # if the coming_from point is properly above the lane, we make a path
            else:
                # to the lane north vertically below coming_from
                p1 = Point(coming_from.x,
                           self.element.xy.y - margin_spec['top'])
                if going_to.east_of(coming_from):
                    # to the lane north-east
                    p2 = Point(
                        self.element.xy.x + self.element.width +
                        margin_spec['right'], p1.y)
                    # debug('southward from: {0} to {1} new {2}'.format(point_from, point_to, new_target_point))
                else:
                    # to the lane north-west
                    p2 = Point(self.element.xy.x - margin_spec['left'], p1.y)
                    # debug('northward from: {0} to {1} new {2}'.format(point_from, point_to, new_target_point))

                # to the lane south vertically below p2
                p3 = Point(
                    p2.x, self.element.xy.y + self.element.height +
                    margin_spec['bottom'])

        # the coming_from point is south of lane, so we have to reach a point north of the lane either through east or west dpending on which direction we are going_to
        else:
            # if the coming_from point is already above the pool, we have no point
            if coming_from.y <= self.element.xy.y - margin_spec['top']:
                return []

            # if the coming_from point's x position is outside the lane, we can directly go north
            elif (self.element.xy.x -
                  margin_spec['left']) >= coming_from.x or coming_from.x >= (
                      self.element.xy.x + self.element.width +
                      margin_spec['right']):
                return [
                    Point(coming_from.x,
                          self.element.xy.y - margin_spec['top'])
                ]

            # if the coming_from point is properly below the lane, we make a path
            else:
                # to the lane south vertically above coming_from
                p1 = Point(
                    coming_from.x, self.element.xy.y + self.element.height +
                    margin_spec['bottom'])
                if going_to.east_of(coming_from):
                    # to the lane south-east
                    p2 = Point(
                        self.element.xy.x + self.element.width +
                        margin_spec['right'], p1.y)
                    # debug('southward from: {0} to {1} new {2}'.format(point_from, point_to, new_target_point))
                else:
                    # to the lane south-west
                    p2 = Point(self.element.xy.x - margin_spec['left'], p1.y)
                    # debug('northward from: {0} to {1} new {2}'.format(point_from, point_to, new_target_point))

                # to the lane north vertically above p2
                p3 = Point(p2.x, self.element.xy.y - margin_spec['top'])

        return [p1, p2, p3]
    def outside_the_lane(self, lane_boundary, pool_boundary, pool_number,
                         channel_boundary, channel, node, side, position, role,
                         approach_snap_point_from, peer, edge_type,
                         lane_margin_spec):
        # first get outside the lane
        points_in_lane_coordinate = self.outside_the_pool(
            pool_boundary, pool_number, channel_boundary, channel, node, side,
            position, role, approach_snap_point_from, peer, edge_type)

        # now get outside the lane (pool_collection) - to do so we we either go south or north depending on lane_boundary
        last_pool_number = len(self.channel_collection_list) - 1
        if lane_boundary == 'south':
            # we have to get to the southern boundary of the lane
            if role == 'from':
                the_point = Point(
                    points_in_lane_coordinate[-1].x,
                    self.element.height + lane_margin_spec['bottom'])
                the_points = self.connect_southward(
                    pool_number, points_in_lane_coordinate[-1],
                    last_pool_number, the_point)
            else:
                the_point = Point(
                    points_in_lane_coordinate[0].x,
                    self.element.height + lane_margin_spec['bottom'])
                the_points = self.connect_southward(
                    pool_number, points_in_lane_coordinate[0],
                    last_pool_number, the_point)

        elif lane_boundary == 'north':
            # we have to get to the northern boundary of the lane
            if role == 'from':
                the_point = Point(points_in_lane_coordinate[-1].x,
                                  -lane_margin_spec['top'])
                the_points = self.connect_southward(
                    0, points_in_lane_coordinate[-1], pool_number, the_point)
            else:
                the_point = Point(points_in_lane_coordinate[0].x,
                                  -lane_margin_spec['top'])
                the_points = self.connect_southward(
                    0, points_in_lane_coordinate[0], pool_number, the_point)

        elif lane_boundary == 'west':
            # we have to get to the western boundary of the lane
            if role == 'from':
                the_points = [
                    Point(-lane_margin_spec['left'],
                          points_in_lane_coordinate[-1].y)
                ]
                # the_points = self.connect_southward(points_in_lane_coordinate[-1], the_point)
            else:
                the_points = [
                    Point(-lane_margin_spec['left'],
                          points_in_lane_coordinate[0].y)
                ]
                # the_points = self.connect_southward(points_in_lane_coordinate[0], the_point)

        elif lane_boundary == 'east':
            # we have to get to the eastern boundary of the lane
            if role == 'from':
                the_points = [
                    Point(self.element.width + lane_margin_spec['right'],
                          points_in_lane_coordinate[-1].y)
                ]
                # the_points = self.connect_southward(points_in_lane_coordinate[-1], the_point)
            else:
                the_points = [
                    Point(self.element.width + lane_margin_spec['right'],
                          points_in_lane_coordinate[0].y)
                ]
                # the_points = self.connect_southward(points_in_lane_coordinate[0], the_point)

        else:
            # should never happen
            warn('lane boundary is unknown')
            return points_in_lane_coordinate

        # debug('{0} outside point for pool [{1}] xy: {2} ({3} x {4}) is at {5}'.format(pool_boundary, self.pool_id, self.element.xy, self.element.width, self.element.height, the_point))

        if role == 'to':
            return the_points + points_in_lane_coordinate
        else:
            return points_in_lane_coordinate + the_points