RoomPlanがどういったものか知りたい方は公式や、以下の記事を参考にしてください。
参考記事
以下のフォーラムの内容をベースに解説します。
CapturedRoomのデータの確認
CapturedRoomをJSONエンコードすると以下のようなJSONになっています。
今回重要になってくるのが、dimensions(寸法)、transform(変換行列)の2つです。
{
... walls以外は省略 ...
"walls": [
{
"category": {
"wall": {}
},
"confidence": {
"high": {}
},
"dimensions": [
3.4638471603393555,
2.3485732078552246,
0
],
"completedEdges": [],
"parentIdentifier": null,
"identifier": "3EFAE2ED-4537-4E74-B9B8-50DA8645184A",
"curve": null,
"transform": [
0.4371742904186249,
0,
-0.8993767499923706,
0,
0,
1,
0,
0,
0.8993766903877258,
0,
0.4371742904186249,
0,
-1.9961872100830078,
-0.15500573813915253,
0.18577753007411957,
1
]
}
]
}
CapturedRoomをエンコードするコードは以下。
func toString(room: CapturedRoom) -> String {
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(room) {
return String(data: encoded, encoding: .utf8)!
}
return ""
}
エンコードした値を使ってCapturedRoomをイニシャライズできます。これで検証のたびに、毎回スキャンしてCapturedRoom生成しなくてよくなります。
let roomStr = "encodeした文字列"
let jsonData = roomStr.data(using: .utf8)!
let decoder = JSONDecoder()
let capturedRoom = try? decoder.decode(CapturedRoom.self, from: jsonData)
2Dに描画する
今回壁を描画するにあって、必要な要素は「壁の寸法」「壁の回転角」「壁の中心位置」の3つです。
1つめの寸法はdimensionsから算出することが可能です。
let surfacePath = CGMutablePath()
let span = CGFloat(dimensions.x) * mapScale / 2
surfacePath.move(to: CGPoint(x: -span, y: 0))
surfacePath.addLine(to: CGPoint(x: span, y: 0))
回転角、中心位置はtransformから算出することができます。
extension simd_float4x4 {
var eulerAngles: simd_float3 {
simd_float3(
x: atan2(self[2][1], self[2][2]),
y: atan2(self[0][2], self[0][0]),
z: atan2(self[0][1], self[1][1])
)
}
var position: simd_float3 {
simd_float3(x: self.columns.3.x,
y: self.columns.3.y,
z: self.columns.3.z
)
}
}
フォーラムのコードをそのまま実行すると部屋を下から見た間取り図になります。
上からみた間取り図が一般的なので position.y
, zRotation
を以下のように変更しました。
wallShape.position.x = CGFloat(wall.transform.position.x) * 200
wallShape.position.y = -CGFloat(wall.transform.position.z) * 200
wallShape.zRotation = -CGFloat(wall.transform.eulerAngles.y)
ここまでのコードを反映すると以下のような間取り図が描画できます。
スキャンで生成された3Dモデルはこんな感じ。
30秒ほどのスキャンでこのようなモデルと間取りができるのは素晴らしいのですが、
部屋全体が傾いていたり、右下の壁がが歪んでいたりしています。
壁の歪みなどはスキャンのやり方(正面から適切な距離をとって測る等)によって変わるため、ある程度はプログラムで補正することができます。
補正してみた間取り図
SceneKit上で壁の歪みなどを補正した結果が以下になります。
壁をブロックで描くことで、より間取り図っぽく仕上がりました。
開発したアプリ
10/24にRoomPlanを使ったアプリをストアに公開しました。
先ほどの部屋をリモデラメジャーで出力した画像は以下のようになっています。