Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 5 additions & 41 deletions DOCUMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ graph TD
subgraph DotNet ["ResPlan.Library (.NET)"]
PL[PlanLoader]
GG[GraphGenerator]
BG[BuildingGenerator]
PR[PlanRenderer]
Models[Data Models]
PEM[PythonEnvManager]
Expand All @@ -33,7 +32,6 @@ graph TD
Wrapper -->|Streams JSON| PL
PL -->|Deserializes to| Models
GG -->|Consumes| Models
BG -->|Consumes & Produces| Models
PR -->|Consumes| Models
PL -.->|Manages| PEM
PEM -.->|Configures| Venv
Expand Down Expand Up @@ -86,12 +84,11 @@ classDiagram
+Dictionary Geometries
+Envelope Bounds
+Graph ReferenceGraph
+Coordinate GetEntrance()
}

class PlanGenerationConstraints {
+Polygon BoundingPolygon
+Vector2? FrontDoorFacing
+Vector2? GarageFacing
}

class Graph {
Expand Down Expand Up @@ -121,25 +118,17 @@ classDiagram
Graph "1" *-- "*" Node
Graph "1" *-- "*" Edge
Node "1" o-- "1" Geometry
Building "1" *-- "*" BuildingFloor
BuildingFloor "1" o-- "1" Plan
```

### Type Definitions

* **`Building`**: Represents a multi-story structure.
* `Floors`: A list of `BuildingFloor` objects sorted by floor number.
* **`BuildingFloor`**: A single floor in a building.
* `Plan`: The floorplan associated with this level.
* `AdditionalGeometries`: Generated common areas (e.g., stairs, corridors) not present in the original plan.
* **`Plan`**: The root object representing a single floorplan.
* `Geometries`: A dictionary mapping category names (e.g., "living", "wall", "door") to lists of NetTopologySuite `Geometry` objects.
* `Bounds`: The spatial bounding box of the plan.
* `ReferenceGraph`: The ground-truth graph provided by the dataset (if available).
* **`PlanGenerationConstraints`**: Configuration for filtering and orienting loaded plans.
* `GetEntrance()`: Returns the coordinate of the plan's entrance (front door), or null if not found.
* **`PlanGenerationConstraints`**: Configuration for filtering loaded plans.
* `BoundingPolygon`: A polygon that must fully contain the plan's bounds.
* `FrontDoorFacing`: A target vector for the front door's orientation relative to the plan's center.
* `GarageFacing`: *Unsupported in current dataset*.
* **`Graph`**: Represents the connectivity graph of the floorplan.
* Generated by `GraphGenerator` or loaded as `ReferenceGraph`.
* **`Node`**: A node in the graph, typically representing a room or a portal (door/window).
Expand All @@ -159,10 +148,8 @@ Handles the loading of plan data.
* **pklPathOverride**: Optional path to a specific `.pkl` file. If null, defaults to the managed dataset path.
* **maxItems**: Optional limit on the number of plans to load.
* **logger**: Optional callback to receive real-time progress updates (e.g., dependency installation logs, download progress).
* **constraints**: Optional `PlanGenerationConstraints` to filter or orient plans.
* **BoundingPolygon**: If set, only plans whose geometry is completely contained within this polygon are returned. The check first validates the plan's Axis-Aligned Bounding Box (AABB) for performance, and if that fails, performs a precise geometry-by-geometry containment check to support rotated plans.
* **FrontDoorFacing**: If set, plans are rotated so their front door (vector from center to door) aligns with this vector.
* **GarageFacing**: Currently unsupported; will log a warning if set.
* **constraints**: Optional `PlanGenerationConstraints` to filter plans.
* **BoundingPolygon**: If set, only plans whose geometry is completely contained within this polygon are returned. The check first validates the plan's Axis-Aligned Bounding Box (AABB) for performance, and if that fails, performs a precise geometry-by-geometry containment check.
* **Returns**: A list of `Plan` objects.

### `ResPlan.Library.Data.PlanSerializer`
Expand Down Expand Up @@ -190,35 +177,12 @@ Generates connectivity graphs from `Plan` geometries.
* Connects rooms via "door" or "window" geometries.
* **Returns**: A new `Graph` object.

## Building Generation

### `ResPlan.Library.BuildingGenerator`

Procedurally generates multi-story buildings from a set of available plans.

* `Building GenerateBuilding(List<Plan> availablePlans, int targetFloors)`
* Stacks plans to form a coherent building structure.
* **Algorithm**:
1. **Normalization**: All candidate plans are translated so their "front door" is at (0,0).
2. **Sorting**: Plans are sorted by bounding box area (largest first).
3. **Stacking**:
* Floor 0 is the largest available plan.
* Subsequent floors are chosen from the remaining plans such that they "fit" within the previous floor's footprint (checking geometric containment > 95%).
* The generator attempts 4 cardinal rotations (0, 90, 180, 270 degrees) to find the best fit.
4. **Stairs**: A "stair core" geometry (4x3m) is automatically generated adjacent to the front door for vertical circulation.
* **Returns**: A `Building` object containing the stacked floors.

### `ResPlan.Library.PlanRenderer`

Visualizes plans using SkiaSharp.

* `static void Render(Plan plan, string outputPath, int width = 800, int height = 800)`
* Renders a single `Plan`.
* `static void RenderFloor(BuildingFloor floor, string outputPath, int width = 800, int height = 800)`
* **floor**: The `BuildingFloor` to render.
* **Details**:
* Combines the `Plan` geometries with `AdditionalGeometries` (e.g., stairs).
* Renders "stairs" in a distinct color (DarkBlue).

## Testing

Expand Down
34 changes: 3 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Console.WriteLine($"Loaded {plans.Count} plans.");

### 2. Applying Constraints (Optional)

You can filter and orient plans using `PlanGenerationConstraints`.
You can filter plans using `PlanGenerationConstraints`.

```csharp
using NetTopologySuite.Geometries;
Expand All @@ -66,10 +66,7 @@ var boundingPoly = new GeometryFactory().CreatePolygon(coordinates);
var constraints = new PlanGenerationConstraints
{
// Filter: Plan must fit inside this polygon
BoundingPolygon = boundingPoly,

// Orientation: Rotate plan so the front door faces "Up" (positive Y)
FrontDoorFacing = new Vector2(0, 1)
BoundingPolygon = boundingPoly
};

var constrainedPlans = await PlanLoader.LoadPlansAsync(
Expand Down Expand Up @@ -121,32 +118,7 @@ foreach (var plan in plans)
}
```

### 5. Multi-Story Building Generation

You can generate multi-story buildings by stacking compatible floor plans using `BuildingGenerator`.

```csharp
using ResPlan.Library;

// 1. Load a pool of plans (load enough to find good matches)
var plans = await PlanLoader.LoadPlansAsync(maxItems: 50, logger: logger);

// 2. Generate a building
var generator = new BuildingGenerator();
// Attempt to stack 3 floors using the available plans
Building building = generator.GenerateBuilding(plans, targetFloors: 3);

Console.WriteLine($"Generated building with {building.Floors.Count} floors.");

// 3. Render each floor (including generated stairs)
foreach (var floor in building.Floors)
{
// RenderFloor visualizes the plan plus additional geometries (e.g., stairs)
PlanRenderer.RenderFloor(floor, $"building_floor_{floor.FloorNumber}.png");
}
```

### 6. Serialization
### 5. Serialization

To support binary serialization and handle special floating-point values (like `NaN` or `Infinity`) which are not standard in JSON, the library provides a helper class `PlanSerializer` using **MessagePack**.

Expand Down
28 changes: 17 additions & 11 deletions ResPlan.Demo/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,38 @@ static async Task Main(string[] args)
try
{
Console.WriteLine("ResPlan Demo");
Console.WriteLine("Generating Multi-Story Building...");
Console.WriteLine("Loading Floor Plans...");

var plans = await PlanLoader.LoadPlansAsync(maxItems: 50);
var plans = await PlanLoader.LoadPlansAsync(maxItems: 5);
if (plans.Count == 0)
{
Console.WriteLine("No plans loaded.");
return;
}

var generator = new BuildingGenerator();
var building = generator.GenerateBuilding(plans, 3);
Console.WriteLine($"Loaded {plans.Count} plans.");

Console.WriteLine($"Generated Building with {building.Floors.Count} floors.");

// Render each floor
string outputDir = "output";
if (!Directory.Exists(outputDir))
{
Directory.CreateDirectory(outputDir);
}

foreach (var floor in building.Floors)
foreach (var plan in plans)
{
string filename = Path.Combine(outputDir, $"floor_{floor.FloorNumber}.png");
PlanRenderer.RenderFloor(floor, filename);
Console.WriteLine($"Rendered {filename}");
string filename = Path.Combine(outputDir, $"plan_{plan.Id}.png");
PlanRenderer.Render(plan, filename);
Console.WriteLine($"Rendered Plan {plan.Id} to {filename}");

var entrance = plan.GetEntrance();
if (entrance != null)
{
Console.WriteLine($" Plan {plan.Id} Entrance: {entrance}");
}
else
{
Console.WriteLine($" Plan {plan.Id} has no entrance.");
}
}

Console.WriteLine("Done.");
Expand Down
181 changes: 0 additions & 181 deletions ResPlan.Library/BuildingGenerator.cs

This file was deleted.

Loading
Loading