esp boards

This commit is contained in:
Bane Stojkovic
2026-08-19 23:22:15 +02:00
parent d4ba10371d
commit 32aa766806
6 changed files with 787 additions and 62 deletions
@@ -21,14 +21,8 @@
*/
package org.diylc.components.micro;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.*;
import java.awt.geom.*;
import org.diylc.awt.StringUtils;
import org.diylc.common.HorizontalAlignment;
@@ -48,7 +42,7 @@ import org.diylc.core.measures.SizeUnit;
import org.diylc.utils.Constants;
@ComponentDescriptor(name = "ESP32 DevKit", category = "Controllers",
author = "Branislav Stojkovic", description = "ESP32 NodeMCU DevKit V1 Wi-Fi and Bluetooth Development Board",
author = "Branislav Stojkovic", description = "ESP32 DevKit V1 DOIT Wi-Fi and Bluetooth Development Board",
instanceNamePrefix = "MCU", zOrder = IDIYComponent.COMPONENT,
bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME,
enableCache = true)
@@ -57,8 +51,12 @@ public class ESP32DevKit extends AbstractMakerBoard {
private static final long serialVersionUID = 1L;
public static Color ESP_BLACK = Color.decode("#1E1E1E");
public static Size BOARD_WIDTH = new Size(28.5d, SizeUnit.mm);
public static Size BOARD_LENGTH = new Size(51.5d, SizeUnit.mm);
public static Size BOARD_WIDTH = new Size(28.2d, SizeUnit.mm);
public static Size BOARD_LENGTH = new Size(51.8d, SizeUnit.mm);
public static Size TOP_MARGIN = new Size(6.7d, SizeUnit.mm);
public static Size ANTENNA_LENGTH = new Size(6.2d, SizeUnit.mm);
public static Size ANTENNA_WIDTH = new Size(20.0d, SizeUnit.mm);
public static Size ROW_SPACING = new Size(0.9d, SizeUnit.in);
public static final String[] PIN_NAMES = new String[] {
// Left row (pins 0..14)
@@ -85,7 +83,7 @@ public class ESP32DevKit extends AbstractMakerBoard {
protected void updateControlPoints() {
Point2D firstPoint = controlPoints[0];
double spacing = PIN_SPACING.convertToPixels();
double rowSpacing = new Size(0.9d, SizeUnit.in).convertToPixels(); // 180px
double rowSpacing = ROW_SPACING.convertToPixels(); // 180px
double[][] relativeOffsets = new double[30][2];
for (int i = 0; i < 15; i++) {
@@ -105,11 +103,12 @@ public class ESP32DevKit extends AbstractMakerBoard {
Point2D p0 = controlPoints[0];
double x = p0.getX();
double y = p0.getY();
double rowSpacing = new Size(0.9d, SizeUnit.in).convertToPixels();
double boardW = rowSpacing + 26;
double boardH = 16 * PIN_SPACING.convertToPixels();
double boardX = x - 13;
double boardY = y - 10;
double rowSpacing = ROW_SPACING.convertToPixels();
double boardW = BOARD_WIDTH.convertToPixels();
double boardH = BOARD_LENGTH.convertToPixels();
double topMargin = TOP_MARGIN.convertToPixels();
double boardX = (x + rowSpacing / 2.0) - boardW / 2.0;
double boardY = y - topMargin;
return new RoundRectangle2D.Double(boardX, boardY, boardW, boardH, 8, 8);
}
@@ -129,11 +128,17 @@ public class ESP32DevKit extends AbstractMakerBoard {
g2d.rotate(orientation.toRadians(), x, y);
}
double rowSpacing = new Size(0.9d, SizeUnit.in).convertToPixels();
double boardW = rowSpacing + 26;
double boardH = 16 * PIN_SPACING.convertToPixels();
double boardX = x - 13;
double boardY = y - 10;
double rowSpacing = ROW_SPACING.convertToPixels();
double boardW = BOARD_WIDTH.convertToPixels();
double boardH = BOARD_LENGTH.convertToPixels();
double topMargin = TOP_MARGIN.convertToPixels();
double boardX = (x + rowSpacing / 2.0) - boardW / 2.0;
double boardY = y - topMargin;
double antennaW = ANTENNA_WIDTH.convertToPixels();
double antennaH = ANTENNA_LENGTH.convertToPixels();
double antennaX = (x + rowSpacing / 2.0) - antennaW / 2.0;
double antennaY = boardY;
Shape boardShape = getBodyShape();
@@ -149,28 +154,80 @@ public class ESP32DevKit extends AbstractMakerBoard {
g2d.draw(boardShape);
if (!outlineMode) {
// Micro-USB Jack at bottom
drawMetalConnector(g2d, boardX + (boardW - 60) / 2.0, boardY + boardH - 25, 60, 35, "USB");
// 4 Corner Mounting Holes (diameter 2.8mm)
double holeDiameter = new Size(2.8d, SizeUnit.mm).convertToPixels();
double topHoleY = boardY + new Size(3.5d, SizeUnit.mm).convertToPixels();
double bottomHoleY = boardY + boardH - new Size(3.5d, SizeUnit.mm).convertToPixels();
double leftHoleX = x;
double rightHoleX = x + rowSpacing;
// ESP-WROOM-32 metal shield module with PCB antenna at top
drawMetalConnector(g2d, boardX + 15, boardY + 40, boardW - 30, 120, "ESP-WROOM-32");
drawMountingHole(g2d, leftHoleX, topHoleY, holeDiameter);
drawMountingHole(g2d, rightHoleX, topHoleY, holeDiameter);
drawMountingHole(g2d, leftHoleX, bottomHoleY, holeDiameter);
drawMountingHole(g2d, rightHoleX, bottomHoleY, holeDiameter);
// PCB antenna trace area (gold/copper)
// Antenna trace (gold/copper serpentine PCB trace)
g2d.setColor(Color.decode("#DAA520"));
g2d.fillRect((int) (boardX + 25), (int) (boardY + 10), (int) (boardW - 50), 20);
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1.5f));
Path2D.Double antPath = new Path2D.Double();
double antPadX = antennaX + 16;
double antPadW = antennaW - 32;
double antTopY = antennaY + 10;
double antMidY = antennaY + antennaH - 12;
antPath.moveTo(antPadX, antMidY);
antPath.lineTo(antPadX, antTopY);
antPath.lineTo(antPadX + antPadW * 0.25, antTopY);
antPath.lineTo(antPadX + antPadW * 0.25, antMidY);
antPath.lineTo(antPadX + antPadW * 0.50, antMidY);
antPath.lineTo(antPadX + antPadW * 0.50, antTopY);
antPath.lineTo(antPadX + antPadW * 0.75, antTopY);
antPath.lineTo(antPadX + antPadW * 0.75, antMidY);
antPath.lineTo(antPadX + antPadW, antMidY);
antPath.lineTo(antPadX + antPadW, antTopY);
g2d.draw(antPath);
// ESP32-WROOM-32 metal shield module below antenna
double shieldW = new Size(18.0d, SizeUnit.mm).convertToPixels();
double shieldH = new Size(18.0d, SizeUnit.mm).convertToPixels();
double shieldX = (x + rowSpacing / 2.0) - shieldW / 2.0;
double shieldY = boardY + antennaH;
drawMetalConnector(g2d, shieldX, shieldY, shieldW, shieldH, "ESP32-WROOM-32");
// Micro-USB Jack at bottom
double usbW = 58;
double usbH = 34;
double usbX = (x + rowSpacing / 2.0) - usbW / 2.0;
double usbY = boardY + boardH - 22;
drawMetalConnector(g2d, usbX, usbY, usbW, usbH, "USB");
// EN & BOOT tactile buttons at bottom (flanking the Micro-USB port)
double btnW = 20;
double btnH = 20;
double btnY = boardY + boardH - 25;
double shift1mm = new Size(1.0d, SizeUnit.mm).convertToPixels();
double btnLeftX = leftHoleX + 14 + shift1mm;
double btnRightX = rightHoleX - 14 - shift1mm - btnW;
g2d.setColor(Color.decode("#383838"));
g2d.fill(new RoundRectangle2D.Double(btnLeftX, btnY, btnW, btnH, 3, 3));
g2d.fill(new RoundRectangle2D.Double(btnRightX, btnY, btnW, btnH, 3, 3));
g2d.setColor(Color.decode("#666666"));
g2d.draw(new RoundRectangle2D.Double(btnLeftX, btnY, btnW, btnH, 3, 3));
g2d.draw(new RoundRectangle2D.Double(btnRightX, btnY, btnW, btnH, 3, 3));
// Button actuators
g2d.setColor(Color.decode("#A0A0A0"));
g2d.fillOval((int) (btnLeftX + btnW / 2.0 - 4), (int) (btnY + btnH / 2.0 - 4), 8, 8);
g2d.fillOval((int) (btnRightX + btnW / 2.0 - 4), (int) (btnY + btnH / 2.0 - 4), 8, 8);
// EN & BOOT buttons
g2d.setColor(Color.decode("#444444"));
g2d.fill(new RoundRectangle2D.Double(boardX + 15, boardY + boardH - 45, 25, 18, 3, 3));
g2d.fill(new RoundRectangle2D.Double(boardX + boardW - 40, boardY + boardH - 45, 25, 18, 3, 3));
g2d.setColor(Color.WHITE);
g2d.setFont(SILK_FONT_SMALL);
StringUtils.drawCenteredText(g2d, "EN", boardX + 27, boardY + boardH - 36, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
StringUtils.drawCenteredText(g2d, "BOOT", boardX + boardW - 28, boardY + boardH - 36, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
StringUtils.drawCenteredText(g2d, "EN", btnLeftX + btnW / 2.0, btnY - 8, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
StringUtils.drawCenteredText(g2d, "BOOT", btnRightX + btnW / 2.0, btnY - 8, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
// Silkscreen
g2d.setFont(SILK_FONT);
StringUtils.drawCenteredText(g2d, "ESP32", boardX + boardW / 2.0, boardY + 190, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
StringUtils.drawCenteredText(g2d, "ESP32", x + rowSpacing / 2.0, shieldY + shieldH + 45, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
}
g2d.setTransform(oldTx);
@@ -0,0 +1,273 @@
/*
*
* 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.micro;
import org.diylc.awt.StringUtils;
import org.diylc.common.HorizontalAlignment;
import org.diylc.common.ObjectCache;
import org.diylc.common.Orientation;
import org.diylc.common.VerticalAlignment;
import org.diylc.components.AbstractMakerBoard;
import org.diylc.core.ComponentState;
import org.diylc.core.IDIYComponent;
import org.diylc.core.IDrawingObserver;
import org.diylc.core.Project;
import org.diylc.core.annotations.BomPolicy;
import org.diylc.core.annotations.ComponentDescriptor;
import org.diylc.core.annotations.KeywordPolicy;
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 = "ESP32 DevKitC", category = "Controllers",
author = "Branislav Stojkovic", description = "ESP32 DevKitC V4 Wi-Fi and Bluetooth Development Board",
instanceNamePrefix = "MCU", zOrder = IDIYComponent.COMPONENT,
bomPolicy = BomPolicy.SHOW_ONLY_TYPE_NAME, keywordPolicy = KeywordPolicy.SHOW_TYPE_NAME,
enableCache = true)
public class ESP32DevKitC extends AbstractMakerBoard {
private static final long serialVersionUID = 1L;
public static Color ESP_BLACK = Color.decode("#1E1E1E");
public static Size BOARD_WIDTH = new Size(27.9d, SizeUnit.mm);
public static Size BOARD_LENGTH = new Size(54.4d, SizeUnit.mm);
public static Size MAIN_BODY_LENGTH = new Size(48.2d, SizeUnit.mm);
public static Size ANTENNA_LENGTH = new Size(6.2d, SizeUnit.mm);
public static Size ANTENNA_WIDTH = new Size(20.0d, SizeUnit.mm);
public static Size ROW_SPACING = new Size(1.0d, SizeUnit.in);
public static final String[] PIN_NAMES = new String[] {
// Left row (pins 0..18, top to bottom)
"3V3", "EN", "VP (GPIO36)", "VN (GPIO39)", "GPIO34", "GPIO35", "GPIO32", "GPIO33",
"GPIO25", "GPIO26", "GPIO27", "GPIO14", "GPIO12", "GND1", "GPIO13",
"D2 (GPIO9)", "D3 (GPIO10)", "CMD (GPIO11)", "5V",
// Right row (pins 19..37, top to bottom)
"GND2", "GPIO23", "GPIO22", "TX0 (GPIO1)", "RX0 (GPIO3)", "GPIO21", "GND3",
"GPIO19", "GPIO18", "GPIO5", "GPIO17", "GPIO16", "GPIO4", "GPIO0", "GPIO2",
"GPIO15", "D1 (GPIO8)", "D0 (GPIO7)", "CLK (GPIO6)"
};
public ESP32DevKitC() {
super();
this.bodyColor = ESP_BLACK;
updateControlPoints();
}
@Override
public String getControlPointNodeName(int index) {
if (index >= 0 && index < PIN_NAMES.length) {
return PIN_NAMES[index];
}
return "Pin " + (index + 1);
}
@Override
protected void updateControlPoints() {
Point2D firstPoint = controlPoints[0];
double spacing = PIN_SPACING.convertToPixels();
double rowSpacing = ROW_SPACING.convertToPixels();
double[][] relativeOffsets = new double[PIN_NAMES.length][2];
for (int i = 0; i < 19; i++) {
relativeOffsets[i][0] = 0;
relativeOffsets[i][1] = i * spacing;
}
for (int i = 0; i < 19; i++) {
relativeOffsets[19 + i][0] = rowSpacing;
relativeOffsets[19 + i][1] = i * spacing;
}
rotatePoints(firstPoint, relativeOffsets);
}
@Override
public Shape getBodyShape() {
Point2D p0 = controlPoints[0];
double x = p0.getX();
double y = p0.getY();
double rowSpacing = ROW_SPACING.convertToPixels();
double mainW = BOARD_WIDTH.convertToPixels();
double mainH = MAIN_BODY_LENGTH.convertToPixels();
double antennaW = ANTENNA_WIDTH.convertToPixels();
double antennaH = ANTENNA_LENGTH.convertToPixels();
double mainX = (x + rowSpacing / 2.0) - mainW / 2.0;
double mainY = (y + 18 * PIN_SPACING.convertToPixels() / 2.0) - mainH / 2.0;
double antennaX = (x + rowSpacing / 2.0) - antennaW / 2.0;
double antennaY = mainY - antennaH;
Area bodyArea = new Area(new RoundRectangle2D.Double(mainX, mainY, mainW, mainH, 8, 8));
bodyArea.add(new Area(new Rectangle2D.Double(antennaX, antennaY, antennaW, antennaH + 1)));
return bodyArea;
}
@Override
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
IDrawingObserver drawingObserver) {
if (checkPointsClipped(g2d.getClip())) {
return;
}
Point2D p0 = controlPoints[0];
double x = p0.getX();
double y = p0.getY();
AffineTransform oldTx = g2d.getTransform();
if (orientation != Orientation.DEFAULT) {
g2d.rotate(orientation.toRadians(), x, y);
}
double rowSpacing = ROW_SPACING.convertToPixels();
double mainW = BOARD_WIDTH.convertToPixels();
double mainH = MAIN_BODY_LENGTH.convertToPixels();
double antennaW = ANTENNA_WIDTH.convertToPixels();
double antennaH = ANTENNA_LENGTH.convertToPixels();
double mainX = (x + rowSpacing / 2.0) - mainW / 2.0;
double mainY = (y + 18 * PIN_SPACING.convertToPixels() / 2.0) - mainH / 2.0;
double antennaX = (x + rowSpacing / 2.0) - antennaW / 2.0;
double antennaY = mainY - antennaH;
Shape boardShape = getBodyShape();
Composite oldComposite = applyAlpha(g2d, componentState);
drawingObserver.startTracking();
if (outlineMode) {
g2d.setColor(Constants.TRANSPARENT_COLOR);
g2d.fill(boardShape);
} else {
// Main board body
g2d.setColor(bodyColor);
g2d.fill(new RoundRectangle2D.Double(mainX, mainY, mainW, mainH, 8, 8));
// Antenna tab in slightly lighter color
Color antennaColor = new Color(
Math.min(255, bodyColor.getRed() + 32),
Math.min(255, bodyColor.getGreen() + 32),
Math.min(255, bodyColor.getBlue() + 32)
);
g2d.setColor(antennaColor);
g2d.fill(new Rectangle2D.Double(antennaX, antennaY, antennaW, antennaH));
}
drawingObserver.stopTracking();
// Outline border around the full board
g2d.setColor(getFinalBorderColor(componentState, outlineMode));
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1.5f));
g2d.draw(boardShape);
if (!outlineMode) {
// Antenna trace (gold/copper serpentine PCB trace)
g2d.setColor(Color.decode("#DAA520"));
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1.5f));
Path2D.Double antPath = new Path2D.Double();
double antPadX = antennaX + 16;
double antPadW = antennaW - 32;
double antTopY = antennaY + 10;
double antMidY = antennaY + antennaH - 12;
antPath.moveTo(antPadX, antMidY);
antPath.lineTo(antPadX, antTopY);
antPath.lineTo(antPadX + antPadW * 0.25, antTopY);
antPath.lineTo(antPadX + antPadW * 0.25, antMidY);
antPath.lineTo(antPadX + antPadW * 0.50, antMidY);
antPath.lineTo(antPadX + antPadW * 0.50, antTopY);
antPath.lineTo(antPadX + antPadW * 0.75, antTopY);
antPath.lineTo(antPadX + antPadW * 0.75, antMidY);
antPath.lineTo(antPadX + antPadW, antMidY);
antPath.lineTo(antPadX + antPadW, antTopY);
g2d.draw(antPath);
// Micro-USB Jack at bottom
double usbW = 58;
double usbH = 34;
double usbX = (x + rowSpacing / 2.0) - usbW / 2.0;
double usbY = mainY + mainH - 22;
drawMetalConnector(g2d, usbX, usbY, usbW, usbH, "USB");
// ESP32-WROOM-32 metal shield module below antenna
double shieldW = new Size(18.0d, SizeUnit.mm).convertToPixels();
double shieldH = new Size(18.0d, SizeUnit.mm).convertToPixels();
double shieldX = (x + rowSpacing / 2.0) - shieldW / 2.0;
double shieldY = mainY + 10;
drawMetalConnector(g2d, shieldX, shieldY, shieldW, shieldH, "ESP32-WROOM-32");
// EN & BOOT tactile buttons at bottom (flanking the Micro-USB port)
double btnW = 20;
double btnH = 20;
double btnY = mainY + mainH - 25;
double btnLeftX = mainX + 38;
double btnRightX = mainX + mainW - 38 - btnW;
g2d.setColor(Color.decode("#383838"));
g2d.fill(new RoundRectangle2D.Double(btnLeftX, btnY, btnW, btnH, 3, 3));
g2d.fill(new RoundRectangle2D.Double(btnRightX, btnY, btnW, btnH, 3, 3));
g2d.setColor(Color.decode("#666666"));
g2d.draw(new RoundRectangle2D.Double(btnLeftX, btnY, btnW, btnH, 3, 3));
g2d.draw(new RoundRectangle2D.Double(btnRightX, btnY, btnW, btnH, 3, 3));
// Button actuators
g2d.setColor(Color.decode("#A0A0A0"));
g2d.fillOval((int) (btnLeftX + btnW / 2.0 - 4), (int) (btnY + btnH / 2.0 - 4), 8, 8);
g2d.fillOval((int) (btnRightX + btnW / 2.0 - 4), (int) (btnY + btnH / 2.0 - 4), 8, 8);
g2d.setColor(Color.WHITE);
g2d.setFont(SILK_FONT_SMALL);
StringUtils.drawCenteredText(g2d, "EN", btnLeftX + btnW / 2.0, btnY - 8, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
StringUtils.drawCenteredText(g2d, "BOOT", btnRightX + btnW / 2.0, btnY - 8, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
// Silkscreen
g2d.setFont(SILK_FONT);
StringUtils.drawCenteredText(g2d, "ESP32", x + rowSpacing / 2.0, mainY + shieldH + 45, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
}
g2d.setTransform(oldTx);
drawPins(g2d, 0, controlPoints.length, false, outlineMode, drawingObserver);
g2d.setComposite(oldComposite);
}
@Override
public void drawIcon(Graphics2D g2d, int width, int height) {
g2d.setColor(ESP_BLACK);
g2d.fill(new RoundRectangle2D.Double(5, 6, width - 10, height - 8, 3, 3));
// Antenna tab
g2d.setColor(Color.decode("#383838"));
g2d.fillRect(8, 2, width - 16, 5);
g2d.setColor(Color.GRAY);
g2d.draw(new RoundRectangle2D.Double(5, 6, width - 10, height - 8, 3, 3));
// Metal shield
g2d.setColor(METAL_SHIELD_COLOR);
g2d.fillRect(8, 9, width - 16, 10);
g2d.setColor(Color.WHITE);
g2d.setFont(new Font("SansSerif", Font.BOLD, 5));
StringUtils.drawCenteredText(g2d, "ESP32", width / 2, height / 2 + 8, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
}
}
@@ -27,6 +27,7 @@ import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.awt.geom.RoundRectangle2D;
@@ -56,9 +57,16 @@ public class ESP8266NodeMCU extends AbstractMakerBoard {
private static final long serialVersionUID = 1L;
public static Color NODEMCU_BLACK = Color.decode("#1C1C1C");
public static Size BOARD_WIDTH = new Size(25.4d, SizeUnit.mm);
public static Size BOARD_LENGTH = new Size(48.3d, SizeUnit.mm);
public static Color NODEMCU_BLACK = Color.decode("#1E1E1E");
public static Size BOARD_WIDTH = new Size(25.7d, SizeUnit.mm);
public static Size BOARD_LENGTH = new Size(48.0d, SizeUnit.mm);
public static Size TOP_MARGIN = new Size(6.22d, SizeUnit.mm);
public static Size ANTENNA_LENGTH = new Size(6.0d, SizeUnit.mm);
public static Size ANTENNA_WIDTH = new Size(16.0d, SizeUnit.mm);
public static Size ROW_SPACING = new Size(0.9d, SizeUnit.in);
public static Size HOLE_DISTANCE_X = new Size(21.0d, SizeUnit.mm);
public static Size HOLE_DISTANCE_Y = new Size(44.0d, SizeUnit.mm);
public static Size HOLE_DIAMETER = new Size(3.2d, SizeUnit.mm);
public static final String[] PIN_NAMES = new String[] {
// Left row (pins 0..14)
@@ -85,7 +93,7 @@ public class ESP8266NodeMCU extends AbstractMakerBoard {
protected void updateControlPoints() {
Point2D firstPoint = controlPoints[0];
double spacing = PIN_SPACING.convertToPixels();
double rowSpacing = new Size(0.9d, SizeUnit.in).convertToPixels(); // 180px
double rowSpacing = ROW_SPACING.convertToPixels(); // 180px
double[][] relativeOffsets = new double[30][2];
for (int i = 0; i < 15; i++) {
@@ -105,11 +113,12 @@ public class ESP8266NodeMCU extends AbstractMakerBoard {
Point2D p0 = controlPoints[0];
double x = p0.getX();
double y = p0.getY();
double rowSpacing = new Size(0.9d, SizeUnit.in).convertToPixels();
double boardW = rowSpacing + 26;
double boardH = 16 * PIN_SPACING.convertToPixels();
double boardX = x - 13;
double boardY = y - 10;
double rowSpacing = ROW_SPACING.convertToPixels();
double boardW = BOARD_WIDTH.convertToPixels();
double boardH = BOARD_LENGTH.convertToPixels();
double topMargin = TOP_MARGIN.convertToPixels();
double boardX = (x + rowSpacing / 2.0) - boardW / 2.0;
double boardY = y - topMargin;
return new RoundRectangle2D.Double(boardX, boardY, boardW, boardH, 8, 8);
}
@@ -129,11 +138,17 @@ public class ESP8266NodeMCU extends AbstractMakerBoard {
g2d.rotate(orientation.toRadians(), x, y);
}
double rowSpacing = new Size(0.9d, SizeUnit.in).convertToPixels();
double boardW = rowSpacing + 26;
double boardH = 16 * PIN_SPACING.convertToPixels();
double boardX = x - 13;
double boardY = y - 10;
double rowSpacing = ROW_SPACING.convertToPixels();
double boardW = BOARD_WIDTH.convertToPixels();
double boardH = BOARD_LENGTH.convertToPixels();
double topMargin = TOP_MARGIN.convertToPixels();
double boardX = (x + rowSpacing / 2.0) - boardW / 2.0;
double boardY = y - topMargin;
double antennaW = ANTENNA_WIDTH.convertToPixels();
double antennaH = ANTENNA_LENGTH.convertToPixels();
double antennaX = (x + rowSpacing / 2.0) - antennaW / 2.0;
double antennaY = boardY + new Size(1.0d, SizeUnit.mm).convertToPixels();
Shape boardShape = getBodyShape();
@@ -149,28 +164,88 @@ public class ESP8266NodeMCU extends AbstractMakerBoard {
g2d.draw(boardShape);
if (!outlineMode) {
// Micro-USB Jack at bottom
drawMetalConnector(g2d, boardX + (boardW - 60) / 2.0, boardY + boardH - 20, 60, 30, "USB");
// 4 Corner Mounting Holes (diameter 3.2mm, spaced 44mm lengthwise, 21mm widthwise)
double holeDiameter = HOLE_DIAMETER.convertToPixels();
double holeDistX = HOLE_DISTANCE_X.convertToPixels();
double holeDistY = HOLE_DISTANCE_Y.convertToPixels();
double topHoleY = boardY + (boardH - holeDistY) / 2.0;
double bottomHoleY = boardY + (boardH + holeDistY) / 2.0;
double leftHoleX = (x + rowSpacing / 2.0) - holeDistX / 2.0;
double rightHoleX = (x + rowSpacing / 2.0) + holeDistX / 2.0;
// ESP-12F Metal shield with antenna at top
drawMetalConnector(g2d, boardX + 20, boardY + 40, boardW - 40, 110, "ESP-12F");
drawMountingHole(g2d, leftHoleX, topHoleY, holeDiameter);
drawMountingHole(g2d, rightHoleX, topHoleY, holeDiameter);
drawMountingHole(g2d, leftHoleX, bottomHoleY, holeDiameter);
drawMountingHole(g2d, rightHoleX, bottomHoleY, holeDiameter);
// Copper trace antenna
// Antenna trace (gold/copper serpentine PCB trace)
g2d.setColor(Color.decode("#DAA520"));
g2d.fillRect((int) (boardX + 25), (int) (boardY + 10), (int) (boardW - 50), 20);
g2d.setStroke(ObjectCache.getInstance().fetchBasicStroke(1.5f));
Path2D.Double antPath = new Path2D.Double();
double antPadX = antennaX + 12;
double antPadW = antennaW - 24;
double antTopY = antennaY + 4;
double antMidY = antennaY + antennaH - 6;
antPath.moveTo(antPadX, antMidY);
antPath.lineTo(antPadX, antTopY);
antPath.lineTo(antPadX + antPadW * 0.25, antTopY);
antPath.lineTo(antPadX + antPadW * 0.25, antMidY);
antPath.lineTo(antPadX + antPadW * 0.50, antMidY);
antPath.lineTo(antPadX + antPadW * 0.50, antTopY);
antPath.lineTo(antPadX + antPadW * 0.75, antTopY);
antPath.lineTo(antPadX + antPadW * 0.75, antMidY);
antPath.lineTo(antPadX + antPadW, antMidY);
antPath.lineTo(antPadX + antPadW, antTopY);
g2d.draw(antPath);
// ESP-12 Metal shield module below antenna
double shieldW = new Size(16.0d, SizeUnit.mm).convertToPixels();
double shieldH = new Size(15.0d, SizeUnit.mm).convertToPixels();
double shieldX = (x + rowSpacing / 2.0) - shieldW / 2.0;
double shieldY = antennaY + antennaH + 2;
drawMetalConnector(g2d, shieldX, shieldY, shieldW, shieldH, "ESP8266");
// USB to UART chip (CP2102)
double chipSize = new Size(4.5d, SizeUnit.mm).convertToPixels();
double chipX = (x + rowSpacing / 2.0) - chipSize / 2.0;
double chipY = shieldY + shieldH + new Size(4.0d, SizeUnit.mm).convertToPixels();
drawChip(g2d, chipX, chipY, chipSize, chipSize, "CP2102");
// Micro-USB Jack at bottom
double usbW = 54;
double usbH = 32;
double usbX = (x + rowSpacing / 2.0) - usbW / 2.0;
double usbY = boardY + boardH - 22;
drawMetalConnector(g2d, usbX, usbY, usbW, usbH, "USB");
// RST & FLASH tactile buttons at bottom (flanking the Micro-USB port)
double btnW = 18;
double btnH = 18;
double btnY = boardY + boardH - 25;
double shift1mm = new Size(1.0d, SizeUnit.mm).convertToPixels();
double btnLeftX = leftHoleX + 10 + shift1mm;
double btnRightX = rightHoleX - 10 - shift1mm - btnW;
g2d.setColor(Color.decode("#383838"));
g2d.fill(new RoundRectangle2D.Double(btnLeftX, btnY, btnW, btnH, 3, 3));
g2d.fill(new RoundRectangle2D.Double(btnRightX, btnY, btnW, btnH, 3, 3));
g2d.setColor(Color.decode("#666666"));
g2d.draw(new RoundRectangle2D.Double(btnLeftX, btnY, btnW, btnH, 3, 3));
g2d.draw(new RoundRectangle2D.Double(btnRightX, btnY, btnW, btnH, 3, 3));
// Button actuators
g2d.setColor(Color.decode("#A0A0A0"));
g2d.fillOval((int) (btnLeftX + btnW / 2.0 - 3.5), (int) (btnY + btnH / 2.0 - 3.5), 7, 7);
g2d.fillOval((int) (btnRightX + btnW / 2.0 - 3.5), (int) (btnY + btnH / 2.0 - 3.5), 7, 7);
// Buttons
g2d.setColor(Color.decode("#555555"));
g2d.fill(new RoundRectangle2D.Double(boardX + 15, boardY + boardH - 45, 25, 18, 3, 3));
g2d.fill(new RoundRectangle2D.Double(boardX + boardW - 40, boardY + boardH - 45, 25, 18, 3, 3));
g2d.setColor(Color.WHITE);
g2d.setFont(SILK_FONT_SMALL);
StringUtils.drawCenteredText(g2d, "RST", boardX + 27, boardY + boardH - 36, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
StringUtils.drawCenteredText(g2d, "FLASH", boardX + boardW - 28, boardY + boardH - 36, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
StringUtils.drawCenteredText(g2d, "RST", btnLeftX + btnW / 2.0, btnY - 8, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
StringUtils.drawCenteredText(g2d, "FLASH", btnRightX + btnW / 2.0, btnY - 8, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
// Silkscreen
g2d.setFont(SILK_FONT);
StringUtils.drawCenteredText(g2d, "NodeMCU", boardX + boardW / 2.0, boardY + 180, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
StringUtils.drawCenteredText(g2d, "NodeMCU", x + rowSpacing / 2.0, chipY - 10, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
}
g2d.setTransform(oldTx);
@@ -187,6 +262,7 @@ public class ESP8266NodeMCU extends AbstractMakerBoard {
g2d.setColor(Color.GRAY);
g2d.draw(new RoundRectangle2D.Double(5, 2, width - 10, height - 4, 3, 3));
// Metal shield
g2d.setColor(METAL_SHIELD_COLOR);
g2d.fillRect(8, 6, width - 16, 12);
@@ -0,0 +1,109 @@
package org.diylc.components.micro;
import java.awt.Shape;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit;
import org.junit.Assert;
import org.junit.Test;
public class ESP32DevKitCTest {
@Test
public void testControlPointCountAndNames() {
ESP32DevKitC devKit = new ESP32DevKitC();
Assert.assertEquals(38, devKit.getControlPointCount());
for (int i = 0; i < devKit.getControlPointCount(); i++) {
String name = devKit.getControlPointNodeName(i);
Assert.assertNotNull("Pin " + i + " name should not be null", name);
Assert.assertFalse("Pin " + i + " name should not be empty", name.trim().isEmpty());
}
// Left row (0..18, top to bottom)
Assert.assertEquals("3V3", devKit.getControlPointNodeName(0));
Assert.assertEquals("EN", devKit.getControlPointNodeName(1));
Assert.assertEquals("VP (GPIO36)", devKit.getControlPointNodeName(2));
Assert.assertEquals("VN (GPIO39)", devKit.getControlPointNodeName(3));
Assert.assertEquals("GPIO34", devKit.getControlPointNodeName(4));
Assert.assertEquals("GPIO35", devKit.getControlPointNodeName(5));
Assert.assertEquals("GPIO32", devKit.getControlPointNodeName(6));
Assert.assertEquals("GPIO33", devKit.getControlPointNodeName(7));
Assert.assertEquals("GPIO25", devKit.getControlPointNodeName(8));
Assert.assertEquals("GPIO26", devKit.getControlPointNodeName(9));
Assert.assertEquals("GPIO27", devKit.getControlPointNodeName(10));
Assert.assertEquals("GPIO14", devKit.getControlPointNodeName(11));
Assert.assertEquals("GPIO12", devKit.getControlPointNodeName(12));
Assert.assertEquals("GND1", devKit.getControlPointNodeName(13));
Assert.assertEquals("GPIO13", devKit.getControlPointNodeName(14));
Assert.assertEquals("D2 (GPIO9)", devKit.getControlPointNodeName(15));
Assert.assertEquals("D3 (GPIO10)", devKit.getControlPointNodeName(16));
Assert.assertEquals("CMD (GPIO11)", devKit.getControlPointNodeName(17));
Assert.assertEquals("5V", devKit.getControlPointNodeName(18));
// Right row (19..37, top to bottom)
Assert.assertEquals("GND2", devKit.getControlPointNodeName(19));
Assert.assertEquals("GPIO23", devKit.getControlPointNodeName(20));
Assert.assertEquals("GPIO22", devKit.getControlPointNodeName(21));
Assert.assertEquals("TX0 (GPIO1)", devKit.getControlPointNodeName(22));
Assert.assertEquals("RX0 (GPIO3)", devKit.getControlPointNodeName(23));
Assert.assertEquals("GPIO21", devKit.getControlPointNodeName(24));
Assert.assertEquals("GND3", devKit.getControlPointNodeName(25));
Assert.assertEquals("GPIO19", devKit.getControlPointNodeName(26));
Assert.assertEquals("GPIO18", devKit.getControlPointNodeName(27));
Assert.assertEquals("GPIO5", devKit.getControlPointNodeName(28));
Assert.assertEquals("GPIO17", devKit.getControlPointNodeName(29));
Assert.assertEquals("GPIO16", devKit.getControlPointNodeName(30));
Assert.assertEquals("GPIO4", devKit.getControlPointNodeName(31));
Assert.assertEquals("GPIO0", devKit.getControlPointNodeName(32));
Assert.assertEquals("GPIO2", devKit.getControlPointNodeName(33));
Assert.assertEquals("GPIO15", devKit.getControlPointNodeName(34));
Assert.assertEquals("D1 (GPIO8)", devKit.getControlPointNodeName(35));
Assert.assertEquals("D0 (GPIO7)", devKit.getControlPointNodeName(36));
Assert.assertEquals("CLK (GPIO6)", devKit.getControlPointNodeName(37));
}
@Test
public void testPinGeometryAndSpacing() {
ESP32DevKitC devKit = new ESP32DevKitC();
// Left row pitch (20px per pin = 0.10")
for (int i = 0; i < 18; i++) {
Point2D p1 = devKit.getControlPoint(i);
Point2D p2 = devKit.getControlPoint(i + 1);
Assert.assertEquals(20.0, p1.distance(p2), 0.01);
Assert.assertEquals(p1.getX(), p2.getX(), 0.01);
}
// Right row pitch (20px per pin = 0.10")
for (int i = 19; i < 37; i++) {
Point2D p1 = devKit.getControlPoint(i);
Point2D p2 = devKit.getControlPoint(i + 1);
Assert.assertEquals(20.0, p1.distance(p2), 0.01);
Assert.assertEquals(p1.getX(), p2.getX(), 0.01);
}
// Row spacing: 1.00" = 200px between Left row and Right row
Point2D pLeftTop = devKit.getControlPoint(0);
Point2D pRightTop = devKit.getControlPoint(19);
Assert.assertEquals(200.0, pLeftTop.distance(pRightTop), 0.01);
Assert.assertEquals(pLeftTop.getY(), pRightTop.getY(), 0.01);
}
@Test
public void testBodyShapeDimensions() {
ESP32DevKitC devKit = new ESP32DevKitC();
Shape body = devKit.getBodyShape();
Assert.assertNotNull(body);
Rectangle2D bounds = body.getBounds2D();
double expectedWidth = new Size(27.9d, SizeUnit.mm).convertToPixels();
double expectedTotalLength = new Size(54.4d, SizeUnit.mm).convertToPixels();
Assert.assertEquals(expectedWidth, bounds.getWidth(), 0.1);
Assert.assertEquals(expectedTotalLength, bounds.getHeight(), 0.1);
}
}
@@ -0,0 +1,105 @@
package org.diylc.components.micro;
import java.awt.Shape;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit;
import org.junit.Assert;
import org.junit.Test;
public class ESP32DevKitTest {
@Test
public void testControlPointCountAndNames() {
ESP32DevKit devKit = new ESP32DevKit();
Assert.assertEquals(30, devKit.getControlPointCount());
for (int i = 0; i < devKit.getControlPointCount(); i++) {
String name = devKit.getControlPointNodeName(i);
Assert.assertNotNull("Pin " + i + " name should not be null", name);
Assert.assertFalse("Pin " + i + " name should not be empty", name.trim().isEmpty());
}
// Left row (0..14)
Assert.assertEquals("EN", devKit.getControlPointNodeName(0));
Assert.assertEquals("VP (GPIO36)", devKit.getControlPointNodeName(1));
Assert.assertEquals("VN (GPIO39)", devKit.getControlPointNodeName(2));
Assert.assertEquals("D34", devKit.getControlPointNodeName(3));
Assert.assertEquals("D35", devKit.getControlPointNodeName(4));
Assert.assertEquals("D32", devKit.getControlPointNodeName(5));
Assert.assertEquals("D33", devKit.getControlPointNodeName(6));
Assert.assertEquals("D25", devKit.getControlPointNodeName(7));
Assert.assertEquals("D26", devKit.getControlPointNodeName(8));
Assert.assertEquals("D27", devKit.getControlPointNodeName(9));
Assert.assertEquals("D14", devKit.getControlPointNodeName(10));
Assert.assertEquals("D12", devKit.getControlPointNodeName(11));
Assert.assertEquals("GND1", devKit.getControlPointNodeName(12));
Assert.assertEquals("D13", devKit.getControlPointNodeName(13));
Assert.assertEquals("3V3", devKit.getControlPointNodeName(14));
// Right row (15..29)
Assert.assertEquals("VIN", devKit.getControlPointNodeName(15));
Assert.assertEquals("GND2", devKit.getControlPointNodeName(16));
Assert.assertEquals("D15", devKit.getControlPointNodeName(17));
Assert.assertEquals("D2", devKit.getControlPointNodeName(18));
Assert.assertEquals("D4", devKit.getControlPointNodeName(19));
Assert.assertEquals("D16 (RX2)", devKit.getControlPointNodeName(20));
Assert.assertEquals("D17 (TX2)", devKit.getControlPointNodeName(21));
Assert.assertEquals("D5", devKit.getControlPointNodeName(22));
Assert.assertEquals("D18", devKit.getControlPointNodeName(23));
Assert.assertEquals("D19", devKit.getControlPointNodeName(24));
Assert.assertEquals("D21", devKit.getControlPointNodeName(25));
Assert.assertEquals("RX0 (GPIO3)", devKit.getControlPointNodeName(26));
Assert.assertEquals("TX0 (GPIO1)", devKit.getControlPointNodeName(27));
Assert.assertEquals("D22", devKit.getControlPointNodeName(28));
Assert.assertEquals("D23", devKit.getControlPointNodeName(29));
}
@Test
public void testPinGeometryAndSpacing() {
ESP32DevKit devKit = new ESP32DevKit();
// Left row pitch (20px per pin = 0.10")
for (int i = 0; i < 14; i++) {
Point2D p1 = devKit.getControlPoint(i);
Point2D p2 = devKit.getControlPoint(i + 1);
Assert.assertEquals(20.0, p1.distance(p2), 0.01);
Assert.assertEquals(p1.getX(), p2.getX(), 0.01);
}
// Right row pitch (20px per pin = 0.10")
for (int i = 15; i < 29; i++) {
Point2D p1 = devKit.getControlPoint(i);
Point2D p2 = devKit.getControlPoint(i + 1);
Assert.assertEquals(20.0, p1.distance(p2), 0.01);
Assert.assertEquals(p1.getX(), p2.getX(), 0.01);
}
// Row spacing: 0.90" = 180px between Left row and Right row
Point2D pLeftTop = devKit.getControlPoint(0);
Point2D pRightTop = devKit.getControlPoint(29);
Assert.assertEquals(180.0, pLeftTop.distance(pRightTop), 0.01);
Assert.assertEquals(pLeftTop.getY(), pRightTop.getY(), 0.01);
}
@Test
public void testBodyShapeDimensions() {
ESP32DevKit devKit = new ESP32DevKit();
Shape body = devKit.getBodyShape();
Assert.assertNotNull(body);
Rectangle2D bounds = body.getBounds2D();
double expectedWidth = new Size(28.2d, SizeUnit.mm).convertToPixels();
double expectedHeight = new Size(51.8d, SizeUnit.mm).convertToPixels();
double expectedTopMargin = new Size(6.7d, SizeUnit.mm).convertToPixels();
Assert.assertEquals(expectedWidth, bounds.getWidth(), 0.1);
Assert.assertEquals(expectedHeight, bounds.getHeight(), 0.1);
Point2D p0 = devKit.getControlPoint(0);
Assert.assertEquals(expectedTopMargin, p0.getY() - bounds.getY(), 0.1);
}
}
@@ -0,0 +1,105 @@
package org.diylc.components.micro;
import java.awt.Shape;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import org.diylc.core.measures.Size;
import org.diylc.core.measures.SizeUnit;
import org.junit.Assert;
import org.junit.Test;
public class ESP8266NodeMCUTest {
@Test
public void testControlPointCountAndNames() {
ESP8266NodeMCU mcu = new ESP8266NodeMCU();
Assert.assertEquals(30, mcu.getControlPointCount());
for (int i = 0; i < mcu.getControlPointCount(); i++) {
String name = mcu.getControlPointNodeName(i);
Assert.assertNotNull("Pin " + i + " name should not be null", name);
Assert.assertFalse("Pin " + i + " name should not be empty", name.trim().isEmpty());
}
// Left row (0..14)
Assert.assertEquals("A0 (ADC0)", mcu.getControlPointNodeName(0));
Assert.assertEquals("RSV1", mcu.getControlPointNodeName(1));
Assert.assertEquals("RSV2", mcu.getControlPointNodeName(2));
Assert.assertEquals("SD3", mcu.getControlPointNodeName(3));
Assert.assertEquals("SD2", mcu.getControlPointNodeName(4));
Assert.assertEquals("SD1", mcu.getControlPointNodeName(5));
Assert.assertEquals("CMD", mcu.getControlPointNodeName(6));
Assert.assertEquals("SD0", mcu.getControlPointNodeName(7));
Assert.assertEquals("CLK", mcu.getControlPointNodeName(8));
Assert.assertEquals("GND1", mcu.getControlPointNodeName(9));
Assert.assertEquals("3V3_1", mcu.getControlPointNodeName(10));
Assert.assertEquals("EN", mcu.getControlPointNodeName(11));
Assert.assertEquals("RST", mcu.getControlPointNodeName(12));
Assert.assertEquals("GND2", mcu.getControlPointNodeName(13));
Assert.assertEquals("VIN", mcu.getControlPointNodeName(14));
// Right row (15..29)
Assert.assertEquals("D0 (GPIO16)", mcu.getControlPointNodeName(15));
Assert.assertEquals("D1 (GPIO5)", mcu.getControlPointNodeName(16));
Assert.assertEquals("D2 (GPIO4)", mcu.getControlPointNodeName(17));
Assert.assertEquals("D3 (GPIO0)", mcu.getControlPointNodeName(18));
Assert.assertEquals("D4 (GPIO2)", mcu.getControlPointNodeName(19));
Assert.assertEquals("3V3_2", mcu.getControlPointNodeName(20));
Assert.assertEquals("GND3", mcu.getControlPointNodeName(21));
Assert.assertEquals("D5 (GPIO14)", mcu.getControlPointNodeName(22));
Assert.assertEquals("D6 (GPIO12)", mcu.getControlPointNodeName(23));
Assert.assertEquals("D7 (GPIO13)", mcu.getControlPointNodeName(24));
Assert.assertEquals("D8 (GPIO15)", mcu.getControlPointNodeName(25));
Assert.assertEquals("RX (GPIO3)", mcu.getControlPointNodeName(26));
Assert.assertEquals("TX (GPIO1)", mcu.getControlPointNodeName(27));
Assert.assertEquals("GND4", mcu.getControlPointNodeName(28));
Assert.assertEquals("3V3_3", mcu.getControlPointNodeName(29));
}
@Test
public void testPinGeometryAndSpacing() {
ESP8266NodeMCU mcu = new ESP8266NodeMCU();
// Left row pitch (20px per pin = 0.10")
for (int i = 0; i < 14; i++) {
Point2D p1 = mcu.getControlPoint(i);
Point2D p2 = mcu.getControlPoint(i + 1);
Assert.assertEquals(20.0, p1.distance(p2), 0.01);
Assert.assertEquals(p1.getX(), p2.getX(), 0.01);
}
// Right row pitch (20px per pin = 0.10")
for (int i = 15; i < 29; i++) {
Point2D p1 = mcu.getControlPoint(i);
Point2D p2 = mcu.getControlPoint(i + 1);
Assert.assertEquals(20.0, p1.distance(p2), 0.01);
Assert.assertEquals(p1.getX(), p2.getX(), 0.01);
}
// Row spacing: 0.90" = 180px between Left row and Right row
Point2D pLeftTop = mcu.getControlPoint(0);
Point2D pRightTop = mcu.getControlPoint(15);
Assert.assertEquals(180.0, pLeftTop.distance(pRightTop), 0.01);
Assert.assertEquals(pLeftTop.getY(), pRightTop.getY(), 0.01);
}
@Test
public void testBodyShapeDimensions() {
ESP8266NodeMCU mcu = new ESP8266NodeMCU();
Shape body = mcu.getBodyShape();
Assert.assertNotNull(body);
Rectangle2D bounds = body.getBounds2D();
double expectedWidth = new Size(25.7d, SizeUnit.mm).convertToPixels();
double expectedHeight = new Size(48.0d, SizeUnit.mm).convertToPixels();
double expectedTopMargin = new Size(6.22d, SizeUnit.mm).convertToPixels();
Assert.assertEquals(expectedWidth, bounds.getWidth(), 0.1);
Assert.assertEquals(expectedHeight, bounds.getHeight(), 0.1);
Point2D p0 = mcu.getControlPoint(0);
Assert.assertEquals(expectedTopMargin, p0.getY() - bounds.getY(), 0.1);
}
}