lib.rs (13201B)
1 use rand::Rng; 2 use std::{io::Cursor, iter::Peekable, str::SplitWhitespace, usize}; 3 use vibrato::{Dictionary, Tokenizer}; 4 use wasm_bindgen::prelude::*; 5 6 #[wasm_bindgen] 7 pub fn chat(dict_data: &[u8], input: &str) -> Result<String, JsValue> { 8 let encoded = Cursor::new(dict_data); 9 let reader = zstd::Decoder::new(encoded).unwrap(); 10 let dict = Dictionary::read(reader) 11 .map_err(|_| JsValue::from(js_sys::Error::new("Dictionary road Error")))?; 12 let tokenizer = Tokenizer::new(dict); 13 let mut worker = tokenizer.new_worker(); 14 let mut rng = rand::rng(); 15 let random_number = rng.random_range(1..=2); 16 17 worker.reset_sentence(input); 18 worker.tokenize(); 19 20 let mut ans: String = if random_number == 1 { 21 "どうせ失敗する。当たり前だ。そうに決まっている。".to_string() 22 } else { 23 "馬鹿なことを言ってないで。".to_string() 24 }; 25 26 match worker.num_tokens() { 27 1..5 => { 28 ans = if random_number == 1 { 29 "は?".to_string() 30 } else { 31 "何を言っているの?".to_string() 32 }; 33 } 34 5..9 => { 35 ans = if random_number == 1 { 36 "期待した私が馬鹿だったの?".to_string() 37 } else { 38 "そんなことができるわけないじゃない?".to_string() 39 }; 40 } 41 9 => { 42 ans = if random_number == 1 { 43 "お前のせいで私の人生がめちゃくちゃだ。".to_string() 44 } else { 45 "そんなこと思ってるんじゃないんでしょ?".to_string() 46 }; 47 } 48 10..=usize::MAX => { 49 ans = if random_number == 1 { 50 "どうでもいいわ。勝手にすれば。私には関係ない。".to_string() 51 } else { 52 "意味がわからない。".to_string() 53 }; 54 } 55 _ => { 56 ans = "どうでもいいわ。勝手にすれば。私には関係ない。".to_string(); 57 } 58 } 59 60 Ok(ans) 61 } 62 63 use kurbo::ParamCurveNearest; 64 use kurbo::{BezPath, ParamCurve, PathSeg, Point, Vec2}; 65 use std::f64::consts::PI; 66 use wasm_bindgen::JsValue; 67 68 // TypeScriptのPoint型に対応する構造体を定義 69 #[derive(Debug, Clone, Copy)] 70 #[wasm_bindgen] 71 pub struct NearestPointResult { 72 pub x: f64, 73 pub y: f64, 74 } 75 76 // ------------------------------------------------------------------------- 77 // 🛠️ Arc to Bezier 変換ヘルパ 78 // ------------------------------------------------------------------------- 79 80 /// ベクトルVを回転角度φだけ回転させます。(名前を rotate_vec2 に変更) 81 fn rotate_vec2(v: Vec2, sin_phi: f64, cos_phi: f64) -> Vec2 { 82 Vec2::new(v.x * cos_phi - v.y * sin_phi, v.x * sin_phi + v.y * cos_phi) 83 } 84 85 /// 単一のArcセグメント(2つの角度間)をCubic Bezierに変換します。 86 fn segment_to_cubic( 87 center: Point, 88 radii: Point, // (rx, ry) 89 phi: f64, // x軸回転角度 90 start_angle: f64, 91 delta_angle: f64, 92 path: &mut BezPath, 93 current_point: Point, 94 ) -> Point { 95 if delta_angle.abs() < 1e-6 { 96 return current_point; 97 } 98 99 let t_factor = 4.0 / 3.0 * (delta_angle / 4.0).tan(); 100 101 let a = radii.x; 102 let b = radii.y; 103 let cos_phi = phi.cos(); 104 let sin_phi = phi.sin(); 105 106 // Vec2として扱う 107 let start_vec = Vec2::new(start_angle.cos() * a, start_angle.sin() * b); 108 let end_vec = Vec2::new( 109 (start_angle + delta_angle).cos() * a, 110 (start_angle + delta_angle).sin() * b, 111 ); 112 113 // Vec2を回転 114 let start_vec_rotated = rotate_vec2(start_vec, sin_phi, cos_phi); 115 let end_vec_rotated = rotate_vec2(end_vec, sin_phi, cos_phi); 116 117 let p0 = center + start_vec_rotated; 118 let p3 = center + end_vec_rotated; 119 120 // Vec2 を使ったタンジェント計算 121 let t_start_vec = Vec2::new(-start_vec.y * t_factor, start_vec.x * t_factor); 122 let t_end_vec = Vec2::new(end_vec.y * t_factor, -end_vec.x * t_factor); 123 124 // Vec2を回転 125 let t_start = rotate_vec2(t_start_vec, sin_phi, cos_phi); 126 let t_end = rotate_vec2(t_end_vec, sin_phi, cos_phi); 127 128 let p1 = p0 + t_start; 129 let p2 = p3 + t_end; 130 131 path.curve_to(p1, p2, p3); 132 p3 133 } 134 135 /// SVG Arcコマンドを複数のCubic Bezierセグメントに分解します。 136 fn arc_to_beziers( 137 start_point: Point, 138 mut rx: f64, 139 mut ry: f64, 140 x_axis_rotation: f64, 141 large_arc_flag: bool, 142 sweep_flag: bool, 143 end_point: Point, 144 path: &mut BezPath, 145 ) -> Point { 146 if (rx.abs() < 1e-6 || ry.abs() < 1e-6) || start_point == end_point { 147 path.line_to(end_point); 148 return end_point; 149 } 150 151 rx = rx.abs(); 152 ry = ry.abs(); 153 154 let phi = x_axis_rotation * PI / 180.0; 155 let cos_phi = phi.cos(); 156 let sin_phi = phi.sin(); 157 158 // Vec2を回転し、結果も Vec2 159 let p_vec = (start_point - end_point) * 0.5; 160 let p_prime_vec = rotate_vec2(p_vec, -sin_phi, cos_phi); 161 // Pointとして使うために一時的に変換 162 let p_prime = Point::new(p_prime_vec.x, p_prime_vec.y); 163 164 let lambda = p_prime.x * p_prime.x / (rx * rx) + p_prime.y * p_prime.y / (ry * ry); 165 if lambda > 1.0 { 166 let root = lambda.sqrt(); 167 rx *= root; 168 ry *= root; 169 } 170 171 let rx_sq = rx * rx; 172 let ry_sq = ry * ry; 173 let x_prime_sq = p_prime.x * p_prime.x; 174 let y_prime_sq = p_prime.y * p_prime.y; 175 176 let mut center_coeff = ((rx_sq * ry_sq - rx_sq * y_prime_sq - ry_sq * x_prime_sq) 177 / (rx_sq * y_prime_sq + ry_sq * x_prime_sq)) 178 .max(0.0) 179 .sqrt(); 180 181 if large_arc_flag == sweep_flag { 182 center_coeff = -center_coeff; 183 } 184 185 let center_prime = Vec2::new( 186 // 中心C'は変位なのでVec2で表現 187 center_coeff * rx * p_prime.y / ry, 188 center_coeff * -ry * p_prime.x / rx, 189 ); 190 191 let center_midpoint_vec: Vec2 = (start_point - Point::ZERO + end_point.to_vec2()) * 0.5; 192 let midpoint: Point = Point::new(center_midpoint_vec.x, center_midpoint_vec.y); 193 194 // C' (Vec2) を回転 195 let center_prime_rotated = rotate_vec2(center_prime, sin_phi, cos_phi); 196 197 // 中点 (Point) + 回転変位 (Vec2) = 最終的な中心 (Point) 198 let center: Point = midpoint + center_prime_rotated; 199 200 // 7. 角度の計算 201 let to_angle = |p: Point| -> f64 { 202 let mut angle = (p.y).atan2(p.x); 203 if angle < 0.0 { 204 angle += 2.0 * PI; 205 } 206 angle 207 }; 208 209 // 始点と終点の角度を計算 (Pointを使って角度を求める) 210 let start_vec_p = Point::new( 211 (p_prime.x - center_prime.x) / rx, 212 (p_prime.y - center_prime.y) / ry, 213 ); 214 let start_angle = to_angle(start_vec_p); 215 216 let end_vec_p = Point::new( 217 (-p_prime.x - center_prime.x) / rx, 218 (-p_prime.y - center_prime.y) / ry, 219 ); 220 let end_angle = to_angle(end_vec_p); 221 222 // 角度差の計算 223 let mut delta_angle = end_angle - start_angle; 224 if !sweep_flag && delta_angle > 0.0 { 225 delta_angle -= 2.0 * PI; 226 } else if sweep_flag && delta_angle < 0.0 { 227 delta_angle += 2.0 * PI; 228 } 229 230 let num_segments = (delta_angle.abs() / (PI / 2.0)).ceil() as i32; 231 let segment_delta = delta_angle / num_segments as f64; 232 233 let mut current_arc_angle = start_angle; 234 let mut current_p = start_point; 235 236 for _ in 0..num_segments { 237 let next_angle = current_arc_angle + segment_delta; 238 239 current_p = segment_to_cubic( 240 center, 241 Point::new(rx, ry), 242 phi, 243 current_arc_angle, 244 segment_delta, 245 path, 246 current_p, 247 ); 248 249 current_arc_angle = next_angle; 250 } 251 252 end_point 253 } 254 255 // ... (残りの関数は変更なし) ... 256 257 /// SVG Path Data (d attribute) を解析し、kurbo::BezPathに変換します。 258 fn parse_svg_path_to_bezpath(path_d: &str) -> Option<BezPath> { 259 let mut path = BezPath::new(); 260 261 let binding = path_d.replace(',', " "); 262 263 let mut tokens: Peekable<SplitWhitespace> = binding.split_whitespace().peekable(); 264 265 let mut current_point = Point::new(0.0, 0.0); 266 let mut subpath_start = Point::new(0.0, 0.0); 267 268 let get_f64 = |tokens: &mut Peekable<SplitWhitespace>| -> Option<f64> { 269 tokens.next().and_then(|s| s.parse::<f64>().ok()) 270 }; 271 272 while let Some(token) = tokens.next() { 273 let command = token.to_uppercase(); 274 275 match command.as_str() { 276 "M" => { 277 let x = get_f64(&mut tokens)?; 278 let y = get_f64(&mut tokens)?; 279 current_point = Point::new(x, y); 280 subpath_start = current_point; 281 path.move_to(current_point); 282 283 while tokens.peek().and_then(|t| t.parse::<f64>().ok()).is_some() { 284 let x = get_f64(&mut tokens)?; 285 let y = get_f64(&mut tokens)?; 286 current_point = Point::new(x, y); 287 path.line_to(current_point); 288 } 289 } 290 "L" => { 291 let x = get_f64(&mut tokens)?; 292 let y = get_f64(&mut tokens)?; 293 current_point = Point::new(x, y); 294 path.line_to(current_point); 295 } 296 "C" => { 297 let x1 = get_f64(&mut tokens)?; 298 let y1 = get_f64(&mut tokens)?; 299 let x2 = get_f64(&mut tokens)?; 300 let y2 = get_f64(&mut tokens)?; 301 let x = get_f64(&mut tokens)?; 302 let y = get_f64(&mut tokens)?; 303 304 let p1 = Point::new(x1, y1); 305 let p2 = Point::new(x2, y2); 306 current_point = Point::new(x, y); 307 308 path.curve_to(p1, p2, current_point); 309 } 310 "A" => { 311 let rx = get_f64(&mut tokens)?; 312 let ry = get_f64(&mut tokens)?; 313 let x_axis_rotation = get_f64(&mut tokens)?; 314 let large_arc_flag = get_f64(&mut tokens)? != 0.0; 315 let sweep_flag = get_f64(&mut tokens)? != 0.0; 316 let x = get_f64(&mut tokens)?; 317 let y = get_f64(&mut tokens)?; 318 let end_point = Point::new(x, y); 319 320 // Arc to Bezier 変換ロジックを呼び出し 321 current_point = arc_to_beziers( 322 current_point, 323 rx, 324 ry, 325 x_axis_rotation, 326 large_arc_flag, 327 sweep_flag, 328 end_point, 329 &mut path, 330 ); 331 } 332 "Z" => { 333 path.close_path(); 334 current_point = subpath_start; 335 } 336 _ => { 337 return None; 338 } 339 } 340 } 341 Some(path) 342 } 343 344 /** 345 * SVGパス上で指定された点に最も近い点を計算します。 346 */ 347 #[wasm_bindgen] 348 pub fn find_nearest_point_on_path( 349 path_d: &str, 350 x: f64, 351 y: f64, 352 _snapping_distance_viewbox: f64, 353 ) -> Option<NearestPointResult> { 354 let target_point = Point::new(x, y); 355 356 let bez_path = parse_svg_path_to_bezpath(path_d)?; 357 358 let mut closest_point: Option<Point> = None; 359 let mut min_dist_sq: f64 = f64::MAX; 360 361 // PathSegのバリアントからジオメトリ型(Line, CubicBez)を抽出 362 for segment in bez_path.segments() { 363 let new_closest_point = match segment { 364 // Line構造体を抽出 365 PathSeg::Line(line) => { 366 // nearest_param の代わりに nearest を使用し、accuracy に 1.0 (デフォルト値) を渡す 367 let nearest_result = line.nearest(target_point, 1.0); 368 let dist_sq = nearest_result.distance_sq; 369 370 if dist_sq < min_dist_sq { 371 min_dist_sq = dist_sq; 372 // nearest_result.point は非公開なので、eval(param) を使用する 373 Some(line.eval(nearest_result.t)) 374 } else { 375 None 376 } 377 } 378 // CubicBez構造体を抽出 379 PathSeg::Cubic(cubic_bez) => { 380 let nearest_result = cubic_bez.nearest(target_point, 1.0); 381 let dist_sq = nearest_result.distance_sq; 382 383 if dist_sq < min_dist_sq { 384 min_dist_sq = dist_sq; 385 Some(cubic_bez.eval(nearest_result.t)) 386 } else { 387 None 388 } 389 } 390 // Quad Bezier (サポート外) およびその他のバリアントはスキップ 391 _ => None, 392 }; 393 394 if new_closest_point.is_some() { 395 closest_point = new_closest_point; 396 } 397 } 398 399 // 4. 結果の返却 400 if let Some(p) = closest_point { 401 return Some(NearestPointResult { x: p.x, y: p.y }); 402 } else { 403 return Some(NearestPointResult { x: 500.0, y: 500.0 }); 404 } 405 406 Some(NearestPointResult { x: 0.0, y: 0.0 }) 407 } 408 409 // WASMの初期化関数 (必須) 410 #[wasm_bindgen(start)] 411 pub fn main_js() -> Result<(), JsValue> { 412 Ok(()) 413 }