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