|
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 <wstoop@gmail.com> |
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 <wstoop@gmail.com> |
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