From d3cd8c5e865318938f69e1b76dc848b178ac1339 Mon Sep 17 00:00:00 2001
From: Jamie Drinkell <94254558+M0JXD@users.noreply.github.com>
Date: Tue, 4 Oct 2022 12:51:47 +0100
Subject: [PATCH] New Components: Bulb, Stingray PKP + Correction: Battery
Symbol (#724)
* Change Icon Lead Colour
Icon lead colour changed to black to match other components.
* Add BulbSchematicSymbol
Add Bulb / Pilot Light / Lamp schematic symbol.
* Add StingrayBassPickup
Stingray Bass Pickup Option.
---
.../components/guitar/StingrayBassPickup.java | 337 ++++++++++++++++++
.../diylc/components/misc/BatterySymbol.java | 2 +-
.../components/misc/BulbSchematicSymbol.java | 142 ++++++++
3 files changed, 480 insertions(+), 1 deletion(-)
create mode 100644 diylc/diylc-library/src/org/diylc/components/guitar/StingrayBassPickup.java
create mode 100644 diylc/diylc-library/src/org/diylc/components/misc/BulbSchematicSymbol.java
diff --git a/diylc/diylc-library/src/org/diylc/components/guitar/StingrayBassPickup.java b/diylc/diylc-library/src/org/diylc/components/guitar/StingrayBassPickup.java
new file mode 100644
index 00000000..01904704
--- /dev/null
+++ b/diylc/diylc-library/src/org/diylc/components/guitar/StingrayBassPickup.java
@@ -0,0 +1,337 @@
+/*
+
+ DIY Layout Creator (DIYLC).
+ Copyright (c) 2009-2018 held jointly by the individual authors.
+
+ This file is part of DIYLC.
+
+ DIYLC is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ DIYLC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with DIYLC. If not, see .
+
+*/
+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.guitar.AbstractGuitarPickup.Polarity;
+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.annotations.ComponentDescriptor;
+import org.diylc.core.annotations.EditableProperty;
+import org.diylc.core.annotations.KeywordPolicy;
+import org.diylc.core.measures.Size;
+import org.diylc.core.measures.SizeUnit;
+import org.diylc.utils.Constants;
+
+@ComponentDescriptor(name = "Stingray Bass Pickup", category = "Guitar", author = "JD",
+ 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)
+
+/**
+ * Component type for Stingray Bass Humbucker
+ * Modified from the P Bass Pickup. Author: JD
+ * @author JD
+ */
+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_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 Color color = BODY_COLOR;
+ private Color poleColor = METAL_COLOR;
+
+ @Override
+ public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode,
+ 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]);
+ g2d.setComposite(oldComposite);
+
+ Color finalBorderColor;
+ if (outlineMode) {
+ Theme theme =
+ (Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME);
+ finalBorderColor =
+ componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
+ : theme.getOutlineColor();
+ } else {
+ finalBorderColor =
+ componentState == ComponentState.SELECTED || componentState == ComponentState.DRAGGING ? SELECTION_COLOR
+ : color.darker();
+ }
+
+ g2d.setColor(finalBorderColor);
+ g2d.draw(body[0]);
+ g2d.draw(body[1]);
+
+ if (!outlineMode) {
+ g2d.setColor(getPoleColor());
+ g2d.fill(body[3]);
+ g2d.setColor(darkerOrLighter(getPoleColor()));
+ 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);
+ }
+
+ @SuppressWarnings("incomplete-switch")
+ @Override
+ public Shape[] getBody() {
+ if (body == null) {
+ 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();
+ int lipHoleSpacing = getClosestOdd(LIP_HOLE_SPACING.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,
+ 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));
+ 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.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))));
+ 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));
+
+ // Poles
+
+ 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
+
+ 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);
+ // Bottom Row
+ 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
+ double theta = 0;
+ switch (orientation) {
+ case _90:
+ theta = Math.PI / 2;
+ break;
+ case _180:
+ theta = Math.PI;
+ break;
+ case _270:
+ theta = Math.PI * 3 / 2;
+ break;
+ }
+ // Do the rotation
+ AffineTransform rotation = AffineTransform.getRotateInstance(theta, x, y);
+ for (Shape shape : body) {
+ Area area = (Area) shape;
+ if (shape != null)
+ area.transform(rotation);
+ }
+ } // end if for rotation
+ } // end the if (body == null)
+ return body;
+ }
+
+ @Override
+ protected int getMainLabelYOffset() {
+ return (int) (WIDTH.convertToPixels() / 2 - 20);
+ }
+
+ @Override
+ public void drawIcon(Graphics2D g2d, int width, int height) {
+ g2d.rotate(Math.PI / 4, width / 2, height / 2);
+ int bodyWidth = (int) (14f * width / 32);
+ int bodyLength = (int) (26f * width / 32);
+
+ g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1f));
+ g2d.setColor(BODY_COLOR);
+ 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, 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.setColor(Color.gray);
+ // g2d.drawLine(width / 2, 4 * width / 32, width / 2, 4 * width / 32);
+ // g2d.drawLine(width / 2, height - 4 * width / 32, width / 2, height - 4 * width / 32);
+
+ g2d.setColor(METAL_COLOR);
+ int poleSize = 3;
+ 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((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);
+ }
+ }
+
+ @Override
+ protected OrientationHV getControlPointDirection() {
+ return OrientationHV.VERTICAL;
+ }
+
+ @EditableProperty
+ public Color getColor() {
+ return color;
+ }
+
+ public void setColor(Color color) {
+ this.color = color;
+ }
+
+ @EditableProperty(name = "Pole Color")
+ public Color getPoleColor() {
+ if (poleColor == null)
+ poleColor = METAL_COLOR;
+ return poleColor;
+ }
+
+ public void setPoleColor(Color poleColor) {
+ this.poleColor = poleColor;
+ }
+
+ @Override
+ public boolean isControlPointSticky(int index) {
+ return true;
+ }
+
+ @Override
+ public boolean isHumbucker() {
+ return true;
+ }
+
+ @Override
+ public Polarity getPolarity() {
+ // just to disable editor
+ return super.getPolarity();
+ }
+}
\ No newline at end of file
diff --git a/diylc/diylc-library/src/org/diylc/components/misc/BatterySymbol.java b/diylc/diylc-library/src/org/diylc/components/misc/BatterySymbol.java
index 045ac210..da8d210d 100644
--- a/diylc/diylc-library/src/org/diylc/components/misc/BatterySymbol.java
+++ b/diylc/diylc-library/src/org/diylc/components/misc/BatterySymbol.java
@@ -116,7 +116,7 @@ public class BatterySymbol extends AbstractSchematicLeadedSymbol {
public void drawIcon(Graphics2D g2d, int width, int height) {
g2d.rotate(-Math.PI / 4, width / 2, height / 2);
- g2d.setColor(COLOR);
+ g2d.setColor(LEAD_COLOR);
g2d.drawLine(0, height / 2, 13 * width / 32, height / 2); // draw leads
g2d.drawLine(width - 13 * width / 32, height / 2, width, height / 2);
g2d.setColor(COLOR);
diff --git a/diylc/diylc-library/src/org/diylc/components/misc/BulbSchematicSymbol.java b/diylc/diylc-library/src/org/diylc/components/misc/BulbSchematicSymbol.java
new file mode 100644
index 00000000..4a15300b
--- /dev/null
+++ b/diylc/diylc-library/src/org/diylc/components/misc/BulbSchematicSymbol.java
@@ -0,0 +1,142 @@
+/*
+
+ DIY Layout Creator (DIYLC).
+ Copyright (c) 2009-2018 held jointly by the individual authors.
+
+ This file is part of DIYLC.
+
+ DIYLC is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ DIYLC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with DIYLC. If not, see .
+
+*/
+package org.diylc.components.misc;
+
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Line2D;
+import org.diylc.components.AbstractSchematicLeadedSymbol;
+import org.diylc.core.CreationMethod;
+import org.diylc.core.IDIYComponent;
+import org.diylc.core.annotations.ComponentDescriptor;
+import org.diylc.core.annotations.EditableProperty;
+import org.diylc.core.measures.Size;
+import org.diylc.core.measures.SizeUnit;
+import org.diylc.core.measures.VoltageUnit;
+
+@ComponentDescriptor(name = "Bulb", author = "JD", category = "Schematic Symbols", creationMethod = CreationMethod.POINT_BY_POINT,
+ instanceNamePrefix = "LMP", description = "Bulb schematic symbol", zOrder = IDIYComponent.COMPONENT)
+
+/**
+ * Component type for Pilot Light/Bulb Schematic Symbol
+ * Modified from the Current Source Symbol component. Author: JD
+ * @author JD
+ */
+public class BulbSchematicSymbol extends AbstractSchematicLeadedSymbol {
+
+ private static final long serialVersionUID = 1L;
+ private String value = "Bulb / Pilot Light / Lamp Symbol";
+
+ // Overall size
+ public static Size DEFAULT_LENGTH = new Size(0.2, SizeUnit.in);
+ public static Size DEFAULT_WIDTH = new Size(0.2, SizeUnit.in);
+
+ // Sets filament voltage to 6.3V by default
+ private org.diylc.core.measures.Voltage voltageNew = new org.diylc.core.measures.Voltage(6.3d, VoltageUnit.V);
+
+ @Override
+ public String getValueForDisplay() {
+ return getValue().toString() + (getVoltageNew() == null ? "" : " " + getVoltageNew().toString());
+ }
+
+ @EditableProperty
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ @EditableProperty(name = "Filament Voltage")
+ public org.diylc.core.measures.Voltage getVoltageNew() {
+ return voltageNew;
+ }
+
+ public void setVoltageNew(org.diylc.core.measures.Voltage voltageNew) {
+ this.voltageNew = voltageNew;
+ }
+
+ @Override
+ protected Size getDefaultWidth() {
+ return DEFAULT_WIDTH;
+ }
+
+ @Override
+ protected Size getDefaultLength() {
+ return DEFAULT_LENGTH;
+ }
+
+ @Override
+ protected Shape getBodyShape() {
+ double width = getWidth().convertToPixels();
+ double length = getLength().convertToPixels();
+ GeneralPath body = new GeneralPath();
+ // Main body is a circle, drawn with an Ellipse
+ body.append(new Ellipse2D.Double(0d, 0d, width, length), true);
+ return (Shape) body;
+ }
+
+ @Override
+ protected void decorateComponentBody(Graphics2D g2d, boolean outlineMode) {
+ double width = getWidth().convertToPixels();
+ double height = getLength().convertToPixels();
+ g2d.setColor(getBorderColor());
+ // Draw cross inside main circle - 0.707 seems to have under-shoot on first coordinate? Maybe just me.
+ g2d.draw(new Line2D.Double(width / 2 - (0.707106 * width / 2), height / 2 - 0.707106 * (height / 2),
+ width / 2 + (0.707106 * width / 2), height / 2 + 0.707106 * height / 2));
+
+ g2d.draw(new Line2D.Double(width / 2 + (0.707106 * width / 2), height / 2 - (0.707106 * height / 2),
+ width / 2 - (0.707106 * width / 2), height / 2 + 0.707106 * height / 2));
+
+ }
+ public void drawIcon(Graphics2D g2d, int width, int height) {
+ g2d.rotate(-Math.PI / 4, width / 2, height / 2);
+ g2d.setColor(LEAD_COLOR);
+
+ // Draw Leads
+ g2d.draw(new Line2D.Double(0, height / 2, width / 4, height / 2));
+ g2d.draw(new Line2D.Double(width, height / 2, width * 0.75, height / 2));
+
+ // Draw Ellipse
+ g2d.setColor(COLOR);
+ double startx = width / 4;
+ double starty = height / 4;
+ g2d.draw(new Ellipse2D.Double(startx, starty, 0.5 * width, 0.5 * height));
+
+ // Draw Cross
+ // g2d.setStroke();
+
+ g2d.draw(new Line2D.Double(startx + width / 4 - 0.707 * (width / 4), starty + height / 4 - 0.707 * (height / 4),
+ startx + width / 4 + 0.707 * (width / 4), starty + height / 4 + 0.707 * height / 4));
+
+ g2d.draw(new Line2D.Double(startx + width / 4 + 0.707 * width / 4, starty + height / 4 - 0.707 * height / 4,
+ startx + width / 4 - 0.707 * width / 4, starty + height / 4 + 0.707 * height / 4));
+ }
+
+ @Override
+ public String getControlPointNodeName(int index) {
+ return getName() + "." + (index == 0 ? "+" : "-");
+ }
+}
\ No newline at end of file