Skip to content

Commit e5304e6

Browse files
committed
Moving _blip_rotate_scale to __init__ to avoid code repetition.
1 parent 3133990 commit e5304e6

File tree

2 files changed

+209
-199
lines changed

2 files changed

+209
-199
lines changed
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
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

Comments
 (0)