Registry / RepositoryTypeScriptRustPython
Rollpie
ReadmeFiles
Versions
Info
Download
0.2.0528.5 KB2026-10-160.1.1542.8 KB2026-10-150.1.0541.1 KB2026-10-15
Version
0.1.0
Copyright
Rollpie, Irohabook
Publisher
math
Published
2026-10-15
Size
541.1 KB
Downloads
9
Checksum
67f9c361d04f05b0299dd8e9ef5e2a0120d67be36205a76945eb5f7ef90443be
Dependencies
None

ring.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//! 環の幾何
//!
//! 環は正多角形として置く。最初の頂点は、その環を抱えている原子である。
//! そこから時計回りに、辺を 1 本ずつたどって頂点を決めていく。
//!
//! 1 本目の辺の向きは、入ってきた結合の向きから決まる。入ってきた結合が
//! 最初の頂点の外角を二等分するように置くので、環は入ってきた向きへまっすぐ伸びる。
//! 入ってくる結合がなければ、真横から入ってきたものとして扱う。

use std::f64::consts::PI;


/// 1 本目の辺の向き(度)
pub fn first_angle(size: usize, incoming: f64) -> f64 {
    incoming + 90.0 - 180.0 / size as f64
}


/// 辺 1 本ごとに向きを変える量(度)。時計回りなので負である
pub fn turn(size: usize) -> f64 {
    -360.0 / size as f64
}


/// 頂点から中心までの長さ
pub fn radius(size: usize, span: f64) -> f64 {
    span / (2.0 * (PI / size as f64).sin())
}


/// 辺から中心までの長さ
pub fn inradius(size: usize, span: f64) -> f64 {
    span / (2.0 * (PI / size as f64).tan())
}


/// 最初の頂点から見た中心の位置
pub fn center(size: usize, span: f64, vertex: (f64, f64), incoming: f64) -> (f64, f64) {
    let length = radius(size, span);
    let radian = incoming.to_radians();

    (vertex.0 + radian.cos() * length, vertex.1 - radian.sin() * length)
}


/// 内側に寄せた二重結合を、両端でどれだけ詰めるか
///
/// 詰めておくと、隣の辺の内側の線と端が合う。詰めないと角からはみ出す
pub fn inset(size: usize, gap: f64) -> f64 {
    let half = (180.0 - 360.0 / size as f64) / 2.0;

    gap / half.to_radians().tan()
}


#[cfg(test)]
mod tests {
    use super::*;

    /// 環をたどって頂点を並べる。試験のためだけの組み立て
    fn walk(size: usize, span: f64, incoming: f64) -> Vec<(f64, f64)> {
        let mut found = vec![(0.0, 0.0)];
        let mut angle = first_angle(size, incoming);

        for _ in 0..size {
            let last = *found.last().unwrap();
            let radian = angle.to_radians();
            found.push((last.0 + radian.cos() * span, last.1 - radian.sin() * span));
            angle += turn(size);
        }

        found
    }

    #[test]
    fn a_ring_comes_back_to_where_it_started() {
        for size in 3..=12 {
            let found = walk(size, 3.0, 0.0);
            let last = found[size];
            assert!(last.0.abs() < 1e-9 && last.1.abs() < 1e-9, "{size} 員環が閉じていません");
        }
    }

    #[test]
    fn every_side_has_the_same_length() {
        let found = walk(6, 3.0, 0.0);

        for pair in found.windows(2) {
            let span = ((pair[1].0 - pair[0].0).powi(2) + (pair[1].1 - pair[0].1).powi(2)).sqrt();
            assert!((span - 3.0).abs() < 1e-9);
        }
    }

    #[test]
    fn a_plain_hexagon_lies_flat() {
        let found = walk(6, 3.0, 0.0);
        // 1 本目が 60 度なので、上と下の辺が水平になり、左右がとがる
        assert!((found[1].0 - 1.5).abs() < 1e-9);
        assert!((found[1].1 + 2.598).abs() < 1e-3);
        assert!((found[3].0 - 6.0).abs() < 1e-9);
        assert!(found[3].1.abs() < 1e-9, "向かいの頂点が同じ高さにありません");
    }

    #[test]
    fn the_ring_grows_along_the_bond_that_came_in() {
        let middle = center(6, 3.0, (0.0, 0.0), 0.0);
        assert!((middle.0 - 3.0).abs() < 1e-9);
        assert!(middle.1.abs() < 1e-9);

        let upward = center(6, 3.0, (0.0, 0.0), 90.0);
        assert!(upward.0.abs() < 1e-9);
        assert!((upward.1 + 3.0).abs() < 1e-9);
    }

    #[test]
    fn the_center_is_the_same_distance_from_every_vertex() {
        let found = walk(5, 3.0, 30.0);
        let middle = center(5, 3.0, (0.0, 0.0), 30.0);
        let length = radius(5, 3.0);

        for vertex in &found[0..5] {
            let span = ((vertex.0 - middle.0).powi(2) + (vertex.1 - middle.1).powi(2)).sqrt();
            assert!((span - length).abs() < 1e-9);
        }
    }

    #[test]
    fn the_inner_radius_is_shorter_than_the_outer() {
        for size in 3..=12 {
            assert!(inradius(size, 3.0) < radius(size, 3.0));
        }
    }

    #[test]
    fn a_hexagon_trims_its_inner_line_by_the_gap_over_root_three() {
        assert!((inset(6, 0.2) - 0.2 / 3f64.sqrt()).abs() < 1e-9);
    }
}