def background(self, cr: cairo.Context): linear = cairo.LinearGradient(0, 0, .25, 1) linear.add_color_stop_rgb(0.0, *colors[0]) linear.add_color_stop_rgb(0.4, *colors[5]) linear.add_color_stop_rgb(1.0, *colors[6]) cr.rectangle(0, 0, .5, 1) cr.set_source(linear) cr.fill() cr.rectangle(0.5, 0, 1, 1) linear = cairo.LinearGradient(1, 0, .75, 1) linear.add_color_stop_rgb(0.0, *colors[0]) linear.add_color_stop_rgb(0.4, *colors[5]) linear.add_color_stop_rgb(1.0, *colors[6]) cr.set_source(linear) cr.fill() cr.move_to(.5, 0) # lower left cr.rel_line_to(-.5, 1) cr.rel_line_to(1, 0) cr.close_path() radial = cairo.RadialGradient(0.5, 0.5, 0.1, 0.5, 0.5, 0.75) radial.add_color_stop_rgba(0, *colors[3], 0.7) radial.add_color_stop_rgba(.4, *colors[1], 0.5) radial.add_color_stop_rgba(1, *colors[2], 0.1) cr.set_source(radial) cr.fill()
def draw_precip_curve( self, context: cairo.Context, points: List[Tuple[int, int]], bottom: int, color, curviness: float = 7, ): # Draw the top curves for i, point in enumerate(points): if i == 0: context.move_to(*point) else: last_point = points[i - 1] context.curve_to( last_point[0] + curviness, last_point[1], point[0] - curviness, point[1], point[0], point[1], ) # Draw the rest and fill context.line_to(points[-1][0], bottom) context.line_to(points[0][0], bottom) context.close_path() context.set_source_rgb(*color) context.fill()
def draw_triag(self, cr: cairo.Context, p): # p-> lower left coordinate of the triangle cr.move_to(*p) # lower left cr.rel_line_to(2 * self.dx, 0) # line to lower right cr.rel_line_to(-self.dx, -self.dy) cr.close_path()
def draw_polyline(context: cairo.Context, polyline: symbols.Polyline) -> None: """draw a polyline""" if not polyline.lines: return # The gotchas for animation and joints will be handled by polyline_frac, not this. context.set_line_width(polyline.thickness) _set_color(context, polyline.color) if polyline.joint_type != '': context.set_line_join(polyline.joint_type) context.move_to(polyline.lines[0].start[0], polyline.lines[0].start[1]) if polyline.closed: for line in polyline.lines[:-1]: context.line_to(line.end[0], line.end[1]) context.close_path() else: for line in polyline.lines: context.line_to(line.end[0], line.end[1]) context.stroke()
def draw_trains(self, layout: Layout, cr: Context): for train in layout.trains.values(): car_start = train.position annotation = train.meta.get("annotation") for i, car in enumerate(train.cars): front_bogey_offset, rear_bogey_offset = car.bogey_offsets bogey_spacing = rear_bogey_offset - front_bogey_offset front_bogey_position = car_start - front_bogey_offset front_bogey_xy = self.transform_track_point(front_bogey_position) rear_bogey_position, rear_bogey_xy = self.point_back( front_bogey_position, bogey_spacing ) cr.save() cr.translate(front_bogey_xy[0], front_bogey_xy[1]) cr.rotate( math.pi + math.atan2( front_bogey_xy[1] - rear_bogey_xy[1], front_bogey_xy[0] - rear_bogey_xy[0], ) ) cr.set_source_rgb(*hex_to_rgb(train.meta.get("color", "#a0a0ff"))) if i == 0 and annotation: cr.move_to(0, -10) cr.set_font_size(5) cr.show_text(annotation) cr.set_line_width(4) cr.move_to(-front_bogey_offset, 0) cr.line_to(car.length - front_bogey_offset, 0) cr.stroke() cr.set_line_width(6) cr.move_to(1 - front_bogey_offset, 0) cr.line_to(car.length - front_bogey_offset - 1, 0) cr.stroke() if i == 0 and train.lights_on: cr.set_source_rgba(1, 1, 0.2, 0.5) for y in (-2.5, 2.5): cr.move_to(-front_bogey_offset - 1, y) cr.arc( -front_bogey_offset - 1, y, 10, 6 / 7 * math.pi, math.pi * 8 / 7, ) cr.close_path() cr.fill() cr.restore() car_start = rear_bogey_position - (car.length - rear_bogey_offset + 1)
def do_render(self, model: Dazzle.GraphModel, x_begin: int, x_end: int, y_begin: float, y_end: float, cairo_context: cairo.Context, area: cairo.RectangleInt) -> None: model_iter = Dazzle.GraphModelIter() cairo_context.save() if model.get_iter_first(model_iter): chunk = area.width / (model.props.max_samples - 1) / 2.0 last_x = self._calc_x(model_iter, x_begin, x_end, area.width) last_y = float(area.height) cairo_context.move_to(last_x, area.height) while Dazzle.GraphModel.iter_next(model_iter): x = self._calc_x(model_iter, x_begin, x_end, area.width) y = self._calc_y(model_iter, y_begin, y_end, area.height, self._column) cairo_context.curve_to(last_x + chunk, last_y, last_x + chunk, y, x, y) last_x = x last_y = y cairo_context.set_line_width(self._line_width) cairo_context.set_source_rgba(self._stacked_color_rgba.red, self._stacked_color_rgba.green, self._stacked_color_rgba.blue, self._stacked_color_rgba.alpha) cairo_context.rel_line_to(0, area.height) cairo_context.stroke_preserve() cairo_context.close_path() cairo_context.fill() if model.get_iter_first(model_iter): chunk = area.width / (model.props.max_samples - 1) / 2.0 last_x = self._calc_x(model_iter, x_begin, x_end, area.width) last_y = float(area.height) cairo_context.move_to(last_x, last_y) while Dazzle.GraphModel.iter_next(model_iter): x = self._calc_x(model_iter, x_begin, x_end, area.width) y = self._calc_y(model_iter, y_begin, y_end, area.height, self._column) cairo_context.curve_to(last_x + chunk, last_y, last_x + chunk, y, x, y) last_x = x last_y = y cairo_context.set_source_rgba(self._stroke_color_rgba.red, self._stroke_color_rgba.green, self._stroke_color_rgba.blue, self._stacked_color_rgba.alpha) cairo_context.stroke() cairo_context.restore()
def draw_poly(poly: RegularPolygon, ctx: cairo.Context): ctx.save() v = poly.vertices() ctx.move_to(v[0][0], v[0][1]) for i in range(1, len(v)): ctx.line_to(v[i][0], v[i][1]) ctx.close_path() ctx.stroke() ctx.restore()
def draw_one_rect(ctx: cairo.Context, rect: PColoredRectangle) -> None: ctx.move_to(rect.x, rect.y) x2 = rect.x + rect.width y2 = rect.y + rect.height ctx.line_to(x2, rect.y) ctx.line_to(x2, y2) ctx.line_to(rect.x, y2) ctx.close_path() ctx.set_source_rgba(rect.r, rect.g, rect.b, rect.a) ctx.fill()
def rounded_rect(ctx: Context, x, y, width, height, radius): def deg(value): return value * math.pi / 180.0 ctx.new_sub_path() ctx.arc(x + width - radius, y + radius, radius, deg(-90), deg(0)) ctx.arc(x + width - radius, y + height - radius, radius, deg(0), deg(90)) ctx.arc(x + radius, y + height - radius, radius, deg(90), deg(180)) ctx.arc(x + radius, y + radius, radius, deg(180), deg(270)) ctx.close_path()
def draw(self, cr: cairo.Context, vp_matrix: np.ndarray): for i in range(len(self.normalized_vertices)): proximo_vp = self.normalized_vertices[i] @ vp_matrix cr.line_to(proximo_vp.x, proximo_vp.y) cr.close_path() if self.filled: cr.stroke_preserve() cr.fill() else: cr.stroke()
def draw(self, cr: Context, vp_matrix: np.ndarray): for v in self.vertices_ndc: next_vp = v @ vp_matrix cr.line_to(next_vp.x, next_vp.y) cr.close_path() if self.filled: cr.stroke_preserve() cr.fill() else: cr.stroke()
def _polygon(self, ctx: cairo.Context, points, color, outline=None): ctx.new_path() for point in points: ctx.line_to(*point) ctx.close_path() ctx.set_source_rgba(*color) if outline is not None: ctx.fill_preserve() ctx.set_source_rgba(*outline) ctx.set_line_width(1) ctx.stroke() else: ctx.fill()
def draw_highlight(self, _area: Gtk.DrawingArea, context: Context) -> None: if self.current_region and self.t: poly: Polygon = self.current_region.poly poly = poly.buffer(1, single_sided=True) # TODO: 239, 134, 97, 0.7 taken from gtk.css, possible to get it from os???? context.set_source_rgba(239 / 255.0, 134 / 255.0, 97 / 255.0, 0.7) context.set_line_width( clamp(self.configurators['scale'].get_exp() * 12, 0.5, 5)) context.new_path() # Nice idea, but didnt work with scrolling: context.set_matrix(Matrix(1.0/self.t.scale, 0, 0, 1.0/self.t.scale, -self.t.tx, -self.t.ty)) for coord in poly.exterior.coords: context.line_to(*self.t.inverse(*coord)) context.close_path() context.stroke()
def draw(self, cr: cairo.Context) -> None: line = self._line if line is None: return viewport_extents = self._parent.props.viewport_extents p0 = line.p0 p1 = line.p1 if p0 == p1: return start_point = line.eval_at(x=viewport_extents.x0) end_point = line.eval_at(x=viewport_extents.x1) if not viewport_extents.contains_point(start_point): if start_point.y < viewport_extents.y0: y_to_eval = viewport_extents.y0 else: y_to_eval = viewport_extents.y1 start_point = line.eval_at(y=y_to_eval) if not viewport_extents.contains_point(end_point): if end_point.y < viewport_extents.y0: y_to_eval = viewport_extents.y0 else: y_to_eval = viewport_extents.y1 end_point = line.eval_at(y=y_to_eval) p0, p1, start_point, end_point = map(self._parent._widget_coord_from_canvas, (p0, p1, start_point, end_point)) cr.move_to(*start_point) cr.line_to(*end_point) stroke_width = self.props.stroke_width stroke_color = self.props.stroke_color cr.set_line_width(stroke_width) cr.set_source_rgb(*stroke_color) # red, green, blue cr.stroke() # Draw the control points of the line. if self.props.draw_control_points: cr.arc(*p0, stroke_width*2, 0, 2*math.pi) cr.close_path() cr.arc(*p1, stroke_width*2, 0, 2*math.pi) cr.close_path() cr.fill()
def draw_on(self, ctx: cairo.Context): for i in range(len(self.points) - 1): ctx.line_to(*self.points[i + 1]) ctx.close_path()
class Canvas: def __init__(self, width: int, height: Optional[int] = None, *, normalise: bool = True): if height is None: height = width self._width = width self._height = height self._surface = ImageSurface(FORMAT_ARGB32, width, height) self._context = Context(self._surface) self._normalise = normalise if self._normalise: self.scale(self._width, self._height) @property def width(self) -> int: return self._width if not self._normalise else 1 @property def height(self) -> int: return self._height if not self._normalise else 1 # TODO depreciate @property def context(self) -> Context: # pragma: no cover return self._context def save(self) -> None: self._context.save() def restore(self) -> None: self._context.restore() # Transformation def rotate(self, angle: float) -> None: self._context.rotate(angle) def translate(self, x: float, y: float) -> None: self._context.translate(x, y) def scale(self, width: int, height: int) -> None: self._context.scale(width, height) def set_line_width(self, width: float) -> None: self._context.set_line_width(width) # Colour functionality def set_colour(self, colour: Colour) -> None: self._context.set_source_rgba(colour.red, colour.blue, colour.green, colour.alpha) def set_grey(self, colour_value: float, alpha: float = 1) -> None: colour = Colour(*(colour_value, ) * 3, alpha) self.set_colour(colour) def set_black(self) -> None: self.set_colour(BLACK) def set_white(self) -> None: self.set_colour(WHITE) def set_background(self, colour: Colour) -> None: self._context.rectangle(0, 0, self.width, self.height) self.set_colour(colour) self._context.fill() def set_line_cap(self, line_cap: LineCap) -> None: self._context.set_line_cap(line_cap.value) def set_line_join(self, line_join: LineJoin) -> None: self._context.set_line_join(line_join.value) def set_fill_rule(self, file_rule: FillRule) -> None: self._context.set_fill_rule(file_rule.value) # Render methods def fill(self, preserve: bool = False) -> None: if not preserve: self._context.fill() else: self._context.fill_preserve() def stroke(self, preserve: bool = False) -> None: if not preserve: self._context.stroke() else: self._context.stroke_preserve() def clip(self) -> None: self._context.clip() def _draw_path(self, path: Iterable[Point], close_path: bool) -> None: self._context.new_sub_path() for p in path: self._context.line_to(*p) if close_path: self._context.close_path() def draw_path(self, path: Iterable[PointType], close_path: bool = False) -> None: points = (p if isinstance(p, Point) else Point(*p) for p in path) self._draw_path(points, close_path) def draw_polygon(self, polygon: Polygon) -> None: self._draw_path(polygon.points, close_path=True) def draw_circle(self, circle: Circle, fill: bool = False, stroke: bool = True) -> None: self._context.new_sub_path() self._context.arc(*circle.centre, circle.radius, 0, 2 * pi) def write_to_png(self, file_name: str) -> None: self._surface.write_to_png(file_name)
def draw(self, cr: cairo.Context, drawing_options: DrawingOptions): cr.set_source_rgb(*drawing_options.sleeper_color) cr.set_line_width(2) # Main sleepers cr.save() cr.move_to(0, 0) cr.line_to(25, 4 * self.coordinate_sign) cr.line_to(32, 4 * self.coordinate_sign) cr.line_to(32, -4 * self.coordinate_sign) cr.line_to(0, -4 * self.coordinate_sign) cr.close_path() cr.clip() for i in range(0, 36, 4): cr.move_to(i, -4) cr.line_to(i, 4) cr.stroke() cr.restore() # Branch sleepers cr.save() cr.move_to(0, 0) cr.line_to(25, 4 * self.coordinate_sign) cr.line_to(32, 4 * self.coordinate_sign) cr.line_to(40, 4 * self.coordinate_sign) cr.line_to(40, 32 * self.coordinate_sign) cr.line_to(0, 32 * self.coordinate_sign) cr.close_path() cr.clip() # cr.stroke() for i in range(0, 10): x, y, theta = self.point_position("in", i / 9 * self.branch_length, out_anchor="branch") theta += -math.pi / 2 x_off, y_off = math.cos(theta) * 4, math.sin(theta) * 4 cr.move_to(x + x_off, y + y_off) cr.line_to(x - x_off, y - y_off) cr.stroke() cr.restore() if self.state == "out": rail_draw_order = ("branch", "out") else: rail_draw_order = ("out", "branch") cr.save() mask = cairo.ImageSurface( cairo.FORMAT_ARGB32, math.ceil(40 * drawing_options.scale), math.ceil(80 * drawing_options.scale), ) mask_cr = cairo.Context(mask) mask_cr.scale(drawing_options.scale, drawing_options.scale) mask_cr.translate(0, 40) mask_cr.set_source_rgb(0, 1, 0) for anchor_name in rail_draw_order: self.draw_rails_path(mask_cr, anchor_name) mask_cr.set_operator(cairo.OPERATOR_CLEAR) mask_cr.set_line_width(8) mask_cr.stroke_preserve() mask_cr.set_operator(cairo.OPERATOR_SOURCE) mask_cr.set_line_width(6) mask_cr.stroke_preserve() mask_cr.set_operator(cairo.OPERATOR_CLEAR) mask_cr.set_line_width(4) mask_cr.stroke() cr.set_source_rgb(*drawing_options.rail_color) cr.scale(1 / drawing_options.scale, 1 / drawing_options.scale) cr.mask_surface(mask, 0, -40 * drawing_options.scale) cr.restore()