Skip to content

Commit

Permalink
Update the variation generation for floorplan-v2
Browse files Browse the repository at this point in the history
This commit also:
- Add example of manually specified model for v2
- Updates the variation model to use the floorplan v2 model
  • Loading branch information
argenos committed Jul 30, 2024
1 parent 7cd29f9 commit 8626cd3
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 80 deletions.
159 changes: 159 additions & 0 deletions models/examples/hospital.fpm2
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
// This is a comment
Floor plan: hospital

// variables
var doorway_width = 2.0 m
var wall_height = 2.5 m

Space reception:
shape: Polygon points:[
(-7.0 m, 6.0 m),
(7.0 m, 6.0 m),
(7.0 m, -3.0 m),
(4.0 m, -6.0 m),
(-4.0 m, -6.0 m),
(-7.0 m, -3.0 m)
]
location:
translation: x: 10.0 m, y: 5.0 m
rotation: 45.0 deg
wrt: world
of: this
walls:
thickness: 0.40 m
height: 3.0 m
features:
Column central_left:
shape: Rectangle width=0.5 m, length=0.5 m
height: 3.0 m
location:
wrt: this
translation: x: -2.5 m
rotation: -35.0 deg

Column central_right:
shape: Rectangle width=0.5 m, length=0.5 m
height: 3.0 m
location:
wrt: this
translation: x: 2.5 m
rotation: 35.0 deg

Divider divider_central:
shape: Rectangle width=doorway_width, length=0.2 m
height: 1.0 m
location:
wrt: this

Divider divider_left:
shape: Rectangle width=2.0 m, length=0.2 m
height: 1.0 m
location:
wrt: this
translation: x: -2.5 m, y: 1.0 m
rotation: 90.0 deg

Divider divider_right:
shape: Rectangle width=2.0 m, length=0.2 m
height: 1.0 m
location:
wrt: this
translation: x: 2.5 m, y: 1.0 m
rotation: 90.0 deg

Space hallway:
shape: Rectangle width=5.0 m, length=14.0 m
location:
wrt: reception.walls[0]
of: this.walls[2]
translation: x: 2.0 m
spaced
walls:
thickness: 0.20 m
height: 2.5 m
features:
Column wall_column_1:
shape: Rectangle width=0.5 m, length=0.3 m
height: 2.5 m
location:
wrt: this.walls[3]
translation: x: -2.5 m
Column wall_column_2:
shape: Rectangle width=0.5 m, length=0.3 m
height: 2.5 m
location:
wrt: this.walls[3]
translation: x: 1.0 m
Column wall_column_3:
shape: Rectangle width=0.5 m, length=0.3 m
height: 2.5 m
location:
wrt: this.walls[3]
translation: x: 5.0 m
Column wall_column_4:
shape: Rectangle width=0.5 m, length=0.3 m
height: 2.5 m
location:
wrt: this.walls[3]
translation: x: 7.0 m

Space room_A:
shape: Rectangle width=3.5 m, length=4.2 m
location:
wrt: hallway.walls[3]
of: this.walls[1]
translation: x: -3.0 m
spaced

Space room_B:
shape: Rectangle width=3.5 m, length=4.2 m
location:
wrt: hallway.walls[3]
of: this.walls[0]
translation: x: 2.0 m
spaced

Entryway reception_main:
shape: Rectangle width=2.5 m, height=2.0 m
location:
in: reception.walls[3]

Entryway reception_hallway:
shape: Rectangle width=4.0 m, height=2.0 m
location:
in: hallway.walls[2] and reception.walls[0]

Entryway hallway_roomA:
shape: Rectangle width=1.2 m, height=2.0 m
location:
in: room_A.walls[1] and hallway.walls[3]
translation: x: 1.0 m

Entryway hallway_roomB:
shape: Rectangle width=1.0 m, height=1.8 m
location:
in: room_B.walls[0] and hallway.walls[3]
translation: x: -1.0 m

Window hallway_window_1:
shape: Rectangle width=3.0 m, height=1.5 m
location:
in: hallway.walls[1]
translation: x: 3.0 m, z: 0.8 m

Window hallway_window_2:
shape: Rectangle width=3.0 m, height=1.5 m
location:
in: hallway.walls[1]
translation: x: -1.0 m, z: 0.8 m

Window hallway_window_3:
shape: Circle radius=1.0 m
location:
in: hallway.walls[1]
translation: x: -1.0 m, z: 0.8 m

Defaults:
walls:
thickness: 0.23 m
height: 2.5 m
17 changes: 10 additions & 7 deletions models/examples/hospital.variation
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import "hospital.floorplan"
import "hospital.fpm2"

hallway: {
location.pose.translation.x : normal(mean=0.0, std=5.0)
wall_thickness : discrete([
location.transformation.translation.x : normal(mean=0.0, std=5.0) // TODO this doesn't match the format in fpm (location.translation)
defaults.wall.thickness : discrete([
(0.2, 0.14),
(0.4, 0.35),
(0.4, 0.51)
Expand All @@ -11,14 +11,17 @@ hallway: {
reception_hallway : {
shape.width : uniform([2.0, 3.0, 4.0])
}
reception.divider_central: {
reception.divider_left: { // TODO Temporarily changed divider_center until we add semantics for default values
height : normal(mean=1.0, std=0.2)
location.pose.rotation : discrete([
location.transformation.rotation.z : discrete([
(0.8, 0.0),
(0.2, 0.20)
])
}
room_B: {
location.pose.translation.x : uniform([2.0, 3.0, 4.0, 5.0])
location.transformation.translation.x : uniform([2.0, 3.0, 4.0, 5.0])
shape.length : uniform([4.2, 5.0, 6.0, 3.0])
}
}

doorway_width : normal(mean=1.0, std=0.2)
wall_height : normal(mean=1.0, std=0.2)
2 changes: 1 addition & 1 deletion src/exsce_floorplan/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ def exsce_variation_metamodel():

variation_floorplan_gen = GeneratorDesc(
language="floorplan-variation",
target="floorplan-v1",
target="floorplan-v2",
description="Generate variations of indoor environments from .floorplan models",
generator=variation_floorplan_generator,
)
Expand Down
109 changes: 38 additions & 71 deletions src/exsce_floorplan/variation/exsce_variations.py
Original file line number Diff line number Diff line change
@@ -1,62 +1,48 @@
import sys, os

from textx import TextXSemanticError, get_location
from operator import attrgetter
import numpy.random as random

dir_path = os.path.dirname(os.path.realpath(__file__))
sys.path.append(dir_path)
from textx import TextXSemanticError, get_children_of_type, metamodel_for_language
from textx.scoping.tools import get_unique_named_object

import jinja2
from textx import metamodel_for_language
from textxjinja import textx_jinja_generator

import numpy.random as random
dir_path = os.path.dirname(os.path.realpath(__file__))
sys.path.append(dir_path)


def get_variable_from_fqn(obj, fqn):
"""Recursive function to get to the object of interest when using a FQN"""
return (
getattr(obj, fqn[0])
if len(fqn) == 1
else get_variable_from_fqn(getattr(obj, fqn[0]), fqn[1:])
)
f = attrgetter(fqn)
return f(obj)


def new_sample(fp_model, var_model):
"""Perform a sample of each distribution of the variation model"""

# For each variation set
for var in var_model.variations:
print("---")
print(var.ref.name)

# If a variable is the target of a distribution, then create a new list of
# attributes with only the variable. Otherwise select the list of attributes
attributes = var.attributes if hasattr(var, "attributes") else [var]
# If it's a variable, sample a new value for it
if var.__class__.__name__ == "VariableRef":
var_obj = get_unique_named_object(fp_model, var.ref.name)
var_obj.value = att.distribution.sample()
continue

# Otherwise select the of attributes
attributes = get_children_of_type("Attribute", var)

# For each attribute, select the value to set and sample the distribution
for att in attributes:
name = var.ref.name
class_name = var.ref.__class__.__name__
obj = fp_model[
"{class_name}.{name}".format(class_name=class_name, name=name)
]

if hasattr(att, "fqn"):
fqn = att.fqn.split(".")
obj = get_variable_from_fqn(obj, fqn)

if not hasattr(obj.value, "value"):
raise TextXSemanticError(
"Semantic Error: This attribute is originally set by a variable.",
**get_location(att),
)
elif (
obj is fp_model["Default.WallThickness"]
or obj is fp_model["Default.WallHeight"]
):
raise TextXSemanticError(
"Semantic Error: This attribute must set in the original model.",
**get_location(att),
)

obj.value.value = att.distribution.sample()
print("\t", att.fqn)
fp_obj = get_unique_named_object(fp_model, var.ref.name)
var_obj = get_variable_from_fqn(fp_obj, att.fqn)
if var_obj.__class__.__name__ in ["LengthValue", "AngleValue"]:
var_obj.value.value = att.distribution.sample()
elif var_obj.__class__.__name__ in ["Length", "Angle"]:
var_obj.value = att.distribution.sample()


def variation_floorplan_generator(
Expand All @@ -66,44 +52,25 @@ def variation_floorplan_generator(
model_folder_path = os.path.dirname(var_model._tx_parser.file_name)
fp_model_path = var_model.import_uri.importURI

fp_mm = metamodel_for_language("floorplan-v1")
fp_mm = metamodel_for_language("floorplan-v2")
fp_model = fp_mm.model_from_file(os.path.join(model_folder_path, fp_model_path))

full_path = os.path.realpath(__file__)
_path, filename = os.path.split(full_path)

path = os.path.join(_path, "templates")
jinja_env = jinja2.Environment(
loader=jinja2.FileSystemLoader(path), trim_blocks=True, lstrip_blocks=True
this_folder = os.path.dirname(__file__)
template_folder = os.path.join(
this_folder, "../templates/__name____seed__.fpm2.jinja"
)
template = jinja_env.get_template("__floorplan_name_____seed__.floorplan.jinja")

variations = custom_args["variations"]
output = custom_args["output"]

fp_model_hashtable = {}
for space in fp_model.spaces:
fp_model_hashtable["Space.{}".format(space.name)] = space
for feature in space.floor_features:
fp_model_hashtable["FloorFeature.{}".format(feature.name)] = feature
for variable in fp_model.variables:
fp_model_hashtable[
"{type}.{name}".format(type=variable.__class__.__name__, name=variable.name)
] = variable
for wall_opening in fp_model.wall_openings:
fp_model_hashtable["WallOpening.{}".format(wall_opening.name)] = wall_opening
fp_model_hashtable["Default.WallThickness"] = fp_model.default.wall_thickness
fp_model_hashtable["Default.WallHeight"] = fp_model.default.wall_height

for i in range(int(variations)):
seed = random.randint(1000, 9999)
random.seed(seed)
fp_model.seed = seed
new_sample(fp_model_hashtable, var_model)
with open(
os.path.join(
output, "{name}_{seed}.floorplan".format(name=fp_model.name, seed=seed)
),
"w",
) as f:
f.write(template.render(fp=fp_model))
new_sample(fp_model, var_model)
context = dict(trim_blocks=True, lstrip_blocks=True)
context["model"] = fp_model
context["seed"] = seed
context["name"] = fp_model.name
textx_jinja_generator(
template_folder, output_path, context, overwrite=overwrite
)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
reference floorplan-v1 as f
reference floorplan-v2 as f
import distributions

Model:
Expand Down

0 comments on commit 8626cd3

Please sign in to comment.