AIdentity

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

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 }