Compare commits
No commits in common. "04708e58356f95957c87b87112d656fc677ee9b1" and "228d78c7397f434e375630d5fcfe9bc71fd23c66" have entirely different histories.
04708e5835
...
228d78c739
@ -11,12 +11,16 @@ public class CONFIG {
|
|||||||
|
|
||||||
public static final double MAX_RESISTANCE = 1 / NO_RESISTANCE;
|
public static final double MAX_RESISTANCE = 1 / NO_RESISTANCE;
|
||||||
|
|
||||||
|
public static boolean SHOW_WIRE_DETAILS = true;
|
||||||
|
|
||||||
|
public static boolean SHOW_NODE_VOLTAGES = false;
|
||||||
|
|
||||||
|
public static boolean SHOW_NODE_NAMES = false;
|
||||||
|
|
||||||
public static final double VOLTAGE_HIGH_MIN = 0.1;
|
public static final double VOLTAGE_HIGH_MIN = 0.1;
|
||||||
|
|
||||||
public static final int RASTER = 200;
|
public static final int RASTER = 200;
|
||||||
|
|
||||||
public static final int SUB_RASTER = RASTER / 5;
|
|
||||||
|
|
||||||
public static final int P03 = (int) round(0.03 * RASTER);
|
public static final int P03 = (int) round(0.03 * RASTER);
|
||||||
|
|
||||||
public static final int P05 = (int) round(0.05 * RASTER);
|
public static final int P05 = (int) round(0.05 * RASTER);
|
||||||
@ -77,12 +81,6 @@ public class CONFIG {
|
|||||||
|
|
||||||
public static final BasicStroke SWITCH_STROKE = new BasicStroke(15);
|
public static final BasicStroke SWITCH_STROKE = new BasicStroke(15);
|
||||||
|
|
||||||
public static boolean SHOW_WIRE_DETAILS = false;
|
|
||||||
|
|
||||||
public static boolean SHOW_NODE_VOLTAGES = false;
|
|
||||||
|
|
||||||
public static boolean SHOW_NODE_NAMES = false;
|
|
||||||
|
|
||||||
public static Point ALIGN(final Point position) {
|
public static Point ALIGN(final Point position) {
|
||||||
return new Point(position.x / RASTER * RASTER, position.y / RASTER * RASTER);
|
return new Point(position.x / RASTER * RASTER, position.y / RASTER * RASTER);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,11 +36,6 @@ public class Window extends JFrame {
|
|||||||
setVisible(true);
|
setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
final Window window = new Window();
|
|
||||||
window.setCircuit(Demos.potiAndVoltmeter());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCircuit(final Circuit circuit) {
|
public void setCircuit(final Circuit circuit) {
|
||||||
circuitPanel.setCircuit(circuit);
|
circuitPanel.setCircuit(circuit);
|
||||||
}
|
}
|
||||||
@ -56,4 +51,9 @@ public class Window extends JFrame {
|
|||||||
setLocation(screenBounds.x, screenBounds.y);
|
setLocation(screenBounds.x, screenBounds.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
final Window window = new Window();
|
||||||
|
window.setCircuit(Demos.potiAndVoltmeter());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,42 +9,38 @@ import de.ph87.electro.circuit.wire.WireDto;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.*;
|
import java.util.Optional;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static de.ph87.electro.CONFIG.ALIGN;
|
import static de.ph87.electro.CONFIG.ALIGN;
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public class Circuit {
|
public class Circuit {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final String created;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final List<Part> parts = new ArrayList<>();
|
||||||
|
|
||||||
|
private final List<Wire> wires = new ArrayList<>();
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
@Getter
|
@Getter
|
||||||
private File file = null;
|
private File file = null;
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Getter
|
|
||||||
private final String created;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Getter
|
|
||||||
private final List<Part> parts = new ArrayList<>();
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final List<Wire> wires = new ArrayList<>();
|
|
||||||
|
|
||||||
public Circuit() {
|
public Circuit() {
|
||||||
this.created = ZonedDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
|
this.created = ZonedDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public Circuit(@NonNull final File file, @NonNull final CircuitDto dto) {
|
public Circuit(final File file, final CircuitDto dto) {
|
||||||
this.created = dto.getCreated();
|
this.created = dto.getCreated();
|
||||||
for (PartDto partDto : dto.getParts()) {
|
for (PartDto partDto : dto.getParts()) {
|
||||||
final Part part = Part.fromDto(partDto);
|
final Part part = Part.fromDto(partDto);
|
||||||
@ -58,23 +54,13 @@ public class Circuit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connect(@NonNull final Node a, @NonNull final Node b) {
|
public Wire connect(final Node a, final Node b) {
|
||||||
if (a == b) {
|
|
||||||
log.warn("No Wire created: Nodes are identical: {}", a);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final Optional<Wire> duplicate = a.getWires().stream().filter(w -> w.getOpposite(a) == b).findFirst();
|
|
||||||
if (duplicate.isPresent()) {
|
|
||||||
log.warn("No Wire created: Between these nodes, a wire already exists: {}", duplicate);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final Wire wire = new Wire(a, b);
|
final Wire wire = new Wire(a, b);
|
||||||
wires.add(wire);
|
wires.add(wire);
|
||||||
log.info("Wire CREATED: {}", wire);
|
return wire;
|
||||||
evaluate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disconnect(@NonNull final Wire wire) {
|
public void disconnect(final Wire wire) {
|
||||||
if (!wires.contains(wire)) {
|
if (!wires.contains(wire)) {
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
@ -83,7 +69,7 @@ public class Circuit {
|
|||||||
wire.getB().getWires().remove(wire);
|
wire.getB().getWires().remove(wire);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends Part> T addPart(@NonNull final T part) {
|
public <T extends Part> T addPart(final T part) {
|
||||||
if (parts.contains(part)) {
|
if (parts.contains(part)) {
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
@ -92,21 +78,7 @@ public class Circuit {
|
|||||||
return part;
|
return part;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removePart(@NonNull final Part part) {
|
public void removePart(final Part part) {
|
||||||
for (final Node node : part.getNodes()) {
|
|
||||||
Node origin = null;
|
|
||||||
Set<Node> destinations = new HashSet<>();
|
|
||||||
for (final Wire wire : node.getWires()) {
|
|
||||||
if (origin == null) {
|
|
||||||
origin = wire.getOpposite(node);
|
|
||||||
} else {
|
|
||||||
destinations.add(wire.getOpposite(node));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (final Node destination : destinations) {
|
|
||||||
connect(origin, destination);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (parts.remove(part)) {
|
if (parts.remove(part)) {
|
||||||
part.getNodes().stream().flatMap(node -> node.getWires().stream()).toList().forEach(this::disconnect); // jep, first toList(), then forEach (due to concurrent modification)
|
part.getNodes().stream().flatMap(node -> node.getWires().stream()).toList().forEach(this::disconnect); // jep, first toList(), then forEach (due to concurrent modification)
|
||||||
} else {
|
} else {
|
||||||
@ -114,13 +86,13 @@ public class Circuit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void verifyFree(@NonNull final Point position) {
|
public void verifyFree(final Point position) {
|
||||||
if (isOccupied(position)) {
|
if (isOccupied(position)) {
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isOccupied(@NonNull final Point position) {
|
public boolean isOccupied(final Point position) {
|
||||||
final Point aligned = ALIGN(position);
|
final Point aligned = ALIGN(position);
|
||||||
return parts.stream().anyMatch(part -> part.getPosition().equals(aligned));
|
return parts.stream().anyMatch(part -> part.getPosition().equals(aligned));
|
||||||
}
|
}
|
||||||
@ -137,15 +109,16 @@ public class Circuit {
|
|||||||
return parts.size();
|
return parts.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Part> findPartByPosition(@NonNull final Point position) {
|
public Optional<Part> findPartByPosition(final Point position) {
|
||||||
return streamParts().filter(p -> p.intersects(position)).findFirst();
|
final Point aligned = ALIGN(position);
|
||||||
|
return streamParts().filter(p -> p.getPosition().equals(aligned)).findFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<? extends Node> findNodeByUuid(@NonNull final String nodeUuid) {
|
public Optional<Node> findNodeByUuid(@NonNull final String nodeUuid) {
|
||||||
return parts.stream().map(part -> part.findNodeByUuid(nodeUuid)).filter(Optional::isPresent).map(Optional::get).findFirst();
|
return parts.stream().map(part -> part.findNodeByUuid(nodeUuid)).filter(Optional::isPresent).map(Optional::get).findFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Wire> findWireByPosition(@NonNull final Point position) {
|
public Optional<Wire> findWireByPosition(final Point position) {
|
||||||
return wires.stream().filter(wire -> wire.intersects(position)).findFirst();
|
return wires.stream().filter(wire -> wire.intersects(position)).findFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -69,7 +69,7 @@ public class CircuitPainter {
|
|||||||
|
|
||||||
for (Part part : circuit.getParts()) {
|
for (Part part : circuit.getParts()) {
|
||||||
for (final Node node : part.getNodes()) {
|
for (final Node node : part.getNodes()) {
|
||||||
final Point absolute = node.getPosition();
|
final Point absolute = node.getAbsolute();
|
||||||
if (SHOW_NODE_NAMES) {
|
if (SHOW_NODE_NAMES) {
|
||||||
int offsetY = third;
|
int offsetY = third;
|
||||||
if (SHOW_NODE_VOLTAGES) {
|
if (SHOW_NODE_VOLTAGES) {
|
||||||
|
|||||||
@ -40,7 +40,7 @@ public class CircuitPanel extends JPanel {
|
|||||||
public void paint(final Graphics graphics) {
|
public void paint(final Graphics graphics) {
|
||||||
final Graphics2D g = (Graphics2D) graphics;
|
final Graphics2D g = (Graphics2D) graphics;
|
||||||
CircuitPainter.draw(g, circuit, getWidth(), getHeight());
|
CircuitPainter.draw(g, circuit, getWidth(), getHeight());
|
||||||
mouseAdapter.drawHovers(g);
|
mouseAdapter.drawHover(g);
|
||||||
mouseAdapter.drawDrag(g);
|
mouseAdapter.drawDrag(g);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,6 +22,12 @@ public class CircuitPanelDropTarget extends AbstractDropTarget {
|
|||||||
final Point aligned = ALIGN(point);
|
final Point aligned = ALIGN(point);
|
||||||
if (data.equals(Battery.class.getSimpleName())) {
|
if (data.equals(Battery.class.getSimpleName())) {
|
||||||
circuitPanel.getCircuit().addPart(new Battery(aligned));
|
circuitPanel.getCircuit().addPart(new Battery(aligned));
|
||||||
|
} else if (data.equals(ConnectorCorner.class.getSimpleName())) {
|
||||||
|
circuitPanel.getCircuit().addPart(new ConnectorCorner(aligned));
|
||||||
|
} else if (data.equals(ConnectorEdge.class.getSimpleName())) {
|
||||||
|
circuitPanel.getCircuit().addPart(new ConnectorEdge(aligned));
|
||||||
|
} else if (data.equals(ConnectorMiddle.class.getSimpleName())) {
|
||||||
|
circuitPanel.getCircuit().addPart(new ConnectorMiddle(aligned));
|
||||||
} else if (data.equals(Light.class.getSimpleName())) {
|
} else if (data.equals(Light.class.getSimpleName())) {
|
||||||
circuitPanel.getCircuit().addPart(new Light(aligned));
|
circuitPanel.getCircuit().addPart(new Light(aligned));
|
||||||
} else if (data.equals(Switch1x1.class.getSimpleName())) {
|
} else if (data.equals(Switch1x1.class.getSimpleName())) {
|
||||||
|
|||||||
@ -2,9 +2,7 @@ package de.ph87.electro.circuit;
|
|||||||
|
|
||||||
import de.ph87.electro.circuit.part.Part;
|
import de.ph87.electro.circuit.part.Part;
|
||||||
import de.ph87.electro.circuit.part.node.Node;
|
import de.ph87.electro.circuit.part.node.Node;
|
||||||
import de.ph87.electro.circuit.part.parts.ConnectorSub;
|
|
||||||
import de.ph87.electro.circuit.wire.Wire;
|
import de.ph87.electro.circuit.wire.Wire;
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
@ -27,112 +25,66 @@ class CircuitPanelMouseAdapter extends MouseAdapter {
|
|||||||
|
|
||||||
private Point dragging = null;
|
private Point dragging = null;
|
||||||
|
|
||||||
private Part part2 = null;
|
CircuitPanelMouseAdapter(final CircuitPanel circuitPanel) {
|
||||||
|
|
||||||
private Node node2 = null;
|
|
||||||
|
|
||||||
private Point draggingSub;
|
|
||||||
|
|
||||||
CircuitPanelMouseAdapter(@NonNull final CircuitPanel circuitPanel) {
|
|
||||||
this.circuitPanel = circuitPanel;
|
this.circuitPanel = circuitPanel;
|
||||||
circuitPanel.addMouseListener(this);
|
circuitPanel.addMouseListener(this);
|
||||||
circuitPanel.addMouseMotionListener(this);
|
circuitPanel.addMouseMotionListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* HOVER ---------------------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseMoved(@NonNull final MouseEvent event) {
|
public void mouseClicked(final MouseEvent event) {
|
||||||
findHovers(event);
|
hoverUpdate(event);
|
||||||
|
|
||||||
|
if (wire != null) {
|
||||||
|
switch (event.getButton()) {
|
||||||
|
case BUTTON3:
|
||||||
|
circuitPanel.getCircuit().disconnect(wire);
|
||||||
|
circuitPanel.getCircuit().evaluate();
|
||||||
|
wire = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (part != null) {
|
||||||
|
switch (event.getButton()) {
|
||||||
|
case BUTTON1:
|
||||||
|
part.action();
|
||||||
|
circuitPanel.getCircuit().evaluate();
|
||||||
|
break;
|
||||||
|
case BUTTON2:
|
||||||
|
part.rotate();
|
||||||
|
break;
|
||||||
|
case BUTTON3:
|
||||||
|
circuitPanel.getCircuit().removePart(part);
|
||||||
|
circuitPanel.getCircuit().evaluate();
|
||||||
|
part = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
circuitPanel.repaint();
|
circuitPanel.repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void findHovers(@NonNull final MouseEvent event) {
|
@Override
|
||||||
final Point position = event.getPoint();
|
public void mouseMoved(final MouseEvent event) {
|
||||||
part = circuitPanel.getCircuit().findPartByPosition(position).orElse(null);
|
hoverUpdate(event);
|
||||||
node = part != null ? part.findNodeByPosition(position).orElse(null) : null;
|
circuitPanel.repaint();
|
||||||
if (node != null) {
|
|
||||||
part = null;
|
|
||||||
if (wire != null) {
|
|
||||||
wire.setGhost(false);
|
|
||||||
}
|
|
||||||
wire = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
wire = circuitPanel.getCircuit().findWireByPosition(position).orElse(null);
|
|
||||||
if (wire != null) {
|
|
||||||
part = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void drawHovers(@NonNull final Graphics2D g) {
|
|
||||||
drawPartHover(g);
|
|
||||||
drawNodeHover(g, node);
|
|
||||||
drawNodeHover(g, node2);
|
|
||||||
drawWireHover(g);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawPartHover(@NonNull final Graphics2D g) {
|
|
||||||
if (part == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g.setColor(NODE_HOVER_BORDER_COLOR);
|
|
||||||
g.setStroke(HOVER_STROKE);
|
|
||||||
g.drawRect(part.getPosition().x, part.getPosition().y, RASTER, RASTER);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawNodeHover(@NonNull final Graphics2D g, final Node n) {
|
|
||||||
if (n == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Point absolute = n.getPosition();
|
|
||||||
|
|
||||||
g.setColor(n.getColor());
|
|
||||||
g.fillArc(absolute.x - NODE_RADIUS_HOVER, absolute.y - NODE_RADIUS_HOVER, 2 * NODE_RADIUS_HOVER, 2 * NODE_RADIUS_HOVER, 0, 360);
|
|
||||||
|
|
||||||
g.setColor(NODE_HOVER_BORDER_COLOR);
|
|
||||||
g.setStroke(HOVER_STROKE);
|
|
||||||
g.drawArc(absolute.x - NODE_RADIUS_HOVER, absolute.y - NODE_RADIUS_HOVER, 2 * NODE_RADIUS_HOVER, 2 * NODE_RADIUS_HOVER, 0, 360);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawWireHover(@NonNull final Graphics2D g) {
|
|
||||||
if (wire == null || wire.isGhost()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Point aa = wire.getA().getPosition();
|
|
||||||
final Point bb = wire.getB().getPosition();
|
|
||||||
|
|
||||||
g.setColor(WIRE_HOVER_COLOR_BACK);
|
|
||||||
g.setStroke(WIRE_HOVER_STROKE_BACK);
|
|
||||||
g.drawLine(aa.x, aa.y, bb.x, bb.y);
|
|
||||||
|
|
||||||
g.setColor(wire.getA().getColor());
|
|
||||||
g.setStroke(WIRE_HOVER_STROKE);
|
|
||||||
g.drawLine(aa.x, aa.y, bb.x, bb.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* DRAG ----------------------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseDragged(@NonNull final MouseEvent event) {
|
public void mouseDragged(final MouseEvent event) {
|
||||||
if (dragging == null) {
|
if (dragging == null) {
|
||||||
findHovers(event);
|
hoverUpdate(event);
|
||||||
if (wire != null) {
|
|
||||||
wire.setGhost(true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
part2 = circuitPanel.getCircuit().findPartByPosition(dragging).orElse(null);
|
|
||||||
node2 = part2 == null ? null : part2.findNodeByPosition(dragging).orElse(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dragging = event.getPoint();
|
dragging = event.getPoint();
|
||||||
draggingSub = new Point(
|
circuitPanel.repaint();
|
||||||
dragging.x / SUB_RASTER * SUB_RASTER,
|
}
|
||||||
dragging.y / SUB_RASTER * SUB_RASTER
|
|
||||||
);
|
@Override
|
||||||
|
public void mouseReleased(final MouseEvent event) {
|
||||||
|
if (dragging == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (part != null) {
|
if (part != null) {
|
||||||
final Point aligned = ALIGN(event.getPoint());
|
final Point aligned = ALIGN(event.getPoint());
|
||||||
@ -144,184 +96,80 @@ class CircuitPanelMouseAdapter extends MouseAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
circuitPanel.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseReleased(@NonNull final MouseEvent event) {
|
|
||||||
if (dragging == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node != null) {
|
if (node != null) {
|
||||||
final Node source = node;
|
final Node source = node;
|
||||||
findHovers(event);
|
hoverUpdate(event);
|
||||||
if (node != null) {
|
if (node != null) {
|
||||||
circuitPanel.getCircuit().connect(source, node);
|
final Wire wire = circuitPanel.getCircuit().connect(source, node);
|
||||||
|
log.info("Wire CREATED: {}", wire);
|
||||||
circuitPanel.getCircuit().evaluate();
|
circuitPanel.getCircuit().evaluate();
|
||||||
} else {
|
} else {
|
||||||
log.info("No Wire created: No destination node found!");
|
log.info("No Wire created: No destination node found!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wire != null) {
|
|
||||||
wireBend();
|
|
||||||
}
|
|
||||||
|
|
||||||
terminateMouseAction();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void wireBend() {
|
|
||||||
if (node2 != null) {
|
|
||||||
wireBendToExistingNode();
|
|
||||||
} else {
|
|
||||||
wireBendToNewConnector();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void wireBendToExistingNode() {
|
|
||||||
if (wire == null) {
|
|
||||||
throw new RuntimeException();
|
|
||||||
}
|
|
||||||
if (node2 == wire.getA() || node2 == wire.getB()) {
|
|
||||||
log.info("Wire-bending-destination node is already part of that wire: wire={}, node={}", wire, node2);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
connectIntermediate(node2);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void wireBendToNewConnector() {
|
|
||||||
final ConnectorSub newConnector = circuitPanel.getCircuit().addPart(new ConnectorSub(draggingSub));
|
|
||||||
connectIntermediate(newConnector.getNode());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void connectIntermediate(@NonNull final Node intermediate) {
|
|
||||||
circuitPanel.getCircuit().connect(wire.getA(), intermediate);
|
|
||||||
circuitPanel.getCircuit().connect(intermediate, wire.getB());
|
|
||||||
circuitPanel.getCircuit().disconnect(wire);
|
|
||||||
circuitPanel.getCircuit().evaluate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void drawDrag(@NonNull final Graphics2D g) {
|
|
||||||
drawPartDrag(g);
|
|
||||||
drawNodeDrag(g);
|
|
||||||
drawWireDrag(g);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawWireDrag(@NonNull final Graphics2D g) {
|
|
||||||
if (dragging == null || wire == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Point vertex;
|
|
||||||
if (part2 != null) {
|
|
||||||
if (node2 == null) {
|
|
||||||
// hovering part, but not a node
|
|
||||||
vertex = dragging;
|
|
||||||
} else {
|
|
||||||
// hovering existing node
|
|
||||||
vertex = node2.getPosition();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// hovering free space (will create a new connector in sub-raster)
|
|
||||||
g.setColor(PART_HOVER_COLOR);
|
|
||||||
g.fillRect(draggingSub.x, draggingSub.y, SUB_RASTER, SUB_RASTER);
|
|
||||||
vertex = new Point(
|
|
||||||
draggingSub.x + SUB_RASTER / 2,
|
|
||||||
draggingSub.y + SUB_RASTER / 2
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// wire
|
|
||||||
g.setColor(wire.getA().getColor());
|
|
||||||
g.setStroke(WIRE_STROKE);
|
|
||||||
g.drawLine(wire.getA().getPosition().x, wire.getA().getPosition().y, vertex.x, vertex.y);
|
|
||||||
g.drawLine(vertex.x, vertex.y, wire.getB().getPosition().x, wire.getB().getPosition().y);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawNodeDrag(@NonNull final Graphics2D g) {
|
|
||||||
if (dragging == null || node == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
g.setColor(node.getColor());
|
|
||||||
g.setStroke(WIRE_STROKE);
|
|
||||||
final Point absolute = node.getPosition();
|
|
||||||
g.drawLine(absolute.x, absolute.y, dragging.x, dragging.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawPartDrag(@NonNull final Graphics2D g) {
|
|
||||||
if (dragging == null || part == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
g.setColor(PART_HOVER_COLOR);
|
|
||||||
g.fillRect(dragging.x - P50, dragging.y - P50, RASTER, RASTER);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* CLICK ---------------------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseClicked(@NonNull final MouseEvent event) {
|
|
||||||
findHovers(event);
|
|
||||||
if (mouseClickedAction(event)) {
|
|
||||||
terminateMouseAction();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean mouseClickedAction(@NonNull final MouseEvent event) {
|
|
||||||
if (node != null && node.getPart() instanceof ConnectorSub) {
|
|
||||||
switch (event.getButton()) {
|
|
||||||
case BUTTON3:
|
|
||||||
circuitPanel.getCircuit().removePart(node.getPart());
|
|
||||||
circuitPanel.getCircuit().evaluate();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (wire != null) {
|
|
||||||
switch (event.getButton()) {
|
|
||||||
case BUTTON3:
|
|
||||||
circuitPanel.getCircuit().disconnect(wire);
|
|
||||||
circuitPanel.getCircuit().evaluate();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (part != null) {
|
|
||||||
switch (event.getButton()) {
|
|
||||||
case BUTTON1:
|
|
||||||
part.action();
|
|
||||||
circuitPanel.getCircuit().evaluate();
|
|
||||||
return true;
|
|
||||||
case BUTTON2:
|
|
||||||
part.rotate();
|
|
||||||
return true;
|
|
||||||
case BUTTON3:
|
|
||||||
circuitPanel.getCircuit().removePart(part);
|
|
||||||
circuitPanel.getCircuit().evaluate();
|
|
||||||
part = null;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* COMMON --------------------------------------------------------------------------------------- */
|
|
||||||
|
|
||||||
private void terminateMouseAction() {
|
|
||||||
if (wire != null) {
|
|
||||||
wire.setGhost(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
part = null;
|
|
||||||
node = null;
|
|
||||||
wire = null;
|
|
||||||
|
|
||||||
part2 = null;
|
|
||||||
node2 = null;
|
|
||||||
|
|
||||||
dragging = null;
|
dragging = null;
|
||||||
draggingSub = null;
|
|
||||||
|
|
||||||
circuitPanel.repaint();
|
circuitPanel.repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void hoverUpdate(final MouseEvent event) {
|
||||||
|
final Point position = event.getPoint();
|
||||||
|
part = circuitPanel.getCircuit().findPartByPosition(position).orElse(null);
|
||||||
|
node = part != null ? part.findNodeByPosition(position).orElse(null) : null;
|
||||||
|
if (node != null) {
|
||||||
|
part = null;
|
||||||
|
wire = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wire = circuitPanel.getCircuit().findWireByPosition(position).orElse(null);
|
||||||
|
if (wire != null) {
|
||||||
|
part = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawHover(final Graphics2D g) {
|
||||||
|
if (part != null) {
|
||||||
|
g.setColor(NODE_HOVER_BORDER_COLOR);
|
||||||
|
g.setStroke(HOVER_STROKE);
|
||||||
|
g.drawRect(part.getPosition().x, part.getPosition().y, RASTER, RASTER);
|
||||||
|
}
|
||||||
|
if (node != null) {
|
||||||
|
final Point absolute = node.getAbsolute();
|
||||||
|
|
||||||
|
g.setColor(node.getColor());
|
||||||
|
g.fillArc(absolute.x - NODE_RADIUS_HOVER, absolute.y - NODE_RADIUS_HOVER, 2 * NODE_RADIUS_HOVER, 2 * NODE_RADIUS_HOVER, 0, 360);
|
||||||
|
|
||||||
|
g.setColor(NODE_HOVER_BORDER_COLOR);
|
||||||
|
g.setStroke(HOVER_STROKE);
|
||||||
|
g.drawArc(absolute.x - NODE_RADIUS_HOVER, absolute.y - NODE_RADIUS_HOVER, 2 * NODE_RADIUS_HOVER, 2 * NODE_RADIUS_HOVER, 0, 360);
|
||||||
|
}
|
||||||
|
if (wire != null) {
|
||||||
|
final Point aa = wire.getA().getAbsolute();
|
||||||
|
final Point bb = wire.getB().getAbsolute();
|
||||||
|
|
||||||
|
g.setColor(WIRE_HOVER_COLOR_BACK);
|
||||||
|
g.setStroke(WIRE_HOVER_STROKE_BACK);
|
||||||
|
g.drawLine(aa.x, aa.y, bb.x, bb.y);
|
||||||
|
|
||||||
|
g.setColor(wire.getA().getColor());
|
||||||
|
g.setStroke(WIRE_HOVER_STROKE);
|
||||||
|
g.drawLine(aa.x, aa.y, bb.x, bb.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawDrag(final Graphics2D g) {
|
||||||
|
if (dragging != null) {
|
||||||
|
if (part != null) {
|
||||||
|
g.setColor(PART_HOVER_COLOR);
|
||||||
|
g.fillRect(dragging.x - P50, dragging.y - P50, RASTER, RASTER);
|
||||||
|
}
|
||||||
|
if (node != null) {
|
||||||
|
g.setColor(node.getColor());
|
||||||
|
g.setStroke(WIRE_STROKE);
|
||||||
|
final Point absolute = node.getAbsolute();
|
||||||
|
g.drawLine(absolute.x, absolute.y, dragging.x, dragging.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,10 @@ import lombok.NonNull;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.math3.linear.*;
|
import org.apache.commons.math3.linear.*;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static java.lang.Math.max;
|
import static java.lang.Math.max;
|
||||||
|
|
||||||
@ -32,6 +35,20 @@ public class Calculation {
|
|||||||
|
|
||||||
private RealVector potentials = null;
|
private RealVector potentials = null;
|
||||||
|
|
||||||
|
public static List<Calculation> calculate(final Circuit circuit) {
|
||||||
|
final List<Calculation> calculations = new ArrayList<>();
|
||||||
|
final List<Battery> batteries = new ArrayList<>(circuit.streamParts().flatMap(Battery::filterCast).toList());
|
||||||
|
while (!batteries.isEmpty()) {
|
||||||
|
final Battery pivot = batteries.removeFirst();
|
||||||
|
final Set<Node> connectedNodes = new HashSet<>();
|
||||||
|
pivot.getPlus().collectConnectedNodes(connectedNodes);
|
||||||
|
pivot.getMinus().collectConnectedNodes(connectedNodes);
|
||||||
|
connectedNodes.stream().map(Node::getOwner).flatMap(Battery::filterCast).forEach(batteries::remove);
|
||||||
|
calculations.add(new Calculation(connectedNodes, pivot));
|
||||||
|
}
|
||||||
|
return calculations;
|
||||||
|
}
|
||||||
|
|
||||||
public Calculation(final int numNodes) {
|
public Calculation(final int numNodes) {
|
||||||
matrix = new Array2DRowRealMatrix(numNodes, numNodes);
|
matrix = new Array2DRowRealMatrix(numNodes, numNodes);
|
||||||
currents = new ArrayRealVector(numNodes);
|
currents = new ArrayRealVector(numNodes);
|
||||||
@ -39,9 +56,7 @@ public class Calculation {
|
|||||||
|
|
||||||
private Calculation(final Set<Node> connectedNodes, final Battery pivot) {
|
private Calculation(final Set<Node> connectedNodes, final Battery pivot) {
|
||||||
for (final Node node : connectedNodes) {
|
for (final Node node : connectedNodes) {
|
||||||
if (node instanceof final Node partNode) {
|
parts.add(node.getOwner());
|
||||||
parts.add(partNode.getPart());
|
|
||||||
}
|
|
||||||
if (!nodes.contains(node) && node != pivot.getMinus()) {
|
if (!nodes.contains(node) && node != pivot.getMinus()) {
|
||||||
// pivot.minus is GND and cannot be part of the matrix (linear dependency)
|
// pivot.minus is GND and cannot be part of the matrix (linear dependency)
|
||||||
this.nodes.add(node);
|
this.nodes.add(node);
|
||||||
@ -56,20 +71,6 @@ public class Calculation {
|
|||||||
toSchematic();
|
toSchematic();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Calculation> calculate(final Circuit circuit) {
|
|
||||||
final List<Calculation> calculations = new ArrayList<>();
|
|
||||||
final List<Battery> batteries = new ArrayList<>(circuit.streamParts().flatMap(Battery::filterCast).toList());
|
|
||||||
while (!batteries.isEmpty()) {
|
|
||||||
final Battery pivot = batteries.removeFirst();
|
|
||||||
final Set<Node> connectedNodes = new HashSet<>();
|
|
||||||
pivot.getPlus().collectConnectedNodes(connectedNodes);
|
|
||||||
pivot.getMinus().collectConnectedNodes(connectedNodes);
|
|
||||||
connectedNodes.stream().map(Node::getPart).flatMap(Battery::filterCast).forEach(batteries::remove);
|
|
||||||
calculations.add(new Calculation(connectedNodes, pivot));
|
|
||||||
}
|
|
||||||
return calculations;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void fromSchematic() {
|
private void fromSchematic() {
|
||||||
wires.forEach(
|
wires.forEach(
|
||||||
wire -> addResistor(wire.getA(), wire.getB(), CONFIG.NO_RESISTANCE)
|
wire -> addResistor(wire.getA(), wire.getB(), CONFIG.NO_RESISTANCE)
|
||||||
@ -190,12 +191,12 @@ public class Calculation {
|
|||||||
@Getter
|
@Getter
|
||||||
private static final class Format {
|
private static final class Format {
|
||||||
|
|
||||||
private final String format;
|
|
||||||
|
|
||||||
private int integer;
|
private int integer;
|
||||||
|
|
||||||
private int decimal;
|
private int decimal;
|
||||||
|
|
||||||
|
private final String format;
|
||||||
|
|
||||||
public Format(final RealMatrix matrix) {
|
public Format(final RealMatrix matrix) {
|
||||||
for (int r = 0; r < matrix.getRowDimension(); r++) {
|
for (int r = 0; r < matrix.getRowDimension(); r++) {
|
||||||
for (int c = 0; c < matrix.getColumnDimension(); c++) {
|
for (int c = 0; c < matrix.getColumnDimension(); c++) {
|
||||||
|
|||||||
@ -14,121 +14,92 @@ import java.awt.geom.Point2D;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static de.ph87.electro.CONFIG.P50;
|
import static de.ph87.electro.CONFIG.*;
|
||||||
import static de.ph87.electro.CONFIG.PART_BACK_COLOR;
|
|
||||||
import static java.lang.Math.round;
|
import static java.lang.Math.round;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ToString(onlyExplicitlyIncluded = true)
|
@ToString(onlyExplicitlyIncluded = true)
|
||||||
public abstract class Part {
|
public abstract class Part {
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@ToString.Include
|
@ToString.Include
|
||||||
private final String uuid;
|
private final String uuid;
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final List<Node> nodes = new ArrayList<>();
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
protected Orientation orientation = Orientation.R0;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Setter
|
@Setter
|
||||||
@ToString.Include
|
@ToString.Include
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private Point position;
|
private Point position;
|
||||||
|
|
||||||
@NonNull
|
protected Orientation orientation = Orientation.R0;
|
||||||
private AffineTransform transform = new AffineTransform();
|
|
||||||
|
|
||||||
protected Part(@NonNull final String name, @NonNull final Point position) {
|
private final List<Node> nodes = new ArrayList<>();
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private AffineTransform transform;
|
||||||
|
|
||||||
|
protected Part(final String name, final Point position) {
|
||||||
this.uuid = UUID.randomUUID().toString();
|
this.uuid = UUID.randomUUID().toString();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.position = position;
|
this.position = position;
|
||||||
updateTransform();
|
this.transform = newTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Part(@NonNull final PartDto dto) {
|
protected Part(final PartDto dto) {
|
||||||
this.uuid = dto.getUuid();
|
this.uuid = dto.getUuid();
|
||||||
this.name = dto.getName();
|
this.name = dto.getName();
|
||||||
this.orientation = dto.getOrientation();
|
this.orientation = dto.getOrientation();
|
||||||
this.position = dto.getPosition();
|
this.position = dto.getPosition();
|
||||||
updateTransform();
|
this.transform = newTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
private AffineTransform newTransform() {
|
||||||
public static Part fromDto(@NonNull final PartDto abstractDto) {
|
final AffineTransform transform = new AffineTransform();
|
||||||
return switch (abstractDto) {
|
|
||||||
case final BatteryDto dto -> new Battery(dto);
|
|
||||||
case final LightDto dto -> new Light(dto);
|
|
||||||
case final ConnectorSubDto dto -> new ConnectorSub(dto);
|
|
||||||
case final Switch1x1Dto dto -> new Switch1x1(dto);
|
|
||||||
case final Switch1x2Dto dto -> new Switch1x2(dto);
|
|
||||||
case final SwitchCrossDto dto -> new SwitchCross(dto);
|
|
||||||
case final PotiDto dto -> new Poti(dto);
|
|
||||||
case final VoltmeterDto dto -> new Voltmeter(dto);
|
|
||||||
case null, default -> throw new RuntimeException();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public abstract Point getSize();
|
|
||||||
|
|
||||||
public void setPosition(@NonNull final Point position) {
|
|
||||||
this.position = position;
|
|
||||||
updateTransform();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void rotate() {
|
|
||||||
this.orientation = orientation.clockwise();
|
|
||||||
updateTransform();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private void updateTransform() {
|
|
||||||
transform = new AffineTransform();
|
|
||||||
transform.translate(position.x, position.y);
|
transform.translate(position.x, position.y);
|
||||||
transform.rotate(orientation.getRadians(), P50, P50);
|
transform.rotate(orientation.getRadians(), P50, P50);
|
||||||
nodes.forEach(Node::positionChanged);
|
return transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
public Point transform(final Point point) {
|
||||||
public Point transform(@NonNull final Point point) {
|
|
||||||
final Point2D result = transform.transform(point, new Point2D.Double());
|
final Point2D result = transform.transform(point, new Point2D.Double());
|
||||||
return new Point((int) round(result.getX()), (int) round(result.getY()));
|
return new Point((int) round(result.getX()), (int) round(result.getY()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
protected Node addNode(final String name, final int x, final int y) {
|
||||||
protected Node addNode(@NonNull final String name, final int x, final int y) {
|
|
||||||
return addNode(new Node(this, name, new Point(x, y)));
|
return addNode(new Node(this, name, new Point(x, y)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
protected Node addNode(final NodeDto dto, final int x, final int y) {
|
||||||
protected Node addNode(@NonNull final NodeDto dto, final int x, final int y) {
|
|
||||||
return addNode(new Node(this, dto, new Point(x, y)));
|
return addNode(new Node(this, dto, new Point(x, y)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
private Node addNode(final Node node) {
|
||||||
private Node addNode(@NonNull final Node node) {
|
|
||||||
nodes.add(node);
|
nodes.add(node);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void draw(@NonNull final Graphics2D g) {
|
public void setPosition(final Point position) {
|
||||||
|
this.position = position;
|
||||||
|
this.transform = newTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void rotate() {
|
||||||
|
this.orientation = orientation.clockwise();
|
||||||
|
this.transform = newTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void draw(final Graphics2D g) {
|
||||||
g.setColor(PART_BACK_COLOR);
|
g.setColor(PART_BACK_COLOR);
|
||||||
g.fillRect(0, 0, getSize().x, getSize().y);
|
g.fillRect(0, 0, RASTER, RASTER);
|
||||||
_render(g);
|
_render(g);
|
||||||
nodes.forEach(node -> node.draw(g));
|
nodes.forEach(node -> node.draw(g));
|
||||||
_labels(g);
|
_labels(g);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void _render(@NonNull final Graphics2D g) {
|
protected void _render(final Graphics2D g) {
|
||||||
// -
|
// -
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void _labels(@NonNull final Graphics2D g) {
|
protected void _labels(final Graphics2D g) {
|
||||||
// -
|
// -
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,24 +111,32 @@ public abstract class Part {
|
|||||||
// -
|
// -
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public List<InnerConnection> getInnerConnections() {
|
public List<InnerConnection> getInnerConnections() {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
public Optional<Node> findNodeByUuid(final String nodeUuid) {
|
||||||
public Optional<Node> findNodeByUuid(@NonNull final String nodeUuid) {
|
|
||||||
return nodes.stream().filter(node -> node.getUuid().equals(nodeUuid)).findFirst();
|
return nodes.stream().filter(node -> node.getUuid().equals(nodeUuid)).findFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
public Optional<Node> findNodeByPosition(final Point position) {
|
||||||
public Optional<Node> findNodeByPosition(@NonNull final Point position) {
|
|
||||||
return nodes.stream().filter(node -> node.intersects(position)).findFirst();
|
return nodes.stream().filter(node -> node.intersects(position)).findFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean intersects(@NonNull final Point point) {
|
public static Part fromDto(final PartDto abstractDto) {
|
||||||
return this.position.x <= point.x && point.x < this.position.x + this.getSize().x
|
return switch (abstractDto) {
|
||||||
&& this.position.y <= point.y && point.y < this.position.y + this.getSize().y;
|
case final BatteryDto dto -> new Battery(dto);
|
||||||
|
case final ConnectorCornerDto dto -> new ConnectorCorner(dto);
|
||||||
|
case final ConnectorEdgeDto dto -> new ConnectorEdge(dto);
|
||||||
|
case final ConnectorMiddleDto dto -> new ConnectorMiddle(dto);
|
||||||
|
case final LightDto dto -> new Light(dto);
|
||||||
|
case final Switch1x1Dto dto -> new Switch1x1(dto);
|
||||||
|
case final Switch1x2Dto dto -> new Switch1x2(dto);
|
||||||
|
case final SwitchCrossDto dto -> new SwitchCross(dto);
|
||||||
|
case final PotiDto dto -> new Poti(dto);
|
||||||
|
case final VoltmeterDto dto -> new Voltmeter(dto);
|
||||||
|
case null, default -> throw new RuntimeException();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,8 +32,10 @@ public abstract class PartDto {
|
|||||||
public static PartDto of(final Part abstractPart) {
|
public static PartDto of(final Part abstractPart) {
|
||||||
return switch (abstractPart) {
|
return switch (abstractPart) {
|
||||||
case final Battery part -> new BatteryDto(part);
|
case final Battery part -> new BatteryDto(part);
|
||||||
|
case final ConnectorCorner part -> new ConnectorCornerDto(part);
|
||||||
|
case final ConnectorEdge part -> new ConnectorEdgeDto(part);
|
||||||
|
case final ConnectorMiddle part -> new ConnectorMiddleDto(part);
|
||||||
case final Light part -> new LightDto(part);
|
case final Light part -> new LightDto(part);
|
||||||
case final ConnectorSub part -> new ConnectorSubDto(part);
|
|
||||||
case final Switch1x1 part -> new Switch1x1Dto(part);
|
case final Switch1x1 part -> new Switch1x1Dto(part);
|
||||||
case final Switch1x2 part -> new Switch1x2Dto(part);
|
case final Switch1x2 part -> new Switch1x2Dto(part);
|
||||||
case final SwitchCross part -> new SwitchCrossDto(part);
|
case final SwitchCross part -> new SwitchCrossDto(part);
|
||||||
|
|||||||
@ -3,7 +3,6 @@ package de.ph87.electro.circuit.part.node;
|
|||||||
import de.ph87.electro.circuit.part.Part;
|
import de.ph87.electro.circuit.part.Part;
|
||||||
import de.ph87.electro.circuit.wire.Wire;
|
import de.ph87.electro.circuit.wire.Wire;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
@ -18,67 +17,50 @@ import static de.ph87.electro.CONFIG.*;
|
|||||||
@ToString(onlyExplicitlyIncluded = true)
|
@ToString(onlyExplicitlyIncluded = true)
|
||||||
public class Node {
|
public class Node {
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@ToString.Include
|
@ToString.Include
|
||||||
private final String uuid;
|
private final String uuid;
|
||||||
|
|
||||||
@NonNull
|
private final Part owner;
|
||||||
|
|
||||||
@ToString.Include
|
@ToString.Include
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final Part part;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final Point inside;
|
private final Point inside;
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final Set<Wire> wires = new HashSet<>();
|
private final Set<Wire> wires = new HashSet<>();
|
||||||
|
|
||||||
@NonNull
|
|
||||||
protected Point position;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@ToString.Include
|
@ToString.Include
|
||||||
private double voltage = Double.NaN;
|
private double voltage = Double.NaN;
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private Color color = VOLTAGE_UNKNOWN_COLOR;
|
private Color color = VOLTAGE_UNKNOWN_COLOR;
|
||||||
|
|
||||||
public Node(@NonNull final Part part, @NonNull final String name, @NonNull final Point inside) {
|
|
||||||
this.part = part;
|
|
||||||
this.inside = inside;
|
|
||||||
this.uuid = UUID.randomUUID().toString();
|
|
||||||
this.name = name;
|
|
||||||
this.position = part.transform(inside);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Node(@NonNull final Part part, @NonNull final NodeDto dto, @NonNull final Point inside) {
|
|
||||||
this.uuid = dto.getUuid();
|
|
||||||
this.name = dto.getName();
|
|
||||||
this.part = part;
|
|
||||||
this.inside = inside;
|
|
||||||
this.position = part.transform(inside);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@ToString.Include
|
@ToString.Include
|
||||||
@SuppressWarnings("unused") // lombok toString
|
@SuppressWarnings("unused") // lombok toString
|
||||||
public List<String> destinations() {
|
public List<String> destinations() {
|
||||||
return wires.stream().map(wire -> wire.getOpposite(this)).map(Node::getUuid).toList();
|
return wires.stream().map(wire -> wire.getOpposite(this)).map(Node::getUuid).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Node(final Part owner, final String name, final Point inside) {
|
||||||
|
this.owner = owner;
|
||||||
|
this.uuid = UUID.randomUUID().toString();
|
||||||
|
this.name = name;
|
||||||
|
this.inside = inside;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node(final Part owner, final NodeDto dto, final Point inside) {
|
||||||
|
this.owner = owner;
|
||||||
|
this.uuid = dto.getUuid();
|
||||||
|
this.name = dto.getName();
|
||||||
|
this.inside = inside;
|
||||||
|
}
|
||||||
|
|
||||||
public void setVoltage(final double voltage) {
|
public void setVoltage(final double voltage) {
|
||||||
this.voltage = voltage;
|
this.voltage = voltage;
|
||||||
this.color = Double.isNaN(voltage) ? VOLTAGE_UNKNOWN_COLOR : ((voltage >= VOLTAGE_HIGH_MIN) ? VOLTAGE_HIGH_COLOR : VOLTAGE_LOW_COLOR);
|
this.color = Double.isNaN(voltage) ? VOLTAGE_UNKNOWN_COLOR : ((voltage >= VOLTAGE_HIGH_MIN) ? VOLTAGE_HIGH_COLOR : VOLTAGE_LOW_COLOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void positionChanged() {
|
public void draw(final Graphics2D g) {
|
||||||
position = part.transform(inside);
|
g.setColor(color);
|
||||||
}
|
|
||||||
|
|
||||||
public void draw(@NonNull final Graphics2D g) {
|
|
||||||
g.setColor(getColor());
|
|
||||||
g.fillArc(inside.x - NODE_RADIUS, inside.y - NODE_RADIUS, 2 * NODE_RADIUS, 2 * NODE_RADIUS, 0, 360);
|
g.fillArc(inside.x - NODE_RADIUS, inside.y - NODE_RADIUS, 2 * NODE_RADIUS, 2 * NODE_RADIUS, 0, 360);
|
||||||
|
|
||||||
g.setColor(Color.BLACK);
|
g.setColor(Color.BLACK);
|
||||||
@ -86,17 +68,21 @@ public class Node {
|
|||||||
g.drawArc(inside.x - NODE_RADIUS, inside.y - NODE_RADIUS, 2 * NODE_RADIUS, 2 * NODE_RADIUS, 0, 360);
|
g.drawArc(inside.x - NODE_RADIUS, inside.y - NODE_RADIUS, 2 * NODE_RADIUS, 2 * NODE_RADIUS, 0, 360);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean intersects(@NonNull final Point position) {
|
public boolean intersects(final Point position) {
|
||||||
return this.position.distance(position) <= NODE_RADIUS_HOVER;
|
return getAbsolute().distance(position) <= NODE_RADIUS_HOVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void collectConnectedNodes(@NonNull final Set<Node> connected) {
|
public void collectConnectedNodes(final Set<Node> connected) {
|
||||||
if (connected.contains(this)) {
|
if (connected.contains(this)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
connected.add(this);
|
connected.add(this);
|
||||||
wires.forEach(wire -> wire.getOpposite(this).collectConnectedNodes(connected));
|
wires.forEach(wire -> wire.getOpposite(this).collectConnectedNodes(connected));
|
||||||
part.getInnerConnections().stream().flatMap(innerConnection -> innerConnection.filter(this)).forEach(opposite -> opposite.collectConnectedNodes(connected));
|
owner.getInnerConnections().stream().flatMap(innerConnection -> innerConnection.filter(this)).forEach(opposite -> opposite.collectConnectedNodes(connected));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point getAbsolute() {
|
||||||
|
return owner.transform(inside);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,8 +29,6 @@ public class Battery extends Part {
|
|||||||
|
|
||||||
private static final int PLUS_H = (int) round(0.6 * RASTER);
|
private static final int PLUS_H = (int) round(0.6 * RASTER);
|
||||||
|
|
||||||
private final Point size = new Point(RASTER, RASTER);
|
|
||||||
|
|
||||||
private final Node minus;
|
private final Node minus;
|
||||||
|
|
||||||
private final Node plus;
|
private final Node plus;
|
||||||
|
|||||||
@ -0,0 +1,33 @@
|
|||||||
|
package de.ph87.electro.circuit.part.parts;
|
||||||
|
|
||||||
|
import de.ph87.electro.circuit.part.Part;
|
||||||
|
import de.ph87.electro.circuit.part.node.Node;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
import static de.ph87.electro.CONFIG.P10;
|
||||||
|
import static de.ph87.electro.CONFIG.P90;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class ConnectorCorner extends Part {
|
||||||
|
|
||||||
|
private final Node j0;
|
||||||
|
|
||||||
|
private final Node j1;
|
||||||
|
|
||||||
|
public ConnectorCorner(final Point position) {
|
||||||
|
super("", position);
|
||||||
|
j0 = addNode("J0", P10, P10);
|
||||||
|
j1 = addNode("J1", P90, P90);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConnectorCorner(final ConnectorCornerDto dto) {
|
||||||
|
super(dto);
|
||||||
|
j0 = addNode(dto.getJ0(), P10, P10);
|
||||||
|
j1 = addNode(dto.getJ1(), P90, P90);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
package de.ph87.electro.circuit.part.parts;
|
||||||
|
|
||||||
|
import de.ph87.electro.circuit.part.PartDto;
|
||||||
|
import de.ph87.electro.circuit.part.node.NodeDto;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class ConnectorCornerDto extends PartDto {
|
||||||
|
|
||||||
|
private NodeDto j0;
|
||||||
|
|
||||||
|
private NodeDto j1;
|
||||||
|
|
||||||
|
public ConnectorCornerDto(final ConnectorCorner part) {
|
||||||
|
j0 = new NodeDto(part.getJ0());
|
||||||
|
j1 = new NodeDto(part.getJ1());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
package de.ph87.electro.circuit.part.parts;
|
||||||
|
|
||||||
|
import de.ph87.electro.circuit.part.Part;
|
||||||
|
import de.ph87.electro.circuit.part.node.Node;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
import static de.ph87.electro.CONFIG.P10;
|
||||||
|
import static de.ph87.electro.CONFIG.P50;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class ConnectorEdge extends Part {
|
||||||
|
|
||||||
|
private final Node j0;
|
||||||
|
|
||||||
|
private final Node j1;
|
||||||
|
|
||||||
|
public ConnectorEdge(final Point position) {
|
||||||
|
super("", position);
|
||||||
|
j0 = addNode("J0", P10, P50);
|
||||||
|
j1 = addNode("J1", P50, P10);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConnectorEdge(final ConnectorEdgeDto dto) {
|
||||||
|
super(dto);
|
||||||
|
j0 = addNode(dto.getJ0(), P10, P50);
|
||||||
|
j1 = addNode(dto.getJ1(), P50, P10);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
package de.ph87.electro.circuit.part.parts;
|
||||||
|
|
||||||
|
import de.ph87.electro.circuit.part.PartDto;
|
||||||
|
import de.ph87.electro.circuit.part.node.NodeDto;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class ConnectorEdgeDto extends PartDto {
|
||||||
|
|
||||||
|
private NodeDto j0;
|
||||||
|
|
||||||
|
private NodeDto j1;
|
||||||
|
|
||||||
|
public ConnectorEdgeDto(final ConnectorEdge part) {
|
||||||
|
j0 = new NodeDto(part.getJ0());
|
||||||
|
j1 = new NodeDto(part.getJ1());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package de.ph87.electro.circuit.part.parts;
|
||||||
|
|
||||||
|
import de.ph87.electro.circuit.part.Part;
|
||||||
|
import de.ph87.electro.circuit.part.node.Node;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
import static de.ph87.electro.CONFIG.P50;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class ConnectorMiddle extends Part {
|
||||||
|
|
||||||
|
private final Node node;
|
||||||
|
|
||||||
|
public ConnectorMiddle(final Point position) {
|
||||||
|
super("", position);
|
||||||
|
node = addNode("J", P50, P50);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConnectorMiddle(final ConnectorMiddleDto dto) {
|
||||||
|
super(dto);
|
||||||
|
node = addNode(dto.getNode(), P50, P50);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -9,11 +9,11 @@ import lombok.ToString;
|
|||||||
@Getter
|
@Getter
|
||||||
@ToString
|
@ToString
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public class ConnectorSubDto extends PartDto {
|
public class ConnectorMiddleDto extends PartDto {
|
||||||
|
|
||||||
private NodeDto node;
|
private NodeDto node;
|
||||||
|
|
||||||
public ConnectorSubDto(final ConnectorSub part) {
|
public ConnectorMiddleDto(final ConnectorMiddle part) {
|
||||||
node = new NodeDto(part.getNode());
|
node = new NodeDto(part.getNode());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
package de.ph87.electro.circuit.part.parts;
|
|
||||||
|
|
||||||
import de.ph87.electro.circuit.part.Part;
|
|
||||||
import de.ph87.electro.circuit.part.node.Node;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.ToString;
|
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
|
|
||||||
import static de.ph87.electro.CONFIG.SUB_RASTER;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@ToString(callSuper = true)
|
|
||||||
public class ConnectorSub extends Part {
|
|
||||||
|
|
||||||
private final Node node;
|
|
||||||
|
|
||||||
private final Point size = new Point(SUB_RASTER, SUB_RASTER);
|
|
||||||
|
|
||||||
public ConnectorSub(final Point position) {
|
|
||||||
super("", position);
|
|
||||||
node = addNode("", SUB_RASTER / 2, SUB_RASTER / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConnectorSub(final ConnectorSubDto dto) {
|
|
||||||
super(dto);
|
|
||||||
node = addNode(dto.getNode(), SUB_RASTER / 2, SUB_RASTER / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -20,12 +20,22 @@ import static java.lang.Math.round;
|
|||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
public class Light extends Part {
|
public class Light extends Part {
|
||||||
|
|
||||||
|
private static final Color COLOR_DEFECT = new Color(255, 0, 234);
|
||||||
|
|
||||||
|
private static final int MINUS_W = (int) round(0.1 * RASTER);
|
||||||
|
|
||||||
|
private static final int MINUS_H = (int) round(0.3 * RASTER);
|
||||||
|
|
||||||
|
private static final int GAP = (int) round(0.05 * RASTER);
|
||||||
|
|
||||||
|
private static final int PLUS_W = (int) round(0.02 * RASTER);
|
||||||
|
|
||||||
|
private static final int PLUS_H = (int) round(0.6 * RASTER);
|
||||||
|
|
||||||
private static final int BULB_RADIUS = (int) round(0.25 * RASTER);
|
private static final int BULB_RADIUS = (int) round(0.25 * RASTER);
|
||||||
|
|
||||||
private static final Color BULB_OFF_COLOR = Color.DARK_GRAY;
|
private static final Color BULB_OFF_COLOR = Color.DARK_GRAY;
|
||||||
|
|
||||||
private final Point size = new Point(RASTER, RASTER);
|
|
||||||
|
|
||||||
private final Node a;
|
private final Node a;
|
||||||
|
|
||||||
private final Node b;
|
private final Node b;
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import de.ph87.electro.circuit.part.InnerConnection;
|
|||||||
import de.ph87.electro.circuit.part.Part;
|
import de.ph87.electro.circuit.part.Part;
|
||||||
import de.ph87.electro.circuit.part.node.Node;
|
import de.ph87.electro.circuit.part.node.Node;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
@ -19,30 +18,25 @@ import static java.lang.Math.max;
|
|||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
public class Poti extends Part {
|
public class Poti extends Part {
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final Node common;
|
private final Node common;
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final Node middle;
|
private final Node middle;
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final Node end;
|
private final Node end;
|
||||||
|
|
||||||
private final Point size = new Point(RASTER, RASTER);
|
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private double resistance = 10;
|
private double resistance = 10;
|
||||||
|
|
||||||
private double ratio = 0.0;
|
private double ratio = 0.0;
|
||||||
|
|
||||||
public Poti(@NonNull final Point position) {
|
public Poti(final Point position) {
|
||||||
super("Poti", position);
|
super("Poti", position);
|
||||||
common = addNode("C", P10, P50);
|
common = addNode("C", P10, P50);
|
||||||
middle = addNode("M", P50, P10);
|
middle = addNode("M", P50, P10);
|
||||||
end = addNode("E", P90, P50);
|
end = addNode("E", P90, P50);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Poti(@NonNull final PotiDto dto) {
|
public Poti(final PotiDto dto) {
|
||||||
super(dto);
|
super(dto);
|
||||||
common = addNode(dto.getCommon().getName(), P10, P50);
|
common = addNode(dto.getCommon().getName(), P10, P50);
|
||||||
middle = addNode(dto.getMiddle().getName(), P50, P10);
|
middle = addNode(dto.getMiddle().getName(), P50, P10);
|
||||||
@ -59,7 +53,7 @@ public class Poti extends Part {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void _labels(@NonNull final Graphics2D g) {
|
protected void _labels(final Graphics2D g) {
|
||||||
drawText(g, LABEL_FONT, "%3.0f%%".formatted(ratio * 100), P50, P50, Color.BLACK, orientation);
|
drawText(g, LABEL_FONT, "%3.0f%%".formatted(ratio * 100), P50, P50, Color.BLACK, orientation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
package de.ph87.electro.common;
|
package de.ph87.electro.circuit.part.parts;
|
||||||
|
|
||||||
import org.apache.commons.math3.linear.Array2DRowRealMatrix;
|
import org.apache.commons.math3.linear.Array2DRowRealMatrix;
|
||||||
import org.apache.commons.math3.linear.RealMatrix;
|
import org.apache.commons.math3.linear.RealMatrix;
|
||||||
@ -18,8 +18,6 @@ public class Switch1x1 extends Part {
|
|||||||
|
|
||||||
private static final Point END = new Point(P90, P25);
|
private static final Point END = new Point(P90, P25);
|
||||||
|
|
||||||
private final Point size = new Point(RASTER, RASTER);
|
|
||||||
|
|
||||||
private final Node common;
|
private final Node common;
|
||||||
|
|
||||||
private final Node output;
|
private final Node output;
|
||||||
@ -51,7 +49,8 @@ public class Switch1x1 extends Part {
|
|||||||
@Override
|
@Override
|
||||||
protected void _render(final Graphics2D g) {
|
protected void _render(final Graphics2D g) {
|
||||||
if (!state) {
|
if (!state) {
|
||||||
drawLine(g, common, END, common.getColor(), SWITCH_STROKE);
|
final Point end = getOrientation().rotate(END);
|
||||||
|
drawLine(g, common.getAbsolute(), end, common.getColor(), SWITCH_STROKE);
|
||||||
} else {
|
} else {
|
||||||
drawLine(g, common, output, common.getColor(), SWITCH_STROKE);
|
drawLine(g, common, output, common.getColor(), SWITCH_STROKE);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,8 +16,6 @@ import static de.ph87.electro.circuit.CircuitPainter.drawLine;
|
|||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
public class Switch1x2 extends Part {
|
public class Switch1x2 extends Part {
|
||||||
|
|
||||||
private final Point size = new Point(RASTER, RASTER);
|
|
||||||
|
|
||||||
private final Node common;
|
private final Node common;
|
||||||
|
|
||||||
private final Node output0;
|
private final Node output0;
|
||||||
|
|||||||
@ -16,8 +16,6 @@ import static de.ph87.electro.circuit.CircuitPainter.drawLine;
|
|||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
public class SwitchCross extends Part {
|
public class SwitchCross extends Part {
|
||||||
|
|
||||||
private final Point size = new Point(RASTER, RASTER);
|
|
||||||
|
|
||||||
private final Node common0;
|
private final Node common0;
|
||||||
|
|
||||||
private final Node common1;
|
private final Node common1;
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import de.ph87.electro.circuit.part.InnerConnection;
|
|||||||
import de.ph87.electro.circuit.part.Part;
|
import de.ph87.electro.circuit.part.Part;
|
||||||
import de.ph87.electro.circuit.part.PartDto;
|
import de.ph87.electro.circuit.part.PartDto;
|
||||||
import de.ph87.electro.circuit.part.node.Node;
|
import de.ph87.electro.circuit.part.node.Node;
|
||||||
import de.ph87.electro.common.RotationMatrix;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.apache.commons.math3.linear.ArrayRealVector;
|
import org.apache.commons.math3.linear.ArrayRealVector;
|
||||||
@ -30,14 +29,10 @@ public class Voltmeter extends Part {
|
|||||||
|
|
||||||
private static final double DEGREES_RANGE = 90;
|
private static final double DEGREES_RANGE = 90;
|
||||||
|
|
||||||
private final Point size = new Point(RASTER, RASTER);
|
|
||||||
|
|
||||||
private final Node a;
|
private final Node a;
|
||||||
|
|
||||||
private final Node b;
|
private final Node b;
|
||||||
|
|
||||||
double x = 0;
|
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private double min = -3;
|
private double min = -3;
|
||||||
|
|
||||||
@ -60,9 +55,7 @@ public class Voltmeter extends Part {
|
|||||||
postCalculate(); // TODO remove
|
postCalculate(); // TODO remove
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Point P(final RealVector anchor) {
|
double x = 0;
|
||||||
return new Point((int) round(anchor.getEntry(0)), (int) round(anchor.getEntry(1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void _render(final Graphics2D g) {
|
public void _render(final Graphics2D g) {
|
||||||
@ -81,6 +74,10 @@ public class Voltmeter extends Part {
|
|||||||
drawCircle(g, P(ANCHOR), P03, 0, 360, null, null, Color.black);
|
drawCircle(g, P(ANCHOR), P03, 0, 360, null, null, Color.black);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Point P(final RealVector anchor) {
|
||||||
|
return new Point((int) round(anchor.getEntry(0)), (int) round(anchor.getEntry(1)));
|
||||||
|
}
|
||||||
|
|
||||||
private double getVoltage() {
|
private double getVoltage() {
|
||||||
return !Double.isNaN(b.getVoltage()) && !Double.isNaN(a.getVoltage()) ? b.getVoltage() - a.getVoltage() : 0.0;
|
return !Double.isNaN(b.getVoltage()) && !Double.isNaN(a.getVoltage()) ? b.getVoltage() - a.getVoltage() : 0.0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,22 +12,20 @@ import java.awt.geom.Rectangle2D;
|
|||||||
import static de.ph87.electro.CONFIG.*;
|
import static de.ph87.electro.CONFIG.*;
|
||||||
import static java.lang.Math.*;
|
import static java.lang.Math.*;
|
||||||
|
|
||||||
@Getter
|
|
||||||
@ToString
|
@ToString
|
||||||
public class Wire {
|
public class Wire {
|
||||||
|
|
||||||
|
@Getter
|
||||||
@NonNull
|
@NonNull
|
||||||
private final Node a;
|
private final Node a;
|
||||||
|
|
||||||
|
@Getter
|
||||||
@NonNull
|
@NonNull
|
||||||
private final Node b;
|
private final Node b;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private double current = Double.NaN;
|
private double current = Double.NaN;
|
||||||
|
|
||||||
@Setter
|
|
||||||
private boolean ghost = false;
|
|
||||||
|
|
||||||
public Wire(@NonNull final Node a, @NonNull final Node b) {
|
public Wire(@NonNull final Node a, @NonNull final Node b) {
|
||||||
this.a = a;
|
this.a = a;
|
||||||
this.b = b;
|
this.b = b;
|
||||||
@ -36,7 +34,7 @@ public class Wire {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean intersects(final Point position) {
|
public boolean intersects(final Point position) {
|
||||||
return distanceToLine(position, a.getPosition(), b.getPosition());
|
return distanceToLine(position, a.getAbsolute(), b.getAbsolute());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean distanceToLine(final Point point, final Point lineStart, final Point lineEnd) {
|
public boolean distanceToLine(final Point point, final Point lineStart, final Point lineEnd) {
|
||||||
@ -70,11 +68,9 @@ public class Wire {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void draw(final Graphics2D g) {
|
public void draw(final Graphics2D g) {
|
||||||
final Color color = ghost ? new Color(a.getColor().getRed(), a.getColor().getGreen(), a.getColor().getBlue(), 64) : a.getColor();
|
g.setColor(a.getColor());
|
||||||
|
|
||||||
g.setColor(color);
|
|
||||||
g.setStroke(WIRE_STROKE);
|
g.setStroke(WIRE_STROKE);
|
||||||
g.drawLine(a.getPosition().x, a.getPosition().y, b.getPosition().x, b.getPosition().y);
|
g.drawLine(a.getAbsolute().x, a.getAbsolute().y, b.getAbsolute().x, b.getAbsolute().y);
|
||||||
|
|
||||||
if (SHOW_WIRE_DETAILS) {
|
if (SHOW_WIRE_DETAILS) {
|
||||||
drawValues(g, "%.2f A".formatted(abs(current)), -0.5);
|
drawValues(g, "%.2f A".formatted(abs(current)), -0.5);
|
||||||
@ -85,8 +81,8 @@ public class Wire {
|
|||||||
private void drawValues(final Graphics2D g, final String string, final double offset) {
|
private void drawValues(final Graphics2D g, final String string, final double offset) {
|
||||||
g.setFont(LABEL_FONT);
|
g.setFont(LABEL_FONT);
|
||||||
final Rectangle2D bounds = g.getFontMetrics().getStringBounds(string, g);
|
final Rectangle2D bounds = g.getFontMetrics().getStringBounds(string, g);
|
||||||
final Point aa = a.getPosition();
|
final Point aa = a.getAbsolute();
|
||||||
final Point bb = b.getPosition();
|
final Point bb = b.getAbsolute();
|
||||||
|
|
||||||
final int mx = (aa.x + bb.x) / 2;
|
final int mx = (aa.x + bb.x) / 2;
|
||||||
final int my = (aa.y + bb.y) / 2;
|
final int my = (aa.y + bb.y) / 2;
|
||||||
|
|||||||
@ -23,6 +23,9 @@ public class Sidebar extends JPanel {
|
|||||||
|
|
||||||
final Point ZERO = new Point();
|
final Point ZERO = new Point();
|
||||||
addPart(new Battery(ZERO));
|
addPart(new Battery(ZERO));
|
||||||
|
addPart(new ConnectorCorner(ZERO));
|
||||||
|
addPart(new ConnectorEdge(ZERO));
|
||||||
|
addPart(new ConnectorMiddle(ZERO));
|
||||||
addPart(new Light(ZERO));
|
addPart(new Light(ZERO));
|
||||||
addPart(new Switch1x1(ZERO));
|
addPart(new Switch1x1(ZERO));
|
||||||
addPart(new Switch1x2(ZERO));
|
addPart(new Switch1x2(ZERO));
|
||||||
|
|||||||
@ -30,8 +30,7 @@ class CalculationServiceTest {
|
|||||||
log.info(" \"%s\" = %.2f V".formatted(node.getName(), node.getVoltage()));
|
log.info(" \"%s\" = %.2f V".formatted(node.getName(), node.getVoltage()));
|
||||||
for (final Wire wire : node.getWires()) {
|
for (final Wire wire : node.getWires()) {
|
||||||
final Node opposite = wire.getOpposite(node);
|
final Node opposite = wire.getOpposite(node);
|
||||||
final String partName = opposite instanceof final Node partNode ? partNode.getPart().getName() : "";
|
log.info(" -> %s.%s = %.2f A".formatted(opposite.getOwner().getName(), opposite.getName(), wire.getCurrent(node)));
|
||||||
log.info(" -> %s.%s = %.2f A".formatted(partName, opposite.getName(), wire.getCurrent(node)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -2,8 +2,8 @@ package de.ph87.electro.circuit.io;
|
|||||||
|
|
||||||
import de.ph87.electro.circuit.Circuit;
|
import de.ph87.electro.circuit.Circuit;
|
||||||
import de.ph87.electro.circuit.CircuitIOService;
|
import de.ph87.electro.circuit.CircuitIOService;
|
||||||
import de.ph87.electro.circuit.part.node.Node;
|
|
||||||
import de.ph87.electro.circuit.part.Part;
|
import de.ph87.electro.circuit.part.Part;
|
||||||
|
import de.ph87.electro.circuit.part.node.Node;
|
||||||
import de.ph87.electro.circuit.part.parts.Battery;
|
import de.ph87.electro.circuit.part.parts.Battery;
|
||||||
import de.ph87.electro.circuit.part.parts.Light;
|
import de.ph87.electro.circuit.part.parts.Light;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -16,7 +16,6 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import static de.ph87.electro.CONFIG.RASTER;
|
import static de.ph87.electro.CONFIG.RASTER;
|
||||||
import static de.ph87.electro.circuit.CircuitIOService.serialize;
|
import static de.ph87.electro.circuit.CircuitIOService.serialize;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
|
||||||
|
|
||||||
class CircuitIOServiceTest {
|
class CircuitIOServiceTest {
|
||||||
|
|
||||||
@ -57,7 +56,7 @@ class CircuitIOServiceTest {
|
|||||||
final Node reloadedNode = reloadedPart.getNodes().stream().filter(node -> node.getUuid().equals(originalNode.getUuid())).findFirst().orElseThrow();
|
final Node reloadedNode = reloadedPart.getNodes().stream().filter(node -> node.getUuid().equals(originalNode.getUuid())).findFirst().orElseThrow();
|
||||||
assertEquals(originalNode.getUuid(), reloadedNode.getUuid());
|
assertEquals(originalNode.getUuid(), reloadedNode.getUuid());
|
||||||
assertEquals(originalNode.getName(), reloadedNode.getName());
|
assertEquals(originalNode.getName(), reloadedNode.getName());
|
||||||
assertEquals(originalNode.getPosition(), reloadedNode.getPosition());
|
assertEquals(originalNode.getAbsolute(), reloadedNode.getAbsolute());
|
||||||
assertEquals(originalNode.getWires().size(), reloadedNode.getWires().size());
|
assertEquals(originalNode.getWires().size(), reloadedNode.getWires().size());
|
||||||
originalNode.getWires().stream()
|
originalNode.getWires().stream()
|
||||||
.map(originalWire -> originalWire.getOpposite(originalNode))
|
.map(originalWire -> originalWire.getOpposite(originalNode))
|
||||||
@ -65,9 +64,7 @@ class CircuitIOServiceTest {
|
|||||||
System.out.printf(" - Destinations: %s\n", originalDestination.getUuid());
|
System.out.printf(" - Destinations: %s\n", originalDestination.getUuid());
|
||||||
final Node reloadedDestination = reloadedNode.getWires().stream().map(wire -> wire.getOpposite(reloadedNode)).filter(destination -> destination.getUuid().equals(originalDestination.getUuid())).findFirst().orElseThrow();
|
final Node reloadedDestination = reloadedNode.getWires().stream().map(wire -> wire.getOpposite(reloadedNode)).filter(destination -> destination.getUuid().equals(originalDestination.getUuid())).findFirst().orElseThrow();
|
||||||
assertEquals(originalDestination.getUuid(), reloadedDestination.getUuid());
|
assertEquals(originalDestination.getUuid(), reloadedDestination.getUuid());
|
||||||
assertInstanceOf(Node.class, originalDestination);
|
assertEquals(originalDestination.getOwner().getUuid(), reloadedDestination.getOwner().getUuid());
|
||||||
assertInstanceOf(Node.class, reloadedDestination);
|
|
||||||
assertEquals(originalDestination.getPart().getUuid(), reloadedDestination.getPart().getUuid());
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user