いいね、そのまま実装レイヤまで降ろそう。
最小限だけど、そのまま動かしながら育てられる Flask+Shapely 構成で書くね。
from flask import Flask, request, jsonify
from shapely.geometry import Polygon
from shapely.ops import unary_union
app = Flask(__name__)
def rooms_to_polygons(rooms):
polys = []
for room in rooms:
b = room["bounds"]
x = b["x"]
y = b["y"]
w = b["width"]
d = b["depth"]
poly = Polygon([
(x, y),
(x + w, y),
(x + w, y + d),
(x, y + d)
])
polys.append(poly)
return polys
def compute_exterior_outline(rooms):
polys = rooms_to_polygons(rooms)
merged = unary_union(polys)
# 単一ポリゴン前提(複数島になる場合は要拡張)
outline_coords = list(merged.exterior.coords)
# Shapely は最後に始点を重ねるので、閉ループの重複を落とす
if len(outline_coords) > 1 and outline_coords[0] == outline_coords[-1]:
outline_coords = outline_coords[:-1]
return outline_coords
def outline_to_walls(outline_coords, total_height):
walls = []
n = len(outline_coords)
for i in range(n):
x1, y1 = outline_coords[i]
x2, y2 = outline_coords[(i + 1) % n]
walls.append({
"from": [x1, y1],
"to": [x2, y2],
"height": total_height
})
return walls
def compute_total_height(rooms, floors=None):
# とりあえず最初の room の height を floor_height とみなす
if not rooms:
return 0
floor_height = rooms[0]["bounds"].get("height", 3)
if floors is None:
floors = 1
return floor_height * floors
@app.route("/generate_exterior", methods=["POST"])
def generate_exterior():
"""
期待する JSON 例:
{
"rooms": [
{"id": "living", "bounds": {"x":0,"y":0,"width":6,"depth":4,"height":3}},
{"id": "kitchen","bounds": {"x":6,"y":0,"width":3,"depth":3,"height":3}},
{"id": "hall","bounds": {"x":0,"y":4,"width":9,"depth":1,"height":3}}
],
"floors": 2,
"openings": {
"windows": [
{
"id": "w1",
"room": "living",
"direction": "south",
"offset": 2.0,
"width": 1.5
}
],
"doors": []
}
}
"""
data = request.get_json()
rooms = data.get("rooms", [])
floors = data.get("floors", 1)
openings = data.get("openings", {"windows": [], "doors": []})
# ①〜③ 外周ポリゴン
outline_coords = compute_exterior_outline(rooms)
# ⑥ 高さ
total_height = compute_total_height(rooms, floors)
# ④ 壁セグメント
walls = outline_to_walls(outline_coords, total_height)
# ⑤ openings の投影はここで拡張(今はそのまま返す)
exterior = {
"outline": [[x, y] for (x, y) in outline_coords],
"walls": walls,
"openings": openings
}
return jsonify({"exterior": exterior})
if __name__ == "__main__":
app.run(debug=True)
このコードは:
- Structure Layer の
roomsを受け取る - Union→外周ポリゴン→壁セグメント→高さ付与までやる
- openings 投影は「フックだけ用意しておいて、あとで Roblox 側と相談しながら詰める」構造
にしてある。
次の一手としては:
- openings を「room+direction→外周セグメント」にマッピングするロジック
- Roblox に渡すための JSON 形状(座標系・単位)の固定
どっちから詰めたい?