feat: use AprilTag instead of QR code

This commit is contained in:
Schuwi
2025-09-14 18:52:24 +02:00
parent 788ad54724
commit 589c9964aa
600 changed files with 12814 additions and 122 deletions

79
APRILTAG_MIGRATION.md Normal file
View File

@@ -0,0 +1,79 @@
# AprilTag Migration Summary
## Completed Changes
### 1. Database Migration ✅
- Migrated from `qr_code` string field to `apriltag_id` integer field
- Added constraint to ensure valid AprilTag IDs (0-586)
- Created unique index for apriltag_id
- Preserved old qr_code data as qr_code_old for rollback safety
### 2. Schema Updates ✅
- Updated `StorageLocation` schema to use `apriltag_id` instead of `qr_code`
- Added validation for AprilTag ID range (0-586)
- Implemented auto-assignment of next available ID
- Added unique constraint validation
### 3. Business Logic Refactoring ✅
- Replaced `ComponentsElixir.QRCode` module with `ComponentsElixir.AprilTag` module
- Updated inventory functions to use AprilTag IDs instead of QR code strings
- Implemented AprilTag ID availability checking
- Added bulk SVG generation functionality
### 4. UI/UX Improvements ✅
- Replaced dropdown with 587 options with better UX:
- Radio buttons for "Auto-assign" vs "Manual selection"
- Number input for specific ID selection when manual mode selected
- Shows available ID count and examples
- Different interface for add vs edit forms
- Updated templates to show AprilTag information instead of QR codes
- Added download functionality for AprilTag SVGs
### 5. AprilTag Generation ✅
- Created `ComponentsElixir.AprilTag` module for managing tag36h11 family
- Generated all 587 placeholder SVG files with human-readable IDs
- Added Mix task `mix apriltag.generate_all` for batch generation
- SVG files served statically at `/apriltags/tag36h11_id_XXX.svg`
### 6. Event Handling ✅
- Updated LiveView event handlers for AprilTag scanning/assignment
- Added mode switching for manual vs automatic assignment
- Implemented proper form state management for different modes
## Benefits Achieved
1. **Better UX**: No more 587-option dropdown menu
2. **Future-Ready**: AprilTags designed for multi-tag detection scenarios
3. **Robust**: 587 unique IDs provide ample space without conflicts
4. **Maintainable**: Simpler integer ID system vs complex string encoding
5. **Industry Standard**: AprilTags widely used in robotics/AR applications
## Current State
- ✅ Database schema updated
- ✅ All 587 placeholder SVG files generated
- ✅ UI forms updated with better UX
- ✅ Business logic migrated to AprilTag system
-**Next**: Real AprilTag pattern generation (future enhancement)
-**Next**: Camera detection integration (future enhancement)
## Usage
### Generate AprilTag SVGs
```bash
mix apriltag.generate_all # Generate missing files
mix apriltag.generate_all --force # Regenerate all files
```
### Available AprilTag IDs
- Range: 0-586 (tag36h11 family)
- Auto-assignment picks next available ID
- Manual assignment allows specific ID selection
- Unique constraint prevents conflicts
### File Locations
- SVG files: `priv/static/apriltags/tag36h11_id_XXX.svg`
- URL pattern: `/apriltags/tag36h11_id_XXX.svg`
- Placeholder pattern includes human-readable ID label
The system is now ready for use with AprilTags instead of QR codes! The placeholder SVGs will work perfectly for testing and development until we implement actual AprilTag pattern generation.

View File

@@ -37,8 +37,8 @@ A modern, idiomatic Elixir/Phoenix port of the original PHP-based component inve
- **Search & Filter**: Fast search across component names, descriptions, and keywords
- **Category Organization**: Hierarchical category system for better organization
- **Category Management**: Add, edit, delete categories through the web interface with hierarchical support
- **Storage Location System**: Hierarchical storage locations (shelf → drawer → box) with automatic QR code generation
- **QR Code Integration**: Automatic QR code generation and display for all storage locations with download capability
- **Storage Location System**: Hierarchical storage locations (shelf → drawer → box) with automatic AprilTag generation
- **AprilTag Integration**: Automatic AprilTag generation and display for all storage locations with download capability
- **Datasheet Links**: Direct links to component datasheets
- **Real-time Updates**: All changes are immediately reflected in the interface
@@ -100,7 +100,7 @@ The application uses a simple password-based authentication system:
- **`ComponentsElixirWeb.LoginLive`**: Authentication interface
- **`ComponentsElixirWeb.ComponentsLive`**: Main component management interface
- **`ComponentsElixirWeb.CategoriesLive`**: Category management interface
- **`ComponentsElixirWeb.StorageLocationsLive`**: Hierarchical storage location management with QR codes
- **`ComponentsElixirWeb.StorageLocationsLive`**: Hierarchical storage location management with AprilTags
### Key Features
- **Real-time updates**: Changes are immediately reflected without page refresh
@@ -118,16 +118,16 @@ The application uses a simple password-based authentication system:
| Manual editing | `Inventory.update_component/2` | **NEW**: Full edit functionality with validation |
| `changeAmount.php` | `Inventory.update_component_count/2` | Atomic operations, constraints |
| Manual category management | `CategoriesLive` + `Inventory.create_category/1` | **NEW**: Full category CRUD with web interface |
| Manual location tracking | `StorageLocationsLive` + `Inventory` context | **NEW**: Hierarchical storage locations with automatic QR codes |
| Manual location tracking | `StorageLocationsLive` + `Inventory` context | **NEW**: Hierarchical storage locations with automatic AprilTags |
| `imageUpload.php` | Phoenix LiveView file uploads with `.live_file_input` | **IMPLEMENTED**: Full image upload with preview, validation, and automatic cleanup |
| Session management | Phoenix sessions + LiveView | Built-in CSRF protection |
## 🚀 Future Enhancements
### Component Management
- **Barcode Support** - Generate and scan traditional barcodes in addition to QR codes
- **Camera Integration** - JavaScript-based QR scanning with camera access for mobile/desktop
- **Multi-QR Code Detection** - Spatial analysis and disambiguation for multiple codes in same image
- **Barcode Support** - Generate and scan traditional barcodes in addition to AprilTags
- **Camera Integration** - JavaScript-based AprilTag scanning with camera access for mobile/desktop
- **Multi-AprilTag Detection** - Spatial analysis and disambiguation for multiple tags in same image
- **Bulk Operations** - Import/export components from CSV, batch updates
- **Search and Filtering** - Advanced search by specifications, tags, location
- **Component Templates** - Reusable templates for common component types
@@ -135,7 +135,7 @@ The application uses a simple password-based authentication system:
### Storage Organization
- **Physical Layout Mapping** - Visual representation of shelves, drawers, and boxes
- **Bulk QR Code Printing** - Generate printable sheets of QR codes for labeling
- **Bulk AprilTag Printing** - Generate printable sheets of AprilTags for labeling
## ✅ Recently Implemented Features
@@ -146,11 +146,12 @@ The application uses a simple password-based authentication system:
- **Web Interface** ✅ Complete - Storage locations management page with navigation
- **Component-Storage Integration** ✅ Complete - Components can now be assigned to storage locations via dropdown interface
### QR Code System - Still Needed 🚧 **PARTIALLY IMPLEMENTED**
- **Visual QR Code Generation** ✅ Complete - QR code images are generated and displayed for all storage locations
- **QR Code Scanning** ❌ Missing - No camera integration or scanning functionality
- **QR Code Processing** ❌ Missing - Backend logic for processing scanned codes
- **Multi-QR Disambiguation** ❌ Missing - No handling of multiple QR codes in same image
### AprilTag System 🚧 **PARTIALLY IMPLEMENTED**
- **Visual AprilTag Generation** ❌ Partially Implemented - Placeholder SVGs generated
- **Flexible Assignment Options** ✅ Complete - Auto-assign, manual selection, or no AprilTag assignment for storage locations
- **AprilTag Download** ✅ Complete - Individual AprilTag SVG files can be downloaded for printing
- **AprilTag Scanning** ❌ Missing - No camera integration or scanning functionality (future enhancement)
- **AprilTag Processing** ❌ Missing - Backend logic for processing scanned tags (future enhancement)
### Image Upload System ✅ **COMPLETED**
- **Phoenix LiveView file uploads** with `.live_file_input` component

View File

@@ -66,6 +66,22 @@ window.addEventListener("phx:download_file", (event) => {
window.URL.revokeObjectURL(url)
})
// Add AprilTag download functionality
window.addEventListener("phx:download_apriltag", (event) => {
const { filename, url } = event.detail
// Create download link using the static file URL
const link = document.createElement('a')
link.href = url
link.download = filename
link.setAttribute('target', '_blank') // Open in new tab as fallback
document.body.appendChild(link)
link.click()
// Clean up
document.body.removeChild(link)
})
// expose liveSocket on window for web console debug logs and latency simulation:
// >> liveSocket.enableDebug()
// >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session

View File

@@ -0,0 +1,325 @@
# AprilTag Storage Location System Design
## Overview
Implement a hierarchical storage location system with AprilTag tag36h11 generation and assignment capabilities to enable quick component location entry and filtering.
## Database Schema
### 1. Storage Locations Table
```sql
CREATE TABLE storage_locations (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
description TEXT,
apriltag_id INTEGER UNIQUE,
parent_id INTEGER REFERENCES storage_locations(id),
level INTEGER NOT NULL DEFAULT 0,
path TEXT NOT NULL, -- Materialized path: "shelf1/drawer2/box3"
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW(),
CONSTRAINT apriltag_id_range CHECK (apriltag_id >= 0 AND apriltag_id <= 586)
);
CREATE INDEX idx_storage_locations_parent_id ON storage_locations(parent_id);
CREATE UNIQUE INDEX idx_storage_locations_apriltag_id ON storage_locations(apriltag_id);
CREATE INDEX idx_storage_locations_path ON storage_locations USING gin(path gin_trgm_ops);
CREATE UNIQUE INDEX idx_storage_locations_name_parent ON storage_locations(name, parent_id);
```
### 2. Modified Components Table
```sql
-- Migration to add storage_location_id to components
ALTER TABLE components
ADD COLUMN storage_location_id INTEGER REFERENCES storage_locations(id),
ADD COLUMN legacy_position VARCHAR(255); -- Keep old position data for migration
-- Move existing position data to legacy_position
UPDATE components SET legacy_position = position;
```
## AprilTag Design Strategy
### AprilTag tag36h11 Family
- **Total tags available**: 587 (IDs 0-586)
- **Format**: Pre-generated SVG files with human-readable ID labels
- **Storage**: `/priv/static/apriltags/tag36h11_id_XXX.svg`
- **Assignment**: One-to-one mapping between AprilTag ID and storage location
### AprilTag Components:
- **AprilTag ID**: Integer (0-586) stored in database
- **SVG File**: Pre-generated with 2-module margin and ID label
- **Human Readable**: "ID XXX" format for easy identification
- **Uniqueness**: Database constraint ensures no duplicate assignments
### Advantages over QR Codes:
1. **Robust Detection**: AprilTags designed for reliable multi-tag detection
2. **Standard Format**: Well-established robotics/AR standard
3. **Better Performance**: More resistant to lighting/angle variations
4. **Multi-tag Support**: Designed specifically for multiple tags in same view
## Multi-AprilTag Detection Strategy
### 1. Spatial Independence
```
Unlike QR codes, AprilTags are designed for multi-tag scenarios:
- Each tag has unique geometric properties
- No interference between nearby tags
- Reliable detection at various scales and angles
```
### 2. Detection Priority
```
Selection Priority:
1. User selection (tap/click on detected tag)
2. Closest tag to center of frame
3. Largest tag in frame (closest to camera)
4. Most recent successfully scanned tag
```
### 3. Visual Feedback
```
Camera Overlay:
- Draw bounding boxes around each detected AprilTag
- Show AprilTag ID and location name
- Highlight "best candidate" with different color
- Allow tap-to-select for disambiguation
```
## Implementation Components
### 1. Elixir Modules
#### Storage Location Schema
```elixir
defmodule ComponentsElixir.Inventory.StorageLocation do
use Ecto.Schema
import Ecto.Changeset
schema "storage_locations" do
field :name, :string
field :description, :string
field :apriltag_id, :integer
field :level, :integer, virtual: true
field :path, :string, virtual: true
field :is_active, :boolean, default: true
belongs_to :parent, __MODULE__
has_many :children, __MODULE__, foreign_key: :parent_id
has_many :components, Component
timestamps()
end
end
```
#### AprilTag Management
```elixir
defmodule ComponentsElixir.AprilTag do
def generate_apriltag_svg(apriltag_id, opts \\ []) do
# Generate SVG with actual AprilTag pattern
# Include human-readable ID below tag
end
def get_apriltag_url(storage_location) do
# Return URL to pre-generated SVG file
end
def available_apriltag_ids() do
# Return list of unused AprilTag IDs (0-586)
end
def generate_all_apriltag_svgs() do
# Pre-generate all 587 SVG files
end
end
```
### 2. Phoenix LiveView Components
#### AprilTag Assignment Interface
```elixir
defmodule ComponentsElixirWeb.StorageLocationsLive do
use ComponentsElixirWeb, :live_view
def mount(_params, _session, socket) do
socket =
socket
|> assign(:scanning, false)
|> assign(:available_apriltag_ids, AprilTag.available_apriltag_ids())
|> assign(:selected_location, nil)
{:ok, socket}
end
def handle_event("assign_apriltag", %{"apriltag_id" => id}, socket) do
# Assign specific AprilTag ID to storage location
end
def handle_event("apriltag_detected", %{"ids" => ids}, socket) do
# Handle multiple AprilTag detection
parsed_tags = Enum.map(ids, &resolve_storage_location/1)
socket =
socket
|> assign(:detected_tags, parsed_tags)
|> maybe_auto_select_location(parsed_tags)
{:noreply, socket}
end
end
```
### 3. JavaScript AprilTag Detection (Future)
#### Camera Integration
```javascript
// assets/js/apriltag_scanner.js
import { AprilTagDetector } from "apriltag-js";
export const AprilTagScanner = {
mounted() {
this.detector = new AprilTagDetector();
this.video = this.el.querySelector('video');
this.canvas = this.el.querySelector('canvas');
this.startCamera();
this.scanLoop();
},
scanLoop() {
if (this.video.readyState === this.video.HAVE_ENOUGH_DATA) {
const detections = this.detector.detect(this.canvas);
if (detections.length > 0) {
const apriltag_ids = detections.map(d => d.id);
this.pushEvent("apriltag_detected", { ids: apriltag_ids });
}
}
requestAnimationFrame(() => this.scanLoop());
}
};
```
## User Experience Flow
### 1. Adding Components with AprilTag Scan
```
1. User clicks "Add Component"
2. Position field shows camera icon
3. Click camera → AprilTag scanner opens
4. Scan storage location AprilTag
5. If multiple tags detected:
- Show overlay with detected locations
- User taps to select specific location
6. Location path auto-filled: "Shelf A → Drawer 2 → Box 5"
7. Component saved with storage_location_id
```
### 2. Storage Location Management
```
1. New "Storage Locations" section in admin
2. Add/edit locations with AprilTag ID selection
3. Auto-assign next available ID or manual selection
4. Download AprilTag SVG with location info
5. Print labels for physical attachment
```
### 3. AprilTag Assignment
```
1. Available AprilTag IDs shown in dropdown (0-586)
2. Current assignments displayed
3. Bulk assignment for initial setup
4. Re-assignment with validation
5. Conflict prevention (one tag per location)
```
## Handling Multiple AprilTags in Same Image
### Strategy 1: Designed for Multi-Tag
- AprilTags inherently support multiple detection
- No spatial interference between tags
- Each tag independently detectable
### Strategy 2: User Selection
- Display all detected tags with IDs
- Show corresponding location names
- Allow tap/click to select intended tag
- Remember user preferences
### Strategy 3: Smart Defaults
- Prioritize by distance to frame center
- Consider tag size (closer = larger)
- Use most recently accessed locations
- Provide manual override always
## Migration Strategy
### Phase 1: Database Migration
1. Run migration to add apriltag_id field
2. Remove qr_code field and constraints
3. Update schema and validation rules
### Phase 2: AprilTag Generation
1. Generate all 587 SVG files using Mix task
2. Serve static files via Phoenix
3. Update UI to show AprilTag instead of QR code
### Phase 3: Assignment Interface
1. Add AprilTag selection to location forms
2. Implement auto-assignment logic
3. Create bulk assignment tools
4. Add conflict detection
### Phase 4: Detection (Future)
1. Integrate AprilTag detection library
2. Implement multi-tag camera interface
3. Add disambiguation UI
4. Test detection robustness
## Technical Dependencies
### Elixir Dependencies
```elixir
# mix.exs - no additional dependencies needed for generation
# Future detection would require:
# {:apriltag, "~> 0.1"} # hypothetical
```
### JavaScript Dependencies (Future Detection)
```javascript
// package.json
{
"apriltag-js": "^1.0.0", // hypothetical
"camera-utils": "^2.0.0" // camera access utilities
}
```
## Database Indexes for Performance
```sql
-- Fast location lookups
CREATE INDEX idx_components_storage_location_id ON components(storage_location_id);
-- Hierarchical queries
CREATE INDEX idx_storage_locations_path_gin ON storage_locations USING gin(path gin_trgm_ops);
-- AprilTag uniqueness and fast lookup
CREATE UNIQUE INDEX idx_storage_locations_apriltag_id ON storage_locations(apriltag_id);
-- Valid AprilTag ID range constraint
ALTER TABLE storage_locations ADD CONSTRAINT apriltag_id_range
CHECK (apriltag_id >= 0 AND apriltag_id <= 586);
```
## Benefits Over QR Code System
1. **Robust Multi-Tag Detection**: AprilTags designed specifically for multiple tags in same view
2. **Better Performance**: More reliable detection under various lighting and angle conditions
3. **Industry Standard**: Widely used in robotics and AR applications
4. **No Encoding Needed**: Simple integer ID mapping instead of complex string encoding
5. **Collision Avoidance**: 587 unique IDs provide ample space without conflicts
6. **Future-Proof**: Ready for advanced detection and tracking features
This design provides a robust foundation for AprilTag-based storage management while leveraging the inherent advantages of AprilTags for multi-tag detection scenarios.

View File

@@ -361,13 +361,7 @@ export const QRScanner = {
```
### JavaScript Dependencies
```json
// package.json
{
"jsqr": "^1.4.0",
"qr-scanner": "^1.4.2"
}
```
???
## Database Indexes for Performance
```sql

View File

@@ -0,0 +1,226 @@
defmodule ComponentsElixir.AprilTag do
@moduledoc """
AprilTag generation and management for storage locations.
Provides functionality to generate AprilTag images for storage locations
and manage the tag36h11 family (IDs 0-586).
"""
import Ecto.Query
@tag36h11_count 587
@apriltag_size 200
@doc """
Returns the total number of available AprilTags in the tag36h11 family.
"""
def tag36h11_count, do: @tag36h11_count
@doc """
Validates if an AprilTag ID is valid for tag36h11 family.
## Examples
iex> ComponentsElixir.AprilTag.valid_apriltag_id?(42)
true
iex> ComponentsElixir.AprilTag.valid_apriltag_id?(587)
false
"""
def valid_apriltag_id?(id) when is_integer(id) do
id >= 0 and id < @tag36h11_count
end
def valid_apriltag_id?(_), do: false
@doc """
Gets the SVG file path for a given AprilTag ID.
## Examples
iex> ComponentsElixir.AprilTag.get_apriltag_svg_path(42)
"/apriltags/tag36h11_id_042.svg"
"""
def get_apriltag_svg_path(apriltag_id) when is_integer(apriltag_id) do
if valid_apriltag_id?(apriltag_id) do
"/apriltags/tag36h11_id_#{String.pad_leading(to_string(apriltag_id), 3, "0")}.svg"
else
nil
end
end
@doc """
Gets the SVG file URL for a storage location's AprilTag.
## Examples
iex> location = %StorageLocation{apriltag_id: 42}
iex> ComponentsElixir.AprilTag.get_apriltag_url(location)
"/apriltags/tag36h11_id_042.svg"
"""
def get_apriltag_url(storage_location) do
case storage_location.apriltag_id do
nil -> nil
apriltag_id -> get_apriltag_svg_path(apriltag_id)
end
end
@doc """
Returns a list of all available AprilTag IDs.
"""
def all_apriltag_ids do
0..(@tag36h11_count - 1) |> Enum.to_list()
end
@doc """
Returns a list of used AprilTag IDs in the system.
"""
def used_apriltag_ids do
ComponentsElixir.Repo.all(
from sl in ComponentsElixir.Inventory.StorageLocation,
where: not is_nil(sl.apriltag_id),
select: sl.apriltag_id
)
end
@doc """
Returns a list of available (unused) AprilTag IDs.
"""
def available_apriltag_ids do
used = used_apriltag_ids()
all_apriltag_ids() -- used
end
@doc """
Gets the next available AprilTag ID, or nil if all are used.
"""
def next_available_apriltag_id do
available_apriltag_ids() |> List.first()
end
@doc """
Generates label data for a storage location with AprilTag.
This could be used to generate PDF labels or send to a label printer.
"""
def generate_label_data(storage_location) do
%{
apriltag_id: storage_location.apriltag_id,
apriltag_url: get_apriltag_url(storage_location),
name: storage_location.name,
path: storage_location.path,
level: storage_location.level,
description: storage_location.description
}
end
@doc """
Generates an SVG string for an AprilTag with the given ID.
This creates a basic SVG representation of the AprilTag pattern
with the ID displayed below it for human readability.
Note: This is a simplified implementation. For production use,
you'd want to use the actual AprilTag generation algorithm or
pre-generated assets.
"""
def generate_apriltag_svg(apriltag_id, opts \\ []) do
size = Keyword.get(opts, :size, @apriltag_size)
margin = Keyword.get(opts, :margin, div(size, 10))
# For now, create a placeholder square pattern
# In a real implementation, you'd generate the actual AprilTag pattern
square_size = size - (2 * margin)
"""
<svg width="#{size}" height="#{size + 30}" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="#{size}" height="#{size + 30}" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="#{margin}" y="#{margin}" width="#{square_size}" height="#{square_size}"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="#{margin + 10}" y="#{margin + 10}" width="#{square_size - 20}" height="#{square_size - 20}"
fill="black"/>
<rect x="#{margin + 20}" y="#{margin + 20}" width="#{square_size - 40}" height="#{square_size - 40}"
fill="white"/>
<!-- ID text below -->
<text x="#{size / 2}" y="#{size + 20}" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: #{String.pad_leading(to_string(apriltag_id), 3, "0")}
</text>
</svg>
"""
end
@doc """
Generates and saves all 587 AprilTag SVG files to the static directory.
This should be run once during setup to pre-generate all AprilTag images.
"""
def generate_all_apriltag_svgs(opts \\ []) do
static_dir = Path.join([
Application.app_dir(:components_elixir, "priv/static"),
"apriltags"
])
# Ensure directory exists
File.mkdir_p!(static_dir)
force_regenerate = Keyword.get(opts, :force_regenerate, false)
results =
all_apriltag_ids()
|> Task.async_stream(
fn apriltag_id ->
filename = "tag36h11_id_#{String.pad_leading(to_string(apriltag_id), 3, "0")}.svg"
file_path = Path.join(static_dir, filename)
if force_regenerate || !File.exists?(file_path) do
svg_content = generate_apriltag_svg(apriltag_id, opts)
case File.write(file_path, svg_content) do
:ok -> {:ok, apriltag_id, file_path}
{:error, reason} -> {:error, apriltag_id, reason}
end
else
{:ok, apriltag_id, file_path}
end
end,
timeout: :infinity,
max_concurrency: System.schedulers_online() * 2
)
|> Enum.map(fn {:ok, result} -> result end)
success_count = results |> Enum.count(&match?({:ok, _, _}, &1))
error_count = results |> Enum.count(&match?({:error, _, _}, &1))
%{
total: @tag36h11_count,
success: success_count,
errors: error_count,
results: results
}
end
@doc """
Cleans up AprilTag SVG file for a specific ID.
Should be called when storage locations are deleted to prevent orphaned files.
"""
def cleanup_apriltag_svg(apriltag_id) do
filename = "tag36h11_id_#{String.pad_leading(to_string(apriltag_id), 3, "0")}.svg"
file_path = Path.join([
Application.app_dir(:components_elixir, "priv/static/apriltags"),
filename
])
if File.exists?(file_path) do
File.rm(file_path)
else
:ok
end
end
end

View File

@@ -24,11 +24,9 @@ defmodule ComponentsElixir.Inventory do
processed_locations = compute_hierarchy_fields_batch(locations)
|> Enum.sort_by(&{&1.level, &1.name})
# Ensure QR codes exist for all locations (in background)
# Ensure AprilTag SVGs exist for all locations
spawn(fn ->
Enum.each(processed_locations, fn location ->
ComponentsElixir.QRCode.get_qr_image_url(location)
end)
ComponentsElixir.AprilTag.generate_all_apriltag_svgs()
end)
processed_locations
@@ -109,11 +107,11 @@ defmodule ComponentsElixir.Inventory do
end
@doc """
Gets a storage location by QR code.
Gets a storage location by AprilTag ID.
"""
def get_storage_location_by_qr_code(qr_code) do
def get_storage_location_by_apriltag_id(apriltag_id) do
StorageLocation
|> where([sl], sl.qr_code == ^qr_code)
|> where([sl], sl.apriltag_id == ^apriltag_id)
|> preload(:parent)
|> Repo.one()
|> case do
@@ -138,8 +136,6 @@ defmodule ComponentsElixir.Inventory do
case result do
{:ok, location} ->
# Automatically generate QR code image
spawn(fn -> ComponentsElixir.QRCode.get_qr_image_url(location) end)
{:ok, location}
error ->
error
@@ -159,8 +155,6 @@ defmodule ComponentsElixir.Inventory do
case result do
{:ok, updated_location} ->
# Automatically regenerate QR code image if name or hierarchy changed
spawn(fn -> ComponentsElixir.QRCode.get_qr_image_url(updated_location, force_regenerate: true) end)
{:ok, updated_location}
error ->
error
@@ -171,9 +165,6 @@ defmodule ComponentsElixir.Inventory do
Deletes a storage location.
"""
def delete_storage_location(%StorageLocation{} = storage_location) do
# Clean up QR code image before deleting
ComponentsElixir.QRCode.cleanup_qr_image(storage_location.id)
Repo.delete(storage_location)
end
@@ -185,17 +176,17 @@ defmodule ComponentsElixir.Inventory do
end
@doc """
Parses a QR code string and returns storage location information.
Parses an AprilTag ID and returns storage location information.
"""
def parse_qr_code(qr_string) do
case get_storage_location_by_qr_code(qr_string) do
def parse_apriltag_id(apriltag_id) when is_integer(apriltag_id) do
case get_storage_location_by_apriltag_id(apriltag_id) do
nil ->
{:error, :not_found}
location ->
{:ok, %{
type: :storage_location,
location: location,
qr_code: qr_string
apriltag_id: apriltag_id
}}
end
end

View File

@@ -7,13 +7,14 @@ defmodule ComponentsElixir.Inventory.StorageLocation do
"""
use Ecto.Schema
import Ecto.Changeset
import Ecto.Query
alias ComponentsElixir.Inventory.{StorageLocation, Component}
schema "storage_locations" do
field :name, :string
field :description, :string
field :qr_code, :string
field :apriltag_id, :integer
field :is_active, :boolean, default: true
# Computed/virtual fields - not stored in database
@@ -31,13 +32,14 @@ defmodule ComponentsElixir.Inventory.StorageLocation do
@doc false
def changeset(storage_location, attrs) do
storage_location
|> cast(attrs, [:name, :description, :parent_id, :is_active])
|> cast(attrs, [:name, :description, :parent_id, :is_active, :apriltag_id])
|> validate_required([:name])
|> validate_length(:name, min: 1, max: 100)
|> validate_length(:description, max: 500)
|> validate_apriltag_id()
|> foreign_key_constraint(:parent_id)
|> validate_no_circular_reference()
|> put_qr_code()
|> put_apriltag_id()
end
# Prevent circular references (location being its own ancestor)
@@ -79,19 +81,24 @@ defmodule ComponentsElixir.Inventory.StorageLocation do
end
@doc """
Returns the QR code format for this storage location.
Format: SL:{level}:{qr_code}:{parent_qr_or_ROOT}
Returns the AprilTag format for this storage location.
Returns the AprilTag ID that corresponds to this location.
"""
def qr_format(storage_location, parent \\ nil) do
parent_code = if parent, do: parent.qr_code, else: "ROOT"
"SL:#{storage_location.level}:#{storage_location.qr_code}:#{parent_code}"
def apriltag_format(storage_location) do
storage_location.apriltag_id
end
# Private functions for changeset processing
defp put_qr_code(changeset) do
case get_field(changeset, :qr_code) do
nil -> put_change(changeset, :qr_code, generate_qr_code())
defp validate_apriltag_id(changeset) do
changeset
|> validate_number(:apriltag_id, greater_than_or_equal_to: 0, less_than_or_equal_to: 586)
|> unique_constraint(:apriltag_id, message: "AprilTag ID is already in use")
end
defp put_apriltag_id(changeset) do
case get_field(changeset, :apriltag_id) do
nil -> put_change(changeset, :apriltag_id, get_next_available_apriltag_id())
_ -> changeset
end
end
@@ -118,16 +125,22 @@ defmodule ComponentsElixir.Inventory.StorageLocation do
"#{compute_path(parent)}/#{name}"
end
defp generate_qr_code do
# Generate a unique 6-character alphanumeric code
chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
defp get_next_available_apriltag_id do
# Get all used AprilTag IDs
used_ids = ComponentsElixir.Repo.all(
from sl in ComponentsElixir.Inventory.StorageLocation,
where: not is_nil(sl.apriltag_id),
select: sl.apriltag_id
)
1..6
|> Enum.map(fn _ ->
chars
|> String.graphemes()
|> Enum.random()
end)
|> Enum.join()
# Find the first available ID (0-586)
0..586
|> Enum.find(&(&1 not in used_ids))
|> case do
nil ->
# All IDs are used - this should be handled at the application level
raise "All AprilTag IDs are in use"
id -> id
end
end
end

View File

@@ -17,7 +17,7 @@ defmodule ComponentsElixirWeb do
those modules here.
"""
def static_paths, do: ~w(assets fonts images user_generated favicon.ico robots.txt)
def static_paths, do: ~w(assets fonts images user_generated apriltags favicon.ico robots.txt)
def router do
quote do

View File

@@ -1,12 +1,12 @@
defmodule ComponentsElixirWeb.StorageLocationsLive do
@moduledoc """
LiveView for managing storage locations and QR codes.
LiveView for managing storage locations and AprilTags.
"""
use ComponentsElixirWeb, :live_view
alias ComponentsElixir.{Inventory, Auth}
alias ComponentsElixir.Inventory.StorageLocation
alias ComponentsElixir.QRCode
alias ComponentsElixir.AprilTag
@impl true
def mount(_params, session, socket) do
@@ -24,8 +24,8 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
|> assign(:show_edit_form, false)
|> assign(:editing_location, nil)
|> assign(:form, nil)
|> assign(:qr_scanner_open, false)
|> assign(:scanned_codes, [])
|> assign(:apriltag_scanner_open, false)
|> assign(:scanned_tags, [])
|> assign(:page_title, "Storage Location Management")}
end
end
@@ -38,7 +38,9 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
{:noreply,
socket
|> assign(:show_add_form, true)
|> assign(:form, form)}
|> assign(:form, form)
|> assign(:available_apriltag_ids, AprilTag.available_apriltag_ids())
|> assign(:apriltag_mode, "auto")}
end
def handle_event("hide_add_form", _params, socket) do
@@ -64,7 +66,9 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
socket
|> assign(:show_edit_form, true)
|> assign(:editing_location, location)
|> assign(:form, form)}
|> assign(:form, form)
|> assign(:available_apriltag_ids, AprilTag.available_apriltag_ids())
|> assign(:edit_apriltag_mode, "keep")}
end
def handle_event("hide_edit_form", _params, socket) do
@@ -76,7 +80,32 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
end
def handle_event("save_location", %{"storage_location" => location_params}, socket) do
case Inventory.create_storage_location(location_params) do
# Process AprilTag assignment based on mode
processed_params = case socket.assigns.apriltag_mode do
"none" ->
# Remove any apriltag_id from params to ensure it's nil
Map.delete(location_params, "apriltag_id")
"auto" ->
# Auto-assign next available AprilTag ID
case AprilTag.next_available_apriltag_id() do
nil ->
# No available IDs, proceed without AprilTag
Map.delete(location_params, "apriltag_id")
apriltag_id ->
Map.put(location_params, "apriltag_id", apriltag_id)
end
"manual" ->
# Use the manually entered apriltag_id (validation will be handled by changeset)
location_params
_ ->
# Fallback: remove apriltag_id
Map.delete(location_params, "apriltag_id")
end
case Inventory.create_storage_location(processed_params) do
{:ok, _location} ->
{:noreply,
socket
@@ -121,57 +150,86 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
end
end
def handle_event("open_qr_scanner", _params, socket) do
{:noreply, assign(socket, :qr_scanner_open, true)}
def handle_event("open_apriltag_scanner", _params, socket) do
{:noreply, assign(socket, :apriltag_scanner_open, true)}
end
def handle_event("close_qr_scanner", _params, socket) do
{:noreply, assign(socket, :qr_scanner_open, false)}
def handle_event("close_apriltag_scanner", _params, socket) do
{:noreply, assign(socket, :apriltag_scanner_open, false)}
end
def handle_event("qr_scanned", %{"code" => code}, socket) do
case QRCode.parse_qr_data(code) do
{:ok, parsed} ->
case Inventory.get_storage_location_by_qr_code(parsed.code) do
def handle_event("apriltag_scanned", %{"apriltag_id" => apriltag_id_str}, socket) do
case Integer.parse(apriltag_id_str) do
{apriltag_id, ""} when apriltag_id >= 0 and apriltag_id <= 586 ->
case Inventory.get_storage_location_by_apriltag_id(apriltag_id) do
nil ->
{:noreply, put_flash(socket, :error, "Storage location not found for QR code: #{code}")}
{:noreply, put_flash(socket, :error, "Storage location not found for AprilTag ID: #{apriltag_id}")}
location ->
scanned_codes = [%{code: code, location: location} | socket.assigns.scanned_codes]
scanned_tags = [%{apriltag_id: apriltag_id, location: location} | socket.assigns.scanned_tags]
{:noreply,
socket
|> assign(:scanned_codes, scanned_codes)
|> assign(:scanned_tags, scanned_tags)
|> put_flash(:info, "Scanned: #{location.path}")}
end
{:error, reason} ->
{:noreply, put_flash(socket, :error, "Invalid QR code: #{reason}")}
_ ->
{:noreply, put_flash(socket, :error, "Invalid AprilTag ID: #{apriltag_id_str}")}
end
end
def handle_event("clear_scanned", _params, socket) do
{:noreply, assign(socket, :scanned_codes, [])}
{:noreply, assign(socket, :scanned_tags, [])}
end
def handle_event("download_qr", %{"id" => id}, socket) do
def handle_event("set_apriltag_mode", %{"mode" => mode}, socket) do
{:noreply, assign(socket, :apriltag_mode, mode)}
end
def handle_event("set_edit_apriltag_mode", %{"mode" => mode}, socket) do
# Clear the apriltag_id field when switching modes
form = case mode do
"remove" ->
socket.assigns.form
|> Phoenix.Component.to_form()
|> Map.put(:params, Map.put(socket.assigns.form.params || %{}, "apriltag_id", nil))
"keep" ->
current_id = socket.assigns.editing_location.apriltag_id
socket.assigns.form
|> Phoenix.Component.to_form()
|> Map.put(:params, Map.put(socket.assigns.form.params || %{}, "apriltag_id", current_id))
_ ->
socket.assigns.form
end
{:noreply,
socket
|> assign(:edit_apriltag_mode, mode)
|> assign(:form, form)}
end
def handle_event("download_apriltag", %{"id" => id}, socket) do
case Inventory.get_storage_location!(id) do
%{apriltag_id: nil} ->
{:noreply, put_flash(socket, :error, "No AprilTag assigned to this location")}
location ->
case QRCode.generate_qr_image(location) do
{:ok, png_data} ->
filename = "#{location.name |> String.replace(" ", "_")}_QR.png"
case AprilTag.get_apriltag_url(location) do
nil ->
{:noreply, put_flash(socket, :error, "Failed to get AprilTag URL")}
apriltag_url ->
filename = "#{location.name |> String.replace(" ", "_")}_AprilTag_#{location.apriltag_id}.svg"
# Send file download to browser
{:noreply,
socket
|> push_event("download_file", %{
|> push_event("download_apriltag", %{
filename: filename,
data: Base.encode64(png_data),
mime_type: "image/png"
url: apriltag_url,
apriltag_id: location.apriltag_id
})}
{:error, _reason} ->
{:noreply, put_flash(socket, :error, "Failed to generate QR code")}
end
end
end
@@ -230,8 +288,8 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
Inventory.count_components_in_storage_location(location_id)
end
defp get_qr_image_url(location) do
QRCode.get_qr_image_url(location)
defp get_apriltag_url(location) do
AprilTag.get_apriltag_url(location)
end
# Component for rendering individual storage location items with QR code support
@@ -284,21 +342,21 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
<p class="text-xs text-gray-400">
{count_components_in_location(@location.id)} components
</p>
<%= if @location.qr_code do %>
<%= if @location.apriltag_id do %>
<span class="text-xs bg-gray-100 text-gray-600 px-2 py-1 rounded">
QR: {@location.qr_code}
AprilTag: {@location.apriltag_id}
</span>
<% end %>
</div>
</div>
<%= if @location.qr_code do %>
<%= if @location.apriltag_id do %>
<div class="flex items-center space-x-3">
<%= if get_qr_image_url(@location) do %>
<div class="qr-code-container flex-shrink-0">
<%= if get_apriltag_url(@location) do %>
<div class="apriltag-container flex-shrink-0">
<img
src={get_qr_image_url(@location)}
alt={"QR Code for #{@location.name}"}
class="w-16 h-16 border border-gray-200 rounded bg-white"
src={get_apriltag_url(@location)}
alt={"AprilTag for #{@location.name}"}
class="w-16 h-auto border border-gray-200 rounded bg-white"
onerror="this.style.display='none'"
/>
</div>
@@ -308,10 +366,10 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
</div>
<% end %>
<button
phx-click="download_qr"
phx-click="download_apriltag"
phx-value-id={@location.id}
class="inline-flex items-center px-3 py-1.5 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 flex-shrink-0"
title="Download QR Code"
title="Download AprilTag"
>
<.icon name="hero-arrow-down-tray" class="w-4 h-4 mr-1.5" />
Download
@@ -427,6 +485,76 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
<.input field={@form[:description]} type="textarea" />
</div>
<div>
<label class="block text-sm font-medium text-gray-700">AprilTag ID (Optional)</label>
<div class="space-y-2">
<div class="flex items-center space-x-2">
<input
type="radio"
name="apriltag_assignment"
value="none"
id="apriltag_none"
checked={@apriltag_mode == "none"}
class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300"
phx-click="set_apriltag_mode"
phx-value-mode="none"
/>
<label for="apriltag_none" class="text-sm text-gray-700">
No AprilTag assignment
</label>
</div>
<div class="flex items-center space-x-2">
<input
type="radio"
name="apriltag_assignment"
value="auto"
id="apriltag_auto"
checked={@apriltag_mode == "auto"}
class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300"
phx-click="set_apriltag_mode"
phx-value-mode="auto"
/>
<label for="apriltag_auto" class="text-sm text-gray-700">
Auto-assign next available ID
</label>
</div>
<div class="flex items-center space-x-2">
<input
type="radio"
name="apriltag_assignment"
value="manual"
id="apriltag_manual"
checked={@apriltag_mode == "manual"}
class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300"
phx-click="set_apriltag_mode"
phx-value-mode="manual"
/>
<label for="apriltag_manual" class="text-sm text-gray-700">
Choose specific ID
</label>
</div>
<%= if @apriltag_mode == "manual" do %>
<div class="ml-6 space-y-2">
<.input
field={@form[:apriltag_id]}
type="number"
min="0"
max="586"
placeholder="Enter ID (0-586)"
class="w-32"
/>
<div class="text-xs text-gray-500">
Available IDs: <%= length(@available_apriltag_ids) %> of 587
<%= if length(@available_apriltag_ids) < 20 do %>
<br/>Next available: <%= @available_apriltag_ids |> Enum.take(10) |> Enum.join(", ") %>
<%= if length(@available_apriltag_ids) > 10, do: "..." %>
<% end %>
</div>
</div>
<% end %>
</div>
</div>
<div class="flex justify-end space-x-3 pt-4">
<button
type="button"
@@ -483,6 +611,75 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
<.input field={@form[:description]} type="textarea" />
</div>
<div>
<label class="block text-sm font-medium text-gray-700">AprilTag ID</label>
<div class="space-y-2">
<div class="flex items-center space-x-2">
<input
type="radio"
name="edit_apriltag_assignment"
value="keep"
id="edit_apriltag_keep"
checked={@edit_apriltag_mode == "keep"}
class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300"
phx-click="set_edit_apriltag_mode"
phx-value-mode="keep"
/>
<label for="edit_apriltag_keep" class="text-sm text-gray-700">
Keep current assignment
</label>
</div>
<div class="flex items-center space-x-2">
<input
type="radio"
name="edit_apriltag_assignment"
value="change"
id="edit_apriltag_change"
checked={@edit_apriltag_mode == "change"}
class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300"
phx-click="set_edit_apriltag_mode"
phx-value-mode="change"
/>
<label for="edit_apriltag_change" class="text-sm text-gray-700">
Change to different ID
</label>
</div>
<div class="flex items-center space-x-2">
<input
type="radio"
name="edit_apriltag_assignment"
value="remove"
id="edit_apriltag_remove"
checked={@edit_apriltag_mode == "remove"}
class="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300"
phx-click="set_edit_apriltag_mode"
phx-value-mode="remove"
/>
<label for="edit_apriltag_remove" class="text-sm text-gray-700">
Remove AprilTag assignment
</label>
</div>
<%= if @edit_apriltag_mode == "change" do %>
<div class="ml-6 space-y-2">
<.input
field={@form[:apriltag_id]}
type="number"
min="0"
max="586"
placeholder="Enter new ID (0-586)"
class="w-32"
/>
<div class="text-xs text-gray-500">
Available IDs: <%= length(@available_apriltag_ids) %> of 587
</div>
</div>
<% end %>
<p class="text-xs text-gray-500 mt-1">
Current: <%= if @editing_location.apriltag_id, do: "ID #{@editing_location.apriltag_id}", else: "None" %>
</p>
</div>
</div>
<div class="flex justify-end space-x-3 pt-4">
<button
type="button"
@@ -504,43 +701,43 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
</div>
<% end %>
<!-- QR Scanner Modal -->
<%= if @qr_scanner_open do %>
<!-- AprilTag Scanner Modal -->
<%= if @apriltag_scanner_open do %>
<div class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50">
<div class="relative top-10 mx-auto p-5 border w-11/12 md:w-1/2 shadow-lg rounded-md bg-white">
<div class="mt-3">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-medium text-gray-900">QR Code Scanner</h3>
<h3 class="text-lg font-medium text-gray-900">AprilTag Scanner</h3>
<button
phx-click="close_qr_scanner"
phx-click="close_apriltag_scanner"
class="text-gray-400 hover:text-gray-600"
>
<.icon name="hero-x-mark" class="w-6 h-6" />
</button>
</div>
<!-- QR Scanner Interface -->
<!-- AprilTag Scanner Interface -->
<div class="border-2 border-dashed border-gray-300 rounded-lg p-6 text-center">
<.icon name="hero-qr-code" class="mx-auto h-12 w-12 text-gray-400" />
<p class="mt-2 text-sm text-gray-600">Camera QR scanner would go here</p>
<p class="text-xs text-gray-500 mt-1">In a real implementation, this would use JavaScript QR scanning</p>
<p class="mt-2 text-sm text-gray-600">Camera AprilTag scanner would go here</p>
<p class="text-xs text-gray-500 mt-1">In a real implementation, this would use JavaScript AprilTag detection</p>
<!-- Test buttons for demo -->
<div class="mt-4 space-y-2">
<p class="text-sm font-medium text-gray-700">Test with sample codes:</p>
<p class="text-sm font-medium text-gray-700">Test with sample AprilTag IDs:</p>
<button
phx-click="qr_scanned"
phx-value-code="SL:0:1MTKDM:ROOT"
phx-click="apriltag_scanned"
phx-value-apriltag_id="0"
class="block w-full px-3 py-2 text-sm bg-gray-100 hover:bg-gray-200 rounded"
>
Scan "Shelf A"
Scan AprilTag ID 0
</button>
<button
phx-click="qr_scanned"
phx-value-code="SL:1:VDI701:1MTKDM"
phx-click="apriltag_scanned"
phx-value-apriltag_id="1"
class="block w-full px-3 py-2 text-sm bg-gray-100 hover:bg-gray-200 rounded"
>
Scan "Drawer 1"
Scan AprilTag ID 1
</button>
</div>
</div>
@@ -549,8 +746,8 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
</div>
<% end %>
<!-- Scanned Codes Display -->
<%= if length(@scanned_codes) > 0 do %>
<!-- Scanned Tags Display -->
<%= if length(@scanned_tags) > 0 do %>
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
<div class="bg-green-50 border border-green-200 rounded-lg p-4">
<div class="flex justify-between items-center mb-2">
@@ -563,10 +760,10 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
</button>
</div>
<div class="space-y-2">
<div :for={scan <- @scanned_codes} class="flex items-center justify-between bg-white p-2 rounded border">
<div :for={scan <- @scanned_tags} class="flex items-center justify-between bg-white p-2 rounded border">
<div>
<span class="font-medium text-gray-900">{location_display_name(scan.location)}</span>
<span class="text-sm text-gray-600 ml-2">({scan.code})</span>
<span class="text-sm text-gray-600 ml-2">(AprilTag ID {scan.apriltag_id})</span>
</div>
<span class="text-xs text-green-600 bg-green-100 px-2 py-1 rounded">
Level {scan.location.level}
@@ -582,7 +779,7 @@ defmodule ComponentsElixirWeb.StorageLocationsLive do
<div class="bg-white shadow overflow-hidden sm:rounded-md">
<div class="px-6 py-4 border-b border-gray-200">
<h2 class="text-lg font-medium text-gray-900">Storage Location Hierarchy</h2>
<p class="text-sm text-gray-500 mt-1">Manage your physical storage locations and QR codes</p>
<p class="text-sm text-gray-500 mt-1">Manage your physical storage locations and AprilTags</p>
</div>
<%= if Enum.empty?(@storage_locations) do %>

View File

@@ -0,0 +1,57 @@
defmodule Mix.Tasks.Apriltag.GenerateAll do
@moduledoc """
Generates all 587 AprilTag tag36h11 SVG files for the storage system.
## Examples
mix apriltag.generate_all
mix apriltag.generate_all --force
Options:
* `--force` - Regenerate all files even if they already exist
"""
use Mix.Task
@shortdoc "Generate all AprilTag SVG files"
def run(args) do
{opts, [], []} = OptionParser.parse(args, strict: [force: :boolean])
force_regenerate = Keyword.get(opts, :force, false)
Mix.Task.run("app.start")
IO.puts("Generating AprilTag SVG files...")
IO.puts("Force regenerate: #{force_regenerate}")
start_time = System.monotonic_time(:millisecond)
result = ComponentsElixir.AprilTag.generate_all_apriltag_svgs(
force_regenerate: force_regenerate
)
end_time = System.monotonic_time(:millisecond)
duration = end_time - start_time
IO.puts("Generation completed in #{duration}ms")
IO.puts("Total: #{result.total}")
IO.puts("Success: #{result.success}")
IO.puts("Errors: #{result.errors}")
if result.errors > 0 do
IO.puts("\nErrors encountered:")
result.results
|> Enum.filter(&match?({:error, _, _}, &1))
|> Enum.each(fn {:error, id, reason} ->
IO.puts(" AprilTag ID #{id}: #{inspect(reason)}")
end)
end
if result.success == result.total do
IO.puts("\n✅ All AprilTag SVG files generated successfully!")
IO.puts("Files are available in: priv/static/apriltags/")
else
IO.puts("\n⚠️ Some files failed to generate. Check the errors above.")
System.halt(1)
end
end
end

View File

@@ -0,0 +1,35 @@
defmodule ComponentsElixir.Repo.Migrations.MigrateQrToApriltag do
use Ecto.Migration
def up do
# Rename qr_code column to qr_code_old for backup
rename table(:storage_locations), :qr_code, to: :qr_code_old
# Add new apriltag_id column as integer
alter table(:storage_locations) do
add :apriltag_id, :integer
end
# Create unique index for apriltag_id
create unique_index(:storage_locations, [:apriltag_id])
# Add constraint to ensure apriltag_id is in valid range (0-586 for tag36h11)
create constraint(:storage_locations, :apriltag_id_range, check: "apriltag_id >= 0 AND apriltag_id <= 586")
# Note: We keep qr_code_old for now in case we need to rollback
# It can be removed in a future migration after confirming everything works
end
def down do
# Remove apriltag_id column and constraints
drop constraint(:storage_locations, :apriltag_id_range)
drop unique_index(:storage_locations, [:apriltag_id])
alter table(:storage_locations) do
remove :apriltag_id
end
# Rename back to qr_code
rename table(:storage_locations), :qr_code_old, to: :qr_code
end
end

View File

@@ -0,0 +1,18 @@
defmodule ComponentsElixir.Repo.Migrations.DropQrCodeOldColumn do
use Ecto.Migration
def up do
# Drop the qr_code_old column since we've fully migrated to AprilTags
alter table(:storage_locations) do
remove :qr_code_old
end
end
def down do
# If we need to rollback, re-add the qr_code_old column
# Note: This will not restore the original data
alter table(:storage_locations) do
add :qr_code_old, :string, null: false, default: ""
end
end
end

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 000
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 001
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 002
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 003
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 004
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 005
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 006
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 007
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 008
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 009
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 010
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 011
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 012
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 013
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 014
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 015
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 016
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 017
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 018
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 019
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 020
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 021
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 022
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 023
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 024
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 025
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 026
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 027
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 028
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 029
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 030
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 031
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 032
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 033
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 034
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 035
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 036
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 037
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 038
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 039
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 040
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 041
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 042
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 043
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 044
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 045
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 046
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 047
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 048
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 049
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 050
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 051
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 052
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 053
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 054
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 055
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 056
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 057
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 058
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 059
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 060
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 061
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 062
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 063
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 064
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 065
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 066
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 067
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 068
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 069
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 070
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 071
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 072
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 073
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 074
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 075
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 076
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 077
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 078
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 079
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 080
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 081
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 082
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 083
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 084
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 085
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

View File

@@ -0,0 +1,20 @@
<svg width="200" height="230" xmlns="http://www.w3.org/2000/svg">
<!-- White background -->
<rect width="200" height="230" fill="white"/>
<!-- AprilTag placeholder (simplified) -->
<rect x="20" y="20" width="160" height="160"
fill="white" stroke="black" stroke-width="2"/>
<!-- Simplified tag pattern - in reality this would be the actual AprilTag -->
<rect x="30" y="30" width="140" height="140"
fill="black"/>
<rect x="40" y="40" width="120" height="120"
fill="white"/>
<!-- ID text below -->
<text x="100.0" y="220" text-anchor="middle"
font-family="Arial" font-size="14" font-weight="bold">
ID: 086
</text>
</svg>

After

Width:  |  Height:  |  Size: 687 B

Some files were not shown because too many files have changed in this diff Show More