#!/usr/bin/env python3 """依頼157(paths155.py の写し:カメラは cams157。寄り 外来の大廊下の清掃 は、7:30〜8:00 のうち清掃の人が寄りの枠(x26〜70)の中の大廊下の点で拭いている(1人でも)、7:40 にいちばん近い時刻(extra157.csv の「着いた:拭く1〜4」から、その点で止まる秒のあいだ))。もとの説明:依頼155(paths154.py の写し:カメラは cams155。寄り 化学療法のトイレの前 は、その日はじめに化学療法のトイレへ行く化学療法の患者が、トイレの前の通り道 x114〜115.5・z53〜60 に入って 1 秒後)。もとの説明:依頼154(paths149.py の写し:カメラは cams154。寄り 救急の待合・正面玄関から救急へ行く道 は、10:00 ごろ・14:00 ごろの窓の中で、救急の患者が正面玄関から救急の待合へ歩いている人数がいちばん多い分)。もとの説明:依頼149(paths147.py の写しを直した:静止画は cams149 の6つを 10:00 ごろ・14:00 ごろの2回)。もとの説明:依頼147(paths143.py の写しを直した):撮る回のカメラの道(-h141CamPath の CSV)を、確かめの回 check143a(同じ種・同じ実行ファイル)から作る。 flowday(1日の早回し。依頼141 の paths141.py と同じ作り):0.05 秒から、ふだん 1.2 秒ごと(30倍)で引き。 ロボットが走っている間(legs の 行き・帰り・移る。続いている区間はつなぐ)は 0.2 秒ごと(5倍)で付いて行く寄り (左30°・75°見下ろし・距離 27.9 m・注視点=ロボットの位置を σ1.5 秒でならした点)。最初と最後の 25 コマで引き⇄寄り(smoothstep)。 引きは、そのときロボットのいる側(x<60 は西半分、それ以外は東半分。cams143.py の w_west・w_east)。最後の便が戻ったところで終わる 静止画(cams143.py の8つ):1行だけの道(その時刻に1枚)。時刻は下の STILLS(ロボットが台の前に止まっている時刻など) python3 paths143.py <出力.csv> """ import csv, json, math, os, re, sys sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from paths141 import Follow, load_track, smooth, g, NEAR, FOV, W, H, TRANS from cams143 import cams as cams143 from cams157 import cams as cams149, still_cams from collections import defaultdict SPLIT_X = 60.0 def main(): run, dst, camtxt = sys.argv[1], sys.argv[2], sys.argv[3] T, X, Z = load_track(run) fo = Follow(T, X, Z) C = {c[0]: c for c in cams143()} WIDE = {"west": dict(tx=C["w_west"][3], tz=C["w_west"][4], dist=C["w_west"][5]), "east": dict(tx=C["w_east"][3], tz=C["w_east"][4], dist=C["w_east"][5])} legs = list(csv.DictReader(open(run + "/legs.csv", encoding="utf-8"))) trips = list(csv.DictReader(open(run + "/trips.csv", encoding="utf-8"))) last = max(float(t["end_s"]) for t in trips if t["end_s"]) # 走っている区間(行き・帰り・移る)をつなぐ wins = [] for l in legs: if l["dir"] not in ("行き", "帰り", "移る"): continue s, e = float(l["start_s"]), float(l["end_s"]) if wins and s - wins[-1][1] < 2.0: wins[-1][1] = e else: wins.append([s, e]) side = lambda t: "west" if fo.raw(t)[0] < SPLIT_X else "east" def blend(a, wide, near_xz): tx = wide["tx"] + a * (near_xz[0] - wide["tx"]) tz = wide["tz"] + a * (near_xz[1] - wide["tz"]) d = math.exp(math.log(wide["dist"]) + a * (math.log(NEAR["dist"]) - math.log(wide["dist"]))) return tx, tz, d rows = [] t, wi = 0.05, 0 while True: if wi < len(wins) and t >= g(wins[wi][0]) - 1e-6: s0, e0 = g(wins[wi][0]), wins[wi][1] n = int(math.ceil((g(e0) - s0) / 0.2 - 1e-6)) ts = [g(s0 + 0.2 * k) for k in range(n + 1)] w_in, w_out = WIDE[side(s0)], WIDE[side(e0)] for k, tt in enumerate(ts): a_in = smooth((k + 1) / TRANS); a_out = smooth((len(ts) - k) / TRANS) a = min(a_in, a_out) wide = w_in if k < len(ts) / 2 else w_out tx, tz, d = blend(a, wide, fo.at(tt)) rows.append(("flowday", tt, tx, tz, d, "5倍", a, side(s0) if k < len(ts) / 2 else side(e0))) t = ts[-1] wi += 1 if t >= last - 1e-6 or wi == len(wins): break t = g(t + 1.2) continue sd = side(t) rows.append(("flowday", t, WIDE[sd]["tx"], WIDE[sd]["tz"], WIDE[sd]["dist"], "30倍", 0.0, sd)) nt = g(t + 1.2) if wi < len(wins) and nt > g(wins[wi][0]): nt = g(wins[wi][0]) t = nt # 静止画の時刻(依頼149):確かめの回の zones147.csv(1分ごとの所ごとの人数)から、9:30〜10:30・13:30〜14:30 で人がいちばん多い分 zl = list(csv.DictReader(open(run + "/zones147.csv", encoding="utf-8"))) tot = defaultdict(int) for r in zl: tot[float(r["t_s"])] += int(r["patients"]) + int(r["staff"]) pick = lambda d, a, b, c: max((t for t in d if a <= t <= b), key=lambda t: (d[t], -abs(t - c))) t10 = pick(tot, 7200.0, 10800.0, 9000.0) t14 = pick(tot, 21600.0, 25200.0, 23400.0) # 救急の患者:正面玄関に出てから救急の待合に着くまで(歩いている)・救急の待合にいる間 walk, wait = [], [] for p in csv.DictReader(open(run + "/people147.csv", encoding="utf-8")): if p["what"] != "救急の患者" or not p["spawn_s"]: continue st = p["steps"].split("|")[0].split(":") if len(st) >= 4 and st[2]: walk.append((float(p["spawn_s"]), float(st[2]))) wait.append((float(st[2]), float(st[3]) if st[3] else 1e9)) er = {} for t in tot: er[t] = (sum(1 for a, b in walk if a <= t < b), sum(1 for a, b in wait if a <= t < b)) def pick_er(a, b, c, k): ts = [t for t in er if a <= t <= b] best = max(ts, key=lambda t: (er[t][k], er[t][1 - k], -abs(t - c))) return best STILLS = {} for n, c, tk in still_cams(): lo, hi, mid, lab = (7200.0, 10800.0, 9000.0, "9時30分〜10時30分") if tk == "10" else (21600.0, 25200.0, 23400.0, "13時30分〜14時30分") if tk == "clean": sm = json.load(open(run + "/summary.json", encoding="utf-8")) wipe = {} for nt in sm.get("flow_notes157", []): m = re.match(r"清掃の人 (\d+):.*1点で止まる ([\d.]+) 秒", nt) if m: wipe[m.group(1)] = float(m.group(2)) iv = [] for r in csv.DictReader(open(run + "/extra157.csv", encoding="utf-8")): m = re.match(r"着いた:拭く(\d+)$", r["what"]) if r["who"] == "清掃の人" and m and int(m.group(1)) <= 4 and float(r["t_s"]) < 1800 and 26.0 <= float(r["x"]) <= 70.0: # 寄りの枠(x26〜70)の中の大廊下の点 a = float(r["t_s"]); iv.append((r["idx"], a, a + wipe[r["idx"]])) best = None for k in range(0, 1800): tt = float(k) cnt = len(set(i for i, a, b in iv if a <= tt < b)) key = (cnt >= 1, -abs(tt - 600.0), cnt) # 1人でもいて、7:40 にいちばん近い時刻 if best is None or key > best[0]: best = (key, tt) (_, _, cnt), tt = best STILLS[n] = (g(tt), "7:40 ごろ:清掃の人がカートを押して外来の大廊下を拭いている(枠の中の大廊下の点で止まっている清掃の人 %d 人)" % cnt) continue if tk == "wc": tl = [r for r in csv.DictReader(open(run + "/toilet149.csv", encoding="utf-8")) if r["what"] == "化学療法の患者" and r["toilet"] == "化学療法のトイレ"] first = min(tl, key=lambda r: float(r["leave_seat_s"])) wy = {r["id"]: r for r in csv.DictReader(open(run + "/chemo_way155.csv", encoding="utf-8")) if r["what"] == "化学療法の患者"} tt = float(wy[first["id"]]["first_s"]) + 1.0 assert float(first["leave_seat_s"]) < tt < float(first["arrive_s"]), (first, tt) STILLS[n] = (g(tt), "化学療法の患者がトイレへ向かっている(席を立った %s 秒・トイレに着いた %s 秒)" % (first["leave_seat_s"], first["arrive_s"])) continue if n.startswith("n_er"): k = 0 if n.startswith("n_erway") else 1 tt = pick_er(lo, hi, mid, k) STILLS[n] = (g(tt), ("%s で救急の待合に救急の患者がいちばん多い分(%d 人)" % (lab, er[tt][1])) if k == 1 else ("%s で正面玄関から救急へ歩く救急の患者がいる分(%d 人)" % (lab, er[tt][0]))) continue tt = t10 if tk == "10" else t14 STILLS[n] = (g(tt), "%s で人がいちばん多い分(%d 人)" % (lab, tot[tt])) SC = {n: c for n, c, tk in still_cams()} with open(dst, "w", newline="") as f: w = csv.writer(f) w.writerow(["cam", "t_s", "tx", "tz", "dist"]) for c, tt, x, z, d, sp, a, sd in rows: w.writerow([c, "%.2f" % tt, "%.4f" % x, "%.4f" % z, "%.4f" % d]) for n in STILLS: c = SC[n] w.writerow([n, "%.2f" % STILLS[n][0], "%.4f" % c[3], "%.4f" % c[4], "%.4f" % c[5]]) with open(dst.replace(".csv", "_meta.csv"), "w", newline="") as f: w = csv.writer(f) w.writerow(["cam", "t_s", "speed", "near_a", "side"]) for c, tt, x, z, d, sp, a, sd in rows: w.writerow([c, "%.2f" % tt, sp, "%.4f" % a, sd]) with open(dst.replace(".csv", "_stills.csv"), "w", newline="") as f: w = csv.writer(f) w.writerow(["cam", "t_s", "what"]) for n, (tt, what) in STILLS.items(): w.writerow([n, "%.2f" % tt, what]) with open(camtxt, "w") as f: x0, z0 = WIDE["east"]["tx"], WIDE["east"]["tz"] f.write("flowday,30,75,%.4f,%.4f,%.4f,%d,%d,%d\n" % (x0, z0, WIDE["east"]["dist"], FOV, W, H)) for n, c, tk in still_cams(): f.write("%s,%g,%g,%.2f,%.2f,%.1f,%d,%d,%d\n" % (n, c[1], c[2], c[3], c[4], c[5], FOV, W, H)) n5 = sum(1 for r in rows if r[5] == "5倍") print("flowday %d コマ(%.1f 秒=%.1f 分。5倍 %d・30倍 %d)〜%.2f/走っている区間 %d" % (len(rows), len(rows) / 25, len(rows) / 25 / 60, n5, len(rows) - n5, rows[-1][1], len(wins))) for n, (tt, what) in STILLS.items(): print(n, tt, what) if __name__ == "__main__": main()