AI Generative Building Design System Development

We design and deploy artificial intelligence systems: from prototype to production-ready solutions. Our team combines expertise in machine learning, data engineering and MLOps to make AI work not in the lab, but in real business.
Showing 1 of 1 servicesAll 1566 services
AI Generative Building Design System Development
Complex
from 2 weeks to 3 months
FAQ
AI Development Areas
AI Solution Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1215
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823

AI Generative Building Design System

Generative design applies optimization algorithms and neural networks to automatically create floor plans that satisfy a set of constraints: area, solar radiation, building codes, cost. The architect defines goals and constraints — the system generates dozens of plan variants and ranks them by specified criteria.

Generative System Architecture

Site parameters + building codes + room program
    ↓ Constraint satisfaction → valid solution space
    ↓ Generative algorithms (evolution / GAN / diffusion)
    ↓ Evaluator (solar radiation, areas, circulation, cost)
    ↓ Pareto front of best variants
    ↓ Export to IFC / DXF / Revit API

Parametric Layout Generation

from dataclasses import dataclass, field
from typing import Callable
import numpy as np
from scipy.optimize import differential_evolution

@dataclass
class BuildingConstraints:
    site_polygon: list[tuple]     # site polygon coordinates
    total_area: float             # total area, sq m
    floors: int
    rooms: list[dict]             # [{"name": "living", "min_area": 20, "max_area": 40, "count": 1}]
    orientation_north: float      # north orientation angle in degrees
    setbacks: dict                # {"front": 5, "side": 3, "rear": 5} — setbacks, m
    max_height: float             # max height, m
    accessibility: bool = True    # accessibility standards (ramps, elevators)

@dataclass
class OptimizationWeights:
    daylight: float = 0.3         # solar radiation
    area_efficiency: float = 0.25 # floor efficiency (habitable / total)
    circulation: float = 0.2      # circulation convenience
    cost: float = 0.25            # unit construction cost

class FloorPlanOptimizer:
    def __init__(
        self,
        constraints: BuildingConstraints,
        weights: OptimizationWeights
    ):
        self.constraints = constraints
        self.weights = weights

    def decode_chromosome(self, x: np.ndarray) -> dict:
        """Convert parameter vector to floor plan"""
        rooms = []
        idx = 0
        for room_spec in self.constraints.rooms:
            rooms.append({
                "name": room_spec["name"],
                "x": x[idx] * self.constraints.total_area**0.5,
                "y": x[idx+1] * self.constraints.total_area**0.5,
                "width": room_spec["min_area"]**0.5 + x[idx+2] * (
                    room_spec["max_area"]**0.5 - room_spec["min_area"]**0.5
                ),
                "height": room_spec["min_area"]**0.5 + x[idx+3] * (
                    room_spec["max_area"]**0.5 - room_spec["min_area"]**0.5
                )
            })
            idx += 4
        return {"rooms": rooms}

    def evaluate_daylight(self, plan: dict) -> float:
        """Evaluate solar radiation via simplified window orientation model"""
        score = 0.0
        south_angle = (180 - self.constraints.orientation_north) % 360
        for room in plan["rooms"]:
            # South-facing rooms receive higher weight
            room_angle = np.degrees(np.arctan2(
                room["y"] - self.constraints.total_area**0.5 / 2,
                room["x"] - self.constraints.total_area**0.5 / 2
            )) % 360
            angular_diff = abs(room_angle - south_angle)
            score += 1 - min(angular_diff, 360 - angular_diff) / 180
        return score / len(plan["rooms"])

    def evaluate_area_efficiency(self, plan: dict) -> float:
        total_room_area = sum(r["width"] * r["height"] for r in plan["rooms"])
        return min(total_room_area / self.constraints.total_area, 1.0)

    def fitness(self, x: np.ndarray) -> float:
        """Objective function — minimize (invert maximization)"""
        plan = self.decode_chromosome(x)
        w = self.weights
        score = (
            w.daylight * self.evaluate_daylight(plan) +
            w.area_efficiency * self.evaluate_area_efficiency(plan)
            # + w.circulation * evaluate_circulation(plan)
            # + w.cost * (1 - evaluate_cost(plan))
        )
        return -score  # scipy minimizes

    def generate_variants(self, n_variants: int = 20) -> list[dict]:
        n_params = len(self.constraints.rooms) * 4
        bounds = [(0, 1)] * n_params

        # Differential evolution — robust for multimodal problems
        results = []
        for seed in range(n_variants):
            result = differential_evolution(
                self.fitness, bounds,
                seed=seed, maxiter=500, tol=0.001,
                popsize=15, mutation=(0.5, 1.0), recombination=0.7
            )
            plan = self.decode_chromosome(result.x)
            plan["score"] = -result.fun
            plan["seed"] = seed
            results.append(plan)

        return sorted(results, key=lambda p: p["score"], reverse=True)

Neural Network Plan Generator (Diffusion Model)

import torch
from diffusers import UNet2DConditionModel, DDPMScheduler

class FloorPlanDiffusion:
    """
    Diffusion model trained on floor plan datasets (RPLAN, LifeHD).
    Generates raster representation of plan 256×256, then vectorizes.
    """
    def __init__(self, model_path: str):
        self.unet = UNet2DConditionModel.from_pretrained(model_path)
        self.scheduler = DDPMScheduler.from_pretrained(model_path)
        self.device = "cuda" if torch.cuda.is_available() else "cpu"
        self.unet.to(self.device)

    def encode_constraints(self, constraints: BuildingConstraints) -> torch.Tensor:
        """Encode constraints as conditioning vector"""
        features = [
            constraints.total_area / 1000,     # normalize
            constraints.floors / 10,
            constraints.orientation_north / 360,
            len(constraints.rooms) / 20,
            float(constraints.accessibility)
        ]
        return torch.tensor(features, dtype=torch.float32).unsqueeze(0).to(self.device)

    @torch.no_grad()
    def generate(self, constraints: BuildingConstraints, num_samples: int = 8) -> list[np.ndarray]:
        condition = self.encode_constraints(constraints)
        noise = torch.randn(num_samples, 1, 256, 256).to(self.device)

        for t in self.scheduler.timesteps:
            noise_pred = self.unet(noise, t, encoder_hidden_states=condition.expand(num_samples, -1, -1)).sample
            noise = self.scheduler.step(noise_pred, t, noise).prev_sample

        plans = noise.squeeze(1).cpu().numpy()
        return [self.rasterize_to_vector(p) for p in plans]

    def rasterize_to_vector(self, raster: np.ndarray) -> dict:
        """Convert raster plan to vector room polygons via contour finding"""
        import cv2
        binary = (raster > 0.5).astype(np.uint8) * 255
        contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        rooms = []
        for cnt in contours:
            approx = cv2.approxPolyDP(cnt, 0.02 * cv2.arcLength(cnt, True), True)
            rooms.append({"polygon": approx.reshape(-1, 2).tolist()})
        return {"rooms": rooms}

Solar Radiation Assessment via EnergyPlus

import subprocess
import json

def evaluate_solar_radiation(
    plan: dict,
    location: dict,   # {"lat": 55.75, "lon": 37.62, "timezone": "Europe/Moscow"}
    month: int = 6    # June — reference month for solar assessment
) -> dict:
    """
    Run EnergyPlus IDF simulation to assess solar radiation.
    Alternative: LADYBUG Tools / Grasshopper API for Rhino integration.
    """
    idf_content = generate_energyplus_idf(plan, location, month)
    with open("/tmp/floorplan.idf", "w") as f:
        f.write(idf_content)

    result = subprocess.run([
        "energyplus", "-w", f"weather/{location['timezone']}.epw",
        "-d", "/tmp/ep_output", "/tmp/floorplan.idf"
    ], capture_output=True)

    return parse_energyplus_results("/tmp/ep_output/floorplan.csv")

Export to IFC and DXF

import ifcopenshell
import ifcopenshell.api

def export_to_ifc(plan: dict, project_name: str) -> bytes:
    """BIM-compatible export per IFC 4.3 standard"""
    model = ifcopenshell.file()
    project = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcProject", name=project_name)
    site = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcSite")
    building = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcBuilding")

    for room_data in plan["rooms"]:
        space = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcSpace", name=room_data["name"])
        # Add geometry from polygon
        coordinates = [(p[0], p[1], 0.0) for p in room_data["polygon"]]
        ifcopenshell.api.run("geometry.add_wall_representation", model, product=space, coordinates=coordinates)

    import io
    buf = io.BytesIO()
    model.write(buf)
    return buf.getvalue()

def export_to_dxf(plan: dict) -> bytes:
    import ezdxf
    doc = ezdxf.new(dxfversion="R2010")
    msp = doc.modelspace()

    for room_data in plan["rooms"]:
        polygon = room_data["polygon"]
        msp.add_lwpolyline(polygon, close=True, dxfattribs={"layer": room_data.get("name", "ROOMS")})

    buf = io.BytesIO()
    doc.write(buf)
    return buf.getvalue()

Revit Integration via Dynamo / Revit API

For teams working in Autodesk Revit, generated plans are imported via Dynamo scripts: the system passes room coordinates through a JSON file, and a Dynamo script creates rooms, walls, and partitions in the BIM model. Alternative: Rhino + Grasshopper with GhPython component, where the optimizer runs directly in the parametric environment.

Comparison of Generation Approaches

Approach Generation Speed Quality Training Application
Differential evolution 30–60 sec High No Parametric optimization
GAN (LayoutGAN++) 0.5–2 sec Medium Dataset 10k plans Fast variants
Diffusion model 10–30 sec High Dataset 50k plans Detailed plans
LLM + SVG 5–15 sec Low No Conceptual diagrams

A floor plan generation system with differential evolution and IFC export — 4–6 weeks. A platform with diffusion model, solar radiation calculation via EnergyPlus, and Revit integration — 3–4 months.