Geometry Base

The Matrix Framework uses a unified geometry abstraction through the GeometryBase class to ensure consistency across different geometry types.

Core Architecture

GeometryBase Class

The GeometryBase class serves as the foundation for all geometries:

import { CoreElement } from '../core/CoreElement';
import { MiddlewareEvent } from '../core/MiddlewareEvent';
import { RoutingStrategy } from '../routing/RoutingStrategy';

export abstract class GeometryBase {
    public name: string;
    public nodes: Set<CoreElement> = new Set();
    public routingStrategies: Map<string, RoutingStrategy> = new Map();

    constructor(name: string) {
        this.name = name;
    }

    public abstract addNode(node: CoreElement): void;
    public abstract removeNode(node: CoreElement): void;

    public addRoutingStrategy(name: string, strategy: RoutingStrategy): void {
        this.routingStrategies.set(name, strategy);
    }

    public getRoutingStrategy(name: string): RoutingStrategy | undefined {
        return this.routingStrategies.get(name);
    }

    public abstract async routeEvent(event: MiddlewareEvent): Promise<void>;
}

Design Principles

1. Unified Abstraction

  • Common interface for all geometries
  • Consistent event routing behavior
  • Shared property management

2. Separation of Concerns

  • Runtime geometry logic separate from visual representation
  • XAML conventions work for both UI and middleware
  • Visual aspects can be stripped for backend deployment

3. Extensibility

  • Easy to add new geometry types
  • Common building blocks across geometries
  • No special cases - all geometries use same core components

Implementation Guidelines

  1. Core Functionality

    • Implement abstract methods for node management
    • Handle routing strategy registration
    • Manage event propagation
  2. Middleware Integration

    • Separate runtime logic from visual aspects
    • Use consistent XAML patterns
    • Support both UI and backend scenarios
  3. Best Practices

    • Avoid special cases in implementations
    • Use shared interfaces for routing
    • Maintain clean separation of concerns

Example Usage

// Creating a custom geometry
class CustomGeometry extends GeometryBase {
    constructor(name: string) {
        super(name);
        
        // Add default routing strategies
        this.addRoutingStrategy('bubble', new BubbleStrategy());
        this.addRoutingStrategy('tunnel', new TunnelStrategy());
    }

    public addNode(node: CoreElement): void {
        this.nodes.add(node);
        // Implement geometry-specific logic
    }

    public removeNode(node: CoreElement): void {
        this.nodes.delete(node);
        // Implement geometry-specific cleanup
    }

    public async routeEvent(event: MiddlewareEvent): Promise<void> {
        const strategy = this.getRoutingStrategy(event.routingStrategy);
        if (!strategy) {
            throw new Error(`Strategy ${event.routingStrategy} not found`);
        }
        await strategy.route(event, this);
    }
}