Compare commits

..

20 Commits

Author SHA1 Message Date
Bane Stojkovic af83a69ee0 initial 2025-05-17 21:29:52 +02:00
Bane Stojkovic b757952533 If the internet connection is present, but unstable, the application starts but nothing can be clicked until the connection restores 2025-05-17 21:28:26 +02:00
Bane Stojkovic fe0dadd64b Increased tolerance of sticky points on guitar pickup terminals in order to make it easier for leads to make proper contact and for the circuit analyzer to work 2025-05-16 12:10:35 +02:00
Bane Stojkovic f1d886865d release 2025-05-13 10:15:06 +02:00
Bane Stojkovic 17c8840dfc Merge pull request #925 from bancika/ai-analyzer
Ai analyzer
2025-05-13 10:03:56 +02:00
Bane Stojkovic d9384d8304 release 2025-05-13 10:02:40 +02:00
Bane Stojkovic a69584411e Fixed the issue with embedding image files into DIY projects 2025-05-09 19:53:28 +02:00
Bane Stojkovic e4f7fb40d7 rendering performance optimization 2025-05-08 22:55:52 +02:00
Bane Stojkovic b2dcf354e6 add icon 2025-05-08 22:20:26 +02:00
Bane Stojkovic a6a9cd1bdf Fixed the issue with some components (e.g. DIP IC) jumping when showing underside of a board 2025-05-03 23:13:02 +02:00
Bane Stojkovic a21ef1962c Update update.xml 2025-05-03 22:08:07 +02:00
Bane Stojkovic c90b722fb6 optimize rendering of guitar switches 2025-05-03 22:05:23 +02:00
Bane Stojkovic 3332b727e0 optimize guitar pickup rendering 2025-05-03 21:56:38 +02:00
Bane Stojkovic 24ee6b3a5f optimize drawing of semiconductors 2025-05-03 21:49:01 +02:00
Bane Stojkovic aa98f27de8 Optimize rendering of electro-mechanical components 2025-05-03 21:35:11 +02:00
Bane Stojkovic b4bcc25f66 'Open Jack 1/4"' and 'Potentiometer Panel' now tolerate connections anywhere on the lugs instead of dead center only 2025-04-30 22:34:23 +02:00
Bane Stojkovic 355c9f2b49 netlist fixes 2025-04-25 22:50:07 +02:00
Bane Stojkovic 5c09ebf7f8 knowledge 2025-04-25 22:11:11 +02:00
Bane Stojkovic f7cd33c80f analyzer added 2025-04-24 21:38:04 +02:00
Bane Stojkovic c914749413 Ai improvements 1 (#914)
* improve netlist

* structure improvement

* chatbot enhancements

* chatbot improvements

* charbot enhancements

* Update user_manual.sql

* chatbot enhancements

* release
2025-04-21 20:46:41 +02:00
73 changed files with 1252 additions and 510 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
<configuration default="false" name="DIYLCStarter" type="Application" factoryName="Application" nameIsGenerated="true">
<option name="MAIN_CLASS_NAME" value="org.diylc.DIYLCStarter" />
<module name="diylc-swing" />
<option name="VM_PARAMETERS" value="-Xms1024m -Xmx4096m -Dorg.diylc.scriptRun=true -Dfile.encoding=UTF-8 --add-exports java.desktop/com.apple.eawt.event=ALL-UNNAMED --add-exports java.desktop/com.apple.eio=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.text=ALL-UNNAMED --add-opens java.desktop/java.awt=ALL-UNNAMED --add-opens java.desktop/java.awt.font=ALL-UNNAMED --add-opens java.desktop/java.awt.geom=ALL-UNNAMED" />
<option name="VM_PARAMETERS" value="-Xms1024m -Xmx4096m -Ddorg.diylc.debugAreaPerformance=true -Dorg.diylc.scriptRun=true -Dfile.encoding=UTF-8 --add-exports java.desktop/com.apple.eawt.event=ALL-UNNAMED --add-exports java.desktop/com.apple.eio=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.text=ALL-UNNAMED --add-opens java.desktop/java.awt=ALL-UNNAMED --add-opens java.desktop/java.awt.font=ALL-UNNAMED --add-opens java.desktop/java.awt.geom=ALL-UNNAMED" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="org.diylc.*" />
+1 -1
View File
@@ -7,7 +7,7 @@
<parent>
<groupId>org.diylc</groupId>
<artifactId>diylc-parent</artifactId>
<version>5.3.0</version>
<version>5.4.0</version>
</parent>
<artifactId>diylc-core</artifactId>
@@ -189,7 +189,7 @@ public abstract class AbstractComponent<T> implements IDIYComponent<T> {
// Deep copy point arrays.
// TODO: something nicer
if (value != null && value.getClass().isArray()
&& value.getClass().getComponentType().isAssignableFrom(Point2D.class)) {
&& Point2D.class.isAssignableFrom(value.getClass().getComponentType())) {
Object newArray = Array.newInstance(value.getClass().getComponentType(), Array.getLength(value));
for (int i = 0; i < Array.getLength(value); i++) {
Point2D p = (Point2D) Array.get(value, i);
@@ -92,7 +92,7 @@ public abstract class AbstractNetlistAnalyzer {
for (int i = 0; i < c.getControlPointCount(); i++) {
if (i != n.getPointIndex() && c.getInternalLinkName(i, n.getPointIndex()) != null) {
TreeLeaf l = new TreeLeaf(c, i, n.getPointIndex());
Node newNodeA = new Node(c, i, n.getZIndex());
Node newNodeA = new Node(c, i);
if (!visited.contains(newNodeA)) {
// visited.add(n);
Tree newCurrentPath = null;
@@ -53,11 +53,7 @@ public class Group implements Comparable<Group> {
}
public Group connect(IDIYComponent<?> component, int index) {
return connect(component, index, 0);
}
public Group connect(IDIYComponent<?> component, int index, int zOrder) {
getNodes().add(new Node(component, index, zOrder));
getNodes().add(new Node(component, index));
return this;
}
@@ -92,7 +92,7 @@ public abstract class NetlistAnalyzer {
continue;
if (c.getInternalLinkName(targetPoint, sourcePoint) != null) {
Node newNodeA = new Node(c, targetPoint, n.getZIndex());
Node newNodeA = new Node(c, targetPoint);
if (pathVisited.contains(newNodeA))
continue;
@@ -46,7 +46,7 @@ public class NetlistBuilder {
public static final float eps = 4; // consider any nodes closer than this as connected
public static int MAX_SWITCH_COMBINATIONS = 64;
public static int MAX_SWITCH_COMBINATIONS = 256;
private static final String MAX_SWITCH_COMBINATIONS_ERROR = LangUtil
.translate("Maximum number of switching combinations exceeded. Allowed: %s, actual: %s");
@@ -75,7 +75,7 @@ public class NetlistBuilder {
String nodeName = c.getControlPointNodeName(i);
if (c.isControlPointSticky(i) && nodeName != null
&& (!includeSwitches || !ISwitch.class.isAssignableFrom(type.getInstanceClass()))) {
nodes.add(new Node(c, i, j));
nodes.add(new Node(c, i));
}
}
}
@@ -86,7 +86,7 @@ public class NetlistBuilder {
String label = ((ICommonNode) c).getCommonNodeLabel();
if (!commonNodes.contains(label)) {
commonNodes.add(label);
nodes.add(new Node(c, 0, j));
nodes.add(new Node(c, 0));
}
}
@@ -22,6 +22,7 @@
package org.diylc.netlist;
import java.awt.geom.Point2D;
import java.util.Objects;
import org.diylc.core.ICommonNode;
import org.diylc.core.IDIYComponent;
@@ -35,13 +36,11 @@ public class Node implements Comparable<Node> {
private IDIYComponent<?> component;
private int pointIndex;
private int zIndex;
public Node(IDIYComponent<?> component, int pointIndex, int zIndex) {
public Node(IDIYComponent<?> component, int pointIndex) {
super();
this.component = component;
this.pointIndex = pointIndex;
this.zIndex = zIndex;
}
public IDIYComponent<?> getComponent() {
@@ -52,10 +51,6 @@ public class Node implements Comparable<Node> {
return pointIndex;
}
public int getZIndex() {
return zIndex;
}
public String getDisplayName() {
String[] section = component.getSectionNames(pointIndex);
return (section == null || section.length > 1 ? "" : section[0] + ".") + component.getControlPointNodeName(pointIndex);
@@ -66,31 +61,16 @@ public class Node implements Comparable<Node> {
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((component == null) ? 0 : component.hashCode());
result = prime * result + pointIndex;
return result;
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof Node)) return false;
Node other = (Node) obj;
return Objects.equals(component, other.component) && pointIndex == other.pointIndex;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Node other = (Node) obj;
if (component == null) {
if (other.component != null)
return false;
} else if (!component.equals(other.component))
return false;
if (pointIndex != other.pointIndex)
return false;
return true;
public int hashCode() {
return Objects.hash(component, pointIndex);
}
@Override
@@ -59,7 +59,7 @@ public class SpiceSumarizer {
if (c instanceof ISpiceMapper)
pointIndex = ((ISpiceMapper)c).mapToSpiceNode(pointIndex);
int nodeIndex = find(new Node(c, pointIndex, 0), groups);
int nodeIndex = find(new Node(c, pointIndex), groups);
if (nodeIndex < 0)
nodeIndex = unconnectedIndex++;
@@ -43,6 +43,20 @@ public interface IChatbotAPI {
@ParamName("machineId") String machineId, @ParamName("project") String project,
@ParamName("netlist") File netlist, @ParamName("prompt") String prompt);
/**
* Analyzes the provided circuit
*
* @param username
* @param token
* @param machineId
* @param project
* @param netlist
* @return
*/
String analyzeCircuit(@ParamName("username") String username, @ParamName("token") String token,
@ParamName("machineId") String machineId, @ParamName("project") String project,
@ParamName("netlist") File netlist);
SubscriptionEntity getSubscriptionInfo(@ParamName("username") String username, @ParamName("token") String token,
@ParamName("machineId") String machineId);
@@ -5,6 +5,7 @@ import java.awt.geom.Point2D;
import java.util.*;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.apache.log4j.Logger;
@@ -13,6 +14,10 @@ import org.diylc.common.PropertyWrapper;
import org.diylc.core.IDIYComponent;
import org.diylc.core.ISwitch;
import org.diylc.core.Project;
import org.diylc.netlist.Netlist;
import org.diylc.netlist.NetlistBuilder;
import org.diylc.netlist.NetlistException;
import org.diylc.netlist.Node;
import org.diylc.plugins.chatbot.model.*;
import org.diylc.presenter.ComponentProcessor;
import org.diylc.presenter.ContinuityArea;
@@ -26,15 +31,31 @@ public class AiProjectBuilder {
List<AiComponent> components = project.getComponents().stream().map(AiProjectBuilder::mapComponent).toList();
List<Set<NetlistBuilder.TerminalRef>> sets =
NetlistBuilder.buildNets(project.getComponents(), continuityAreas);
// List<Set<Node>> sets =
List<Netlist> netlists = null;
try {
netlists = NetlistBuilder.extractNetlists(false, project, continuityAreas);
} catch (NetlistException e) {
throw new RuntimeException(e);
}
Map<String, Set<String>> nets;
if (netlists == null || netlists.isEmpty()) {
nets = new HashMap<>();
} else {
AtomicInteger counter = new AtomicInteger();
nets = netlists.get(0).getGroups().stream().map(s -> s.getNodes().stream()
.map(AiProjectBuilder::mapTerminal)
.collect(Collectors.toSet()))
.collect(Collectors.toMap(x -> "N" + String.format("%03d", counter.incrementAndGet()),
Function.identity()));
}
AtomicInteger counter = new AtomicInteger();
Map<String, Set<String>> nets =
sets.stream().map(s -> s.stream()
.map(AiProjectBuilder::mapTerminal)
.collect(Collectors.toSet()))
.collect(Collectors.toMap(x -> "N" + counter.incrementAndGet(), x -> x));
// Map<String, Set<String>> nets =
// sets.stream().map(s -> s.stream()
// .map(AiProjectBuilder::mapTerminal)
// .collect(Collectors.toSet()))
// .collect(Collectors.toMap(x -> "N" + String.format("%03d", counter.incrementAndGet()),
// Function.identity()));
List<AiSwitch> switches =
project.getComponents().stream()
@@ -159,7 +180,7 @@ public class AiProjectBuilder {
fromPos, toPos, pos, terminals.isEmpty() ? null : terminals);
}
static String mapTerminal(NetlistBuilder.TerminalRef terminalRef) {
return terminalRef.component.getName() + "." + terminalRef.terminalIndex;
static String mapTerminal(Node terminalRef) {
return terminalRef.getComponent().getName() + "." + terminalRef.getPointIndex();
}
}
@@ -123,9 +123,57 @@ public class ChatbotService {
String currentFile = plugInPort.getCurrentFileName();
String fileName = extractFileName(currentFile);
File aiProjectFile = null;
File aiProjectFile = getAiProjectFile();
try {
return getService().promptChatbot(
plugInPort.getCloudService().getCurrentUsername(),
plugInPort.getCloudService().getCurrentToken(),
plugInPort.getCloudService().getMachineId(),
fileName,
aiProjectFile,
prompt);
} finally {
// Clean up the temp file immediately after use
if (aiProjectFile != null && aiProjectFile.exists()) {
aiProjectFile.delete();
}
}
}
public String analyzeCircuit() throws NotLoggedInException {
if (!plugInPort.getCloudService().isLoggedIn())
throw new NotLoggedInException();
LOG.info("Analyzing circuit...");
String currentFile = plugInPort.getCurrentFileName();
String fileName = extractFileName(currentFile);
File aiProjectFile = getAiProjectFile();
try {
String jsonResult = getService().analyzeCircuit(plugInPort.getCloudService().getCurrentUsername(),
plugInPort.getCloudService().getCurrentToken(),
plugInPort.getCloudService().getMachineId(), fileName, aiProjectFile);
return JsonToHtmlConverter.convertToHtml(jsonResult);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
// Clean up the temp file immediately after use
if (aiProjectFile != null && aiProjectFile.exists()) {
aiProjectFile.delete();
}
}
}
private File getAiProjectFile() {
File aiProjectFile = null;
AiProject aiProject = extractAiProject();
if (aiProject == null) {
return null;
}
try {
AiProject aiProject = extractAiProject();
String aiProjectStr = null;
try {
aiProjectStr = MAPPER.writeValueAsString(aiProject);
@@ -181,24 +229,13 @@ public class ChatbotService {
} catch (Exception e) {
LOG.error("Error extracting or saving netlist", e);
}
try {
return getService().promptChatbot(
plugInPort.getCloudService().getCurrentUsername(),
plugInPort.getCloudService().getCurrentToken(),
plugInPort.getCloudService().getMachineId(),
fileName,
aiProjectFile,
prompt);
} finally {
// Clean up the temp file immediately after use
if (aiProjectFile != null && aiProjectFile.exists()) {
aiProjectFile.delete();
}
}
return aiProjectFile;
}
private AiProject extractAiProject() throws NetlistException {
private AiProject extractAiProject() {
if (plugInPort.getCurrentProject().getComponents().isEmpty()) {
return null;
}
List<ContinuityArea> continuityAreas = plugInPort.getDrawingManager().getContinuityAreas();
return AiProjectBuilder.build(plugInPort.getCurrentProject(), continuityAreas);
}
@@ -0,0 +1,92 @@
package org.diylc.plugins.chatbot.service;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
public class JsonToHtmlConverter {
private static final ObjectMapper MAPPER = new ObjectMapper();
/**
* Convert the given JSON string into HTML.
*
* @param json the input JSON
* @return an HTML document as a String
* @throws IOException if JSON parsing fails
*/
public static String convertToHtml(String json) throws IOException {
JsonNode root = MAPPER.readTree(json);
StringBuilder html = new StringBuilder();
html.append("<!DOCTYPE html>\n<html>\n<head>\n")
.append(" <meta charset=\"UTF-8\">\n")
.append(" <title>Validation Report</title>\n")
.append(" <style>\n")
.append(" body { font-family: Arial, sans-serif; }\n")
.append(" h2 { color: #444; }\n")
.append(" ul { list-style: disc; margin-left: 20px; }\n")
.append(" li { margin-bottom: 5px; }\n")
.append(" </style>\n")
.append("</head>\n<body>\n");
// Process each section
processSection(root, "critical", html, "#c00");
processSection(root, "warnings", html, "#e65c00");
processSection(root, "optimizations", html, "#0066c0");
html.append("</body>\n</html>");
return html.toString();
}
private static void processSection(JsonNode root, String field, StringBuilder html, String color) {
JsonNode array = root.path(field);
if (array.isArray() && array.size() > 0) {
html.append(String.format("<h2 style=\"color:%s;\">%s</h2>\n", color, capitalize(field)));
html.append("<ul>\n");
for (JsonNode item : array) {
String message = escapeHtml(item.path("message").asText(""));
if (item.hasNonNull("componentId") && !item.path("componentId").asText().isEmpty()) {
String id = escapeHtml(item.path("componentId").asText());
html.append(" <li><strong>")
.append(id)
.append("</strong>: ")
.append(message)
.append("</li>\n");
} else {
html.append(" <li>")
.append(message)
.append("</li>\n");
}
}
html.append("</ul>\n");
}
}
private static String capitalize(String text) {
if (text == null || text.isEmpty()) return text;
return Character.toUpperCase(text.charAt(0)) + text.substring(1);
}
/**
* Very basic HTML escapement; for more robust use Apache Commons StringEscapeUtils.escapeHtml4().
*/
private static String escapeHtml(String s) {
return s.replace("&", "&amp;")
.replace("<", "&lt;")
.replace(">", "&gt;")
.replace("\"", "&quot;");
}
// Example usage:
public static void main(String[] args) throws IOException {
String json = "{\n" +
" \"critical\": [{\"message\":\"Value too low\"}],\n" +
" \"warnings\": [{\"componentId\":\"C3\",\"message\":\"Consider higher tolerance\"}],\n" +
" \"optimizations\": [{\"componentId\":\"L2\",\"message\":\"Could use 0805 package\"}]\n" +
"}";
String html = convertToHtml(json);
System.out.println(html);
}
}
@@ -1,137 +1,125 @@
package org.diylc.plugins.chatbot.service;
import org.diylc.core.IContinuity;
import org.diylc.core.IDIYComponent;
import org.diylc.core.ISwitch;
import org.diylc.presenter.ContinuityArea;
import java.awt.geom.Area;
import java.awt.geom.Point2D;
import java.util.*;
public class NetlistBuilder {
public static class TerminalRef {
public final IDIYComponent<?> component;
public final int terminalIndex;
public TerminalRef(IDIYComponent<?> component, int terminalIndex) {
this.component = component;
this.terminalIndex = terminalIndex;
}
public Point2D getPosition() {
return component.getControlPoint(terminalIndex);
}
@Override
public String toString() {
return component.getName() + "." + terminalIndex;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof TerminalRef)) return false;
TerminalRef other = (TerminalRef) obj;
return Objects.equals(component, other.component) && terminalIndex == other.terminalIndex;
}
@Override
public int hashCode() {
return Objects.hash(component, terminalIndex);
}
}
public static List<Set<TerminalRef>> buildNets(List<IDIYComponent<?>> components, List<ContinuityArea> continuityAreas) {
Map<TerminalRef, Integer> terminalIndex = new HashMap<>();
List<TerminalRef> allTerminals = new ArrayList<>();
int idx = 0;
for (IDIYComponent<?> c : components) {
for (int i = 0; i < c.getControlPointCount(); i++) {
if (c.isControlPointSticky(i)) {
TerminalRef ref = new TerminalRef(c, i);
terminalIndex.put(ref, idx++);
allTerminals.add(ref);
}
}
}
UnionFind uf = new UnionFind(allTerminals.size());
// Step 1: connect conductive components
for (IDIYComponent<?> c : components) {
if (c instanceof IContinuity continuity && !(c instanceof ISwitch)) {
int count = c.getControlPointCount();
for (int i = 0; i < count; i++) {
for (int j = i + 1; j < count; j++) {
if (continuity.arePointsConnected(i, j)) {
TerminalRef a = new TerminalRef(c, i);
TerminalRef b = new TerminalRef(c, j);
uf.union(terminalIndex.get(a), terminalIndex.get(b));
}
}
}
}
}
// Step 2: connect terminals inside continuity areas
for (ContinuityArea continuity : continuityAreas) {
Area area = continuity.getSimplifiedArea();
List<TerminalRef> inside = new ArrayList<>();
for (TerminalRef t : allTerminals) {
Point2D p = t.getPosition();
if (area.contains(p)) {
inside.add(t);
}
}
for (int i = 0; i < inside.size(); i++) {
for (int j = i + 1; j < inside.size(); j++) {
uf.union(terminalIndex.get(inside.get(i)), terminalIndex.get(inside.get(j)));
}
}
}
Map<Integer, Set<TerminalRef>> netMap = new HashMap<>();
for (TerminalRef t : allTerminals) {
int root = uf.find(terminalIndex.get(t));
netMap.computeIfAbsent(root, k -> new HashSet<>()).add(t);
}
// Filter out nets with only one terminal and remove exact duplicates
List<Set<TerminalRef>> nets = new ArrayList<>();
Set<Set<TerminalRef>> seen = new HashSet<>();
for (Set<TerminalRef> net : netMap.values()) {
if (net.size() > 1 && seen.add(net)) {
nets.add(net);
}
}
return nets;
}
// Union-Find with path compression
static class UnionFind {
int[] parent;
UnionFind(int n) {
parent = new int[n];
for (int i = 0; i < n; i++) parent[i] = i;
}
int find(int x) {
if (parent[x] != x)
parent[x] = find(parent[x]);
return parent[x];
}
void union(int x, int y) {
parent[find(x)] = find(y);
}
}
}
//package org.diylc.plugins.chatbot.service;
//
//import org.diylc.core.IContinuity;
//import org.diylc.core.IDIYComponent;
//import org.diylc.core.ISwitch;
//import org.diylc.netlist.Node;
//import org.diylc.presenter.ContinuityArea;
//
//import java.awt.geom.Area;
//import java.awt.geom.Point2D;
//import java.util.*;
//
//public class NetlistBuilder {
// private static final double eps = 1e-6;
//
// public static List<Set<Node>> buildNets(List<IDIYComponent<?>> components, List<ContinuityArea> continuityAreas) {
// Map<Node, Integer> terminalIndex = new HashMap<>();
// List<Node> allTerminals = new ArrayList<>();
// int idx = 0;
//
// for (IDIYComponent<?> c : components) {
// for (int i = 0; i < c.getControlPointCount(); i++) {
// if (c.isControlPointSticky(i)) {
// Node ref = new Node(c, i);
// terminalIndex.put(ref, idx++);
// allTerminals.add(ref);
// }
// }
// }
//
// UnionFind uf = new UnionFind(allTerminals.size());
//
// // Step 1: connect conductive components
// for (IDIYComponent<?> c : components) {
// if (c instanceof IContinuity continuity && !(c instanceof ISwitch)) {
// int count = c.getControlPointCount();
// for (int i = 0; i < count; i++) {
// for (int j = i + 1; j < count; j++) {
// if (continuity.arePointsConnected(i, j)) {
// Node a = new Node(c, i);
// Node b = new Node(c, j);
// uf.union(terminalIndex.get(a), terminalIndex.get(b));
// }
// }
// }
// }
// }
//
// // Step 2: connect terminals inside continuity areas
// for (ContinuityArea continuity : continuityAreas) {
// Area area = continuity.getSimplifiedArea();
// List<Node> inside = new ArrayList<>();
//
// for (Node t : allTerminals) {
// Point2D p = t.getPoint2D();
// if (area.contains(p) || area.intersects(p.getX() - eps/2, p.getY() - eps/2, eps, eps)) {
// inside.add(t);
// }
// }
//
// for (int i = 0; i < inside.size(); i++) {
// for (int j = i + 1; j < inside.size(); j++) {
// uf.union(terminalIndex.get(inside.get(i)), terminalIndex.get(inside.get(j)));
// }
// }
// }
//
// Map<Integer, Set<Node>> netMap = new HashMap<>();
// for (Node t : allTerminals) {
// int root = uf.find(terminalIndex.get(t));
// netMap.computeIfAbsent(root, k -> new HashSet<>()).add(t);
// }
//
// // Filter out nets with only one terminal and remove exact duplicates
// List<Set<Node>> nets = new ArrayList<>();
// Set<Set<Node>> seen = new HashSet<>();
//
// for (Set<Node> net : netMap.values()) {
// if (net.size() > 1 && seen.add(net)) {
// nets.add(net);
// }
// }
// return nets;
//
// }
//
// // Union-Find with path compression and union by size
// static class UnionFind {
// private final int[] parent;
// private final int[] size;
//
// UnionFind(int n) {
// parent = new int[n];
// size = new int[n];
// for (int i = 0; i < n; i++) {
// parent[i] = i;
// size[i] = 1;
// }
// }
//
// int find(int x) {
// if (parent[x] != x) {
// parent[x] = find(parent[x]); // Path compression
// }
// return parent[x];
// }
//
// void union(int x, int y) {
// int rootX = find(x);
// int rootY = find(y);
//
// if (rootX == rootY) return;
//
// // Union by size: attach smaller tree to larger tree
// if (size[rootX] < size[rootY]) {
// parent[rootX] = rootY;
// size[rootY] += size[rootX];
// } else {
// parent[rootY] = rootX;
// size[rootX] += size[rootY];
// }
// }
// }
//}
//
@@ -63,6 +63,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.log4j.Logger;
import org.diylc.common.ObjectCache;
import org.diylc.common.ZoomableStroke;
import org.diylc.core.IDrawingObserver;
@@ -79,9 +80,14 @@ import org.diylc.core.IDrawingObserver;
class G2DWrapper extends Graphics2D implements IDrawingObserver {
public static int LINE_SENSITIVITY_MARGIN = 2;
public static int CURVE_SENSITIVITY = 6;
public static int CURVE_SENSITIVITY = 6;
private static final Logger LOG = Logger.getLogger(G2DWrapper.class);
public static String DEBUG_AREA_PERFORMANCE = "org.diylc.debugAreaPerformance";
private boolean drawingComponent = false;
private final boolean debugAreaPerformance;
private boolean trackingAllowed = true;
private boolean trackingContinuityAllowed = false;
private boolean trackingContinuityPositive = true;
@@ -115,6 +121,8 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
public G2DWrapper(Graphics2D canvasGraphics, double zoom) {
super();
this.canvasGraphics = canvasGraphics;
String debugAreaPerformanceStr = System.getProperty(DEBUG_AREA_PERFORMANCE);
debugAreaPerformance = "true".equalsIgnoreCase(debugAreaPerformanceStr);
this.zoom = zoom;
currentArea = new Area();
continuityPositiveAreas = new HashMap<String, Area>();
@@ -236,8 +244,18 @@ class G2DWrapper extends Graphics2D implements IDrawingObserver {
Area area = new Area(s);
area.transform(currentTx);
if (trackingAllowed)
currentArea.add(area);
Area areaBefore = null;
if (debugAreaPerformance) {
areaBefore = new Area(currentArea);
}
if (trackingAllowed) {
currentArea.add(area);
if (debugAreaPerformance && currentArea.equals(areaBefore)) {
LOG.warn("Detected unnecessary shape tracking at", new Throwable());
}
}
Map<String, Area> toAdd;
if (trackingContinuityAllowed) {
+60 -52
View File
@@ -1,57 +1,5 @@
<java.util.Arrays_-ArrayList>
<a class="org.diylc.appframework.update.Version-array">
<org.diylc.appframework.update.Version>
<versionNumber>
<major>4</major>
<minor>41</minor>
<build>0</build>
</versionNumber>
<releaseDate>2025-03-08 00:00:00.000 CET</releaseDate>
<name></name>
<changes>
<org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType>
<description>Export traces, pads (with holes), ground fill and PCB text to Gerber files</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType>
<description>Added ability to select PTH or NPTH holes for solder pads</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>IMPROVEMENT</changeType>
<description>Optimized continuity calculations to be faster</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>IMPROVEMENT</changeType>
<description>Increased maximum available memory for DIYLC to 4GB</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>IMPROVEMENT</changeType>
<description>Upgraded Java JRE to version 17 LTE</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>IMPROVEMENT</changeType>
<description>Added support for high DPI displays</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>IMPROVEMENT</changeType>
<description>Added windows x64 build</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>BUG_FIX</changeType>
<description>Pasting a building block sometimes messes up the z-order of components</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>BUG_FIX</changeType>
<description>Pasting a building block sometimes switches selection to previously added components and canvas moves to the wrong position</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>BUG_FIX</changeType>
<description>'Highlight Continuity Areas' sometimes renders stale areas when clicked</description>
</org.diylc.appframework.update.Change>
</changes>
<url>https://github.com/bancika/diy-layout-creator/releases</url>
</org.diylc.appframework.update.Version>
<org.diylc.appframework.update.Version>
<versionNumber>
<major>4</major>
@@ -296,5 +244,65 @@
</changes>
<url>https://github.com/bancika/diy-layout-creator/releases</url>
</org.diylc.appframework.update.Version>
<org.diylc.appframework.update.Version>
<versionNumber>
<major>5</major>
<minor>4</minor>
<build>0</build>
</versionNumber>
<releaseDate>2025-05-13 00:00:00.000 CET</releaseDate>
<name></name>
<changes>
<org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType>
<description>'AI Analyzer' feature added which uses AI to scan the circuit diagram and report issues and suggestions</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>IMPROVEMENT</changeType>
<description>Significantly improve rendering performance of most components</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>IMPROVEMENT</changeType>
<description>'Open Jack 1/4"' and 'Potentiometer Panel' now tolerate connections anywhere on the lugs instead of dead center only</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>IMPROVEMENT</changeType>
<description>Increased maximum number of switching combinations to 256 for circuit analysis</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>BUG_FIX</changeType>
<description>'Pilot Lamp Holder' component can sometimes hang the application</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>BUG_FIX</changeType>
<description>Fixed the issue with embedding image files into DIY projects</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>BUG_FIX</changeType>
<description>Fixed the issue with some components (e.g. DIP IC) jumping when showing underside of a board</description>
</org.diylc.appframework.update.Change>
</changes>
<url>https://github.com/bancika/diy-layout-creator/releases</url>
</org.diylc.appframework.update.Version>
<org.diylc.appframework.update.Version>
<versionNumber>
<major>5</major>
<minor>5</minor>
<build>0</build>
</versionNumber>
<releaseDate>2025-05-13 00:00:00.000 CET</releaseDate>
<name></name>
<changes>
<org.diylc.appframework.update.Change>
<changeType>IMPROVEMENT</changeType>
<description>Increased tolerance of sticky points on guitar pickup terminals in order to make it easier for leads to make proper contact and for the circuit analyzer to work</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>BUG_FIX</changeType>
<description>If the internet connection is present, but unstable, the application starts but nothing can be clicked until the connection restores</description>
</org.diylc.appframework.update.Change>
</changes>
<url>https://github.com/bancika/diy-layout-creator/releases</url>
</org.diylc.appframework.update.Version>
</a>
</java.util.Arrays_-ArrayList>
@@ -4721,5 +4721,57 @@
</changes>
<url>https://github.com/bancika/diy-layout-creator/releases</url>
</org.diylc.appframework.update.Version>
<org.diylc.appframework.update.Version>
<versionNumber>
<major>4</major>
<minor>41</minor>
<build>0</build>
</versionNumber>
<releaseDate>2025-03-08 00:00:00.000 CET</releaseDate>
<name></name>
<changes>
<org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType>
<description>Export traces, pads (with holes), ground fill and PCB text to Gerber files</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType>
<description>Added ability to select PTH or NPTH holes for solder pads</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>IMPROVEMENT</changeType>
<description>Optimized continuity calculations to be faster</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>IMPROVEMENT</changeType>
<description>Increased maximum available memory for DIYLC to 4GB</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>IMPROVEMENT</changeType>
<description>Upgraded Java JRE to version 17 LTE</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>IMPROVEMENT</changeType>
<description>Added support for high DPI displays</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>IMPROVEMENT</changeType>
<description>Added windows x64 build</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>BUG_FIX</changeType>
<description>Pasting a building block sometimes messes up the z-order of components</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>BUG_FIX</changeType>
<description>Pasting a building block sometimes switches selection to previously added components and canvas moves to the wrong position</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>BUG_FIX</changeType>
<description>'Highlight Continuity Areas' sometimes renders stale areas when clicked</description>
</org.diylc.appframework.update.Change>
</changes>
<url>https://github.com/bancika/diy-layout-creator/releases</url>
</org.diylc.appframework.update.Version>
</a>
</java.util.Arrays_-ArrayList>
@@ -0,0 +1,188 @@
//package org.diylc.plugins.chatbot.service;
//
//import org.diylc.core.IContinuity;
//import org.diylc.core.IDIYComponent;
//import org.diylc.core.ComponentState;
//import org.diylc.core.IDrawingObserver;
//import org.diylc.core.Project;
//import org.diylc.core.VisibilityPolicy;
//import org.diylc.netlist.Node;
//import org.diylc.presenter.ContinuityArea;
//import org.junit.Test;
//import org.diylc.components.AbstractComponent;
//
//import java.awt.Graphics2D;
//import java.awt.geom.Area;
//import java.awt.geom.Point2D;
//import java.util.*;
//
//import static org.junit.Assert.*;
//
//public class NetlistBuilderTest {
//
// // Mock component that implements IContinuity
// private static class MockConductiveComponent extends AbstractComponent<Void> implements IContinuity {
// private final Point2D[] points;
// private final boolean[][] connections;
//
// public MockConductiveComponent(Point2D[] points, boolean[][] connections) {
// this.points = points;
// this.connections = connections;
// }
//
// @Override
// public int getControlPointCount() {
// return points.length;
// }
//
// @Override
// public Point2D getControlPoint(int index) {
// return points[index];
// }
//
// @Override
// public boolean isControlPointSticky(int index) {
// return true;
// }
//
// @Override
// public boolean arePointsConnected(int index1, int index2) {
// return connections[index1][index2];
// }
//
// @Override
// public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, IDrawingObserver drawingObserver) {
// // Not needed for testing
// }
//
// @Override
// public void drawIcon(Graphics2D g2d, int width, int height) {
// // Not needed for testing
// }
//
// @Override
// public VisibilityPolicy getControlPointVisibilityPolicy(int index) {
// return VisibilityPolicy.ALWAYS;
// }
//
// @Override
// public void setControlPoint(Point2D point, int index) {
// // Not needed for testing
// }
//
// @Override
// public Void getValue() {
// return null;
// }
//
// @Override
// public void setValue(Void value) {
// // Not needed for testing
// }
// }
//
// // Mock component that doesn't implement IContinuity
// private static class MockNonConductiveComponent extends AbstractComponent<Void> {
// private final Point2D[] points;
//
// public MockNonConductiveComponent(Point2D[] points) {
// this.points = points;
// }
//
// @Override
// public int getControlPointCount() {
// return points.length;
// }
//
// @Override
// public Point2D getControlPoint(int index) {
// return points[index];
// }
//
// @Override
// public boolean isControlPointSticky(int index) {
// return true;
// }
//
// @Override
// public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project, IDrawingObserver drawingObserver) {
// // Not needed for testing
// }
//
// @Override
// public void drawIcon(Graphics2D g2d, int width, int height) {
// // Not needed for testing
// }
//
// @Override
// public VisibilityPolicy getControlPointVisibilityPolicy(int index) {
// return VisibilityPolicy.ALWAYS;
// }
//
// @Override
// public void setControlPoint(Point2D point, int index) {
// // Not needed for testing
// }
//
// @Override
// public Void getValue() {
// return null;
// }
//
// @Override
// public void setValue(Void value) {
// // Not needed for testing
// }
// }
//
// @Test
// public void testBuildNets() {
// // Create test components
// Point2D[] points1 = {
// new Point2D.Double(0, 0),
// new Point2D.Double(10, 0),
// new Point2D.Double(20, 0)
// };
// boolean[][] connections1 = {
// {false, true, false},
// {true, false, true},
// {false, true, false}
// };
// MockConductiveComponent comp1 = new MockConductiveComponent(points1, connections1);
//
// Point2D[] points2 = {
// new Point2D.Double(30, 0),
// new Point2D.Double(40, 0)
// };
// MockNonConductiveComponent comp2 = new MockNonConductiveComponent(points2);
//
// // Create a continuity area that connects comp1 and comp2
// Area area = new Area();
// area.add(new Area(new java.awt.geom.Rectangle2D.Double(15, -5, 20, 10)));
// ContinuityArea continuityArea = new ContinuityArea(0, area);
//
// // Build nets
// List<IDIYComponent<?>> components = Arrays.asList(comp1, comp2);
// List<ContinuityArea> continuityAreas = Collections.singletonList(continuityArea);
// List<Set<Node>> nets = NetlistBuilder.buildNets(components, continuityAreas);
//
// // Verify results
// assertEquals("Should have exactly one net", 1, nets.size());
// Set<Node> net = nets.get(0);
// assertEquals("Net should contain all terminals", 5, net.size());
//
// // Verify that all terminals are connected
// Set<Integer> terminalIndices = new HashSet<>();
// for (Node node : net) {
// terminalIndices.add(node.getPointIndex());
// System.out.println("Found terminal: " + node.getPointIndex() + " at " + node.getPoint2D());
// }
// System.out.println("All terminals: " + terminalIndices);
// assertEquals("Should contain all terminal indices", 5, terminalIndices.size());
// assertTrue("Should contain terminal 0", terminalIndices.contains(0));
// assertTrue("Should contain terminal 1", terminalIndices.contains(1));
// assertTrue("Should contain terminal 2", terminalIndices.contains(2));
// assertTrue("Should contain terminal 3", terminalIndices.contains(3));
// assertTrue("Should contain terminal 4", terminalIndices.contains(4));
// }
//}
+1 -1
View File
@@ -7,7 +7,7 @@
<parent>
<groupId>org.diylc</groupId>
<artifactId>diylc-parent</artifactId>
<version>5.3.0</version>
<version>5.4.0</version>
</parent>
<artifactId>diylc-library</artifactId>
@@ -355,39 +355,42 @@ public abstract class AbstractLeadedComponent<T> extends AbstractLabeledComponen
if (getDisplay() == Display.BOTH) {
label = getName() + " " + (getValue() == null ? "" : getValue().toString());
}
Rectangle2D textRect = fontMetrics.getStringBounds(label, g2d);
// Don't offset in outline mode.
int offset = outlineMode ? 0 : getLabelOffset((int) length, (int) width, (int) textRect.getWidth());
// Adjust label angle if needed to make sure that it's readable.
if ((theta >= Math.PI / 2 && theta <= Math.PI) || (theta < -Math.PI / 2 && theta > -Math.PI)) {
g2d.rotate(Math.PI, length / 2, width / 2);
theta += Math.PI;
offset = -offset;
}
drawingObserver.startTracking();
if (getMoveLabel()) {
g2d.setTransform(oldTransform);
g2d.translate(getPoints()[2].getX(), getPoints()[2].getY());
if (getLabelOriantation() != LabelOriantation.Horizontal) {
g2d.rotate(theta);
if (!label.isEmpty()) {
Rectangle2D textRect = fontMetrics.getStringBounds(label, g2d);
// Don't offset in outline mode.
int offset = outlineMode ? 0 : getLabelOffset((int) length, (int) width, (int) textRect.getWidth());
// Adjust label angle if needed to make sure that it's readable.
if ((theta >= Math.PI / 2 && theta <= Math.PI) || (theta < -Math.PI / 2 && theta > -Math.PI)) {
g2d.rotate(Math.PI, length / 2, width / 2);
theta += Math.PI;
offset = -offset;
}
StringUtils.drawCenteredText(g2d, label, offset, 0, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
g2d.setTransform(oldTransform);
} else {
if (isStanding() || getLabelOriantation() == LabelOriantation.Horizontal) {
if (getMoveLabel()) {
drawingObserver.startTracking();
g2d.setTransform(oldTransform);
g2d.translate(getPoints()[2].getX(), getPoints()[2].getY());
if (getLabelOriantation() != LabelOriantation.Horizontal) {
g2d.rotate(theta);
}
StringUtils.drawCenteredText(g2d, label, offset, 0, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
g2d.setTransform(oldTransform);
double x = (getPoints()[0].getX() + getPoints()[1].getX() - length) / 2.0;
double y = (getPoints()[0].getY() + getPoints()[1].getY() - width) / 2.0;
g2d.drawString(label, (int) (x + (length - textRect.getWidth()) / 2 + offset),
(int)(y + calculateLabelYOffset(shapeRect, textRect, fontMetrics)));
} else {
g2d.drawString(label, (int) (length - textRect.getWidth()) / 2 + offset,
calculateLabelYOffset(shapeRect, textRect, fontMetrics));
g2d.setTransform(oldTransform);
}
if (isStanding() || getLabelOriantation() == LabelOriantation.Horizontal) {
drawingObserver.startTracking();
g2d.setTransform(oldTransform);
double x = (getPoints()[0].getX() + getPoints()[1].getX() - length) / 2.0;
double y = (getPoints()[0].getY() + getPoints()[1].getY() - width) / 2.0;
g2d.drawString(label, (int) (x + (length - textRect.getWidth()) / 2 + offset),
(int) (y + calculateLabelYOffset(shapeRect, textRect, fontMetrics)));
} else {
drawingObserver.stopTracking();
g2d.drawString(label, (int) (length - textRect.getWidth()) / 2 + offset,
calculateLabelYOffset(shapeRect, textRect, fontMetrics));
g2d.setTransform(oldTransform);
}
}
}
// if (getLabelOriantation() == LabelOriantation.Horizontal) {
//
@@ -2,15 +2,24 @@ package org.diylc.components.boards;
import org.diylc.common.Orientation;
import org.diylc.components.AbstractComponent;
import org.diylc.core.BoardUndersideDisplay;
import org.diylc.core.IBoard;
import org.diylc.core.annotations.EditableProperty;
import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit;
public abstract class AbstractProtoBoard extends AbstractComponent<Void> {
public abstract class AbstractProtoBoard extends AbstractComponent<Void> implements IBoard {
private static final long serialVersionUID = 1L;
public static final Size DEFAULT_UNDERSIDE_OFFSET = new Size(0.1, SizeUnit.in);
protected Orientation orientation;
protected BoardUndersideDisplay boardUndersideDisplay = BoardUndersideDisplay.NONE;
protected Size undersideOffset = DEFAULT_UNDERSIDE_OFFSET;
private Boolean undersideTransparency = true;
@EditableProperty
public Orientation getOrientation() {
if (orientation == null)
@@ -21,4 +30,48 @@ public abstract class AbstractProtoBoard extends AbstractComponent<Void> {
public void setOrientation(Orientation orientation) {
this.orientation = orientation;
}
@EditableProperty(name = "Underside Display")
@Override
public BoardUndersideDisplay getUndersideDisplay() {
if (this.boardUndersideDisplay == null) {
this.boardUndersideDisplay = BoardUndersideDisplay.NONE;
}
return this.boardUndersideDisplay;
}
public void setUndersideDisplay(BoardUndersideDisplay boardUndersideDisplay) {
this.boardUndersideDisplay = boardUndersideDisplay;
}
@EditableProperty(name = "Underside Offset")
@Override
public Size getUndersideOffset() {
if (undersideOffset == null) {
undersideOffset = DEFAULT_UNDERSIDE_OFFSET;
}
return undersideOffset;
}
public void setUndersideOffset(Size undersideOffset) {
this.undersideOffset = undersideOffset;
}
@EditableProperty(name = "Underside Transparency")
@Override
public Boolean getUndersideTransparency() {
if (undersideTransparency == null) {
undersideTransparency = true;
}
return undersideTransparency;
}
public void setUndersideTransparency(Boolean undersideTransparency) {
this.undersideTransparency = undersideTransparency;
}
@Override
public boolean shouldExportToGerber() {
return false;
}
}
@@ -369,6 +369,13 @@ public class Breadboard extends AbstractProtoBoard {
public String getControlPointNodeName(int index) {
return null;
}
@Override
public Rectangle2D getBoardRectangle() {
Point2D finalSecondPoint = getControlPoint(1);
return new Rectangle2D.Double(Math.min(point.getX(), finalSecondPoint.getX()), Math.min(point.getY(), finalSecondPoint.getY()),
Math.abs(finalSecondPoint.getX() - point.getX()), Math.abs(finalSecondPoint.getY() - point.getY()));
}
@Override
public Rectangle2D getCachingBounds() {
@@ -720,6 +720,16 @@ public class EurorackStripboard extends AbstractProtoBoard {
return null;
}
@Override
public Rectangle2D getBoardRectangle() {
Point2D finalSecondPoint = getControlPoint(1);
double offset = BODY_OFFSET_Y.convertToPixels();
return new Rectangle2D.Double(Math.min(point.getX(), finalSecondPoint.getX()) - offset,
Math.min(point.getY(), finalSecondPoint.getY()) - offset,
Math.abs(finalSecondPoint.getX() - point.getX()) + offset,
Math.abs(finalSecondPoint.getY() - point.getY()) + offset);
}
@Override
public Rectangle2D getCachingBounds() {
Point2D finalSecondPoint = getControlPoint(1);
@@ -685,6 +685,13 @@ public class ProtoBoard extends AbstractProtoBoard {
public String getControlPointNodeName(int index) {
return null;
}
@Override
public Rectangle2D getBoardRectangle() {
Point2D finalSecondPoint = getControlPoint(1);
return new Rectangle2D.Double(Math.min(point.getX(), finalSecondPoint.getX()), Math.min(point.getY(), finalSecondPoint.getY()),
Math.abs(finalSecondPoint.getX() - point.getX()), Math.abs(finalSecondPoint.getY() - point.getY()));
}
@Override
public Rectangle2D getCachingBounds() {
@@ -510,6 +510,21 @@ public class ProtoBoard780 extends AbstractProtoBoard {
return null;
}
@Override
public Rectangle2D getBoardRectangle() {
double spacing = SPACING.convertToPixels();
double offsetX = X_OFFSET.convertToPixels();
double dx = translateToGrid ? -offsetX : 0;
double dy = translateToGrid ? spacing / 2 : 0;
Point2D finalSecondPoint = getControlPoint(1);
return new Rectangle2D.Double(Math.min(point.getX(), finalSecondPoint.getX()) + dx,
Math.min(point.getY(), finalSecondPoint.getY()) + dy,
Math.abs(finalSecondPoint.getX() - point.getX()),
Math.abs(finalSecondPoint.getY() - point.getY()));
}
@Override
public Rectangle2D getCachingBounds() {
double spacing = SPACING.convertToPixels();
@@ -213,6 +213,9 @@ public class PCBTerminalBlock extends AbstractTransparentComponent<PCBTerminalBl
}
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBodyColor());
g2d.fill(body[0]);
// Do not track these changes because the whole switch has been tracked
// so far.
drawingObserver.stopTracking();
g2d.setComposite(oldComposite);
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
Color finalBorderColor;
@@ -232,9 +235,7 @@ public class PCBTerminalBlock extends AbstractTransparentComponent<PCBTerminalBl
g2d.setColor(finalBorderColor);
g2d.draw(body[0]);
}
// Do not track these changes because the whole switch has been tracked
// so far.
drawingObserver.stopTracking();
// Draw lugs.
int circleDiameter = getClosestOdd((int) (getPitch().convertToPixels() * 3d / 5));
@@ -109,6 +109,7 @@ public class SolderPad extends AbstractTransparentComponent<Void>
g2d.fill(new Rectangle2D.Double(point.getX() - diameter / 2, point.getY() - diameter / 2,
diameter, diameter));
}
drawingObserver.stopTracking();
drawingObserver.stopTrackingContinuityArea();
if (gerberDrawingObserver != null)
gerberDrawingObserver.stopGerberOutput(org.diylc.core.gerber.GerberLayer.SolderMaskBot);
@@ -103,6 +103,8 @@ public class BatterySnap9V extends AbstractTransparentComponent<String> {
: color.brighter();
}
drawingObserver.stopTracking();
g2d.setColor(finalBorderColor);
g2d.draw(body[0]);
g2d.setColor(METAL_COLOR.darker());
@@ -236,6 +236,8 @@ public class ClosedJack1_4 extends AbstractMultiPartComponent<JackType> implemen
g2d.setComposite(oldComposite);
// }
drawingObserver.stopTracking();
Color finalBorderColor;
if (outlineMode) {
Theme theme =
@@ -356,6 +356,8 @@ public class DIPSwitch extends AbstractTransparentComponent<String> implements I
g2d.fill(mainArea);
g2d.setComposite(oldComposite);
drawingObserver.stopTracking();
Color finalBorderColor;
if (outlineMode) {
Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY,
@@ -392,8 +394,6 @@ public class DIPSwitch extends AbstractTransparentComponent<String> implements I
}
}
drawingObserver.stopTracking();
// Draw label.
g2d.setFont(project.getFont());
Color finalLabelColor;
@@ -304,6 +304,8 @@ public class MiniRelay extends AbstractLabeledComponent<String> implements IGerb
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BODY_COLOR);
g2d.fill(mainArea);
g2d.setComposite(oldComposite);
drawingObserver.stopTracking();
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
@@ -129,18 +129,29 @@ public class OpenJack1_4 extends AbstractMultiPartComponent<OpenJackType> {
if (alpha < MAX_ALPHA) {
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
}
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BASE_COLOR);
g2d.setColor(Constants.TRANSPARENT_COLOR);
drawingObserver.startTrackingContinuityArea(true);
g2d.fill(body[1]);
g2d.fill(body[2]);
if (body[3] != null)
g2d.fill(body[3]);
g2d.fill(body[4]);
g2d.fill(body[5]);
if (body[6] != null)
g2d.fill(body[6]);
drawingObserver.stopTrackingContinuityArea();
if (!outlineMode) {
g2d.setColor(BASE_COLOR);
g2d.fill(body[1]);
g2d.fill(body[2]);
if (body[3] != null)
g2d.fill(body[3]);
}
g2d.setComposite(oldComposite);
// }
drawingObserver.stopTracking();
if (outlineMode) {
Theme theme =
(Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME);
@@ -148,16 +159,12 @@ public class OpenJack1_4 extends AbstractMultiPartComponent<OpenJackType> {
} else {
finalBorderColor = BASE_COLOR.darker();
}
drawingObserver.stopTracking();
g2d.setColor(finalBorderColor);
g2d.draw(body[1]);
g2d.draw(body[2]);
if (body[3] != null)
g2d.draw(body[3]);
drawingObserver.startTracking();
// draw labels
if (showLabels) {
@@ -193,7 +200,7 @@ public class OpenJack1_4 extends AbstractMultiPartComponent<OpenJackType> {
public Area[] getBody() {
if (body == null) {
body = new Area[4];
body = new Area[7];
double x = controlPoints[0].getX();
double y = controlPoints[0].getY();
@@ -224,6 +231,13 @@ public class OpenJack1_4 extends AbstractMultiPartComponent<OpenJackType> {
body[1] = tip;
// no-hole tip for continuity
tip =
new Area(new RoundRectangle2D.Double(x - springWidth / 2, y - holeToEdge, springWidth, springLength
- ringDiameter / 2, springWidth, springWidth));
tip.subtract(wafer);
body[4] = tip;
Area sleeve =
new Area(new RoundRectangle2D.Double(x - springWidth / 2, y - holeToEdge, springWidth, springLength,
springWidth, springWidth));
@@ -237,6 +251,17 @@ public class OpenJack1_4 extends AbstractMultiPartComponent<OpenJackType> {
body[2] = sleeve;
// no-hole sleeve for continuity
sleeve =
new Area(new RoundRectangle2D.Double(x - springWidth / 2, y - holeToEdge, springWidth, springLength,
springWidth, springWidth));
sleeve.transform(AffineTransform.getRotateInstance(getValue() == OpenJackType.SWITCHED ? SLEEVE_SWITCHED_THETA : SLEEVE_THETA, x, centerY));
sleeve.add(new Area(new Ellipse2D.Double(x - ringDiameter / 2, centerY - ringDiameter / 2, ringDiameter,
ringDiameter)));
sleeve.subtract(new Area(new Ellipse2D.Double(x - innerDiameter / 2, centerY - innerDiameter / 2, innerDiameter,
innerDiameter)));
body[5] = sleeve;
if (getValue() != OpenJackType.MONO) {
Area ringOrSwitch =
new Area(new RoundRectangle2D.Double(x - springWidth / 2, y - holeToEdge, springWidth, springLength,
@@ -248,6 +273,15 @@ public class OpenJack1_4 extends AbstractMultiPartComponent<OpenJackType> {
outerDiameter)));
body[3] = ringOrSwitch;
ringOrSwitch =
new Area(new RoundRectangle2D.Double(x - springWidth / 2, y - holeToEdge, springWidth, springLength,
springWidth, springWidth));
ringOrSwitch.transform(AffineTransform.getRotateInstance(getValue() == OpenJackType.SWITCHED ? SWITCH_THETA : RING_THETA, x, centerY));
ringOrSwitch.subtract(new Area(new Ellipse2D.Double(x - outerDiameter / 2, centerY - outerDiameter / 2, outerDiameter,
outerDiameter)));
body[6] = ringOrSwitch;
}
// Rotate if needed
@@ -141,6 +141,8 @@ public class OpenJack1_8 extends AbstractMultiPartComponent<OpenJackType> {
g2d.setComposite(oldComposite);
// }
drawingObserver.stopTracking();
if (outlineMode) {
Theme theme =
(Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME);
@@ -148,8 +150,6 @@ public class OpenJack1_8 extends AbstractMultiPartComponent<OpenJackType> {
} else {
finalBorderColor = BASE_COLOR.darker();
}
drawingObserver.stopTracking();
g2d.setColor(finalBorderColor);
g2d.draw(body[1]);
@@ -134,6 +134,7 @@ public class PilotLampHolder extends AbstractMultiPartComponent<String> {
g2d.fill(body[2]);
drawingObserver.stopTrackingContinuityArea();
drawingObserver.stopTracking();
g2d.setComposite(oldComposite);
// }
@@ -232,6 +232,7 @@ public class PinHeader extends AbstractTransparentComponent<Void> {
g2d.setColor(shroudColor);
g2d.fill(shroudArea);
}
drawingObserver.stopTracking();
g2d.setComposite(oldComposite);
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
@@ -142,6 +142,7 @@ public class PlasticDCJack extends AbstractMultiPartComponent<String> implements
}
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BODY_COLOR);
g2d.fill(body[0]);
drawingObserver.stopTracking();
if (!outlineMode) {
g2d.setColor(PHENOLIC_DARK_COLOR);
g2d.fill(body[1]);
@@ -93,6 +93,8 @@ public class RCAJack extends AbstractMultiPartComponent<String> {
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : WAFER_COLOR);
g2d.fill(body[0]);
drawingObserver.stopTracking();
g2d.setComposite(oldComposite);
// }
@@ -116,8 +118,10 @@ public class RCAJack extends AbstractMultiPartComponent<String> {
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BASE_COLOR);
drawingObserver.startTrackingContinuityArea(true);
drawingObserver.startTracking();
g2d.fill(body[1]);
g2d.fill(body[2]);
drawingObserver.stopTracking();
drawingObserver.stopTrackingContinuityArea();
if (body[3] != null)
@@ -362,7 +362,9 @@ public class RotarySwitchOpen extends AbstractAngledComponent<RotarySwitchOpenTy
drawingObserver.startTrackingContinuityArea(true);
for (int i = secondLevelStart; i < body.length; i++) {
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : pinColor);
drawingObserver.startTracking();
g2d.fill(body[i]);
drawingObserver.stopTracking();
g2d.setColor(outlineMode ? finalBorderColor : pinColor.darker());
g2d.draw(body[i]);
}
@@ -376,8 +378,8 @@ public class RotarySwitchOpen extends AbstractAngledComponent<RotarySwitchOpenTy
}
g2d.setColor(finalBorderColor);
drawingObserver.startTracking();
g2d.draw(body[0]);
drawingObserver.stopTracking();
// Draw pins
@@ -182,6 +182,7 @@ public class RotarySwitchSealed extends AbstractAngledComponent<RotarySwitchSeal
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getColor());
g2d.fill(body[0]);
}
drawingObserver.stopTracking();
g2d.setComposite(oldComposite);
Color finalBorderColor;
if (outlineMode) {
@@ -198,8 +199,6 @@ public class RotarySwitchSealed extends AbstractAngledComponent<RotarySwitchSeal
g2d.setColor(finalBorderColor);
g2d.draw(body[0]);
drawingObserver.stopTracking();
// Draw pins
if (!outlineMode) {
for (int i = 1; i < controlPoints.length; i++) {
@@ -247,7 +247,7 @@ public class SlideSwitch extends AbstractTransparentComponent<SlideSwitchType> i
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBodyColor());
g2d.fill(body[0]);
drawingObserver.stopTracking();
g2d.setComposite(oldComposite);
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
Color finalBorderColor;
@@ -269,9 +269,7 @@ public class SlideSwitch extends AbstractTransparentComponent<SlideSwitchType> i
}
g2d.draw(body[0]);
}
// Do not track these changes because the whole switch has been tracked
// so far.
drawingObserver.stopTracking();
// Draw lugs.
int lugWidth;
@@ -232,7 +232,9 @@ public class TactileMicroSwitch extends AbstractLabeledComponent<String> impleme
Rectangle2D rect = new Rectangle2D.Double(point.getX() - pinSize / 2,
point.getY() - pinSize / 2, pinSize, pinSize);
g2d.setColor(PIN_COLOR);
drawingObserver.startTracking();
g2d.fill(rect);
drawingObserver.stopTrackingContinuityArea();
g2d.setColor(PIN_BORDER_COLOR);
g2d.draw(rect);
}
@@ -242,7 +244,9 @@ public class TactileMicroSwitch extends AbstractLabeledComponent<String> impleme
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
}
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBodyColor());
drawingObserver.stopTracking();
g2d.fill(mainArea);
drawingObserver.stopTracking();
g2d.setColor(INDENT_COLOR);
g2d.fill(indentArea);
@@ -23,6 +23,7 @@ import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import org.diylc.appframework.miscutils.ConfigurationManager;
@@ -34,10 +35,7 @@ import org.diylc.common.Orientation;
import org.diylc.common.OrientationHV;
import org.diylc.common.VerticalAlignment;
import org.diylc.components.AbstractLabeledComponent;
import org.diylc.core.ComponentState;
import org.diylc.core.Project;
import org.diylc.core.Theme;
import org.diylc.core.VisibilityPolicy;
import org.diylc.core.*;
import org.diylc.core.annotations.EditableProperty;
import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit;
@@ -48,6 +46,7 @@ public abstract class AbstractGuitarPickup extends AbstractLabeledComponent<Stri
private static final long serialVersionUID = 1L;
protected static Size POINT_SPACING = new Size(0.1d, SizeUnit.in);
private static Size POINT_SIZE = new Size(1.5d, SizeUnit.mm);
protected static final int TERMINAL_FONT_SIZE = 11;
@@ -66,7 +65,7 @@ public abstract class AbstractGuitarPickup extends AbstractLabeledComponent<Stri
updateControlPoints();
}
protected void drawlTerminalLabels(Graphics2D g2d, Color color, Project project) {
protected void drawTerminalLabels(Graphics2D g2d, Color color, Project project) {
Point2D[] points = getControlPoints();
g2d.setColor(color);
@@ -131,6 +130,21 @@ public abstract class AbstractGuitarPickup extends AbstractLabeledComponent<Stri
g2d.setTransform(originalTx);
}
protected void markContactPoints(Graphics2D g2d, IDrawingObserver drawingObserver) {
g2d.setColor(Constants.TRANSPARENT_COLOR);
int pointSize = getClosestOdd(POINT_SIZE.convertToPixels());
drawingObserver.startTrackingContinuityArea(true);
for (int i = 0; i < getControlPointCount(); i++) {
if (isControlPointSticky(i)) {
Point2D p = getControlPoint(i);
g2d.fill(
new Ellipse2D.Double(p.getX() - pointSize / 2, p.getY() - pointSize / 2, pointSize,
pointSize));
}
}
drawingObserver.stopTrackingContinuityArea();
}
protected abstract Shape[] getBody();
@@ -34,7 +34,7 @@ public abstract class AbstractSingleOrHumbuckerPickup extends AbstractGuitarPick
private static final long serialVersionUID = 1L;
@Override
protected void drawlTerminalLabels(Graphics2D g2d, Color color, Project project) {
protected void drawTerminalLabels(Graphics2D g2d, Color color, Project project) {
Point2D[] points = getControlPoints();
g2d.setColor(color);
@@ -74,7 +74,6 @@ public class HumbuckerPickup extends AbstractGuitarPickup {
private static Size EDGE_RADIUS = new Size(4d, SizeUnit.mm);
private static Size POINT_MARGIN = new Size(1.5d, SizeUnit.mm);
private static Size SCREW_LINE = new Size(1d, SizeUnit.mm);
private static Size POINT_SIZE = new Size(2d, SizeUnit.mm);
private static Size LIP_HOLE_SIZE = new Size(2d, SizeUnit.mm);
private static Size POLE_SIZE = new Size(4d, SizeUnit.mm);
private static Size POLE_SIZE_FILTERTRON = new Size(5d, SizeUnit.mm);
@@ -93,6 +92,8 @@ public class HumbuckerPickup extends AbstractGuitarPickup {
@Override
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
IDrawingObserver drawingObserver) {
drawingObserver.stopTracking();
Shape[] body = getBody();
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
@@ -102,10 +103,16 @@ public class HumbuckerPickup extends AbstractGuitarPickup {
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
}
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : color);
if (getType() != HumbuckerType.Filtertron)
if (getType() != HumbuckerType.Filtertron) {
drawingObserver.startTracking();
g2d.fill(body[0]);
if (body[1] != null)
drawingObserver.stopTracking();
}
if (body[1] != null) {
drawingObserver.startTracking();
g2d.fill(body[1]);
drawingObserver.stopTracking();
}
if (!outlineMode) {
if (body[4] != null) {
@@ -120,15 +127,13 @@ public class HumbuckerPickup extends AbstractGuitarPickup {
if (getType() == HumbuckerType.Filtertron) {
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : color);
drawingObserver.startTracking();
g2d.fill(body[0]);
drawingObserver.stopTracking();
}
// g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : POINT_COLOR);
// g2d.fill(body[2]);
g2d.setComposite(oldComposite);
Color finalBorderColor;
if (outlineMode) {
Theme theme =
@@ -148,6 +153,8 @@ public class HumbuckerPickup extends AbstractGuitarPickup {
if (body[1] != null)
g2d.draw(body[1]);
markContactPoints(g2d, drawingObserver);
if (!outlineMode) {
g2d.setColor(getPoleColor());
g2d.fill(body[3]);
@@ -175,7 +182,7 @@ public class HumbuckerPickup extends AbstractGuitarPickup {
drawMainLabel(g2d, project, outlineMode, componentState);
drawlTerminalLabels(g2d, finalBorderColor, project);
drawTerminalLabels(g2d, finalBorderColor, project);
}
@Override
@@ -198,7 +205,7 @@ public class HumbuckerPickup extends AbstractGuitarPickup {
int lipLength = (int) LIP_LENGTH.convertToPixels();
int edgeRadius = (int) EDGE_RADIUS.convertToPixels();
int pointMargin = (int) POINT_MARGIN.convertToPixels();
int pointSize = getClosestOdd(POINT_SIZE.convertToPixels());
int lipHoleSize = getClosestOdd(LIP_HOLE_SIZE.convertToPixels());
int poleSize = (int) getType().getPoleSize().convertToPixels();
int poleSpacing = (int) POLE_SPACING.convertToPixels();
@@ -269,9 +276,6 @@ public class HumbuckerPickup extends AbstractGuitarPickup {
body[1] = legArea;
}
// contact point
body[2] = new Area(new Ellipse2D.Double(x - pointSize / 2, y - pointSize / 2, pointSize, pointSize));
Area poleArea = new Area();
Area poleDecorationArea = new Area();
@@ -70,7 +70,6 @@ public class JazzBassPickup extends AbstractSingleOrHumbuckerPickup {
private static Size LIP_HOLE_SPACING = new Size(0.1d, SizeUnit.in);
private static Size POINT_MARGIN = new Size(1.5d, SizeUnit.mm);
private static Size POINT_SIZE = new Size(2d, SizeUnit.mm);
private static Size POLE_SIZE = new Size(4d, SizeUnit.mm);
private static Size POLE_SPACING = new Size(0.85d, SizeUnit.in);
private static Size POLE_SPACING_MINOR = new Size(0.28d, SizeUnit.in);
@@ -81,6 +80,7 @@ public class JazzBassPickup extends AbstractSingleOrHumbuckerPickup {
@Override
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
IDrawingObserver drawingObserver) {
Shape[] body = getBody();
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
@@ -91,9 +91,12 @@ public class JazzBassPickup extends AbstractSingleOrHumbuckerPickup {
}
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : color);
g2d.fill(body[0]);
g2d.fill(body[1]);
g2d.fill(body[1]);
drawingObserver.stopTracking();
g2d.setComposite(oldComposite);
markContactPoints(g2d, drawingObserver);
Color finalBorderColor;
if (outlineMode) {
Theme theme =
@@ -137,7 +140,7 @@ public class JazzBassPickup extends AbstractSingleOrHumbuckerPickup {
// VerticalAlignment.CENTER);
drawMainLabel(g2d, project, outlineMode, componentState);
drawlTerminalLabels(g2d, finalBorderColor, project);
drawTerminalLabels(g2d, finalBorderColor, project);
}
@SuppressWarnings("incomplete-switch")
@@ -155,7 +158,6 @@ public class JazzBassPickup extends AbstractSingleOrHumbuckerPickup {
int pointMargin = (int) POINT_MARGIN.convertToPixels();
int lipRadius = (int) LIP_RADIUS.convertToPixels();
int lipSpacing = (int) LIP_SPACING.convertToPixels();
int pointSize = getClosestOdd(POINT_SIZE.convertToPixels());
int lipHoleSize = getClosestOdd(LIP_HOLE_SIZE.convertToPixels());
int lipHoleSpacing = getClosestOdd(LIP_HOLE_SPACING.convertToPixels());
@@ -178,8 +180,6 @@ public class JazzBassPickup extends AbstractSingleOrHumbuckerPickup {
((Area)body[1]).subtract((Area)body[0]);
body[2] = new Area(new Ellipse2D.Double(x - pointSize / 2, y - pointSize / 2, pointSize, pointSize));
int poleSize = (int) POLE_SIZE.convertToPixels();
int poleSpacing = (int) POLE_SPACING.convertToPixels();
int poleSpacingMinor = (int) POLE_SPACING_MINOR.convertToPixels();
@@ -93,6 +93,8 @@ public class LPSwitch extends AbstractTransparentComponent<String> implements IS
g2d.setComposite(oldComposite);
}
drawingObserver.stopTracking();
Color finalBorderColor;
if (outlineMode) {
@@ -127,7 +129,9 @@ public class LPSwitch extends AbstractTransparentComponent<String> implements IS
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(2));
g2d.setColor(METAL_COLOR);
drawingObserver.startTracking();
g2d.draw(body[2]);
drawingObserver.stopTracking();
}
@SuppressWarnings("incomplete-switch")
@@ -111,6 +111,8 @@ public class LeverSwitch extends AbstractAngledComponent<LeverSwitch.LeverSwitch
g2d.setComposite(oldComposite);
}
drawingObserver.stopTracking();
Color finalBorderColor;
if (outlineMode) {
Theme theme =
@@ -142,7 +144,9 @@ public class LeverSwitch extends AbstractAngledComponent<LeverSwitch.LeverSwitch
g2d.draw(body[1]);
g2d.setColor(LUG_COLOR);
drawingObserver.startTracking();
g2d.fill(body[2]);
drawingObserver.stopTracking();
g2d.setColor(LUG_COLOR.darker());
g2d.draw(body[2]);
@@ -75,7 +75,6 @@ public class P90Pickup extends AbstractSingleOrHumbuckerPickup {
private static Size LIP_RADIUS = new Size(10d, SizeUnit.mm);
private static Size POINT_MARGIN = new Size(3.5d, SizeUnit.mm);
private static Size POINT_SIZE = new Size(2d, SizeUnit.mm);
private static Size LIP_HOLE_SIZE = new Size(2.5d, SizeUnit.mm);
private static Size LIP_HOLE_SPACING = new Size(97d, SizeUnit.mm);
private static Size POLE_SIZE = new Size(4d, SizeUnit.mm);
@@ -107,6 +106,7 @@ public class P90Pickup extends AbstractSingleOrHumbuckerPickup {
g2d.fill(body[1]);
// g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : POINT_COLOR);
// g2d.fill(body[2]);
drawingObserver.stopTracking();
g2d.setComposite(oldComposite);
Color finalBorderColor;
@@ -126,7 +126,9 @@ public class P90Pickup extends AbstractSingleOrHumbuckerPickup {
g2d.draw(body[0]);
if (body[1] != null)
g2d.draw(body[1]);
markContactPoints(g2d, drawingObserver);
if (!outlineMode) {
g2d.setColor(getPoleColor());
g2d.fill(body[3]);
@@ -153,7 +155,7 @@ public class P90Pickup extends AbstractSingleOrHumbuckerPickup {
// VerticalAlignment.CENTER);
drawMainLabel(g2d, project, outlineMode, componentState);
drawlTerminalLabels(g2d, finalBorderColor, project);
drawTerminalLabels(g2d, finalBorderColor, project);
// terminal labels
// Point[] points = getControlPoints();
// g2d.setColor(finalBorderColor);
@@ -204,7 +206,6 @@ public class P90Pickup extends AbstractSingleOrHumbuckerPickup {
int pointMargin = (int) POINT_MARGIN.convertToPixels();
int totalLength = (int) TOTAL_LENGTH.convertToPixels();
int lipRadius = (int) LIP_RADIUS.convertToPixels();
int pointSize = getClosestOdd(POINT_SIZE.convertToPixels());
int lipHoleSize = getClosestOdd(LIP_HOLE_SIZE.convertToPixels());
int lipHoleSpacing = getClosestOdd(LIP_HOLE_SPACING.convertToPixels());
@@ -236,8 +237,6 @@ public class P90Pickup extends AbstractSingleOrHumbuckerPickup {
body[1] = lipArea;
}
body[2] = new Area(new Ellipse2D.Double(x - pointSize / 2, y - pointSize / 2, pointSize, pointSize));
int poleSize = (int) POLE_SIZE.convertToPixels();
int poleSpacing = (int) POLE_SPACING.convertToPixels();
int poleMargin = (length - poleSpacing * 5) / 2;
@@ -69,7 +69,6 @@ public class PBassPickup extends AbstractSingleOrHumbuckerPickup {
private static Size LIP_HOLE_SPACING = new Size(0.1d, SizeUnit.in);
private static Size POINT_MARGIN = new Size(1.5d, SizeUnit.mm);
private static Size POINT_SIZE = new Size(2d, SizeUnit.mm);
private static Size POLE_SIZE = new Size(4d, SizeUnit.mm);
private static Size POLE_SPACING = new Size(0.38d, SizeUnit.in);
@@ -90,8 +89,11 @@ public class PBassPickup extends AbstractSingleOrHumbuckerPickup {
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : color);
g2d.fill(body[0]);
g2d.fill(body[1]);
drawingObserver.stopTracking();
g2d.setComposite(oldComposite);
markContactPoints(g2d, drawingObserver);
Color finalBorderColor;
if (outlineMode) {
Theme theme =
@@ -135,7 +137,7 @@ public class PBassPickup extends AbstractSingleOrHumbuckerPickup {
// VerticalAlignment.CENTER);
drawMainLabel(g2d, project, outlineMode, componentState);
drawlTerminalLabels(g2d, finalBorderColor, project);
drawTerminalLabels(g2d, finalBorderColor, project);
}
@SuppressWarnings("incomplete-switch")
@@ -152,7 +154,6 @@ public class PBassPickup extends AbstractSingleOrHumbuckerPickup {
int edgeRadius = (int) EDGE_RADIUS.convertToPixels();
int pointMargin = (int) POINT_MARGIN.convertToPixels();
int lipRadius = (int) LIP_RADIUS.convertToPixels();
int pointSize = getClosestOdd(POINT_SIZE.convertToPixels());
int lipHoleSize = getClosestOdd(LIP_HOLE_SIZE.convertToPixels());
int lipHoleSpacing = getClosestOdd(LIP_HOLE_SPACING.convertToPixels());
@@ -173,8 +174,6 @@ public class PBassPickup extends AbstractSingleOrHumbuckerPickup {
((Area)body[1]).subtract((Area)body[0]);
body[2] = new Area(new Ellipse2D.Double(x - pointSize / 2, y - pointSize / 2, pointSize, pointSize));
int poleSize = (int) POLE_SIZE.convertToPixels();
int poleSpacing = (int) POLE_SPACING.convertToPixels();
int poleMargin = (length - poleSpacing * 3) / 2;
@@ -162,6 +162,7 @@ public class S1Switch extends AbstractTransparentComponent<Void> implements ISwi
}
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BODY_COLOR);
g2d.fill(body);
drawingObserver.stopTracking();
g2d.setComposite(oldComposite);
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
Color finalBorderColor;
@@ -110,11 +110,14 @@ public class SchallerMegaSwitch extends AbstractAngledComponent<String> implemen
}
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : BASE_COLOR);
g2d.fill(body[0]);
drawingObserver.stopTracking();
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : WAFER_COLOR);
g2d.fill(body[1]);
g2d.setComposite(oldComposite);
}
drawingObserver.stopTracking();
Color finalBorderColor;
if (outlineMode) {
Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY,
@@ -150,12 +153,16 @@ public class SchallerMegaSwitch extends AbstractAngledComponent<String> implemen
g2d.draw(body[1]);
g2d.setColor(LUG_COLOR);
drawingObserver.startTracking();
g2d.fill(body[2]);
drawingObserver.stopTracking();
g2d.setColor(LUG_COLOR.darker());
g2d.draw(body[2]);
for (int i = 3; i < body.length; i++) {
g2d.setColor(ISwitch.POLE_COLORS[i - 3]);
drawingObserver.startTracking();
g2d.fill(body[i]);
drawingObserver.stopTracking();
g2d.setColor(ISwitch.POLE_COLORS[i - 3].darker());
g2d.draw(body[i]);
}
@@ -124,7 +124,11 @@ public class SingleCoilPickup extends AbstractSingleOrHumbuckerPickup {
g2d.fill(body[0]);
else
g2d.fill(body[3]);
drawingObserver.stopTracking();
markContactPoints(g2d, drawingObserver);
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getLugColor());
g2d.fill(body[1]);
g2d.setColor(outlineMode ? theme.getOutlineColor() : darkerOrLighter(LUG_COLOR));
@@ -172,7 +176,7 @@ public class SingleCoilPickup extends AbstractSingleOrHumbuckerPickup {
drawMainLabel(g2d, project, outlineMode, componentState);
drawlTerminalLabels(g2d, finalBorderColor, project);
drawTerminalLabels(g2d, finalBorderColor, project);
}
@Override
@@ -21,28 +21,13 @@
*/
package org.diylc.components.guitar;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.RoundRectangle2D;
import org.diylc.appframework.miscutils.ConfigurationManager;
import org.diylc.common.IPlugInPort;
import org.diylc.common.ObjectCache;
import org.diylc.common.Orientation;
import org.diylc.common.OrientationHV;
import org.diylc.components.transform.GuitarPickupTransformer;
import org.diylc.core.ComponentState;
import org.diylc.core.IDIYComponent;
import org.diylc.core.IDrawingObserver;
import org.diylc.core.Project;
import org.diylc.core.Theme;
import org.diylc.core.*;
import org.diylc.core.annotations.ComponentDescriptor;
import org.diylc.core.annotations.EditableProperty;
import org.diylc.core.annotations.KeywordPolicy;
@@ -50,77 +35,86 @@ import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit;
import org.diylc.utils.Constants;
import java.awt.*;
import java.awt.geom.*;
@ComponentDescriptor(name = "Stingray Bass Pickup", category = "Guitar", author = "JD",
description = "Humbucker Bass Pickup for Musicman Stingray and similar guitars",
description = "Humbucker Bass Pickup for Musicman Stingray and similar guitars",
zOrder = IDIYComponent.COMPONENT, instanceNamePrefix = "PKP", autoEdit = false,
keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "Guitar Wiring Diagram", enableCache = true,
transformer = GuitarPickupTransformer.class)
keywordPolicy = KeywordPolicy.SHOW_TAG, keywordTag = "Guitar Wiring Diagram",
enableCache = true, transformer = GuitarPickupTransformer.class)
/**
* Component type for Stingray Bass Humbucker
* Modified from the P Bass Pickup. Author: JD
* @author JD
*/
public class StingrayBassPickup extends AbstractGuitarPickup {
*/ public class StingrayBassPickup extends AbstractGuitarPickup {
private static final long serialVersionUID = 1L;
private static Color BODY_COLOR = Color.decode("#333333");
private static Size WIDTH = new Size(1.910, SizeUnit.in);
private static Size LENGTH = new Size(3.505, SizeUnit.in);
private static Size EDGE_RADIUS = new Size(0.08d, SizeUnit.in);
private static Size LIP_RADIUS = new Size(0.4d, SizeUnit.in);
private static Size LIP_HOLE_SIZE = new Size(0.1d, SizeUnit.in);
private static Size LIP_HOLE_SPACING = new Size(0.05d, SizeUnit.in);
private static Size LIP_DISTANCE_VERTICAL = new Size(0.935d, SizeUnit.in);// Left side vertical between mount points
private static Size LIP_DISTANCE_VERTICAL = new Size(0.935d, SizeUnit.in);
// Left side vertical between mount points
// private static Size LIP_DISTANCE_HORIZONTAL = new Size(3.7000d, SizeUnit.in); // Distance across pickup
private static Size POINT_MARGIN = new Size(1.5d, SizeUnit.mm);
private static Size POINT_SIZE = new Size(2d, SizeUnit.mm);
private static Size POLE_SIZE = new Size(.39d, SizeUnit.in);
private static Size POLE_SPACING_HORIZONTAL = new Size(0.75366d, SizeUnit.in); // Distance Between poles
private static Size POLE_SPACING_TO_EDGE= new Size(0.4875d, SizeUnit.in);// Outer edge to centre of nearest pole
// (Perpendicular of course!)
private static Size POLE_SPACING_HORIZONTAL = new Size(0.75366d, SizeUnit.in);
// Distance Between poles
private static Size POLE_SPACING_TO_EDGE = new Size(0.4875d, SizeUnit.in);
// Outer edge to centre of nearest pole
// (Perpendicular of course!)
private Color color = BODY_COLOR;
private Color poleColor = METAL_COLOR;
@Override
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode,
Project project, IDrawingObserver drawingObserver) {
Project project, IDrawingObserver drawingObserver) {
Shape[] body = getBody();
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1));
Composite oldComposite = g2d.getComposite();
if (alpha < MAX_ALPHA) {
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
}
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : color);
g2d.fill(body[0]);
g2d.fill(body[1]);
drawingObserver.stopTracking();
g2d.setComposite(oldComposite);
Color finalBorderColor;
if (outlineMode) {
Theme theme =
(Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME);
Theme theme = (Theme) ConfigurationManager.getInstance()
.readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME);
finalBorderColor =
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
: theme.getOutlineColor();
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ?
SELECTION_COLOR :
theme.getOutlineColor();
} else {
finalBorderColor =
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
: color.darker();
componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ?
SELECTION_COLOR :
color.darker();
}
g2d.setColor(finalBorderColor);
g2d.draw(body[0]);
g2d.draw(body[1]);
markContactPoints(g2d, drawingObserver);
if (!outlineMode) {
g2d.setColor(getPoleColor());
g2d.fill(body[3]);
@@ -128,27 +122,9 @@ public class StingrayBassPickup extends AbstractGuitarPickup {
g2d.draw(body[3]);
}
// Color finalLabelColor;
// if (outlineMode) {
// Theme theme =
// (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME);
// finalLabelColor =
// componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED
// : theme.getOutlineColor();
// } else {
// finalLabelColor =
// componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? LABEL_COLOR_SELECTED
// : LABEL_COLOR;
// }
// g2d.setColor(finalLabelColor);
// g2d.setFont(project.getFont());
// Rectangle bounds = body[0].getBounds();
// drawCenteredText(g2d, value, bounds.x + bounds.width / 2, bounds.y + bounds.height / 2, HorizontalAlignment.CENTER,
// VerticalAlignment.CENTER);
drawMainLabel(g2d, project, outlineMode, componentState);
drawlTerminalLabels(g2d, finalBorderColor, project);
drawTerminalLabels(g2d, finalBorderColor, project);
}
@SuppressWarnings("incomplete-switch")
@@ -158,72 +134,76 @@ public class StingrayBassPickup extends AbstractGuitarPickup {
body = new Shape[4];
Point2D[] points = getControlPoints();
double x = points[0].getX();
double y = points[0].getY();
int width = (int) WIDTH.convertToPixels();
int length = (int) LENGTH.convertToPixels();
int edgeRadius = (int) EDGE_RADIUS.convertToPixels();
int pointMargin = (int) POINT_MARGIN.convertToPixels();
int lipRadius = (int) LIP_RADIUS.convertToPixels();
int pointSize = getClosestOdd(POINT_SIZE.convertToPixels());
int lipHoleSize = (int) LIP_HOLE_SIZE.convertToPixels();
double x = points[0].getX();
double y = points[0].getY();
int width = (int) WIDTH.convertToPixels();
int length = (int) LENGTH.convertToPixels();
int edgeRadius = (int) EDGE_RADIUS.convertToPixels();
int pointMargin = (int) POINT_MARGIN.convertToPixels();
int lipRadius = (int) LIP_RADIUS.convertToPixels();
int lipHoleSize = (int) LIP_HOLE_SIZE.convertToPixels();
int lipHoleSpacing = getClosestOdd(LIP_HOLE_SPACING.convertToPixels());
int lipDistanceV = (int) LIP_DISTANCE_VERTICAL.convertToPixels();
int lipDistanceV = (int) LIP_DISTANCE_VERTICAL.convertToPixels();
// This is the main body
body[0] =
new Area(new RoundRectangle2D.Double(x - length, y - pointMargin, length, width, edgeRadius,
body[0] = new Area(
new RoundRectangle2D.Double(x - length, y - pointMargin, length, width, edgeRadius,
edgeRadius));
// Lips around pickup - change transforms
Area lip = new Area(new Ellipse2D.Double(-lipRadius / 2, -lipRadius / 2, lipRadius, lipRadius));
lip.subtract(new Area(new Ellipse2D.Double(-lipRadius / 2 + lipHoleSpacing, -lipRadius / 4 + lipHoleSize / 2, lipHoleSize, lipHoleSize)));
lip.transform(AffineTransform.getTranslateInstance(x - length, y - pointMargin + (width - lipDistanceV) / 2));
Area lip2 = new Area(new Ellipse2D.Double(-lipRadius / 2, -lipRadius / 2, lipRadius, lipRadius));
Area lip =
new Area(new Ellipse2D.Double(-lipRadius / 2, -lipRadius / 2, lipRadius, lipRadius));
lip.subtract(new Area(
new Ellipse2D.Double(-lipRadius / 2 + lipHoleSpacing, -lipRadius / 4 + lipHoleSize / 2,
lipHoleSize, lipHoleSize)));
lip.transform(AffineTransform.getTranslateInstance(x - length,
y - pointMargin + (width - lipDistanceV) / 2));
Area lip2 =
new Area(new Ellipse2D.Double(-lipRadius / 2, -lipRadius / 2, lipRadius, lipRadius));
lip2 = new Area(new Ellipse2D.Double(-lipRadius / 2, -lipRadius / 2, lipRadius, lipRadius));
lip2.subtract(new Area(new Ellipse2D.Double(lipRadius / 2 - lipHoleSize - lipHoleSpacing, -lipRadius / 4 + lipHoleSize / 2, lipHoleSize, lipHoleSize)));
lip2.subtract(new Area(new Ellipse2D.Double(lipRadius / 2 - lipHoleSize - lipHoleSpacing,
-lipRadius / 4 + lipHoleSize / 2, lipHoleSize, lipHoleSize)));
lip2.transform(AffineTransform.getTranslateInstance(x, y - pointMargin + width / 2));
lip.add(lip2);
Area lip3 = new Area(new Ellipse2D.Double(-lipRadius / 2, -lipRadius / 2, lipRadius, lipRadius));
lip3.subtract(new Area(new Ellipse2D.Double(-lipRadius / 2 + lipHoleSpacing, -lipRadius / 4 + lipHoleSize / 2, lipHoleSize, lipHoleSize)));
lip3.transform(AffineTransform.getTranslateInstance(x - length, (y - pointMargin) + (width - ((width - lipDistanceV) / 2))));
Area lip3 =
new Area(new Ellipse2D.Double(-lipRadius / 2, -lipRadius / 2, lipRadius, lipRadius));
lip3.subtract(new Area(
new Ellipse2D.Double(-lipRadius / 2 + lipHoleSpacing, -lipRadius / 4 + lipHoleSize / 2,
lipHoleSize, lipHoleSize)));
lip3.transform(AffineTransform.getTranslateInstance(x - length,
(y - pointMargin) + (width - ((width - lipDistanceV) / 2))));
lip.add(lip3);
body[1] = new Area(lip);
// Merge
((Area)body[1]).subtract((Area)body[0]);
// ??? - Perhaps Overall Area - it's never filled in draw()
body[2] = new Area(new Ellipse2D.Double(x - pointSize / 2, y - pointSize / 2, pointSize, pointSize));
((Area) body[1]).subtract((Area) body[0]);
// Poles
int poleSize = (int) POLE_SIZE.convertToPixels();
int poleSpacing = (int) POLE_SPACING_HORIZONTAL.convertToPixels();
int poleSize = (int) POLE_SIZE.convertToPixels();
int poleSpacing = (int) POLE_SPACING_HORIZONTAL.convertToPixels();
int poleSpacingEdge = (int) POLE_SPACING_TO_EDGE.convertToPixels();
int poleMargin = (length - poleSpacing * 3) / 2; // Edge to centre of outer poles
int poleMargin = (length - poleSpacing * 3) / 2; // Edge to centre of outer poles
Area poleArea = new Area();
for (int i = 0; i < 4; i++) {
// Top Row
Ellipse2D pole =
new Ellipse2D.Double(x - length + poleMargin + i * poleSpacing - poleSize / 2,
y + poleSpacingEdge - pointMargin - poleSize / 2 ,
poleSize, poleSize);
new Ellipse2D.Double(x - length + poleMargin + i * poleSpacing - poleSize / 2,
y + poleSpacingEdge - pointMargin - poleSize / 2, poleSize, poleSize);
// Bottom Row
Ellipse2D pole2 =
new Ellipse2D.Double(x - length + poleMargin + i * poleSpacing - poleSize / 2,
Ellipse2D pole2 =
new Ellipse2D.Double(x - length + poleMargin + i * poleSpacing - poleSize / 2,
y - pointMargin - poleSize / 2 + (width - poleSpacingEdge), poleSize, poleSize);
poleArea.add(new Area(pole));
poleArea.add(new Area(pole2));
}
body[3] = poleArea;
// Rotate if needed
if (orientation != Orientation.DEFAULT) {
// Set variables depending on required transform
@@ -250,7 +230,7 @@ public class StingrayBassPickup extends AbstractGuitarPickup {
} // end the if (body == null)
return body;
}
@Override
protected int getMainLabelYOffset() {
return (int) (WIDTH.convertToPixels() / 2 - 20);
@@ -262,23 +242,28 @@ public class StingrayBassPickup extends AbstractGuitarPickup {
int bodyWidth = (int) (14f * width / 32);
int bodyLength = (int) (26f * width / 32);
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f));
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f));
g2d.setColor(BODY_COLOR);
g2d.fillRoundRect((width - bodyWidth) / 2, (height - bodyLength) / 2, bodyWidth, bodyLength, 3, 3);
g2d.fillRoundRect((width - bodyWidth) / 2, (height - bodyLength) / 2, bodyWidth, bodyLength, 3,
3);
// Very neat solution, doesn't work for this :(
// Could potentially make them shorter so they don't poke out both ends and then do three of them?
int lipSize = (int) (4f * width / 32);
// g2d.fillRoundRect((width - lipSize) / 2, (height - bodyLength) / 2 - lipSize + 1, lipSize, bodyLength + 2 * lipSize - 2, lipSize, lipSize);
g2d.fillRoundRect((width - lipSize) / 2, (height - bodyLength) / 2 - lipSize + 1, lipSize, lipSize, lipSize, lipSize); // Right, center
g2d.fillRoundRect(9 * width / 32, bodyLength + ((height - bodyLength) / 2), lipSize, lipSize, lipSize, lipSize);
g2d.fillRoundRect(18 * width / 32, bodyLength + ((height - bodyLength) / 2), lipSize, lipSize, lipSize, lipSize);
g2d.fillRoundRect((width - lipSize) / 2, (height - bodyLength) / 2 - lipSize + 1, lipSize,
lipSize, lipSize, lipSize); // Right, center
g2d.fillRoundRect(9 * width / 32, bodyLength + ((height - bodyLength) / 2), lipSize, lipSize,
lipSize, lipSize);
g2d.fillRoundRect(18 * width / 32, bodyLength + ((height - bodyLength) / 2), lipSize, lipSize,
lipSize, lipSize);
//g2d.fillRoundRect((width - lipSize) / 2, 12 * width / 32, lipSize, lipSize,lipSize,lipSize);
//g2d.fillRoundRect((width - lipSize) / 2, 20 * width / 32, lipSize, lipSize,lipSize,lipSize);
g2d.setColor(BODY_COLOR.darker());
g2d.drawRoundRect((width - bodyWidth) / 2, (height - bodyLength) / 2, bodyWidth, bodyLength, 3, 3);
g2d.drawRoundRect((width - bodyWidth) / 2, (height - bodyLength) / 2, bodyWidth, bodyLength, 3,
3);
// g2d.setColor(Color.gray);
// g2d.drawLine(width / 2, 4 * width / 32, width / 2, 4 * width / 32);
@@ -289,15 +274,17 @@ public class StingrayBassPickup extends AbstractGuitarPickup {
int poleSpacing = (int) (6d * width / 32);
for (int i = 0; i < 4; i++) {
// Top Row
g2d.fillOval(11 * width / 32, 5 * width / 32 + i * poleSpacing, poleSize * width / 32, poleSize * width / 32);
g2d.fillOval(11 * width / 32, 5 * width / 32 + i * poleSpacing, poleSize * width / 32,
poleSize * width / 32);
//g2d.fillOval((width - poleSize) / 2, (height - poleSpacing) / 2 + (i * poleSpacing / 3), poleSize, poleSize);
// Bottom Row
g2d.fillOval(17 * width / 32, 5 * width / 32 + i * poleSpacing, poleSize * width / 32, poleSize * width / 32);
g2d.fillOval(17 * width / 32, 5 * width / 32 + i * poleSpacing, poleSize * width / 32,
poleSize * width / 32);
}
}
@Override
protected OrientationHV getControlPointDirection() {
protected OrientationHV getControlPointDirection() {
return OrientationHV.VERTICAL;
}
@@ -309,7 +296,7 @@ public class StingrayBassPickup extends AbstractGuitarPickup {
public void setColor(Color color) {
this.color = color;
}
@EditableProperty(name = "Pole Color")
public Color getPoleColor() {
if (poleColor == null)
@@ -320,7 +307,7 @@ public class StingrayBassPickup extends AbstractGuitarPickup {
public void setPoleColor(Color poleColor) {
this.poleColor = poleColor;
}
@Override
public boolean isControlPointSticky(int index) {
return true;
@@ -330,10 +317,10 @@ public class StingrayBassPickup extends AbstractGuitarPickup {
public boolean isHumbucker() {
return true;
}
@Override
public Polarity getPolarity() {
// just to disable editor
return super.getPolarity();
}
}
}
@@ -234,6 +234,7 @@ public class Image extends AbstractTransparentComponent<Void> {
public void setData(byte[] data) {
this.data = data;
this.imageIcon = null;
this.image = null;
if (getSizingMode() == ImageSizingMode.TwoPoints) {
ImageIcon imageIcon = getImage();
@@ -121,7 +121,7 @@ public class PotentiometerPanel extends AbstractPotentiometer implements ILayere
if (body == null) {
// mandatory: 0, 1, 2 pins, 3 body, 9 wafer
// optional: 4, 5, 6 lugs, 7 nut, 8 shaft
body = new Area[10];
body = new Area[13];
// Add lugs.
int pinWidth = (int) PIN_SIZE.convertToPixels();
@@ -210,6 +210,7 @@ public class PotentiometerPanel extends AbstractPotentiometer implements ILayere
new Area(new Ellipse2D.Double(controlPoints[i].getX() - lugDiameter / 2, controlPoints[i].getY() - lugDiameter / 2,
lugDiameter, lugDiameter));
body[4 + i] = area;
body[10 + i] = new Area(area);
}
for (int i = 0; i < 3; i++) {
@@ -272,6 +273,11 @@ public class PotentiometerPanel extends AbstractPotentiometer implements ILayere
case 9:
g2d.setColor(getWaferColor());
break;
case 10:
case 11:
case 12:
g2d.setColor(Constants.TRANSPARENT_COLOR);
break;
default:
g2d.setColor(getBodyColor());
}
@@ -281,11 +287,11 @@ public class PotentiometerPanel extends AbstractPotentiometer implements ILayere
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
}
if (!outlineMode) {
// if (i >= 3 && i <= 6)
// drawingObserver.startTrackingContinuityArea(true);
if (i >= 10)
drawingObserver.startTrackingContinuityArea(true);
g2d.fill(shape);
// if (i >= 3 && i <= 6)
// drawingObserver.stopTrackingContinuityArea();
if (i >= 10)
drawingObserver.stopTrackingContinuityArea();
}
g2d.setComposite(oldComposite);
Color finalBorderColor;
@@ -302,6 +308,9 @@ public class PotentiometerPanel extends AbstractPotentiometer implements ILayere
g2d.draw(shape);
}
}
drawingObserver.stopTracking();
// Draw caption.
g2d.setFont(project.getFont());
@@ -375,14 +375,13 @@ public class TrimmerPotentiometer extends AbstractPotentiometer {
Shape shaftShape = getBody()[1];
Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME);
if (mainShape != null) {
g2d.setColor(bodyColor);
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor);
Composite oldComposite = g2d.getComposite();
if (alpha < MAX_ALPHA) {
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
}
if (!outlineMode) {
g2d.fill(mainShape);
}
g2d.fill(mainShape);
drawingObserver.stopTracking();
if (!outlineMode && shaftShape != null) {
g2d.setColor(SHAFT_COLOR);
g2d.fill(shaftShape);
@@ -315,7 +315,9 @@ public class DIL_IC extends AbstractLabeledComponent<String> implements IGerberC
Rectangle2D rect = new Rectangle2D.Double(point.getX() - pinSize / 2,
point.getY() - pinSize / 2, pinSize, pinSize);
g2d.setColor(PIN_COLOR);
drawingObserver.startTracking();
g2d.fill(rect);
drawingObserver.stopTracking();
g2d.setColor(PIN_BORDER_COLOR);
g2d.draw(rect);
}
@@ -325,7 +327,9 @@ public class DIL_IC extends AbstractLabeledComponent<String> implements IGerberC
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
}
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBodyColor());
drawingObserver.startTracking();
g2d.fill(mainArea);
drawingObserver.stopTracking();
g2d.setComposite(oldComposite);
Color finalBorderColor;
@@ -356,8 +360,6 @@ public class DIL_IC extends AbstractLabeledComponent<String> implements IGerberC
}
}
drawingObserver.stopTracking();
// Draw label.
g2d.setFont(project.getFont());
@@ -308,6 +308,7 @@ public class SIL_IC extends AbstractTransparentComponent<String> implements IGer
}
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : getBodyColor());
g2d.fill(mainArea);
drawingObserver.stopTracking();
g2d.setComposite(oldComposite);
Color finalBorderColor;
@@ -161,6 +161,8 @@ public class TransistorTO1 extends AbstractTransistorPackage {
@Override
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
IDrawingObserver drawingObserver) {
drawingObserver.stopTracking();
if (checkPointsClipped(g2d.getClip())) {
return;
}
@@ -184,7 +186,9 @@ public class TransistorTO1 extends AbstractTransistorPackage {
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
}
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor);
drawingObserver.startTracking();
g2d.fill(mainArea);
drawingObserver.stopTracking();
g2d.setComposite(oldComposite);
Color finalBorderColor;
@@ -183,6 +183,7 @@ public class TransistorTO126 extends AbstractTransistorPackage {
if (checkPointsClipped(g2d.getClip())) {
return;
}
drawingObserver.stopTracking();
int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2;
Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME);
@@ -211,7 +212,9 @@ public class TransistorTO126 extends AbstractTransistorPackage {
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness));
g2d.setColor(finalPinBorderColor);
line = new Line2D.Double(point.getX(), point.getY(), point.getX() + leadLength - leadThickness / 2, point.getY());
drawingObserver.startTracking();
g2d.draw(line);
drawingObserver.stopTracking();
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2));
g2d.setColor(finalPinColor);
g2d.draw(line);
@@ -220,7 +223,9 @@ public class TransistorTO126 extends AbstractTransistorPackage {
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness));
g2d.setColor(finalPinBorderColor);
line = new Line2D.Double(point.getX(), point.getY(), point.getX(), point.getY() + leadLength - leadThickness / 2);
drawingObserver.startTracking();
g2d.draw(line);
drawingObserver.stopTracking();
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2));
g2d.setColor(finalPinColor);
g2d.draw(line);
@@ -229,7 +234,9 @@ public class TransistorTO126 extends AbstractTransistorPackage {
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness));
g2d.setColor(finalPinBorderColor);
line = new Line2D.Double(point.getX(), point.getY(), point.getX() - leadLength - leadThickness / 2, point.getY());
drawingObserver.startTracking();
g2d.draw(line);
drawingObserver.stopTracking();
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2));
g2d.setColor(finalPinColor);
g2d.draw(line);
@@ -238,7 +245,9 @@ public class TransistorTO126 extends AbstractTransistorPackage {
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness));
g2d.setColor(finalPinBorderColor);
line = new Line2D.Double(point.getX(), point.getY(), point.getX(), point.getY() - leadLength);
drawingObserver.startTracking();
g2d.draw(line);
drawingObserver.stopTracking();
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2));
g2d.setColor(finalPinColor);
g2d.draw(line);
@@ -266,7 +275,9 @@ public class TransistorTO126 extends AbstractTransistorPackage {
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
}
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor);
g2d.fill(mainArea);
drawingObserver.startTracking();
g2d.fill(mainArea);
drawingObserver.stopTracking();
g2d.setComposite(oldComposite);
if (!outlineMode) {
@@ -210,6 +210,7 @@ public class TransistorTO220 extends AbstractTransistorPackage {
if (checkPointsClipped(g2d.getClip())) {
return;
}
drawingObserver.stopTracking();
int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2;
Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME);
@@ -238,7 +239,9 @@ public class TransistorTO220 extends AbstractTransistorPackage {
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness));
g2d.setColor(finalPinBorderColor);
line = new Line2D.Double(point.getX(), point.getY(), point.getX() + leadLength - leadThickness / 2, point.getY());
drawingObserver.startTracking();
g2d.draw(line);
drawingObserver.stopTracking();
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2));
g2d.setColor(finalPinColor);
g2d.draw(line);
@@ -247,7 +250,9 @@ public class TransistorTO220 extends AbstractTransistorPackage {
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness));
g2d.setColor(finalPinBorderColor);
line = new Line2D.Double(point.getX(), point.getY(), point.getX(), point.getY() + leadLength - leadThickness / 2);
drawingObserver.startTracking();
g2d.draw(line);
drawingObserver.stopTracking();
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2));
g2d.setColor(finalPinColor);
g2d.draw(line);
@@ -256,7 +261,9 @@ public class TransistorTO220 extends AbstractTransistorPackage {
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness));
g2d.setColor(finalPinBorderColor);
line = new Line2D.Double(point.getX(), point.getY(), point.getX() - leadLength - leadThickness / 2, point.getY());
drawingObserver.startTracking();
g2d.draw(line);
drawingObserver.stopTracking();
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2));
g2d.setColor(finalPinColor);
g2d.draw(line);
@@ -265,7 +272,9 @@ public class TransistorTO220 extends AbstractTransistorPackage {
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness));
g2d.setColor(finalPinBorderColor);
line = new Line2D.Double(point.getX(), point.getY(), point.getX(), point.getY() - leadLength);
drawingObserver.startTracking();
g2d.draw(line);
drawingObserver.stopTracking();
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(leadThickness - 2));
g2d.setColor(finalPinColor);
g2d.draw(line);
@@ -294,7 +303,9 @@ public class TransistorTO220 extends AbstractTransistorPackage {
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
}
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor);
drawingObserver.startTracking();
g2d.fill(mainArea);
drawingObserver.stopTracking();
Color finalTabColor;
if (outlineMode) {
finalTabColor = theme.getOutlineColor();
@@ -231,6 +231,7 @@ public class TransistorTO3 extends AbstractLabeledComponent<String> {
if (checkPointsClipped(g2d.getClip())) {
return;
}
drawingObserver.stopTracking();
int pinSize = (int) PIN_DIAMETER.convertToPixels() / 2 * 2;
Theme theme = (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME);
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f));
@@ -251,7 +252,9 @@ public class TransistorTO3 extends AbstractLabeledComponent<String> {
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
}
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor);
drawingObserver.startTracking();
g2d.fill(mainArea);
drawingObserver.stopTracking();
g2d.setComposite(oldComposite);
Color finalBorderColor;
@@ -187,6 +187,7 @@ public class TransistorTO92 extends AbstractTransistorPackage {
if (checkPointsClipped(g2d.getClip())) {
return;
}
drawingObserver.stopTracking();
int pinSize = (int) PIN_SIZE.convertToPixels() / 2 * 2;
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f));
@@ -206,7 +207,9 @@ public class TransistorTO92 extends AbstractTransistorPackage {
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
}
g2d.setColor(outlineMode ? Constants.TRANSPARENT_COLOR : bodyColor);
drawingObserver.startTracking();
g2d.fill(mainArea);
drawingObserver.stopTracking();
g2d.setComposite(oldComposite);
Color finalBorderColor;
if (outlineMode) {
+1 -1
View File
@@ -7,7 +7,7 @@
<parent>
<groupId>org.diylc</groupId>
<artifactId>diylc-parent</artifactId>
<version>5.3.0</version>
<version>5.4.0</version>
</parent>
<artifactId>diylc-swing</artifactId>
@@ -21,6 +21,7 @@ import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.ClipboardOwner;
import javax.swing.Icon;
import org.apache.log4j.Logger;
import org.diylc.swing.actions.analyze.AiAnalyzeAction;
import org.diylc.swing.actions.analyze.HighlightConnectedAreasAction;
import org.diylc.swingframework.IDrawingProvider;
@@ -275,6 +276,10 @@ public class ActionFactory {
return new GenerateNetlistAction(plugInPort, swingUI, includeSwitches);
}
public AiAnalyzeAction createAiAnalyzeAction(IPlugInPort plugInPort, ISwingUI swingUI) {
return new AiAnalyzeAction(plugInPort, swingUI);
}
public SummarizeNetlistAction createSummarizeNetlistAction(IPlugInPort plugInPort,
ISwingUI swingUI, INetlistAnalyzer summarizer, boolean includeSwitches) {
return new SummarizeNetlistAction(plugInPort, swingUI, summarizer, includeSwitches);
@@ -0,0 +1,59 @@
package org.diylc.swing.actions.analyze;
import org.diylc.common.INetlistAnalyzer;
import org.diylc.common.IPlugInPort;
import org.diylc.common.ITask;
import org.diylc.netlist.Netlist;
import org.diylc.netlist.Summary;
import org.diylc.swing.ISwingUI;
import org.diylc.swingframework.TextDialog;
import org.diylc.utils.IconLoader;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.List;
public class AiAnalyzeAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private IPlugInPort plugInPort;
private ISwingUI swingUI;
public AiAnalyzeAction(IPlugInPort plugInPort, ISwingUI swingUI) {
super();
this.plugInPort = plugInPort;
this.swingUI = swingUI;
putValue(AbstractAction.NAME, "AI Circuit Analyzer");
putValue(AbstractAction.SMALL_ICON, IconLoader.Brain.getIcon());
}
@Override
public void actionPerformed(ActionEvent e) {
swingUI.executeBackgroundTask(new ITask<String>() {
@Override
public String doInBackground() throws Exception {
return plugInPort.getChatbotService().analyzeCircuit();
}
@Override
public void failed(Exception e) {
swingUI.showMessage(e.getMessage(), "AI Circuit Analyzer", ISwingUI.ERROR_MESSAGE);
}
@Override
public void complete(String res) {
if (res == null || res.isEmpty()) {
swingUI.showMessage("The generated analysis is empty, nothing to show.",
"AI Circuit Analyzer", ISwingUI.INFORMATION_MESSAGE);
return;
}
new TextDialog(swingUI.getOwnerFrame().getRootPane(), res, "AI Circuit Analyzer",
new Dimension(800, 600)).setVisible(true);
}
}, true);
}
}
@@ -66,6 +66,7 @@ public class AnalyzeMenuPlugin implements IPlugIn {
List<Action> menuActions = new ArrayList<>();
// Add all menu actions to the list
menuActions.add(actionFactory.createAiAnalyzeAction(plugInPort, swingUI));
menuActions.add(actionFactory.createCheckProximityAction(plugInPort, swingUI));
menuActions.add(actionFactory.createBomAction(plugInPort));
menuActions.add(actionFactory.createGenerateNetlistAction(plugInPort, swingUI, false));
@@ -273,23 +273,40 @@ public class ChatbotPane extends JPanel {
getClearButton().setEnabled(false);
getPremiumButton().setVisible(false);
} else {
fetchChatHistory();
if (this.subscriptionInfo != null) {
getPremiumButton().setVisible(FREE_TIER.equals(this.subscriptionInfo.getTier()));
String subscriptionInfoText = "Your are currently subscribed to the '" + this.subscriptionInfo.getTier() + "' tier, expiring on " + this.subscriptionInfo.getEndDate() + ", with " + this.subscriptionInfo.getRemainingCredits() + " credits remaining.";
if (FREE_TIER.equals(this.subscriptionInfo.getTier())) {
subscriptionInfoText +=
" To subscribe to one of the premium tiers, unlock advanced AI models and get more credits, visit <a href='http://" + GET_PREMIUM_URL + "'>" + GET_PREMIUM_URL + "</a> and become a Patreon supporter. " +
"All the details about the AI Assistant limits and other benefits will be specified there. " +
"If you are already a Patreon supporter, make sure to link your account with the DIYLC Cloud account from the 'Cloud' menu.";
} else {
subscriptionInfoText += " Thank you for supporting further development of DIYLC!";
swingUI.executeBackgroundTask(new ITask<Void>() {
@Override
public Void doInBackground() throws Exception {
fetchChatHistory();
return null;
}
appendSection(ChatbotService.SYSTEM, subscriptionInfoText);
}
getAskButton().setEnabled(true);
getClearButton().setEnabled(true);
@Override
public void failed(Exception e) {
}
@Override
public void complete(Void result) {
if (ChatbotPane.this.subscriptionInfo != null) {
getPremiumButton().setVisible(FREE_TIER.equals(ChatbotPane.this.subscriptionInfo.getTier()));
String subscriptionInfoText = "Your are currently subscribed to the '" +
ChatbotPane.this.subscriptionInfo.getTier() + "' tier, expiring on " +
ChatbotPane.this.subscriptionInfo.getEndDate() + ", with " +
ChatbotPane.this.subscriptionInfo.getRemainingCredits() + " credits remaining.";
if (FREE_TIER.equals(ChatbotPane.this.subscriptionInfo.getTier())) {
subscriptionInfoText +=
" To subscribe to one of the premium tiers, unlock advanced AI models and get more credits, visit <a href='http://" + GET_PREMIUM_URL + "'>" + GET_PREMIUM_URL + "</a> and become a Patreon supporter. " +
"All the details about the AI Assistant limits and other benefits will be specified there. " +
"If you are already a Patreon supporter, make sure to link your account with the DIYLC Cloud account from the 'Cloud' menu.";
} else {
subscriptionInfoText += " Thank you for supporting further development of DIYLC!";
}
appendSection(ChatbotService.SYSTEM, subscriptionInfoText);
}
getAskButton().setEnabled(true);
getClearButton().setEnabled(true);
}
}, false);
}
// Scroll to the end of the chat pane
@@ -72,7 +72,7 @@ public enum IconLoader {
ComponentLarge("component_large.png"), ImportNetlist("import_netlist.png"), SplashIC("splash_ic.png"),
ComponentPreferences("component_preferences.png"), ComponentReplace("component_replace.png"), Barcode("barcode.png"),
DocumentGerber("document_gerber.png"), DocumentX2("document_x2.png"), Export("export.png"), Multimeter("multimeter.png"),
Patreon("patreon.png");
Patreon("patreon.png"), Brain("brain.png");
protected String name;
Binary file not shown.

After

Width:  |  Height:  |  Size: 802 B

+1 -1
View File
@@ -6,7 +6,7 @@
<groupId>org.diylc</groupId>
<artifactId>diylc-parent</artifactId>
<version>5.3.0</version>
<version>5.4.0</version>
<packaging>pom</packaging>
<name>DIY Layout Creator</name>
+44
View File
@@ -0,0 +1,44 @@
DELETE FROM diylc_knowledge_base WHERE section = 'Circuit Building Tips - Component placement';
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('Building', 'Circuit Building Tips - Component placement','
When designing a circuit layout, it''s a good practice to align the component placement with the signal path—typically from left to right, though the reverse can also work depending on the context. One key consideration is to keep AC power sources as far away from the signal path as possible to minimize noise and interference. A common strategy is to position the power supply on the opposite side of the board from the input and ensure that the DC supply flows in the opposite direction of the signal.
Components are often arranged perpendicular to the signal path. This orientation can help make efficient use of space while maintaining a clear flow of the circuit.
When working with integrated circuits—like in a Tubescreamer-style overdrive pedal—the same principles apply, although it can be a bit more challenging. A useful approach is to place the IC at the center of the layout and arrange surrounding components in a “bug-like” formation, radiating outward. This helps maintain logical signal flow and simplifies connections, especially in point-to-point builds.');
DELETE FROM diylc_knowledge_base WHERE section = 'Circuit Building Tips - Grounding scheme';
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('Building', 'Circuit Building Tips - Grounding scheme','
For both amplifiers and effects, a variation of the bus grounding scheme is often effective. The input jack should be grounded either through direct contact with the chassis or via a short ground lead to minimize noise at the entry point.
It''s a good idea to ground all stages of the amplifier in close proximity to each other, along with their corresponding filter capacitors. This approach resembles star grounding and helps reduce ground loops and hum.
When grounding control pots, it''s best to connect them to the bus near the stage they belong to. Keeping grounds local to each stage helps maintain a clean, stable ground reference throughout the circuit.');
DELETE FROM diylc_knowledge_base WHERE section = 'Circuit Building Tips - Lead dress';
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('Building', 'Circuit Building Tips - Lead dress','
Lead routing plays a critical role in minimizing noise. Keep the following guidelines in mind:
- Shorter is better: Keep leads as short as practical to reduce the chance of picking up interference.
- Separate AC and signal paths: Maintain as much distance as possible between leads carrying AC power and those carrying audio signals.
- Use orthogonal crossings: If AC and signal leads must cross, do so at right angles to minimize crosstalk.
- Respect signal levels: Avoid routing high-level signal leads close to low-level signal paths. If necessary, use shielded wire or route the leads orthogonally to each other.
Balancing these principles often involves compromise, but following them as closely as possible leads to cleaner, quieter builds.
');
DELETE FROM diylc_knowledge_base WHERE section = 'Circuit Building Tips - Shielded wire';
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('Building', 'Circuit Building Tips - Shielded wire','
Shielded wire can help eliminate noise and oscillations, especially in sensitive parts of a circuit. It’s most useful at the input, where low-level signals are especially vulnerable to interference. Since any noise picked up there will be amplified downstream, keeping this path clean is essential.
Generally, only one end of the shield should be grounded to avoid ground loops. However, in some cases—such as connecting a gain pot—it may be practical to ground both ends and use the shield as the ground conductor.
While shielded wire improves noise resistance, it’s harder to work with than standard wire. Teflon-coated shielded wire is a strong choice due to its durability and resistance to melting during soldering, though it''s less flexible than PVC-insulated wire.
Use shielded wire where it matters most, and route it thoughtfully—keeping input and output paths orthogonal and avoiding tight clusters with unrelated leads. This helps reduce crosstalk and keeps the layout clean and quiet.
');
DELETE FROM diylc_knowledge_base WHERE section = 'Circuit Building Tips - Twisted wire pair';
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('Building', 'Circuit Building Tips - Twisted wire pair','
Twisting wire pairs is a simple and effective technique for reducing noise in AC-carrying leads—such as tube heater lines or high-voltage secondaries. By twisting the wires tightly, electromagnetic radiation from one lead cancels out that of the other, helping to minimize interference.
To create a clean and consistent twist, place both wires in the chuck of a hand drill and twist slowly while holding the other end about 5 inches apart. This method produces uniform results in seconds and is far more effective than twisting by hand.
For best results, twists should be tight, uniform, and run parallel to the target route. Zip wire (parallel conductor cable) is also effective for AC lines, as it naturally maintains close and consistent spacing, which also aids in noise rejection.
As a general rule, keep AC leads well separated from sensitive signal paths and ensure good grounding practices—such as grounding central tube socket pins to a chassis lug—to further reduce noise and hum.');
DELETE FROM diylc_knowledge_base WHERE section = 'Circuit Building Tips - Shielding with Components and Materials';
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('Building', 'Circuit Building Tips - Shielding with Components and Materials', '
Effective shielding isn’t limited to wires—many components can serve as physical barriers to block noise. For example, transformers can act as shields when placed between noisy elements (like rectifier diodes) and sensitive circuitry. Grounding the transformer’s metal housing enhances this shielding effect.
Large electrolytic capacitors also serve a dual purpose. Since one terminal is grounded, they can be positioned between noise sources and signal paths to absorb interference.
Sheet metal, such as aluminum L-profiles, can be used to mount and simultaneously shield power transformers or tubes from other parts of the circuit. Even tube sockets may contribute—some include a central metal sleeve that can be grounded to help reduce pin-to-pin interference.
Pots also offer shielding when their bodies make contact with a grounded chassis. If using a painted enclosure, ensure bare metal contact by stripping paint around pot holes. Alternatively, grounding a bus wire across the pot backs works too—but avoid mixing both methods to prevent ground loops.
Strategic placement and grounding of these components can significantly reduce noise and improve circuit performance.');
+8
View File
@@ -288,3 +288,11 @@ There are several ways to create a new component:
- for more complex components that require custom appearance and behavior, you can create a new component from scratch using the Component API, as described in the [Component API](https://github.com/bancika/diy-layout-creator/blob/wiki/ComponentAPI.md) documentation
- you can file a component request on the [DIYLC GitHub repository](https://github.com/bancika/diy-layout-creator/issues) and I will implement it if I think it would be useful for other users without guaranteeing if and when it will be implemented
- you can reach out to me at [bancika@gmail.com](mailto:bancika@gmail.com) to sponsor a custom component for your project and expedite its development');
DELETE FROM diylc_knowledge_base WHERE section = 'User Manual - Panning/Moving the Screen/Canvas';
INSERT INTO diylc_knowledge_base(category, section, content) VALUES ('User Manual', 'Panning/Moving the Screen/Canvas','
There are several ways you can pan the screen/canvas and move around:
- horizontal and vertical scroll bars
- touch pad (if available)
- mouse scroll button (if available) - hold ctrl for horizontal scrolling
- click on the tiny "Auto-scroll" button in the bottom-right corner of the canvas to open a miniature version of the canvas and quickly jump to any part of it');