Skip to content

Commit ec6e749

Browse files
authored
♻️ refactor: rustify writer utility convert_flash_rotation (#317)
1 parent 1050744 commit ec6e749

File tree

6 files changed

+97
-60
lines changed

6 files changed

+97
-60
lines changed

packages/biliass/rust/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,6 @@ fn biliass_pyo3(m: &Bound<'_, PyModule>) -> PyResult<()> {
2929
m.add_function(wrap_pyfunction!(python::py_ass_escape, m)?)?;
3030
m.add_function(wrap_pyfunction!(python::py_convert_color, m)?)?;
3131
m.add_function(wrap_pyfunction!(python::py_get_zoom_factor, m)?)?;
32+
m.add_function(wrap_pyfunction!(python::py_convert_flash_rotation, m)?)?;
3233
Ok(())
3334
}

packages/biliass/rust/src/python/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,7 @@ mod writer;
66
pub use comment::{PyComment, PyCommentPosition};
77
pub use proto::{PyDanmakuElem, PyDmSegMobileReply};
88
pub use reader::{py_read_comments_from_protobuf, py_read_comments_from_xml};
9-
pub use writer::{py_ass_escape, py_convert_color, py_convert_timestamp, py_get_zoom_factor};
9+
pub use writer::{
10+
py_ass_escape, py_convert_color, py_convert_flash_rotation, py_convert_timestamp,
11+
py_get_zoom_factor,
12+
};

packages/biliass/rust/src/python/writer.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,17 @@ pub fn py_get_zoom_factor(
2525
) -> PyResult<(f32, f32, f32)> {
2626
Ok(writer::utils::get_zoom_factor(source_size, target_size))
2727
}
28+
29+
#[pyfunction(name = "convert_flash_rotation")]
30+
pub fn py_convert_flash_rotation(
31+
rot_y: f64,
32+
rot_z: f64,
33+
x: f64,
34+
y: f64,
35+
width: f64,
36+
height: f64,
37+
) -> PyResult<(f64, f64, f64, f64, f64, f64, f64)> {
38+
Ok(writer::utils::convert_flash_rotation(
39+
rot_y, rot_z, x, y, width, height,
40+
))
41+
}

packages/biliass/rust/src/writer/utils.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,77 @@ pub fn get_zoom_factor(source_size: (u32, u32), target_size: (u32, u32)) -> (f32
103103
(target_size.0 / source_size.0, 0.0, 0.0)
104104
}
105105
}
106+
107+
// Calculation is based on https://github.com/jabbany/CommentCoreLibrary/issues/5#issuecomment-40087282
108+
// and https://github.com/m13253/danmaku2ass/issues/7#issuecomment-41489422
109+
// ASS FOV = width*4/3.0
110+
// But Flash FOV = width/math.tan(100*math.pi/360.0)/2 will be used instead
111+
// Result: (trans_x, trans_y, rot_x, rot_y, rot_z, scale_x, scale_y)
112+
pub fn convert_flash_rotation(
113+
rot_y: f64,
114+
rot_z: f64,
115+
x: f64,
116+
y: f64,
117+
width: f64,
118+
height: f64,
119+
) -> (f64, f64, f64, f64, f64, f64, f64) {
120+
let wrap_angle = |deg: f64| -> f64 { 180.0 - ((180.0 - deg).rem_euclid(360.0)) };
121+
let mut rot_y = wrap_angle(rot_y);
122+
let rot_z = wrap_angle(rot_z);
123+
let pi_angle = std::f64::consts::PI / 180.0;
124+
if rot_y == 90.0 || rot_y == -90.0 {
125+
rot_y -= 1.0;
126+
}
127+
let (out_x, out_y, out_z, rot_y, rot_z) = if rot_y == 0. || rot_z == 0. {
128+
let out_x = 0.;
129+
let out_y = -rot_y; // Positive value means clockwise in Flash
130+
let out_z = -rot_z;
131+
let rot_y_rad = rot_y * pi_angle;
132+
let rot_z_rad = rot_z * pi_angle;
133+
(out_x, out_y, out_z, rot_y_rad, rot_z_rad)
134+
} else {
135+
let rot_y_rad = rot_y * pi_angle;
136+
let rot_z_rad = rot_z * pi_angle;
137+
let out_y = (-rot_y_rad.sin() * rot_z_rad.cos()).atan2(rot_y_rad.cos()) / pi_angle;
138+
let out_z = (-rot_y_rad.cos() * rot_z_rad.sin()).atan2(rot_z_rad.cos()) / pi_angle;
139+
let out_x = (rot_y_rad.sin() * rot_z_rad.sin()).asin() / pi_angle;
140+
(out_x, out_y, out_z, rot_y_rad, rot_z_rad)
141+
};
142+
let trans_x = (x * rot_z.cos() + y * rot_z.sin()) / rot_y.cos()
143+
+ (1.0 - rot_z.cos() / rot_y.cos()) * width / 2.0
144+
- rot_z.sin() / rot_y.cos() * height / 2.0;
145+
let trans_y = y * rot_z.cos() - x * rot_z.sin()
146+
+ rot_z.sin() * width / 2.0
147+
+ (1.0 - rot_z.cos()) * height / 2.0;
148+
let trans_z = (trans_x - width / 2.0) * rot_y.sin();
149+
let fov = width * (2.0 * std::f64::consts::PI / 9.0).tan() / 2.0;
150+
let scale_xy = if fov + trans_z != 0.0 {
151+
fov / (fov + trans_z)
152+
} else {
153+
// eprintln!(
154+
// "Rotation makes object behind the camera: trZ == {:.0}",
155+
// trans_z
156+
// );
157+
1.
158+
};
159+
let trans_x = (trans_x - width / 2.0) * scale_xy + width / 2.0;
160+
let trans_y = (trans_y - height / 2.0) * scale_xy + height / 2.0;
161+
let (scale_xy, out_x, out_y) = if scale_xy < 0. {
162+
// eprintln!(
163+
// "Rotation makes object behind the camera: trZ == {:.0} < {:.0}",
164+
// trans_z, fov
165+
// );
166+
(-scale_xy, out_x + 180., out_y + 180.)
167+
} else {
168+
(scale_xy, out_x, out_y)
169+
};
170+
(
171+
trans_x,
172+
trans_y,
173+
wrap_angle(out_x),
174+
wrap_angle(out_y),
175+
wrap_angle(out_z),
176+
scale_xy * 100.,
177+
scale_xy * 100.,
178+
)
179+
}

packages/biliass/src/biliass/_core.pyi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,6 @@ def convert_timestamp(timestamp: float) -> float: ...
6161
def ass_escape(text: str) -> str: ...
6262
def convert_color(rgb: int, width: int = ..., height: int = ...) -> str: ...
6363
def get_zoom_factor(source_size: tuple[int, int], target_size: tuple[int, int]) -> tuple[float, float, float]: ...
64+
def convert_flash_rotation(
65+
rot_y: float, rot_z: float, x: float, y: float, width: float, height: float
66+
) -> tuple[float, float, float, float, float, float, float]: ...

packages/biliass/src/biliass/biliass.py

Lines changed: 1 addition & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
CommentPosition,
1515
ass_escape,
1616
convert_color,
17+
convert_flash_rotation,
1718
convert_timestamp,
1819
get_zoom_factor,
1920
read_comments_from_protobuf,
@@ -221,69 +222,10 @@ def write_comment(
221222
styleid=styleid,
222223
)
223224

224-
def to_file(self, f):
225-
f.write(self._text)
226-
227225
def to_string(self):
228226
return self._text
229227

230228

231-
# Calculation is based on https://github.com/jabbany/CommentCoreLibrary/issues/5#issuecomment-40087282
232-
# and https://github.com/m13253/danmaku2ass/issues/7#issuecomment-41489422
233-
# ASS FOV = width*4/3.0
234-
# But Flash FOV = width/math.tan(100*math.pi/360.0)/2 will be used instead
235-
# Result: (transX, transY, rotX, rotY, rotZ, scaleX, scaleY)
236-
def convert_flash_rotation(rotY, rotZ, X, Y, width, height):
237-
def wrap_angle(deg):
238-
return 180 - ((180 - deg) % 360)
239-
240-
rotY = wrap_angle(rotY)
241-
rotZ = wrap_angle(rotZ)
242-
if rotY in (90, -90):
243-
rotY -= 1
244-
if rotY == 0 or rotZ == 0:
245-
outX = 0
246-
outY = -rotY # Positive value means clockwise in Flash
247-
outZ = -rotZ
248-
rotY *= math.pi / 180.0
249-
rotZ *= math.pi / 180.0
250-
else:
251-
rotY *= math.pi / 180.0
252-
rotZ *= math.pi / 180.0
253-
outY = math.atan2(-math.sin(rotY) * math.cos(rotZ), math.cos(rotY)) * 180 / math.pi
254-
outZ = math.atan2(-math.cos(rotY) * math.sin(rotZ), math.cos(rotZ)) * 180 / math.pi
255-
outX = math.asin(math.sin(rotY) * math.sin(rotZ)) * 180 / math.pi
256-
trX = (
257-
(X * math.cos(rotZ) + Y * math.sin(rotZ)) / math.cos(rotY)
258-
+ (1 - math.cos(rotZ) / math.cos(rotY)) * width / 2
259-
- math.sin(rotZ) / math.cos(rotY) * height / 2
260-
)
261-
trY = Y * math.cos(rotZ) - X * math.sin(rotZ) + math.sin(rotZ) * width / 2 + (1 - math.cos(rotZ)) * height / 2
262-
trZ = (trX - width / 2) * math.sin(rotY)
263-
FOV = width * math.tan(2 * math.pi / 9.0) / 2
264-
try:
265-
scaleXY = FOV / (FOV + trZ)
266-
except ZeroDivisionError:
267-
logging.error(f"Rotation makes object behind the camera: trZ == {trZ:.0f}")
268-
scaleXY = 1
269-
trX = (trX - width / 2) * scaleXY + width / 2
270-
trY = (trY - height / 2) * scaleXY + height / 2
271-
if scaleXY < 0:
272-
scaleXY = -scaleXY
273-
outX += 180
274-
outY += 180
275-
logging.error(f"Rotation makes object behind the camera: trZ == {trZ:.0f} < {FOV:.0f}")
276-
return (
277-
trX,
278-
trY,
279-
wrap_angle(outX),
280-
wrap_angle(outY),
281-
wrap_angle(outZ),
282-
scaleXY * 100,
283-
scaleXY * 100,
284-
)
285-
286-
287229
def process_comments(
288230
comments,
289231
width,

0 commit comments

Comments
 (0)