|
1 | | -# SPDX-FileCopyrightText: Kevin Matocha |
2 | | -# |
3 | | -# SPDX-License-Identifier: MIT |
4 | | - |
5 | | -""" |
6 | | -`adafruit_displayio_layout.widgets` |
7 | | -======================= |
8 | | -""" |
9 | | - |
10 | | -import math |
11 | | - |
12 | | -# * Copyright (c) 2017 Werner Stoop <[email protected]> |
13 | | -# * |
14 | | -# * Permission is hereby granted, free of charge, to any person obtaining a copy |
15 | | -# * of this software and associated documentation files (the "Software"), to deal |
16 | | -# * in the Software without restriction, including without limitation the rights |
17 | | -# * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
18 | | -# * copies of the Software, and to permit persons to whom the Software is |
19 | | -# * furnished to do so, subject to the following conditions: |
20 | | -# * |
21 | | -# * The above copyright notice and this permission notice shall be included in all |
22 | | -# * copies or substantial portions of the Software. |
23 | | -# * |
24 | | -# * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
25 | | -# * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
26 | | -# * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
27 | | -# * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
28 | | -# * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
29 | | -# * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
30 | | -# * SOFTWARE. |
31 | | - |
32 | | - |
33 | | -# Credit from https://github.com/wernsey/bitmap |
34 | | -# MIT License from |
35 | | -# * Copyright (c) 2017 Werner Stoop <[email protected]> |
36 | | -# |
37 | | -# /** |
38 | | -# * #### `void bm_rotate_blit(Bitmap *dst, int ox, int oy, Bitmap *src, int px, |
39 | | -# * int py, double angle, double scale);` |
40 | | -# * |
41 | | -# * Rotates a source bitmap `src` around a pivot point `px,py` and blits it |
42 | | -# * onto a destination bitmap `dst`. |
43 | | -# * |
44 | | -# * The bitmap is positioned such that the point `px,py` on the source is at |
45 | | -# * the offset `ox,oy` on the destination. |
46 | | -# * |
47 | | -# * The `angle` is clockwise, in radians. The bitmap is also scaled by the |
48 | | -# * factor `scale`. |
49 | | -# */ |
50 | | -# void bm_rotate_blit(Bitmap *dst, int ox, int oy, Bitmap *src, int px, |
51 | | -# int py, double angle, double scale); |
52 | | - |
53 | | - |
54 | | -# /* |
55 | | -# Reference: |
56 | | -# "Fast Bitmap Rotation and Scaling" By Steven Mortimer, Dr Dobbs' Journal, July 01, 2001 |
57 | | -# http://www.drdobbs.com/architecture-and-design/fast-bitmap-rotation-and-scaling/184416337 |
58 | | -# See also http://www.efg2.com/Lab/ImageProcessing/RotateScanline.htm |
59 | | -# */ |
60 | | -# This function is provided in case the bitmaptools.rotozoom function is not available |
61 | | - |
62 | | -# pylint: disable=invalid-name, too-many-branches, too-many-statements, too-many-locals |
63 | | -# pylint: disable=too-many-arguments |
64 | | -def _blit_rotate_scale( |
65 | | - destination, # destination bitmap |
66 | | - ox=None, |
67 | | - oy=None, # (ox, oy) is the destination point where the source (px,py) is placed |
68 | | - dest_clip0=None, |
69 | | - dest_clip1=None, # clip0,1 is (x,y) corners of clip window on the destination bitmap |
70 | | - source=None, # source bitmap |
71 | | - px=None, |
72 | | - py=None, # (px, py) is the rotation point of the source bitmap |
73 | | - source_clip0=None, |
74 | | - source_clip1=None, # clip0,1 is (x,y) corners of clip window on the source bitmap |
75 | | - angle=0, # in radians, clockwise |
76 | | - scale=1.0, # scale factor (float) |
77 | | - skip_index=None, # color index to ignore |
78 | | -): |
79 | | - |
80 | | - if source is None: |
81 | | - pass |
82 | | - |
83 | | - # Check the input limits |
84 | | - |
85 | | - if ox is None: |
86 | | - ox = destination.width / 2 |
87 | | - if oy is None: |
88 | | - oy = destination.height / 2 |
89 | | - if px is None: |
90 | | - px = source.width / 2 |
91 | | - if py is None: |
92 | | - py = source.height / 2 |
93 | | - |
94 | | - if dest_clip0 is None: |
95 | | - dest_clip0 = (0, 0) |
96 | | - if dest_clip1 is None: |
97 | | - dest_clip1 = (destination.width, destination.height) |
98 | | - |
99 | | - if source_clip0 is None: |
100 | | - source_clip0 = (0, 0) |
101 | | - if source_clip1 is None: |
102 | | - source_clip1 = (source.width, source.height) |
103 | | - |
104 | | - minx = dest_clip1[0] |
105 | | - miny = dest_clip1[1] |
106 | | - maxx = dest_clip0[0] |
107 | | - maxy = dest_clip0[1] |
108 | | - |
109 | | - sinAngle = math.sin(angle) |
110 | | - cosAngle = math.cos(angle) |
111 | | - |
112 | | - dx = -cosAngle * px * scale + sinAngle * py * scale + ox |
113 | | - dy = -sinAngle * px * scale - cosAngle * py * scale + oy |
114 | | - if dx < minx: |
115 | | - minx = int(round(dx)) |
116 | | - if dx > maxx: |
117 | | - maxx = int(round(dx)) |
118 | | - if dy < miny: |
119 | | - miny = int(round(dy)) |
120 | | - if dy > maxy: |
121 | | - maxy = int(dy) |
122 | | - dx = cosAngle * (source.width - px) * scale + sinAngle * py * scale + ox |
123 | | - dy = sinAngle * (source.width - px) * scale - cosAngle * py * scale + oy |
124 | | - if dx < minx: |
125 | | - minx = int(round(dx)) |
126 | | - if dx > maxx: |
127 | | - maxx = int(round(dx)) |
128 | | - if dy < miny: |
129 | | - miny = int(round(dy)) |
130 | | - if dy > maxy: |
131 | | - maxy = int(round(dy)) |
132 | | - |
133 | | - dx = ( |
134 | | - cosAngle * (source.width - px) * scale |
135 | | - - sinAngle * (source.height - py) * scale |
136 | | - + ox |
137 | | - ) |
138 | | - dy = ( |
139 | | - sinAngle * (source.width - px) * scale |
140 | | - + cosAngle * (source.height - py) * scale |
141 | | - + oy |
142 | | - ) |
143 | | - if dx < minx: |
144 | | - minx = int(round(dx)) |
145 | | - if dx > maxx: |
146 | | - maxx = int(round(dx)) |
147 | | - if dy < miny: |
148 | | - miny = int(round(dy)) |
149 | | - if dy > maxy: |
150 | | - maxy = int(round(dy)) |
151 | | - |
152 | | - dx = -cosAngle * px * scale - sinAngle * (source.height - py) * scale + ox |
153 | | - dy = -sinAngle * px * scale + cosAngle * (source.height - py) * scale + oy |
154 | | - if dx < minx: |
155 | | - minx = int(round(dx)) |
156 | | - if dx > maxx: |
157 | | - maxx = int(round(dx)) |
158 | | - if dy < miny: |
159 | | - miny = int(round(dy)) |
160 | | - if dy > maxy: |
161 | | - maxy = int(round(dy)) |
162 | | - |
163 | | - # /* Clipping */ |
164 | | - if minx < dest_clip0[0]: |
165 | | - minx = dest_clip0[0] |
166 | | - if maxx > dest_clip1[0] - 1: |
167 | | - maxx = dest_clip1[0] - 1 |
168 | | - if miny < dest_clip0[1]: |
169 | | - miny = dest_clip0[1] |
170 | | - if maxy > dest_clip1[1] - 1: |
171 | | - maxy = dest_clip1[1] - 1 |
172 | | - |
173 | | - dvCol = math.cos(angle) / scale |
174 | | - duCol = math.sin(angle) / scale |
175 | | - |
176 | | - duRow = dvCol |
177 | | - dvRow = -duCol |
178 | | - |
179 | | - startu = px - (ox * dvCol + oy * duCol) |
180 | | - startv = py - (ox * dvRow + oy * duRow) |
181 | | - |
182 | | - rowu = startu + miny * duCol |
183 | | - rowv = startv + miny * dvCol |
184 | | - |
185 | | - for y in range(miny, maxy + 1): # (y = miny, y <= maxy, y++) |
186 | | - u = rowu + minx * duRow |
187 | | - v = rowv + minx * dvRow |
188 | | - for x in range(minx, maxx + 1): # (x = minx, x <= maxx, x++) |
189 | | - if (source_clip0[0] <= u < source_clip1[0]) and ( |
190 | | - source_clip0[1] <= v < source_clip1[1] |
191 | | - ): |
192 | | - # get the pixel color (c) from the source bitmap at (u,v) |
193 | | - c = source[ |
194 | | - int(u) + source.width * int(v) |
195 | | - ] # direct index into bitmap is faster than tuple |
196 | | - # c = source[int(u), int(v)] |
197 | | - |
198 | | - if c != skip_index: # ignore any pixels with skip_index |
199 | | - # place the pixel color (c) into the destination bitmap at (x,y) |
200 | | - destination[ |
201 | | - x + y * destination.width |
202 | | - ] = c # direct index into bitmap is faster than tuple |
203 | | - # destination[x,y] = c |
204 | | - u += duRow |
205 | | - v += dvRow |
206 | | - |
207 | | - rowu += duCol |
208 | | - rowv += dvCol |
0 commit comments