class EL_MODEL_ROTATED_PICTURE

(source code)

Client examples: REPLICATED_IMAGE_MODEL

description

Model of a flippable, rotatable picture. Requires projector of type EL_MODEL_BUFFER_PROJECTOR to be rendered. Flipping is achieved via routine mirror.

note
	description: "[
		Model of a flippable, rotatable picture. Requires projector of type ${EL_MODEL_BUFFER_PROJECTOR}
		to be rendered. Flipping is achieved via routine `mirror'.
	]"

	author: "Finnian Reilly"
	copyright: "Copyright (c) 2001-2022 Finnian Reilly"
	contact: "finnian at eiffel hyphen loop dot com"

	license: "MIT license (See: en.wikipedia.org/wiki/MIT_License)"
	date: "2024-01-29 17:03:37 GMT (Monday 29th January 2024)"
	revision: "30"

class
	EL_MODEL_ROTATED_PICTURE

inherit
	EL_MODEL_ROTATED_RECTANGLE
		rename
			make as make_from_rectangle
		redefine
			copy, default_create, set_from_other, is_equal
		end

	EL_SHARED_PROGRESS_LISTENER

create
	make, default_create, make_from_other

feature {NONE} -- Initialization

	default_create
		do
			Precursor
			border_drawing := False
			drawing_area := Default_drawing_area
		end

	make (a_points: EL_POINT_ARRAY; a_pixel_buffer: like drawing_area)
		do
			make_with_coordinates (a_points)
			drawing_area := a_pixel_buffer
		end

	make_from_other (other: EL_MODEL_ROTATED_PICTURE)
		do
			default_create
			set_from_other (other)
		end

feature -- Access

	mirror_state: NATURAL_8
		-- bit OR'd combination of `X_axis' and `Y_axis'

	outer_radial_square: EV_RECTANGLE
		local
			l_width, l_height: INTEGER
		do
			if attached outer_radial_square_coordinates.area as p then
				l_width := (p [1].x_precise - p [0].x_precise).rounded
				l_height := (p [2].y_precise - p [1].y_precise).rounded

				create Result.make (p [0].x, p [0].y, l_width, l_height)
			end
		end

feature -- Constants

	Max_width: INTEGER = 65535

feature -- Status query

	border_drawing: EL_BOOLEAN_OPTION

	is_mirrored (axis: INTEGER): BOOLEAN
		require
			valid_axis: Orientation.is_valid_axis (axis)
		do
			Result := (mirror_state.to_integer_32 & axis).to_boolean
		end

	is_mirrored_x: BOOLEAN
		do
			Result := is_mirrored ({EL_DIRECTION}.X_axis)
		end

	is_mirrored_y: BOOLEAN
		do
			Result := is_mirrored ({EL_DIRECTION}.Y_axis)
		end

feature -- Comparison

	is_equal (other: like Current): BOOLEAN
		do
			Result := same_points (other)
					and then mirror_state = other.mirror_state
					and then drawing_area = other.drawing_area
		end

feature -- Transformation

	mirror (axis: INTEGER)
		-- invert the mirror state for axis `axis'
		require
			valid_axis: Orientation.is_valid_axis (axis)
		do
			mirror_state := mirror_state.bit_xor (axis.to_natural_8)
			invalidate
		end

feature -- Basic operations

	render (drawing: CAIRO_DRAWING_AREA)
		require
			valid_width: width <= Max_width
		local
			scaled_drawing: CAIRO_DRAWING_AREA
		do
			if attached point_array as p then
				drawing.save
				drawing.translate (p [0].x, p [0].y)
				drawing.rotate (angle)

				drawing.flip (width, height, mirror_state)
				if attached Scaled_drawing_cache as cache then
					cache.set_drawing_area (drawing_area) -- Ensure `new_scaled_pixel_buffer' refers to `pixel_buffer'
					scaled_drawing := cache.dimension_item (width, height)
				end
				drawing.draw_area (0, 0, scaled_drawing)
				drawing.restore
				progress_listener.notify_tick
			end
		end

feature -- Duplication

	copy (other: like Current)
		do
			if other /= Current then
				Precursor (other)
				create border_drawing.make (other.border_drawing.is_enabled)
			end
		end

	set_from_other (other: EL_MODEL_ROTATED_PICTURE)
		do
			set_coordinates_from (other)
			drawing_area := other.drawing_area
			set_foreground_color (other.foreground_color)
			if other.is_filled then
				set_background_color (other.background_color)
			end
			border_drawing.set_state (other.border_drawing.is_enabled)
			mirror_state := other.mirror_state
		end

feature {NONE} -- Implementation

	new_scaled_drawing_area (id_width_key: NATURAL): like drawing_area
		local
			scaled_width: INTEGER
		do
			scaled_width := (id_width_key & Width_mask).to_integer_32

			if scaled_width = drawing_area.width then
				Result := drawing_area
			else
				create Result.make_scaled_to_width (drawing_area, scaled_width, Void)
			end
		end

feature {EV_MODEL_DRAWER, EV_MODEL} -- Access

	drawing_area: CAIRO_DRAWING_AREA

feature {NONE} -- Constants

	Default_drawing_area: CAIRO_DRAWING_AREA
		once
			create Result.make_with_size (1, 1)
		end

	Scaled_drawing_cache: EL_DRAWING_AREA_CACHE_TABLE
		once
			create Result.make (13)
		end

	Width_mask: NATURAL = 0xFFFF

invariant
	valid_pixel_buffer_id: drawing_area.id.to_integer_32 <= Max_width

end