mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-07 12:24:58 +10:00
Added heat sink resistor
This commit is contained in:
@@ -4328,4 +4328,179 @@
|
||||
</org.diylc.core.Template>
|
||||
</list>
|
||||
</entry>
|
||||
<entry>
|
||||
<string>org.diylc.components.passive.HeatSinkResistor</string>
|
||||
<list>
|
||||
<org.diylc.core.Template>
|
||||
<name>HS10</name>
|
||||
<values>
|
||||
<entry><string>Value</string><null/></entry>
|
||||
<entry><string>Power Rating</string><org.diylc.core.measures.Power value="10.0" unit="W"/></entry>
|
||||
<entry><string>Length</string><org.diylc.core.measures.Size value="15.9" unit="mm"/></entry>
|
||||
<entry><string>Width</string><org.diylc.core.measures.Size value="16.5" unit="mm"/></entry>
|
||||
<entry><string>Lead Length</string><org.diylc.core.measures.Size value="7.05" unit="mm"/></entry>
|
||||
<entry><string>Lip Width</string><org.diylc.core.measures.Size value="4.1" unit="mm"/></entry>
|
||||
<entry><string>Mounting Holes</string><diylc.passive.HeatSinkResistor_-MountingHoleCount>TWO_DIAGONAL</diylc.passive.HeatSinkResistor_-MountingHoleCount></entry>
|
||||
<entry><string>Hole Spacing</string><org.diylc.core.measures.Size value="11.3" unit="mm"/></entry>
|
||||
<entry><string>Hole Diameter</string><org.diylc.core.measures.Size value="2.4" unit="mm"/></entry>
|
||||
<entry><string>Lead Diameter</string><org.diylc.core.measures.Size value="2.0" unit="mm"/></entry>
|
||||
</values>
|
||||
<points><point x="0.0" y="0.0"/><point x="1.181" y="0.0"/></points>
|
||||
<defaultFlag>false</defaultFlag>
|
||||
</org.diylc.core.Template>
|
||||
<org.diylc.core.Template>
|
||||
<name>HS15</name>
|
||||
<values>
|
||||
<entry><string>Value</string><null/></entry>
|
||||
<entry><string>Power Rating</string><org.diylc.core.measures.Power value="15.0" unit="W"/></entry>
|
||||
<entry><string>Length</string><org.diylc.core.measures.Size value="19.9" unit="mm"/></entry>
|
||||
<entry><string>Width</string><org.diylc.core.measures.Size value="21.0" unit="mm"/></entry>
|
||||
<entry><string>Lead Length</string><org.diylc.core.measures.Size value="8.3" unit="mm"/></entry>
|
||||
<entry><string>Lip Width</string><org.diylc.core.measures.Size value="5.1" unit="mm"/></entry>
|
||||
<entry><string>Mounting Holes</string><diylc.passive.HeatSinkResistor_-MountingHoleCount>TWO_DIAGONAL</diylc.passive.HeatSinkResistor_-MountingHoleCount></entry>
|
||||
<entry><string>Hole Spacing</string><org.diylc.core.measures.Size value="14.3" unit="mm"/></entry>
|
||||
<entry><string>Hole Diameter</string><org.diylc.core.measures.Size value="2.4" unit="mm"/></entry>
|
||||
<entry><string>Lead Diameter</string><org.diylc.core.measures.Size value="2.0" unit="mm"/></entry>
|
||||
</values>
|
||||
<points><point x="0.0" y="0.0"/><point x="1.437" y="0.0"/></points>
|
||||
<defaultFlag>false</defaultFlag>
|
||||
</org.diylc.core.Template>
|
||||
<org.diylc.core.Template>
|
||||
<name>HS25</name>
|
||||
<values>
|
||||
<entry><string>Value</string><null/></entry>
|
||||
<entry><string>Power Rating</string><org.diylc.core.measures.Power value="25.0" unit="W"/></entry>
|
||||
<entry><string>Length</string><org.diylc.core.measures.Size value="27.3" unit="mm"/></entry>
|
||||
<entry><string>Width</string><org.diylc.core.measures.Size value="28.0" unit="mm"/></entry>
|
||||
<entry><string>Lead Length</string><org.diylc.core.measures.Size value="11.85" unit="mm"/></entry>
|
||||
<entry><string>Lip Width</string><org.diylc.core.measures.Size value="8.2" unit="mm"/></entry>
|
||||
<entry><string>Mounting Holes</string><diylc.passive.HeatSinkResistor_-MountingHoleCount>TWO_DIAGONAL</diylc.passive.HeatSinkResistor_-MountingHoleCount></entry>
|
||||
<entry><string>Hole Spacing</string><org.diylc.core.measures.Size value="18.3" unit="mm"/></entry>
|
||||
<entry><string>Hole Diameter</string><org.diylc.core.measures.Size value="3.2" unit="mm"/></entry>
|
||||
<entry><string>Lead Diameter</string><org.diylc.core.measures.Size value="2.0" unit="mm"/></entry>
|
||||
</values>
|
||||
<points><point x="0.0" y="0.0"/><point x="2.008" y="0.0"/></points>
|
||||
<defaultFlag>true</defaultFlag>
|
||||
</org.diylc.core.Template>
|
||||
<org.diylc.core.Template>
|
||||
<name>HS50</name>
|
||||
<values>
|
||||
<entry><string>Value</string><null/></entry>
|
||||
<entry><string>Power Rating</string><org.diylc.core.measures.Power value="50.0" unit="W"/></entry>
|
||||
<entry><string>Length</string><org.diylc.core.measures.Size value="49.1" unit="mm"/></entry>
|
||||
<entry><string>Width</string><org.diylc.core.measures.Size value="29.7" unit="mm"/></entry>
|
||||
<entry><string>Lead Length</string><org.diylc.core.measures.Size value="11.7" unit="mm"/></entry>
|
||||
<entry><string>Lip Width</string><org.diylc.core.measures.Size value="8.3" unit="mm"/></entry>
|
||||
<entry><string>Mounting Holes</string><diylc.passive.HeatSinkResistor_-MountingHoleCount>TWO_DIAGONAL</diylc.passive.HeatSinkResistor_-MountingHoleCount></entry>
|
||||
<entry><string>Hole Spacing</string><org.diylc.core.measures.Size value="39.7" unit="mm"/></entry>
|
||||
<entry><string>Hole Diameter</string><org.diylc.core.measures.Size value="3.2" unit="mm"/></entry>
|
||||
<entry><string>Lead Diameter</string><org.diylc.core.measures.Size value="2.0" unit="mm"/></entry>
|
||||
</values>
|
||||
<points><point x="0.0" y="0.0"/><point x="2.854" y="0.0"/></points>
|
||||
<defaultFlag>false</defaultFlag>
|
||||
</org.diylc.core.Template>
|
||||
<org.diylc.core.Template>
|
||||
<name>HS75</name>
|
||||
<values>
|
||||
<entry><string>Value</string><null/></entry>
|
||||
<entry><string>Power Rating</string><org.diylc.core.measures.Power value="75.0" unit="W"/></entry>
|
||||
<entry><string>Length</string><org.diylc.core.measures.Size value="48.7" unit="mm"/></entry>
|
||||
<entry><string>Width</string><org.diylc.core.measures.Size value="47.5" unit="mm"/></entry>
|
||||
<entry><string>Lead Length</string><org.diylc.core.measures.Size value="11.65" unit="mm"/></entry>
|
||||
<entry><string>Lip Width</string><org.diylc.core.measures.Size value="10.5" unit="mm"/></entry>
|
||||
<entry><string>Mounting Holes</string><diylc.passive.HeatSinkResistor_-MountingHoleCount>FOUR</diylc.passive.HeatSinkResistor_-MountingHoleCount></entry>
|
||||
<entry><string>Hole Spacing</string><org.diylc.core.measures.Size value="29.0" unit="mm"/></entry>
|
||||
<entry><string>Hole Diameter</string><org.diylc.core.measures.Size value="4.4" unit="mm"/></entry>
|
||||
<entry><string>Lead Diameter</string><org.diylc.core.measures.Size value="3.2" unit="mm"/></entry>
|
||||
</values>
|
||||
<points><point x="0.0" y="0.0"/><point x="2.835" y="0.0"/></points>
|
||||
<defaultFlag>false</defaultFlag>
|
||||
</org.diylc.core.Template>
|
||||
<org.diylc.core.Template>
|
||||
<name>HS100</name>
|
||||
<values>
|
||||
<entry><string>Value</string><null/></entry>
|
||||
<entry><string>Power Rating</string><org.diylc.core.measures.Power value="100.0" unit="W"/></entry>
|
||||
<entry><string>Length</string><org.diylc.core.measures.Size value="65.2" unit="mm"/></entry>
|
||||
<entry><string>Width</string><org.diylc.core.measures.Size value="47.5" unit="mm"/></entry>
|
||||
<entry><string>Lead Length</string><org.diylc.core.measures.Size value="11.4" unit="mm"/></entry>
|
||||
<entry><string>Lip Width</string><org.diylc.core.measures.Size value="10.5" unit="mm"/></entry>
|
||||
<entry><string>Mounting Holes</string><diylc.passive.HeatSinkResistor_-MountingHoleCount>FOUR</diylc.passive.HeatSinkResistor_-MountingHoleCount></entry>
|
||||
<entry><string>Hole Spacing</string><org.diylc.core.measures.Size value="35.0" unit="mm"/></entry>
|
||||
<entry><string>Hole Diameter</string><org.diylc.core.measures.Size value="4.4" unit="mm"/></entry>
|
||||
<entry><string>Lead Diameter</string><org.diylc.core.measures.Size value="3.2" unit="mm"/></entry>
|
||||
</values>
|
||||
<points><point x="0.0" y="0.0"/><point x="3.465" y="0.0"/></points>
|
||||
<defaultFlag>false</defaultFlag>
|
||||
</org.diylc.core.Template>
|
||||
<org.diylc.core.Template>
|
||||
<name>HS150</name>
|
||||
<values>
|
||||
<entry><string>Value</string><null/></entry>
|
||||
<entry><string>Power Rating</string><org.diylc.core.measures.Power value="150.0" unit="W"/></entry>
|
||||
<entry><string>Length</string><org.diylc.core.measures.Size value="97.7" unit="mm"/></entry>
|
||||
<entry><string>Width</string><org.diylc.core.measures.Size value="47.5" unit="mm"/></entry>
|
||||
<entry><string>Lead Length</string><org.diylc.core.measures.Size value="11.65" unit="mm"/></entry>
|
||||
<entry><string>Lip Width</string><org.diylc.core.measures.Size value="10.5" unit="mm"/></entry>
|
||||
<entry><string>Mounting Holes</string><diylc.passive.HeatSinkResistor_-MountingHoleCount>SIX</diylc.passive.HeatSinkResistor_-MountingHoleCount></entry>
|
||||
<entry><string>Hole Spacing</string><org.diylc.core.measures.Size value="29.0" unit="mm"/></entry>
|
||||
<entry><string>Hole Diameter</string><org.diylc.core.measures.Size value="4.4" unit="mm"/></entry>
|
||||
<entry><string>Lead Diameter</string><org.diylc.core.measures.Size value="3.2" unit="mm"/></entry>
|
||||
</values>
|
||||
<points><point x="0.0" y="0.0"/><point x="4.764" y="0.0"/></points>
|
||||
<defaultFlag>false</defaultFlag>
|
||||
</org.diylc.core.Template>
|
||||
<org.diylc.core.Template>
|
||||
<name>HS200</name>
|
||||
<values>
|
||||
<entry><string>Value</string><null/></entry>
|
||||
<entry><string>Power Rating</string><org.diylc.core.measures.Power value="200.0" unit="W"/></entry>
|
||||
<entry><string>Length</string><org.diylc.core.measures.Size value="89.7" unit="mm"/></entry>
|
||||
<entry><string>Width</string><org.diylc.core.measures.Size value="72.5" unit="mm"/></entry>
|
||||
<entry><string>Lead Length</string><org.diylc.core.measures.Size value="28.0" unit="mm"/></entry>
|
||||
<entry><string>Lip Width</string><org.diylc.core.measures.Size value="15.3" unit="mm"/></entry>
|
||||
<entry><string>Mounting Holes</string><diylc.passive.HeatSinkResistor_-MountingHoleCount>SIX</diylc.passive.HeatSinkResistor_-MountingHoleCount></entry>
|
||||
<entry><string>Hole Spacing</string><org.diylc.core.measures.Size value="35.0" unit="mm"/></entry>
|
||||
<entry><string>Hole Diameter</string><org.diylc.core.measures.Size value="5.1" unit="mm"/></entry>
|
||||
<entry><string>Lead Diameter</string><org.diylc.core.measures.Size value="6.0" unit="mm"/></entry>
|
||||
</values>
|
||||
<points><point x="0.0" y="0.0"/><point x="5.736" y="0.0"/></points>
|
||||
<defaultFlag>false</defaultFlag>
|
||||
</org.diylc.core.Template>
|
||||
<org.diylc.core.Template>
|
||||
<name>HS250</name>
|
||||
<values>
|
||||
<entry><string>Value</string><null/></entry>
|
||||
<entry><string>Power Rating</string><org.diylc.core.measures.Power value="250.0" unit="W"/></entry>
|
||||
<entry><string>Length</string><org.diylc.core.measures.Size value="109.7" unit="mm"/></entry>
|
||||
<entry><string>Width</string><org.diylc.core.measures.Size value="72.5" unit="mm"/></entry>
|
||||
<entry><string>Lead Length</string><org.diylc.core.measures.Size value="28.65" unit="mm"/></entry>
|
||||
<entry><string>Lip Width</string><org.diylc.core.measures.Size value="15.3" unit="mm"/></entry>
|
||||
<entry><string>Mounting Holes</string><diylc.passive.HeatSinkResistor_-MountingHoleCount>SIX</diylc.passive.HeatSinkResistor_-MountingHoleCount></entry>
|
||||
<entry><string>Hole Spacing</string><org.diylc.core.measures.Size value="44.5" unit="mm"/></entry>
|
||||
<entry><string>Hole Diameter</string><org.diylc.core.measures.Size value="5.1" unit="mm"/></entry>
|
||||
<entry><string>Lead Diameter</string><org.diylc.core.measures.Size value="6.0" unit="mm"/></entry>
|
||||
</values>
|
||||
<points><point x="0.0" y="0.0"/><point x="6.575" y="0.0"/></points>
|
||||
<defaultFlag>false</defaultFlag>
|
||||
</org.diylc.core.Template>
|
||||
<org.diylc.core.Template>
|
||||
<name>HS300</name>
|
||||
<values>
|
||||
<entry><string>Value</string><null/></entry>
|
||||
<entry><string>Power Rating</string><org.diylc.core.measures.Power value="300.0" unit="W"/></entry>
|
||||
<entry><string>Length</string><org.diylc.core.measures.Size value="127.7" unit="mm"/></entry>
|
||||
<entry><string>Width</string><org.diylc.core.measures.Size value="72.5" unit="mm"/></entry>
|
||||
<entry><string>Lead Length</string><org.diylc.core.measures.Size value="28.35" unit="mm"/></entry>
|
||||
<entry><string>Lip Width</string><org.diylc.core.measures.Size value="13.5" unit="mm"/></entry>
|
||||
<entry><string>Mounting Holes</string><diylc.passive.HeatSinkResistor_-MountingHoleCount>SIX</diylc.passive.HeatSinkResistor_-MountingHoleCount></entry>
|
||||
<entry><string>Hole Spacing</string><org.diylc.core.measures.Size value="52.0" unit="mm"/></entry>
|
||||
<entry><string>Hole Diameter</string><org.diylc.core.measures.Size value="6.6" unit="mm"/></entry>
|
||||
<entry><string>Lead Diameter</string><org.diylc.core.measures.Size value="6.0" unit="mm"/></entry>
|
||||
</values>
|
||||
<points><point x="0.0" y="0.0"/><point x="7.260" y="0.0"/></points>
|
||||
<defaultFlag>false</defaultFlag>
|
||||
</org.diylc.core.Template>
|
||||
</list>
|
||||
</entry>
|
||||
</map>
|
||||
|
||||
@@ -297,6 +297,10 @@
|
||||
<releaseDate>2026-03-26 00:00:00.000 CET</releaseDate>
|
||||
<name></name>
|
||||
<changes>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>NEW_FEATURE</changeType>
|
||||
<description>Added new 'Heat Sink Resistor' component with a bunch of factory variants covering the most common types</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>NEW_FEATURE</changeType>
|
||||
<description>Added new 'Dial Scale' variations - 'Ticks + Numeric (0/5.5/11)' a'la Friedman and another variation of 'Ticks' with more pronounced 9/12/3 o'clock indices</description>
|
||||
|
||||
@@ -0,0 +1,532 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2025 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.components.passive;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
import org.diylc.appframework.miscutils.ConfigurationManager;
|
||||
import org.diylc.common.IPlugInPort;
|
||||
import org.diylc.common.ObjectCache;
|
||||
import org.diylc.components.AbstractLeadedComponent;
|
||||
import org.diylc.components.transform.SimpleComponentTransformer;
|
||||
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.annotations.PositiveMeasureValidator;
|
||||
import org.diylc.core.annotations.PositiveNonZeroMeasureValidator;
|
||||
import org.diylc.core.gerber.IGerberComponentSimple;
|
||||
import org.diylc.core.measures.Power;
|
||||
import org.diylc.core.measures.PowerUnit;
|
||||
import org.diylc.core.measures.Resistance;
|
||||
import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.Theme;
|
||||
import org.diylc.utils.Constants;
|
||||
|
||||
@ComponentDescriptor(name = "Heat Sink Resistor", author = "Branislav Stojkovic", category = "Passive",
|
||||
creationMethod = CreationMethod.SINGLE_CLICK, instanceNamePrefix = "R",
|
||||
description = "Power resistor with heatsink; similar to Arcol HS series",
|
||||
zOrder = IDIYComponent.COMPONENT, transformer = SimpleComponentTransformer.class, enableCache = true)
|
||||
public class HeatSinkResistor extends AbstractLeadedComponent<Resistance> implements IGerberComponentSimple {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** Horizontal fin lines on each side of the central label band (datasheet-style). */
|
||||
private static final int COOLING_FIN_LINES_EACH_SIDE = 6;
|
||||
/**
|
||||
* Fraction of fin-band height reserved for the middle (label) strip; fins share the rest equally
|
||||
* above and below.
|
||||
*/
|
||||
private static final double COOLING_FIN_LABEL_BAND_FRACTION = 0.35;
|
||||
|
||||
public static final Color HOUSING_COLOR = Color.decode("#c9a227");
|
||||
public static final Color HOUSING_BORDER = Color.decode("#8a7018");
|
||||
|
||||
public static Size DEFAULT_MOUNTING_HOLE_DIAMETER = new Size(3.2, SizeUnit.mm);
|
||||
public static Size DEFAULT_HORIZONTAL_HOLE_SPACING = new Size(18.3, SizeUnit.mm);
|
||||
public static Size DEFAULT_TERMINAL_LEAD_DIAMETER = new Size(2.0, SizeUnit.mm);
|
||||
public static Size DEFAULT_LEAD_LENGTH = new Size(11.85, SizeUnit.mm);
|
||||
public static Size DEFAULT_LIP_SIZE = new Size(7.0, SizeUnit.mm);
|
||||
public static Size DEFAULT_LENGTH = new Size(27.3, SizeUnit.mm);
|
||||
public static Size DEFAULT_WIDTH = new Size(28.0, SizeUnit.mm);
|
||||
|
||||
private Resistance value = null;
|
||||
private Power power;
|
||||
private MountingHoleCount mountingHoles = MountingHoleCount.TWO_DIAGONAL;
|
||||
/** L ±0.25 (mounting hole Ø). */
|
||||
private Size mountingHoleDiameter = DEFAULT_MOUNTING_HOLE_DIAMETER;
|
||||
/** F ±0.3 (hole spacing along body length). */
|
||||
private Size horizontalHoleSpacing = DEFAULT_HORIZONTAL_HOLE_SPACING;
|
||||
/** Lead Ø 2.0 ±0.25 mm per HS25 outline. */
|
||||
private Size terminalLeadDiameter = DEFAULT_TERMINAL_LEAD_DIAMETER;
|
||||
/** (B − E) / 2: overall length B=51 mm, body E=27.3 mm. */
|
||||
private Size leadLength = DEFAULT_LEAD_LENGTH;
|
||||
/**
|
||||
* Top/bottom lip thickness; main body height = A − 2 × lip = D (HS25: A=28, D=14 → lip 7 mm each).
|
||||
*/
|
||||
private Size lipSize = DEFAULT_LIP_SIZE;
|
||||
|
||||
public HeatSinkResistor() {
|
||||
super();
|
||||
bodyColor = HOUSING_COLOR;
|
||||
borderColor = HOUSING_BORDER;
|
||||
// HS25: E body length 27.3 mm, A total width 28 mm, B 51 mm with leads
|
||||
length = DEFAULT_LENGTH;
|
||||
width = DEFAULT_WIDTH;
|
||||
leadLength = DEFAULT_LEAD_LENGTH;
|
||||
}
|
||||
|
||||
private MountingHoleCount holeCount() {
|
||||
return mountingHoles == null ? MountingHoleCount.TWO_DIAGONAL : mountingHoles;
|
||||
}
|
||||
|
||||
/** Control points span body length plus one lead stub on each side. */
|
||||
private void repositionEndpointsToSpanBodyAndLeads() {
|
||||
Point2D[] pts = getPoints();
|
||||
if (pts.length < 2 || getLength() == null) {
|
||||
return;
|
||||
}
|
||||
Point2D p0 = pts[0];
|
||||
Point2D p1 = pts[1];
|
||||
double cx = (p0.getX() + p1.getX()) / 2.0;
|
||||
double cy = (p0.getY() + p1.getY()) / 2.0;
|
||||
double theta = Math.atan2(p1.getY() - p0.getY(), p1.getX() - p0.getX());
|
||||
double bodyL = getLength().convertToPixels();
|
||||
double ll = leadLength != null ? leadLength.convertToPixels() : 0;
|
||||
double half = bodyL / 2.0 + ll;
|
||||
p0.setLocation(cx - Math.cos(theta) * half, cy - Math.sin(theta) * half);
|
||||
p1.setLocation(cx + Math.cos(theta) * half, cy + Math.sin(theta) * half);
|
||||
pts[2] = calculateLabelPosition(p0, p1);
|
||||
}
|
||||
|
||||
/**
|
||||
* After default grid placement, expand pin span to body length + lead stubs on each side (see
|
||||
* {@link AbstractLeadedComponent#draw} lead length from control-point distance minus pin spacing).
|
||||
*/
|
||||
@Override
|
||||
public void createdIn(Project project) {
|
||||
super.createdIn(project);
|
||||
repositionEndpointsToSpanBodyAndLeads();
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Mounting Holes")
|
||||
public MountingHoleCount getMountingHoles() {
|
||||
return holeCount();
|
||||
}
|
||||
|
||||
public void setMountingHoles(MountingHoleCount mountingHoles) {
|
||||
this.mountingHoles = mountingHoles;
|
||||
}
|
||||
|
||||
@EditableProperty(validatorClass = PositiveMeasureValidator.class)
|
||||
public Resistance getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(Resistance value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Power Rating")
|
||||
public Power getPower() {
|
||||
return power;
|
||||
}
|
||||
|
||||
public void setPower(Power power) {
|
||||
this.power = power;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Hole Spacing", validatorClass = PositiveNonZeroMeasureValidator.class)
|
||||
public Size getHorizontalHoleSpacing() {
|
||||
return horizontalHoleSpacing;
|
||||
}
|
||||
|
||||
public void setHorizontalHoleSpacing(Size horizontalHoleSpacing) {
|
||||
this.horizontalHoleSpacing = horizontalHoleSpacing;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Hole Diameter", validatorClass = PositiveNonZeroMeasureValidator.class)
|
||||
public Size getMountingHoleDiameter() {
|
||||
return mountingHoleDiameter;
|
||||
}
|
||||
|
||||
public void setMountingHoleDiameter(Size mountingHoleDiameter) {
|
||||
this.mountingHoleDiameter = mountingHoleDiameter;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Lead Diameter", validatorClass = PositiveNonZeroMeasureValidator.class)
|
||||
public Size getTerminalLeadDiameter() {
|
||||
return terminalLeadDiameter;
|
||||
}
|
||||
|
||||
public void setTerminalLeadDiameter(Size terminalLeadDiameter) {
|
||||
this.terminalLeadDiameter = terminalLeadDiameter;
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Lead Length", validatorClass = PositiveNonZeroMeasureValidator.class)
|
||||
public Size getLeadLength() {
|
||||
return leadLength;
|
||||
}
|
||||
|
||||
public void setLeadLength(Size leadLength) {
|
||||
this.leadLength = leadLength;
|
||||
repositionEndpointsToSpanBodyAndLeads();
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Lip Width", validatorClass = PositiveNonZeroMeasureValidator.class)
|
||||
public Size getLipSize() {
|
||||
return lipSize;
|
||||
}
|
||||
|
||||
public void setLipSize(Size lipSize) {
|
||||
this.lipSize = lipSize;
|
||||
}
|
||||
|
||||
private double lipThicknessPixels() {
|
||||
if (lipSize == null) {
|
||||
return DEFAULT_LIP_SIZE.convertToPixels();
|
||||
}
|
||||
return lipSize.convertToPixels();
|
||||
}
|
||||
|
||||
private double horizontalHolePitchXPixels(double bodyL, int holeD, MountingHoleCount holes) {
|
||||
Size s = horizontalHoleSpacing != null ? horizontalHoleSpacing : DEFAULT_HORIZONTAL_HOLE_SPACING;
|
||||
double f = s.convertToPixels();
|
||||
double minF = Math.max(2.0 * holeD, 2.0);
|
||||
double maxSpan = Math.max(minF, bodyL - 2.0);
|
||||
double maxF = holes == MountingHoleCount.SIX ? maxSpan / 2.0 : maxSpan;
|
||||
return Math.min(maxF, Math.max(minF, f));
|
||||
}
|
||||
|
||||
/** Y centers of top and bottom lip strips (holes centered vertically in each lip). */
|
||||
private static double[] holeRowCentersYInLips(double lip, double totalW) {
|
||||
return new double[] {lip / 2.0, totalW - lip / 2.0};
|
||||
}
|
||||
|
||||
/** Lip thickness clamped so main band remains and holes fit. */
|
||||
private double clampedLipThickness(double totalW, int holeD) {
|
||||
double lip = Math.max(holeD, lipThicknessPixels());
|
||||
double maxLip = Math.max(holeD, (totalW - 1.0) / 2.0);
|
||||
return Math.min(lip, maxLip);
|
||||
}
|
||||
|
||||
/** {@code [lip, mainH]} matching {@link #getBodyShape()} after the minimum main-band clamp. */
|
||||
private double[] resolveLipGeometry(double totalW, int holeD) {
|
||||
double lipRaw = clampedLipThickness(totalW, holeD);
|
||||
double mainH = totalW - 2 * lipRaw;
|
||||
double lip = lipRaw;
|
||||
if (mainH < 1) {
|
||||
mainH = 1;
|
||||
lip = (totalW - mainH) / 2.0;
|
||||
}
|
||||
return new double[] {lip, mainH};
|
||||
}
|
||||
|
||||
/**
|
||||
* Full-length horizontal lines in the fin rectangle, six per side of the central band, evenly
|
||||
* spaced within each side (datasheet: seven intervals).
|
||||
*/
|
||||
private void drawCoolingFinLines(Graphics2D g2d, double bodyL, double lipTopY, double mainH, Color lineColor,
|
||||
float strokeWidth) {
|
||||
Stroke prev = g2d.getStroke();
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(strokeWidth));
|
||||
g2d.setColor(lineColor);
|
||||
int n = COOLING_FIN_LINES_EACH_SIDE;
|
||||
double band = mainH * COOLING_FIN_LABEL_BAND_FRACTION;
|
||||
double finZoneH = (mainH - band) / 2.0;
|
||||
if (finZoneH < 0.75) {
|
||||
g2d.setStroke(prev);
|
||||
return;
|
||||
}
|
||||
double step = finZoneH / (n + 1);
|
||||
for (int k = 1; k <= n; k++) {
|
||||
double y = lipTopY + step * k;
|
||||
g2d.draw(new Line2D.Double(0, y, bodyL, y));
|
||||
}
|
||||
double lower0 = lipTopY + finZoneH + band;
|
||||
for (int k = 1; k <= n; k++) {
|
||||
double y = lower0 + step * k;
|
||||
g2d.draw(new Line2D.Double(0, y, bodyL, y));
|
||||
}
|
||||
g2d.setStroke(prev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLength(Size length) {
|
||||
super.setLength(length);
|
||||
if (length != null) {
|
||||
repositionEndpointsToSpanBodyAndLeads();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWidth(Size width) {
|
||||
super.setWidth(width);
|
||||
if (width != null) {
|
||||
repositionEndpointsToSpanBodyAndLeads();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValueForDisplay() {
|
||||
String v = getValue() == null ? "" : getValue().toString();
|
||||
String p = getPower() == null ? "" : (" " + getPower().toString());
|
||||
return (v + p).trim();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPointMoveFreely(int pointIndex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Size getDefaultLength() {
|
||||
return DEFAULT_LENGTH;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Size getDefaultWidth() {
|
||||
return DEFAULT_WIDTH;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public boolean getMoveLabel() {
|
||||
return super.getMoveLabel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pin spacing along the lead axis equals {@link #getLength()} (body only); lead stubs are outside
|
||||
* the body shape.
|
||||
*/
|
||||
@Override
|
||||
protected int calculatePinSpacing(java.awt.Rectangle shapeRect) {
|
||||
if (getLength() == null) {
|
||||
return shapeRect.width;
|
||||
}
|
||||
return (int) Math.round(getLength().convertToPixels());
|
||||
}
|
||||
|
||||
/**
|
||||
* Use property length/width for body placement so it matches {@link #calculatePinSpacing} and lead
|
||||
* rendering (default {@code true} uses integer shape bounds and can zero-out leads).
|
||||
*/
|
||||
@Override
|
||||
protected boolean useShapeRectAsPosition() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getLeadThickness() {
|
||||
if (terminalLeadDiameter == null) {
|
||||
return super.getLeadThickness();
|
||||
}
|
||||
return getClosestOdd((float) terminalLeadDiameter.convertToPixels());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Shape getBodyShape() {
|
||||
double bodyL = Math.max(4.0, getLength().convertToPixels());
|
||||
double totalW = Math.max(4.0, getWidth().convertToPixels());
|
||||
int holeD = Math.max(1, (int) Math.round(mountingHoleDiameter.convertToPixels()));
|
||||
MountingHoleCount holes = holeCount();
|
||||
double fPx = horizontalHolePitchXPixels(bodyL, holeD, holes);
|
||||
double[] lg = resolveLipGeometry(totalW, holeD);
|
||||
double lip = lg[0];
|
||||
double mainH = lg[1];
|
||||
Area housing = buildLippedBody(bodyL, totalW, lip, mainH, holes, fPx);
|
||||
cutMountingHoles(housing, holes, bodyL, totalW, fPx, lip, holeD);
|
||||
return housing;
|
||||
}
|
||||
|
||||
/**
|
||||
* HS10–HS50 style: central fin band plus mounting tabs; tab length along body = body length − F
|
||||
* (flush with body ends), tab width = lip (same as top/bottom lip thickness). HS75+ style:
|
||||
* full-length top/bottom lips (datasheet E).
|
||||
*/
|
||||
private static Area buildLippedBody(double bodyL, double totalW, double lip, double mainH, MountingHoleCount holes,
|
||||
double fPx) {
|
||||
Area area = new Area();
|
||||
if (holes == MountingHoleCount.TWO_DIAGONAL) {
|
||||
area.add(new Area(new Rectangle2D.Double(0, lip, bodyL, mainH)));
|
||||
double tabAlongBody = Math.max(1.0, bodyL - fPx);
|
||||
double hcx = bodyL / 2.0;
|
||||
double[] rows = holeRowCentersYInLips(lip, totalW);
|
||||
double yTop = rows[0];
|
||||
double yBot = rows[1];
|
||||
addMountingTab(area, hcx + fPx / 2.0, yTop, tabAlongBody, lip);
|
||||
addMountingTab(area, hcx - fPx / 2.0, yBot, tabAlongBody, lip);
|
||||
} else {
|
||||
area.add(new Area(new Rectangle2D.Double(0, 0, bodyL, lip)));
|
||||
area.add(new Area(new Rectangle2D.Double(0, lip, bodyL, mainH)));
|
||||
area.add(new Area(new Rectangle2D.Double(0, totalW - lip, bodyL, lip)));
|
||||
}
|
||||
return area;
|
||||
}
|
||||
|
||||
/** Mounting tab rectangle, centered on the hole: extent along body × lip width. */
|
||||
private static void addMountingTab(Area area, double holeCx, double holeCy, double alongBody, double lipWidth) {
|
||||
area.add(new Area(new Rectangle2D.Double(holeCx - alongBody / 2.0, holeCy - lipWidth / 2.0, alongBody,
|
||||
lipWidth)));
|
||||
}
|
||||
|
||||
private void cutMountingHoles(Area housing, MountingHoleCount holes, double bodyL, double totalW, double fPx,
|
||||
double lip, int holeD) {
|
||||
double cx = bodyL / 2.0;
|
||||
double[] rows = holeRowCentersYInLips(lip, totalW);
|
||||
double yTop = rows[0];
|
||||
double yBot = rows[1];
|
||||
|
||||
switch (holes) {
|
||||
case TWO_DIAGONAL:
|
||||
cutHole(housing, cx + fPx / 2, yTop, holeD);
|
||||
cutHole(housing, cx - fPx / 2, yBot, holeD);
|
||||
break;
|
||||
case FOUR:
|
||||
cutHole(housing, cx - fPx / 2, yTop, holeD);
|
||||
cutHole(housing, cx + fPx / 2, yTop, holeD);
|
||||
cutHole(housing, cx - fPx / 2, yBot, holeD);
|
||||
cutHole(housing, cx + fPx / 2, yBot, holeD);
|
||||
break;
|
||||
case SIX:
|
||||
default:
|
||||
cutHole(housing, cx - fPx, yTop, holeD);
|
||||
cutHole(housing, cx + fPx, yTop, holeD);
|
||||
cutHole(housing, cx - fPx, yBot, holeD);
|
||||
cutHole(housing, cx + fPx, yBot, holeD);
|
||||
cutHole(housing, cx, yTop, holeD);
|
||||
cutHole(housing, cx, yBot, holeD);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void cutHole(Area housing, double x, double y, int holeD) {
|
||||
housing.subtract(new Area(new Ellipse2D.Double(x - holeD / 2.0, y - holeD / 2.0, holeD, holeD)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Union of lip + main + lip has no internal boundary for {@link #getBodyShape()}, so the border
|
||||
* stroke is only the outer rectangle. Draw seam lines at lip/main interfaces so the package reads
|
||||
* correctly (and matches drill-template intent).
|
||||
*/
|
||||
@Override
|
||||
protected boolean decorateAboveBorder() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decorateComponentBody(Graphics2D g2d, boolean outlineMode) {
|
||||
double bodyL = Math.max(4.0, getLength().convertToPixels());
|
||||
double totalW = Math.max(4.0, getWidth().convertToPixels());
|
||||
int holeD = Math.max(1, (int) Math.round(mountingHoleDiameter.convertToPixels()));
|
||||
double[] lg = resolveLipGeometry(totalW, holeD);
|
||||
double lip = lg[0];
|
||||
double mainH = lg[1];
|
||||
if (mainH < 0.5) {
|
||||
return;
|
||||
}
|
||||
float outlineStroke = getOutlineStrokeSize();
|
||||
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(outlineStroke));
|
||||
Color seam;
|
||||
if (outlineMode) {
|
||||
Theme theme =
|
||||
(Theme) ConfigurationManager.getInstance().readObject(IPlugInPort.THEME_KEY, Constants.DEFAULT_THEME);
|
||||
seam = theme.getOutlineColor();
|
||||
} else {
|
||||
seam = borderColor != null ? borderColor.darker() : HOUSING_BORDER.darker();
|
||||
}
|
||||
g2d.setColor(seam);
|
||||
g2d.draw(new Line2D.Double(0, lip, bodyL, lip));
|
||||
g2d.draw(new Line2D.Double(0, totalW - lip, bodyL, totalW - lip));
|
||||
float finStroke = Math.max(0.5f, outlineStroke * 0.55f);
|
||||
drawCoolingFinLines(g2d, bodyL, lip, mainH, seam, finStroke);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawIcon(Graphics2D g2d, int width, int height) {
|
||||
g2d.rotate(-Math.PI / 4, width / 2, height / 2);
|
||||
g2d.setColor(LEAD_COLOR_ICON);
|
||||
g2d.drawLine(0, height / 2, width, height / 2);
|
||||
|
||||
int bodyW = width / 2;
|
||||
int bodyH = height / 3;
|
||||
int finW = bodyW / 3;
|
||||
int finH = bodyH / 2;
|
||||
|
||||
int bx = (width - bodyW) / 2;
|
||||
int by = (height - bodyH) / 2;
|
||||
|
||||
Area a = new Area(new Rectangle2D.Double(bx, by, bodyW, bodyH));
|
||||
a.add(new Area(new Rectangle2D.Double(bx, by + bodyH, finW, finH)));
|
||||
a.add(new Area(new Rectangle2D.Double(bx + bodyW - finW, by - finH, finW, finH)));
|
||||
|
||||
int holeD = 2;
|
||||
a.subtract(new Area(new Ellipse2D.Double(bx + (finW - holeD) / 2.0, by + bodyH + (finH - holeD) / 2.0, holeD, holeD)));
|
||||
a.subtract(new Area(new Ellipse2D.Double(bx + bodyW - finW + (finW - holeD) / 2.0, by - finH + (finH - holeD) / 2.0, holeD, holeD)));
|
||||
|
||||
g2d.setColor(HOUSING_COLOR);
|
||||
g2d.fill(a);
|
||||
|
||||
g2d.setColor(HOUSING_BORDER.darker());
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
int ly = by + (int) (i * bodyH / 4.0);
|
||||
g2d.drawLine(bx, ly, bx + bodyW, ly);
|
||||
}
|
||||
|
||||
g2d.setColor(HOUSING_BORDER);
|
||||
g2d.draw(a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPolarized() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public enum MountingHoleCount {
|
||||
TWO_DIAGONAL("2 diagonal"),
|
||||
FOUR("4 holes"),
|
||||
SIX("6 holes");
|
||||
|
||||
private final String label;
|
||||
|
||||
MountingHoleCount(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return label;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user