Skip to content
Open
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
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ This plugin provides seamless integration between Mappedin's indoor mapping plat

### 🏗️ **Smart Layer Organization**
- **Floor-based Grouping**: Automatically organizes layers by floor levels
- **Layer Categorization**: Separates doors, windows, walls, connections, spaces, and locations
- **Layer Categorization**: Separates doors, windows, walls, objects, connections, spaces, and locations
- **Multi-floor Visibility**: Auto-hides upper floors, shows ground floor by default

### 🎨 **Intelligent Styling**
- **Doors**: White lines (1.4 width) with proper categorization
- **Windows**: Blue lines (1.2 width) for clear identification
- **Walls**: Dark grey lines for structural elements
- **Objects**: Tan polygon, line, or point layers for desks, furniture, and fixtures
- **Connections**: Green arrow markers (size 4) for stairs/elevators only
- **Locations**: Styled point markers with labeling

Expand Down Expand Up @@ -86,6 +87,7 @@ The plugin creates a comprehensive layer structure:
│ ├── 🚪 Level 1 - Doors (white lines)
│ ├── 🪟 Level 1 - Windows (blue lines)
│ ├── 🧱 Level 1 - Walls (grey lines)
│ ├── 🪑 Level 1 - Objects (tan polygons/lines/points)
│ ├── ⬆️ Level 1 - Connections (green arrows)
│ └── 🏠 Level 1 - Spaces (polygons)
├── 📁 Level 2 Group (hidden by default)
Expand Down
7 changes: 6 additions & 1 deletion mappedin_mvf_importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ def _organize_and_add_layers(self, parser, layers_data):
"doors": [],
"windows": [],
"walls": [],
"objects": [],
"points": [],
"lines": [],
"spaces": [],
Expand All @@ -326,6 +327,8 @@ def _organize_and_add_layers(self, parser, layers_data):
floor_layers[floor_key]["windows"].append(layer_info)
elif "Walls" in layer_name:
floor_layers[floor_key]["walls"].append(layer_info)
elif "Objects" in layer_name or "Object " in layer_name:
floor_layers[floor_key]["objects"].append(layer_info)
elif "Connections" in layer_name:
floor_layers[floor_key]["points"].append(layer_info)
elif "Lines" in layer_name or "Doors" in layer_name:
Expand Down Expand Up @@ -357,6 +360,7 @@ def _organize_and_add_layers(self, parser, layers_data):
+ len(floor_data["doors"])
+ len(floor_data["windows"])
+ len(floor_data["walls"])
+ len(floor_data["objects"])
+ len(floor_data["points"])
+ len(floor_data["lines"])
+ len(floor_data["spaces"])
Expand All @@ -371,12 +375,13 @@ def _organize_and_add_layers(self, parser, layers_data):
floor_groups_created.append((floor_key, group))
layers_added = 0

# Add layers in specific order: Locations, Doors, Windows, Walls, Connections, Lines, Spaces
# Add layers in specific order: Locations, Doors, Windows, Walls, Objects, Connections, Lines, Spaces
layer_order = [
("locations", floor_data["locations"]),
("doors", floor_data["doors"]),
("windows", floor_data["windows"]),
("walls", floor_data["walls"]),
("objects", floor_data["objects"]),
("connections", floor_data["points"]),
("lines", floor_data["lines"]),
("spaces", floor_data["spaces"]),
Expand Down
133 changes: 106 additions & 27 deletions mvf_parser_v3.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,16 +224,16 @@ def _process_geometry(
if not geometry_data["features"]:
return []

# Group geometry by type AND by kind (doors, windows, walls, etc.)
# Group geometry by type AND by kind (doors, windows, walls, objects, etc.)
polygons = []
lines = []
points = []
doors = []
windows = []
walls = []

# Counters for debugging
objects_skipped = 0
object_polygons = []
object_lines = []
object_points = []

# Get kinds data for this floor
floor_kinds = self.kinds.get(floor_id, {})
Expand Down Expand Up @@ -278,10 +278,16 @@ def _process_geometry(

geom_type = geometry.type()

# Skip objects entirely - they clutter the visualization
# Extract map objects (desks, furniture, fixtures, etc.) to their own
# layers instead of mixing them with spaces.
kind_lower = geom_kind.lower()
if "object" in kind_lower:
objects_skipped += 1
if geom_type == QgsWkbTypes.PolygonGeometry:
object_polygons.append(feature_data)
elif geom_type == QgsWkbTypes.LineGeometry:
object_lines.append(feature_data)
elif geom_type == QgsWkbTypes.PointGeometry:
object_points.append(feature_data)
continue

# Categorize by kind first, then by geometry type
Expand All @@ -308,24 +314,12 @@ def _process_geometry(
else:
# Fallback to geometry type for other features (but only specific types for connections)
if geom_type == QgsWkbTypes.PolygonGeometry:
# Only add non-object polygons
if "object" not in kind_lower:
polygons.append(feature_data)
else:
if len(polygons) < 3: # Debug what we're filtering
# DEBUG: print(f" -> SKIPPED POLYGON OBJECT: {geom_id} (kind: {geom_kind})")
pass
polygons.append(feature_data)
elif geom_type == QgsWkbTypes.LineGeometry:
# Only add non-object lines
if "object" not in kind_lower:
lines.append(feature_data)
if len(lines) <= 3: # Debug first few lines
# DEBUG: print(f" -> Added to LINES: {geom_id} (kind: {geom_kind})")
pass
else:
if len(lines) < 3: # Debug what we're filtering
# DEBUG: print(f" -> SKIPPED LINE OBJECT: {geom_id} (kind: {geom_kind})")
pass
lines.append(feature_data)
if len(lines) <= 3: # Debug first few lines
# DEBUG: print(f" -> Added to LINES: {geom_id} (kind: {geom_kind})")
pass
elif geom_type == QgsWkbTypes.PointGeometry:
# Skip door navigation points (API MVF creates -p1, -p2 points for doors)
is_door_navigation_point = "-p1" in geom_id or "-p2" in geom_id
Expand Down Expand Up @@ -359,10 +353,6 @@ def _process_geometry(
else:
pass

# Debug summary - count processed features
# total_processed = len(doors) + len(windows) + len(walls) + len(polygons) + len(lines) + len(points)
# DEBUG: print(f"Processing summary: {total_features} total -> {objects_skipped} objects skipped -> {processed_features} features processed")

layers = []
floor_name = self._get_floor_name(floor_id)

Expand Down Expand Up @@ -414,6 +404,39 @@ def _process_geometry(
pass
# DEBUG: print(f"Skipping empty Walls layer for {floor_name}")

if object_polygons:
layers.append(
{
"name": f"{floor_name} - Objects",
"type": "polygon",
"features": object_polygons,
"fields": self._get_geometry_fields(),
"style_type": "object_polygon",
}
)

if object_lines:
layers.append(
{
"name": f"{floor_name} - Object Lines",
"type": "linestring",
"features": object_lines,
"fields": self._get_geometry_fields(),
"style_type": "object_line",
}
)

if object_points:
layers.append(
{
"name": f"{floor_name} - Object Points",
"type": "point",
"features": object_points,
"fields": self._get_geometry_fields(),
"style_type": "object_point",
}
)

# Only create layers if they have actual features
if polygons:
layers.append(
Expand Down Expand Up @@ -676,6 +699,53 @@ def _configure_space_layer_styling(self, layer: QgsVectorLayer):
except Exception:
pass

def _configure_object_polygon_layer_styling(self, layer: QgsVectorLayer):
"""Styling for map object polygons such as desks and furniture."""
try:
symbol = QgsFillSymbol.createSimple(
{
"color": "#C8A45D",
"outline_color": "#5C4A2A",
"outline_width": "0.25",
"style": "solid",
}
)
layer.setRenderer(QgsSingleSymbolRenderer(symbol))
layer.setOpacity(0.9)
except Exception:
pass

def _configure_object_line_layer_styling(self, layer: QgsVectorLayer):
"""Styling for map object line geometry."""
try:
symbol = QgsLineSymbol.createSimple(
{
"color": "#8A6F3D",
"width": "0.5",
"capstyle": "round",
"joinstyle": "round",
}
)
layer.setRenderer(QgsSingleSymbolRenderer(symbol))
except Exception:
pass

def _configure_object_point_layer_styling(self, layer: QgsVectorLayer):
"""Styling for map object point geometry."""
try:
symbol = QgsMarkerSymbol.createSimple(
{
"name": "square",
"color": "#C8A45D",
"outline_color": "#5C4A2A",
"outline_width": "0.25",
"size": "2.5",
}
)
layer.setRenderer(QgsSingleSymbolRenderer(symbol))
except Exception:
pass

def _configure_door_layer_styling(self, layer: QgsVectorLayer):
"""White styling for door layers."""
try:
Expand Down Expand Up @@ -1090,6 +1160,15 @@ def create_qgis_layer(self, layer_info: Dict[str, Any]) -> Optional[QgsVectorLay
elif style_type == "line_doors":
self._configure_line_doors_layer_styling(layer)
layer.triggerRepaint()
elif style_type == "object_polygon":
self._configure_object_polygon_layer_styling(layer)
layer.triggerRepaint()
elif style_type == "object_line":
self._configure_object_line_layer_styling(layer)
layer.triggerRepaint()
elif style_type == "object_point":
self._configure_object_point_layer_styling(layer)
layer.triggerRepaint()
elif "Connections" in layer_name:
self._configure_connections_layer_styling(layer)
layer.triggerRepaint()
Expand Down