Switch + REFACTOR: moved circuit modifiers to Circuit instead of CircuitComponent

This commit is contained in:
Patrick Haßel 2025-02-03 19:35:20 +01:00
parent c9d0a36f92
commit 8a3a31e0c0
19 changed files with 271 additions and 146 deletions

View File

@ -1,25 +1,25 @@
import {Part} from "../parts/Part";
import {Wire} from "../wire/Wire";
import {Calculation} from './Calculation';
import {Calculation, RESISTANCE_MIN} from './Calculation';
import {Battery} from '../parts/battery/Battery';
import {Light} from '../parts/light/Light';
import {Relay} from '../parts/relay/Relay';
import {Junction} from '../junction/Junction';
import {Switch} from '../parts/switch/Switch';
export class Circuit {
constructor(
readonly uuid: string,
public name: string,
readonly parts: Part[],
readonly wires: Wire[],
readonly parts: Part[] = [],
readonly wires: Wire[] = [],
) {
//
}
static new() {
return new Circuit(
self.crypto.randomUUID(),
"Unbenannt",
[],
[]
);
return new Circuit(self.crypto.randomUUID(), "Unbenannt");
}
calculate() {
@ -45,4 +45,57 @@ export class Circuit {
this.wires.forEach(wire => wire.resetCalculations());
}
newBattery(rasterX: number, rasterY: number, name: string | undefined = undefined, voltage: number = 1.5, resistance: number = 0.5): Battery {
name = this.generateName(name, "Batterie");
return this.add(new Battery(this, rasterX, rasterY, name, voltage, resistance));
}
newLight(rasterX: number, rasterY: number, name: string | undefined = undefined, voltageMax: number = 3, resistance: number = 100): Light {
name = this.generateName(name, "Licht");
return this.add(new Light(this, rasterX, rasterY, name, voltageMax, resistance));
}
newRelay(rasterX: number, rasterY: number, name: string | undefined = undefined, voltageMin: number = 1.0, voltageMax: number = 3, resistance: number = 150): Relay {
name = this.generateName(name, "Relais");
return this.add(new Relay(this, rasterX, rasterY, name, voltageMin, voltageMax, resistance));
}
newSwitch(rasterX: number, rasterY: number, name: string | undefined = undefined, momentary: boolean = false): Switch {
name = this.generateName(name, "Relais");
return this.add(new Switch(this, rasterX, rasterY, name, momentary));
}
private generateName(name: string | undefined, baseName: string) {
if (name !== undefined) {
return name;
}
let counter = 1;
while (true) {
name = `${baseName} #${counter++}`;
if (!this.parts.some(p => p.name === name)) {
break
}
}
return name;
}
private add<T extends Part>(part: T): T {
this.parts.push(part);
return part;
}
connect(start: Junction, end: Junction) {
const wire = new Wire(start, end, RESISTANCE_MIN);
this.wires.push(wire);
console.log(`Wire connected: ${wire}`);
this.calculate();
}
disconnect(wire: Wire) {
this.wires.splice(this.wires.indexOf(wire), 1);
wire.disconnect();
console.log("Wire disconnected: ", wire);
this.calculate();
}
}

View File

@ -1,19 +1,14 @@
import {Circuit} from "./Circuit";
import {Battery} from '../parts/battery/Battery';
import {Light} from '../parts/light/Light';
import {Wire} from '../wire/Wire';
import {RESISTANCE_MIN} from './Calculation';
const battery = new Battery(1, 3, "Batterie");
export const DEMO_001 = create();
const light = new Light(1, 1, "Licht");
export const DEMO_001 = new Circuit(
"DEMO_001",
"1. Batterie und Licht",
[battery, light],
[
new Wire(battery.minus, light.a, RESISTANCE_MIN, ""),
new Wire(battery.plus, light.b, RESISTANCE_MIN, ""),
],
);
function create() {
const circuit = new Circuit("DEMO_001", "1. Batterie und Licht");
const battery = circuit.newBattery(1, 3);
const light = circuit.newLight(1, 1);
circuit.parts.push(battery);
circuit.parts.push(light);
circuit.connect(battery.minus, light.a);
circuit.connect(battery.plus, light.b);
return circuit;
}

View File

@ -1,25 +1,19 @@
import {Circuit} from "./Circuit";
import {Battery} from '../parts/battery/Battery';
import {Light} from '../parts/light/Light';
import {Wire} from '../wire/Wire';
import {RESISTANCE_MIN} from './Calculation';
const battery0 = new Battery(1, 3, "Batterie 1", 1.5, 0.5);
const battery1 = new Battery(3, 3, "Batterie 2", 1.5, 0.5);
const light0 = new Light(1, 1, "Licht 1");
const light1 = new Light(3, 1, "Licht 2");
const light2 = new Light(2, 5, "Licht 3");
export const DEMO_002 = create();
export const DEMO_002 = new Circuit(
"DEMO_002",
"2. Reihe und Parallel",
[battery0, battery1, light0, light1, light2],
[
new Wire(light0.a, battery0.minus, RESISTANCE_MIN, ""),
new Wire(light0.b, light1.a, RESISTANCE_MIN, ""),
new Wire(light1.b, battery1.plus, RESISTANCE_MIN, ""),
new Wire(battery0.plus, battery1.minus, RESISTANCE_MIN, ""),
new Wire(light2.a, battery0.minus, RESISTANCE_MIN, ""),
new Wire(light2.b, battery1.plus, RESISTANCE_MIN, ""),
],
);
function create() {
const circuit = new Circuit("DEMO_002", "2. Reihe und Parallel");
const battery0 = circuit.newBattery(1, 3);
const battery1 = circuit.newBattery(3, 3);
const light0 = circuit.newLight(1, 1);
const light1 = circuit.newLight(3, 1);
const light2 = circuit.newLight(2, 5);
circuit.connect(light0.a, battery0.minus);
circuit.connect(light0.b, light1.a);
circuit.connect(light1.b, battery1.plus);
circuit.connect(battery0.plus, battery1.minus);
circuit.connect(light2.a, battery0.minus);
circuit.connect(light2.b, battery1.plus);
return circuit;
}

View File

@ -1,28 +1,22 @@
import {Circuit} from "./Circuit";
import {Battery} from '../parts/battery/Battery';
import {Light} from '../parts/light/Light';
import {Wire} from '../wire/Wire';
import {RESISTANCE_MIN} from './Calculation';
import {Relay} from '../parts/relay/Relay';
const batteryLight = new Battery(1, 1, "Licht Batterie");
export const DEMO_003 = create();
const light = new Light(2, 1, "Licht");
const relay = new Relay(1, 2, "Relais");
const batteryRelay = new Battery(1, 3, "Relais Batterie");
export const DEMO_003 = new Circuit(
"DEMO_003",
"3. Relais",
[batteryRelay, relay, batteryLight, light],
[
new Wire(batteryLight.plus, light.a, RESISTANCE_MIN, ""),
new Wire(batteryLight.minus, relay.common, RESISTANCE_MIN, ""),
new Wire(light.b, relay.active, RESISTANCE_MIN, ""),
new Wire(batteryRelay.minus, relay.coilA, RESISTANCE_MIN, ""),
new Wire(batteryRelay.plus, relay.coilB, RESISTANCE_MIN, ""),
],
);
function create() {
const circuit = new Circuit("DEMO_003", "3. Relais");
const batteryLight = circuit.newBattery(2, 0, "Licht Batterie");
const lightInactive = circuit.newLight(2, 1, "Licht Inaktiv");
const lightActive = circuit.newLight(3, 2, "Licht Aktiv");
const relay = circuit.newRelay(1, 2, "Relais");
const relaySwitch = circuit.newSwitch(0, 3, "Taster", true);
const batteryRelay = circuit.newBattery(1, 4, "Relais Batterie");
circuit.connect(batteryLight.plus, lightActive.b);
circuit.connect(batteryLight.plus, lightInactive.b);
circuit.connect(batteryLight.minus, relay.common);
circuit.connect(lightInactive.a, relay.inactive);
circuit.connect(lightActive.a, relay.active);
circuit.connect(batteryRelay.minus, relaySwitch.common);
circuit.connect(relaySwitch.active, relay.coilA);
circuit.connect(batteryRelay.plus, relay.coilB);
return circuit;
}

View File

@ -1,8 +1,5 @@
import {Point} from '../Point';
import {Part, RASTER} from '../parts/Part';
import {Battery} from '../parts/battery/Battery';
import {Light} from '../parts/light/Light';
import {Relay} from '../parts/relay/Relay';
import {Circuit} from './Circuit';
export class Parts {
@ -42,33 +39,4 @@ export class Parts {
this.dragCursor = Point.fromEvent($event);
}
newBattery(rasterX: number, rasterY: number): Battery {
return this.add(new Battery(rasterX, rasterY, this.generateName("Batterie")));
}
newLight(rasterX: number, rasterY: number): Light {
return this.add(new Light(rasterX, rasterY, this.generateName("Licht")));
}
newRelay(rasterX: number, rasterY: number): Relay {
return this.add(new Relay(rasterX, rasterY, this.generateName("Relais")));
}
private generateName(baseName: string) {
let counter = 1;
let name: string;
while (true) {
name = `${baseName} #${counter++}`;
if (!this.circuit.parts.some(p => p.name === name)) {
break
}
}
return name;
}
private add<T extends Part>(part: T): T {
this.circuit.parts.push(part);
return part;
}
}

View File

@ -1,6 +1,5 @@
import {Point} from '../Point';
import {Junction} from '../junction/Junction';
import {Wire} from '../wire/Wire';
import {MessageService} from '../message/message.service';
import {Circuit} from './Circuit';
@ -68,7 +67,15 @@ export class Wires {
this.updateDragCursor($event);
if ($event.button === 0) {
if (this.dragStartJunction !== null && this.dragEndJunction !== null) {
this.connect(this.dragStartJunction, this.dragEndJunction);
if (this.dragStartJunction !== this.dragEndJunction) {
if (!this.dragEndDuplicate) {
this.circuit.connect(this.dragStartJunction, this.dragEndJunction);
} else {
this.messageService.warn("Diese Verbindung existiert bereits.");
}
} else {
console.log("Not connecting junction with itself.");
}
}
this.dragReset();
}
@ -90,26 +97,4 @@ export class Wires {
this.dragEndDuplicate = false;
}
connect(start: Junction, end: Junction) {
if (start === end) {
console.log("Not connecting junction with itself.");
return;
}
if (this.dragEndDuplicate) {
this.messageService.warn("Diese Verbindung existiert bereits.");
return;
}
const wire = new Wire(start, end, 0);
this.circuit.wires.push(wire);
console.log(`Wire connected: ${wire}`);
this.circuit.calculate();
}
disconnect(wire: Wire) {
this.circuit.wires.splice(this.circuit.wires.indexOf(wire), 1);
wire.disconnect();
console.log("Wire disconnected: ", wire);
this.circuit.calculate();
}
}

View File

@ -1,5 +1,6 @@
import {PartType} from './PartType';
import {Junction} from '../junction/Junction';
import {Circuit} from '../circuit/Circuit';
import {PartType} from './PartType';
export const RASTER = 50;
@ -16,6 +17,7 @@ export abstract class Part {
private readonly _h: number;
protected constructor(
readonly circuit: Circuit,
readonly type: PartType,
readonly name: string,
rasterX: number,
@ -74,6 +76,14 @@ export abstract class Part {
//
}
mouseDown() {
//
}
mouseUp() {
//
}
abstract get junctions(): Junction[];
}

View File

@ -1,4 +1,6 @@
export enum PartType {
Battery = 'Battery',
Light = 'Light',
Relay = 'Relay',
Switch = 'Switch',
}

View File

@ -3,6 +3,7 @@ import {Junction} from '../../junction/Junction';
import {PartType} from '../PartType';
import {siPrefix} from '../../siPrefix';
import {Wire} from '../../wire/Wire';
import {Circuit} from '../../circuit/Circuit';
export class Battery extends Part {
@ -11,13 +12,14 @@ export class Battery extends Part {
readonly plus: Junction = new Junction(this, 85, 50, "+");
constructor(
circuit: Circuit,
rasterX: number,
rasterY: number,
name: string,
public voltage: number = 3,
public resistance: number = 0.5,
public voltage: number,
public resistance: number,
) {
super(PartType.Battery, name, rasterX, rasterY);
super(circuit, PartType.Battery, name, rasterX, rasterY);
new Wire(this.minus, this.plus, resistance, "Innenwiderstand");
}

View File

@ -5,6 +5,7 @@ import {siPrefix} from '../../siPrefix';
import {fadeColor} from '../../colorHelpers';
import {Wire} from '../../wire/Wire';
import {Circuit} from '../../circuit/Circuit';
export class Light extends Part {
@ -13,13 +14,14 @@ export class Light extends Part {
readonly b = new Junction(this, 85, 50, "B");
constructor(
circuit: Circuit,
rasterX: number,
rasterY: number,
name: string,
public voltageMax: number = 3,
public resistance: number = 100,
public voltageMax: number,
public resistance: number,
) {
super(PartType.Light, name, rasterX, rasterY);
super(circuit, PartType.Light, name, rasterX, rasterY);
new Wire(this.a, this.b, resistance, "Glühdraht");
}

View File

@ -9,7 +9,7 @@
(mousedown)="parts.mouseDown(part, $event)"
>
<rect class="background" height="100%" width="100%" x="0" y="0"></rect>
<rect class="background" height="100%" width="100%" x="0" y="0" (mousedown)="part.mouseDown()" (mouseup)="part.mouseUp()"></rect>
<g inner-part-battery *ngIf="isBattery(part)" [battery]="asBattery(part)"></g>
@ -17,6 +17,8 @@
<g inner-part-relay *ngIf="isRelay(part)" [relay]="asRelay(part)"></g>
<g inner-part-switch *ngIf="isSwitch(part)" [switch]="asSwitch(part)"></g>
<g inner-junction *ngFor="let junction of part.junctions" [junction]="junction" [wires]="wires"></g>
</svg>

Before

Width:  |  Height:  |  Size: 695 B

After

Width:  |  Height:  |  Size: 831 B

View File

@ -10,6 +10,8 @@ import {LightComponent} from './light/light.component';
import {JunctionComponent} from '../junction/junction.component';
import {Relay} from './relay/Relay';
import {RelayComponent} from './relay/relay.component';
import {SwitchComponent} from './switch/switch.component';
import {Switch} from './switch/Switch';
@Component({
selector: 'g[inner-part]',
@ -19,7 +21,8 @@ import {RelayComponent} from './relay/relay.component';
NgForOf,
LightComponent,
JunctionComponent,
RelayComponent
RelayComponent,
SwitchComponent
],
templateUrl: './part.component.svg',
styleUrl: './part.component.less',
@ -59,4 +62,12 @@ export class PartComponent {
return part instanceof Relay;
}
asSwitch(part: Part): Switch {
return part as Switch;
}
isSwitch(part: Part): boolean {
return part instanceof Switch;
}
}

View File

@ -4,6 +4,7 @@ import {PartType} from '../PartType';
import {siPrefix} from '../../siPrefix';
import {Wire} from '../../wire/Wire';
import {RESISTANCE_MIN} from '../../circuit/Calculation';
import {Circuit} from '../../circuit/Circuit';
export class Relay extends Part {
@ -22,14 +23,15 @@ export class Relay extends Part {
contact: Wire = new Wire(this.common, this.inactive, RESISTANCE_MIN, "Schaltkontakt");
constructor(
circuit: Circuit,
rasterX: number,
rasterY: number,
name: string,
public voltageMin: number = 1.5,
public voltageMax: number = 3,
public resistance: number = 150,
public voltageMin: number,
public voltageMax: number,
public resistance: number,
) {
super(PartType.Light, name, rasterX, rasterY);
super(circuit, PartType.Relay, name, rasterX, rasterY);
this.coil = new Wire(this.coilA, this.coilB, resistance, "Spule");
}

View File

@ -10,7 +10,6 @@
[attr.x2]="50 + '%'"
[attr.y2]="65 + '%'"
></line>
<g inner-wire [partWire]="relay.contact"></g>
</ng-container>
<ng-container *ngIf="relay.isCoilActive">
@ -20,9 +19,10 @@
[attr.x2]="50 + '%'"
[attr.y2]="65 + '%'"
></line>
<g inner-wire [partWire]="relay.contact"></g>
</ng-container>
<g inner-wire [partWire]="relay.contact"></g>
<g inner-wire [partWire]="relay.coil" extraClassesBack="partWireBack"></g>
<rect class="coil" [class.coilActive]="relay.isCoilActive" [class.defect]="relay.defect" x="40%" y="65%" width="20%" height="30%"></rect>

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 975 B

View File

@ -1,6 +1,5 @@
import {Component, Input} from '@angular/core';
import {Relay} from './Relay';
import {JUNCTION_RADIUS_PERCENT} from '../../junction/Junction';
import {NgIf} from '@angular/common';
import {WireComponent} from '../../part-wire/wire.component';
@ -18,6 +17,4 @@ export class RelayComponent {
@Input()
relay!: Relay;
protected readonly JUNCTION_RADIUS_PERCENT = JUNCTION_RADIUS_PERCENT;
}

View File

@ -0,0 +1,66 @@
import {Part} from "../Part";
import {Junction} from '../../junction/Junction';
import {PartType} from '../PartType';
import {Wire} from '../../wire/Wire';
import {RESISTANCE_MIN} from '../../circuit/Calculation';
import {Circuit} from '../../circuit/Circuit';
export class Switch extends Part {
readonly common = new Junction(this, 15, 50, "COM");
readonly active = new Junction(this, 85, 50, "NO");
readonly inactive = new Junction(this, 85, 15, "NC");
contact: Wire = new Wire(this.common, this.inactive, RESISTANCE_MIN, "Schaltkontakt");
isActive: boolean = false;
constructor(
circuit: Circuit,
rasterX: number,
rasterY: number,
name: string,
readonly momentary: boolean,
) {
super(circuit, PartType.Switch, name, rasterX, rasterY);
}
override get junctions(): Junction[] {
return [this.common, this.active, this.inactive];
}
override resetCalculations2() {
this.contact.resetCalculations();
}
override mouseDown() {
if (this.momentary) {
this.setIsActive(true);
} else {
this.setIsActive(!this.isActive);
}
}
override mouseUp() {
if (this.momentary) {
this.setIsActive(false);
}
}
setIsActive(isActive: boolean) {
if (this.isActive === isActive) {
return;
}
this.isActive = isActive;
this.contact.disconnect();
if (this.isActive) {
this.contact = new Wire(this.common, this.active, RESISTANCE_MIN, "Schaltkontakt (Aktiv)");
} else {
this.contact = new Wire(this.common, this.inactive, RESISTANCE_MIN, "Schaltkontakt (Inaktiv)");
}
this.circuit.calculate();
}
}

View File

@ -0,0 +1,21 @@
@import "../part.component.less";
.defect {
filter: drop-shadow(0 0 30px black);
}
.mechanic {
stroke-width: 3px;
stroke: dimgray;
stroke-dasharray: 5 5;
}
.coil {
stroke: black;
stroke-width: 1px;
fill: darkgray;
}
.coilActive {
fill: dodgerblue;
}

View File

@ -0,0 +1,3 @@
<svg width="100%" height="100%">
<g inner-wire [partWire]="switch.contact"></g>
</svg>

After

Width:  |  Height:  |  Size: 89 B

View File

@ -0,0 +1,18 @@
import {Component, Input} from '@angular/core';
import {Switch} from './Switch';
import {WireComponent} from '../../part-wire/wire.component';
@Component({
selector: 'g[inner-part-switch]',
imports: [
WireComponent
],
templateUrl: './switch.component.svg',
styleUrl: './switch.component.less',
})
export class SwitchComponent {
@Input()
switch!: Switch;
}