From 2f89edb04c5966e064f667e9efc89bf849793fc8 Mon Sep 17 00:00:00 2001 From: nathanrsxtn <37890449+nathanrsxtn@users.noreply.github.com> Date: Thu, 7 Oct 2021 17:32:50 -0600 Subject: [PATCH] Add the correct version of the code this time --- .../frc4388/robot/subsystems/Shooter.java | 148 +++++------------- src/main/java/frc4388/utility/CSV.java | 92 +++-------- 2 files changed, 61 insertions(+), 179 deletions(-) diff --git a/src/main/java/frc4388/robot/subsystems/Shooter.java b/src/main/java/frc4388/robot/subsystems/Shooter.java index add0f49..8bc8daa 100644 --- a/src/main/java/frc4388/robot/subsystems/Shooter.java +++ b/src/main/java/frc4388/robot/subsystems/Shooter.java @@ -25,45 +25,18 @@ import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import edu.wpi.first.wpilibj2.command.SubsystemBase; import frc4388.robot.Constants.ShooterConstants; import frc4388.utility.CSV; -import frc4388.utility.Gains; import frc4388.utility.Trims; -import frc4388.utility.controller.IHandController; public class Shooter extends SubsystemBase { - public WPI_TalonFX m_shooterFalconLeft = new WPI_TalonFX(ShooterConstants.SHOOTER_FALCON_BALLER_ID); - public WPI_TalonFX m_shooterFalconRight = new WPI_TalonFX(ShooterConstants.SHOOTER_FALCON_BALLER_FOLLOWER_ID); - public static Gains m_drumShooterGains = ShooterConstants.DRUM_SHOOTER_GAINS; - public static Shooter m_shooter; - public static IHandController m_controller; + public final WPI_TalonFX m_shooterFalconLeft = new WPI_TalonFX(ShooterConstants.SHOOTER_FALCON_BALLER_ID); + public final WPI_TalonFX m_shooterFalconRight = new WPI_TalonFX(ShooterConstants.SHOOTER_FALCON_BALLER_FOLLOWER_ID); - double velP; - double input; - - private class ShooterDataEntry { - Double distance; - Double hoodExt; - Double drumVelocity; - Double centerDisplacement; - - public Double getDistance() { - return distance; - } - - public Double getHoodExt() { - return hoodExt; - } - - public Double getDrumVelocity() { - return drumVelocity; - } - - public Double getCenterDisplacement() { - return centerDisplacement; - } + public static class ShooterTableEntry { + public Double distance, hoodExt, drumVelocity, centerDisplacement; } - private ShooterDataEntry[] m_shooterTable; + private ShooterTableEntry[] m_shooterTable; public boolean m_isDrumReady = false; public double m_fireVel; @@ -74,8 +47,7 @@ public class Shooter extends SubsystemBase { public ShooterAim m_shooterAimSubsystem; /* - * Creates a new Shooter subsystem, with the drum shooter and the angle - * adjsuter. + * Creates a new Shooter subsystem, with the drum shooter and the angle adjuster. */ public Shooter() { // Testing purposes reseting gyros @@ -99,55 +71,32 @@ public class Shooter extends SubsystemBase { m_shooterFalconRight.configClosedloopRamp(0.75, ShooterConstants.SHOOTER_TIMEOUT_MS); setShooterGains(); - int closedLoopTimeMs = 1; + final int closedLoopTimeMs = 1; // LEFT FALCON m_shooterFalconLeft.configPeakOutputReverse(0, ShooterConstants.SHOOTER_TIMEOUT_MS); - - m_shooterFalconLeft.setSelectedSensorPosition(0, ShooterConstants.SHOOTER_PID_LOOP_IDX, - ShooterConstants.SHOOTER_TIMEOUT_MS); - + m_shooterFalconLeft.setSelectedSensorPosition(0, ShooterConstants.SHOOTER_PID_LOOP_IDX, ShooterConstants.SHOOTER_TIMEOUT_MS); m_shooterFalconLeft.configClosedLoopPeriod(0, closedLoopTimeMs, ShooterConstants.SHOOTER_TIMEOUT_MS); - - m_shooterFalconLeft.configSupplyCurrentLimit(ShooterConstants.SUPPLY_CURRENT_LIMIT_CONFIG, - ShooterConstants.SHOOTER_TIMEOUT_MS); + m_shooterFalconLeft.configSupplyCurrentLimit(ShooterConstants.SUPPLY_CURRENT_LIMIT_CONFIG, ShooterConstants.SHOOTER_TIMEOUT_MS); // RIGHT FALCON - // m_shooterFalconRight.configPeakOutputForward(0, - // ShooterConstants.SHOOTER_TIMEOUT_MS); - - m_shooterFalconRight.setSelectedSensorPosition(0, ShooterConstants.SHOOTER_PID_LOOP_IDX, - ShooterConstants.SHOOTER_TIMEOUT_MS); - + // m_shooterFalconRight.configPeakOutputForward(0, ShooterConstants.SHOOTER_TIMEOUT_MS); + m_shooterFalconRight.setSelectedSensorPosition(0, ShooterConstants.SHOOTER_PID_LOOP_IDX, ShooterConstants.SHOOTER_TIMEOUT_MS); m_shooterFalconRight.configClosedLoopPeriod(0, closedLoopTimeMs, ShooterConstants.SHOOTER_TIMEOUT_MS); - - m_shooterFalconRight.configSupplyCurrentLimit(ShooterConstants.SUPPLY_CURRENT_LIMIT_CONFIG, - ShooterConstants.SHOOTER_TIMEOUT_MS); + m_shooterFalconRight.configSupplyCurrentLimit(ShooterConstants.SUPPLY_CURRENT_LIMIT_CONFIG, ShooterConstants.SHOOTER_TIMEOUT_MS); try { - m_shooterTable = new CSV<>(ShooterDataEntry::new) { + m_shooterTable = new CSV<>(ShooterTableEntry::new) { private final Pattern parentheses = Pattern.compile("\\([^\\)]*+\\)"); @Override protected String headerSanitizer(final String header) { return super.headerSanitizer(parentheses.matcher(header).replaceAll("")); } - }.read(new File(Filesystem.getDeployDirectory(), "example_data.csv").toPath()); - System.out.println(CSV.ReflectionTable.create(m_shooterTable)); - } catch (IOException e) { + }.read(new File(Filesystem.getDeployDirectory(), "Robot Data - Distances.csv").toPath()); + new Thread(() -> System.out.println(CSV.ReflectionTable.create(m_shooterTable))).start(); + } catch (final IOException e) { throw new RuntimeException(e); } - // SmartDashboard.putNumber("CSV 10", m_shooterTable.getVelocity(10)); - // SmartDashboard.putNumber("CSV 200", m_shooterTable.getVelocity(200)); - // SmartDashboard.putNumber("CSV 250", m_shooterTable.getVelocity(250)); - // SmartDashboard.putNumber("CSV 500", m_shooterTable.getVelocity(500)); - - // SmartDashboard.putNumber("CSV A -30", - // m_shooterTable.getAngleDisplacement(-30)); - // SmartDashboard.putNumber("CSV A 10", - // m_shooterTable.getAngleDisplacement(10)); - // SmartDashboard.putNumber("CSV A 5", m_shooterTable.getAngleDisplacement(5)); - // SmartDashboard.putNumber("CSV A 30", - // m_shooterTable.getAngleDisplacement(30)); } @Override @@ -155,24 +104,17 @@ public class Shooter extends SubsystemBase { // This method will be called once per scheduler run try { SmartDashboard.putNumber("Drum Velocity", m_shooterFalconLeft.getSelectedSensorVelocity()); - SmartDashboard.putNumber("Drum Velocity CSV", m_fireVel); - SmartDashboard.putNumber("Shooter Temp C", m_shooterFalconLeft.getTemperature()); - SmartDashboard.putNumber("Shooter Current", m_shooterFalconLeft.getSupplyCurrent()); - SmartDashboard.putBoolean("Drum Ready", m_isDrumReady); - } - - catch (Exception e) { + } catch (final Exception e) { } } /** * Passes subsystem needed. - * * @param subsystem Subsystem needed. */ public void passRequiredSubsystem(ShooterHood subsystem0, ShooterAim subsystem1) { @@ -186,7 +128,6 @@ public class Shooter extends SubsystemBase { /** * Runs drum shooter motor. - * * @param speed Speed to set the motor at */ public void runDrumShooter(double speed) { @@ -200,19 +141,14 @@ public class Shooter extends SubsystemBase { */ public void setShooterGains() { m_shooterFalconLeft.selectProfileSlot(ShooterConstants.SHOOTER_SLOT_IDX, ShooterConstants.SHOOTER_PID_LOOP_IDX); - m_shooterFalconLeft.config_kF(ShooterConstants.SHOOTER_SLOT_IDX, m_drumShooterGains.m_kF, - ShooterConstants.SHOOTER_TIMEOUT_MS); - m_shooterFalconLeft.config_kP(ShooterConstants.SHOOTER_SLOT_IDX, m_drumShooterGains.m_kP, - ShooterConstants.SHOOTER_TIMEOUT_MS); - m_shooterFalconLeft.config_kI(ShooterConstants.SHOOTER_SLOT_IDX, m_drumShooterGains.m_kI, - ShooterConstants.SHOOTER_TIMEOUT_MS); - m_shooterFalconLeft.config_kD(ShooterConstants.SHOOTER_SLOT_IDX, m_drumShooterGains.m_kD, - ShooterConstants.SHOOTER_TIMEOUT_MS); + m_shooterFalconLeft.config_kF(ShooterConstants.SHOOTER_SLOT_IDX, ShooterConstants.DRUM_SHOOTER_GAINS.m_kF, ShooterConstants.SHOOTER_TIMEOUT_MS); + m_shooterFalconLeft.config_kP(ShooterConstants.SHOOTER_SLOT_IDX, ShooterConstants.DRUM_SHOOTER_GAINS.m_kP, ShooterConstants.SHOOTER_TIMEOUT_MS); + m_shooterFalconLeft.config_kI(ShooterConstants.SHOOTER_SLOT_IDX, ShooterConstants.DRUM_SHOOTER_GAINS.m_kI, ShooterConstants.SHOOTER_TIMEOUT_MS); + m_shooterFalconLeft.config_kD(ShooterConstants.SHOOTER_SLOT_IDX, ShooterConstants.DRUM_SHOOTER_GAINS.m_kD, ShooterConstants.SHOOTER_TIMEOUT_MS); } /** * Runs drum shooter velocity PID. - * * @param targetVel Target velocity to run motor at */ public void runDrumShooterVelocityPID(double targetVel) { @@ -221,44 +157,32 @@ public class Shooter extends SubsystemBase { m_shooterFalconRight.follow(m_shooterFalconLeft); } - public Double getCenterDisplacement(Double distance) { - return linearInterpolate(distance, ShooterDataEntry::getDistance, ShooterDataEntry::getCenterDisplacement) - .doubleValue(); + public Double getCenterDisplacement(final Double distance) { + return linearInterpolate(m_shooterTable, distance, e -> e.distance, e -> e.centerDisplacement).doubleValue(); } - public Double getVelocity(Double distance) { - return linearInterpolate(distance, ShooterDataEntry::getDistance, ShooterDataEntry::getDrumVelocity).doubleValue(); + public Double getVelocity(final Double distance) { + return linearInterpolate(m_shooterTable, distance, e -> e.distance, e -> e.drumVelocity).doubleValue(); } - public Double getHood(Double distance) { - return linearInterpolate(distance, ShooterDataEntry::getDistance, ShooterDataEntry::getHoodExt).doubleValue(); + public Double getHood(final Double distance) { + return linearInterpolate(m_shooterTable, distance, e -> e.distance, e -> e.hoodExt).doubleValue(); } - private Number linearInterpolate(final Number lookupValue, final Function lookupGetter, - final Function targetGetter) { - final Map.Entry closestEntry = lookup(lookupValue.doubleValue(), lookupGetter, false) - .orElse(Map.entry(m_shooterTable.length - 1, m_shooterTable[m_shooterTable.length - 1])); - final ShooterDataEntry closestRecord = closestEntry.getValue(); + private static Number linearInterpolate(final E[] table, final Number lookupValue, final Function lookupGetter, final Function targetGetter) { + final Map.Entry closestEntry = lookup(table, lookupValue.doubleValue(), lookupGetter, false).orElse(Map.entry(table.length - 1, table[table.length - 1])); + final E closestRecord = closestEntry.getValue(); final int closestRecordIndex = closestEntry.getKey(); - final ShooterDataEntry neighborRecord = m_shooterTable[lookupValue.doubleValue() <= lookupGetter - .apply(closestRecord).doubleValue() ? Math.max(closestRecordIndex == 0 ? 1 : 0, closestRecordIndex - 1) - : Math.min(closestRecordIndex + 1, - m_shooterTable.length - (closestRecordIndex == m_shooterTable.length - 1 ? 2 : 1))]; - return lerp2(lookupValue, lookupGetter.apply(closestRecord), targetGetter.apply(closestRecord), - lookupGetter.apply(neighborRecord), targetGetter.apply(neighborRecord)); + final E neighborRecord = table[lookupValue.doubleValue() <= lookupGetter.apply(closestRecord).doubleValue() ? Math.max(closestRecordIndex == 0 ? 1 : 0, closestRecordIndex - 1) : Math.min(closestRecordIndex + 1, table.length - (closestRecordIndex == table.length - 1 ? 2 : 1))]; + return lerp2(lookupValue, lookupGetter.apply(closestRecord), targetGetter.apply(closestRecord), lookupGetter.apply(neighborRecord), targetGetter.apply(neighborRecord)); } - private Optional> lookup(final Number value, - final Function valueGetter, boolean exactMatch) { - Optional> match = IntStream.range(0, m_shooterTable.length) - .mapToObj(i -> Map.entry(i, m_shooterTable[i])).min(Comparator - .comparingDouble(e -> Math.abs(valueGetter.apply(e.getValue()).doubleValue() - value.doubleValue()))); - return !exactMatch || match.map(e -> valueGetter.apply(e.getValue()).equals(value)).orElse(false) ? match - : Optional.empty(); - + private static Optional> lookup(final E[] table, final Number value, final Function valueGetter, final boolean exactMatch) { + final Optional> match = IntStream.range(0, table.length).mapToObj(i -> Map.entry(i, table[i])).min(Comparator.comparingDouble(e -> Math.abs(valueGetter.apply(e.getValue()).doubleValue() - value.doubleValue()))); + return !exactMatch || match.map(e -> valueGetter.apply(e.getValue()).equals(value)).orElse(false) ? match : Optional.empty(); } - private Number lerp2(final Number x, final Number x0, final Number y0, final Number x1, final Number y1) { + private static Number lerp2(final Number x, final Number x0, final Number y0, final Number x1, final Number y1) { final Number f = (x.doubleValue() - x0.doubleValue()) / (x1.doubleValue() - x0.doubleValue()); return (1.0 - f.doubleValue()) * y0.doubleValue() + f.doubleValue() * y1.doubleValue(); } diff --git a/src/main/java/frc4388/utility/CSV.java b/src/main/java/frc4388/utility/CSV.java index cbe8f98..aa148ad 100644 --- a/src/main/java/frc4388/utility/CSV.java +++ b/src/main/java/frc4388/utility/CSV.java @@ -57,15 +57,8 @@ public class CSV { } /** - * Creates a new {@code CSV} instance and prepares for populating the fields of - * objects created by the given generator. Fields of primitive types is not - * supported. - * - * @param generator a parameterless supplier which produces a new object with - * any number of fields corresponding to header names from a - * CSV file. The first character of the names from the header - * in the CSV file will be made lowercase and invalid - * characters will be removed to match Java naming conventions. + * Creates a new {@code CSV} instance and prepares for populating the fields of objects created by the given generator. Private fields and fields of primitive types are not supported. + * @param generator a parameterless supplier which produces a new object with any number of fields corresponding to header names from a CSV file. The first character of the names from the header in the CSV file will be made lowercase and invalid characters will be removed to match Java naming conventions. * @see #read(Path) */ @SuppressWarnings("unchecked") @@ -76,8 +69,7 @@ public class CSV { this.generator = generator; this.setters = new HashMap<>(); for (final Field field : clazz.getFields()) { - final Function parser = Modifier.isStatic(field.getModifiers()) ? null - : fieldParsers.computeIfAbsent(field.getType(), CSV::getTypeParser); + final Function parser = Modifier.isStatic(field.getModifiers()) ? null : fieldParsers.computeIfAbsent(field.getType(), CSV::getTypeParser); if (parser != null) this.setters.put(field.getName(), (final R obj, final String rawValue) -> { try { @@ -90,11 +82,7 @@ public class CSV { } /** - * Reads and parses the contents of the given CSV file, and returns an array - * filled with populated objects created with the previously given generator. - * Cells are parsed using their corresponding field's {@code valueOf(String)} - * function. - * + * Reads and parses the contents of the given CSV file, and returns an array filled with populated objects created with the previously given generator. Cells are parsed using their corresponding field's {@code valueOf(String)} function. * @param path the path to a CSV file * @return the parsed data from the CSV file * @throws IOException if an I/O error occurs opening the file @@ -102,34 +90,27 @@ public class CSV { @SuppressWarnings("unchecked") public R[] read(final Path path) throws IOException { try (final BufferedReader reader = Files.newBufferedReader(path)) { - final BiConsumer[] fieldSetters = Stream.of(headerSanitizer(reader.readLine()).split(",")) - .map(this::nameProcessor).map(setters::get).toArray(BiConsumer[]::new); + final BiConsumer[] fieldSetters = Stream.of(headerSanitizer(reader.readLine()).split(",")).map(this::nameProcessor).map(setters::get).toArray(BiConsumer[]::new); final Stream lines = reader.lines(); - return lines.filter(Predicate.not(String::isBlank)) - .map(line -> deserializeRecordString(line, fieldSetters, generator.get())) - .toArray(this.arrayGenerator); + return lines.filter(Predicate.not(String::isBlank)).map(line -> deserializeRecordString(line, fieldSetters, generator.get())).toArray(this.arrayGenerator); } } @SuppressWarnings("unchecked") private static Function getTypeParser(final Class type) { try { - return type.isAssignableFrom(String.class) ? Function.identity() - : MethodHandleProxies.asInterfaceInstance(Function.class, MethodHandles.publicLookup() - .findStatic(type, "valueOf", MethodType.methodType(type, String.class))); + return type.isAssignableFrom(String.class) ? Function.identity() : MethodHandleProxies.asInterfaceInstance(Function.class, MethodHandles.publicLookup().findStatic(type, "valueOf", MethodType.methodType(type, String.class))); } catch (final NoSuchMethodException | IllegalAccessException e) { return null; } } - private static R deserializeRecordString(final String recordString, - final BiConsumer[] fieldParseSetters, final R object) { + private static R deserializeRecordString(final String recordString, final BiConsumer[] fieldParseSetters, final R object) { final int recordStringLength = recordString.length(); int fieldBeginIndex = 0, tryFieldEndFromIndex = 0, i = 0; while (tryFieldEndFromIndex < recordStringLength && i < fieldParseSetters.length) { final int tryFieldEndIndex = recordString.indexOf(',', tryFieldEndFromIndex); - String field = recordString - .substring(fieldBeginIndex, tryFieldEndIndex == -1 ? recordStringLength : tryFieldEndIndex).strip(); + String field = recordString.substring(fieldBeginIndex, tryFieldEndIndex == -1 ? recordStringLength : tryFieldEndIndex).strip(); if (!field.isEmpty() && (tryFieldEndFromIndex != fieldBeginIndex || field.charAt(0) == '"')) { final int fieldLength = field.length(); if (countTrailing(field, '"') % 2 == 0) { @@ -157,35 +138,20 @@ public class CSV { public static class ReflectionTable { public static String create(final T[] objects) { - final Field[] fields = Stream.of(objects).flatMap(object -> Stream.of(object.getClass().getFields())) - .distinct().toArray(Field[]::new); + final Field[] fields = Stream.of(objects).flatMap(object -> Stream.of(object.getClass().getFields())).distinct().toArray(Field[]::new); final List> rows = new ArrayList<>(); rows.add(Stream.of(fields).map(ReflectionTable::new).collect(Collectors.toList())); - rows.addAll(Stream.of(objects).map( - obj -> Stream.of(fields).map(field -> new ReflectionTable(obj, field)).collect(Collectors.toList())) - .collect(Collectors.toList())); - final int[] columnWidths = rows.stream() - .map(row -> row.stream().map(cell -> cell.string).mapToInt(String::length).toArray()) - .reduce(new int[fields.length], (result, row) -> IntStream.range(0, row.length) - .map(i -> Math.max(result[i], row[i])).toArray()); + rows.addAll(Stream.of(objects).map(obj -> Stream.of(fields).map(field -> new ReflectionTable(obj, field)).collect(Collectors.toList())).collect(Collectors.toList())); + final int[] columnWidths = rows.stream().map(row -> row.stream().map(cell -> cell.string).mapToInt(String::length).toArray()).reduce(new int[fields.length], (result, row) -> IntStream.range(0, row.length).map(i -> Math.max(result[i], row[i])).toArray()); IntStream.range(0, fields.length).forEach(i -> { - final var columnSummaryStatistics = rows.stream().skip(1) - .mapToDouble(row -> row.get(i).getValue().doubleValue()).summaryStatistics(); - rows.stream().skip(1).forEach(row -> row.get(i).colorByValue(columnSummaryStatistics.getMin(), - columnSummaryStatistics.getMax())); + final var columnSummaryStatistics = rows.stream().skip(1).mapToDouble(row -> row.get(i).getValue().doubleValue()).summaryStatistics(); + rows.stream().skip(1).forEach(row -> row.get(i).colorByValue(columnSummaryStatistics.getMin(), columnSummaryStatistics.getMax())); }); - return rows.stream() - .map(row -> IntStream.range(0, row.size()) - .mapToObj(i -> String.format( - MessageFormat.format("{0} %{1}{2}s {3}", row.get(i).escape, - row.get(i).padRight ? "-" : "", columnWidths[i], RESET_STYLE), - row.get(i).string)) - .collect(Collectors.joining("|"))) - .collect(Collectors.joining(LF)); + return rows.stream().map(row -> IntStream.range(0, row.size()).mapToObj(i -> String.format(MessageFormat.format("{0} %{1}{2}s {3}", row.get(i).escape, row.get(i).padRight ? "-" : "", columnWidths[i], RESET_STYLE), row.get(i).string)).collect(Collectors.joining("|"))).collect(Collectors.joining(LF)); } - private static final Color GRADIENT_MIN = new Color(0, 51, 0); - private static final Color GRADIENT_MAX = new Color(0, 255, 0); + private static final Color GRADIENT_MIN = new Color(0x00, 0x33, 0x00); + private static final Color GRADIENT_MAX = new Color(0x00, 0xFF, 0x00); private static final String CONTROL = "\033"; private static final String CSI = "["; private static final String LF = "\n"; @@ -235,20 +201,15 @@ public class CSV { private void colorByValue(final Number min, final Number max) { if (Objects.nonNull(value)) { - final double normal = (getValue().doubleValue() - min.doubleValue()) - / (max.doubleValue() - min.doubleValue()); - final Color color = new Color(range(normal, GRADIENT_MIN.getRed(), GRADIENT_MAX.getRed()), - range(normal, GRADIENT_MIN.getGreen(), GRADIENT_MAX.getGreen()), - range(normal, GRADIENT_MIN.getBlue(), GRADIENT_MAX.getBlue())); - escape += (contrastRatio(color, Color.BLACK) > contrastRatio(Color.WHITE, color) - ? colorTo24BitSGR(Color.BLACK, false) - : colorTo24BitSGR(Color.WHITE, false)) + colorTo24BitSGR(color, true); + final double range = max.doubleValue() - min.doubleValue(); + final double normal = range == 0 ? 0 : (getValue().doubleValue() - min.doubleValue()) / range; + final Color color = new Color(range(normal, GRADIENT_MIN.getRed(), GRADIENT_MAX.getRed()), range(normal, GRADIENT_MIN.getGreen(), GRADIENT_MAX.getGreen()), range(normal, GRADIENT_MIN.getBlue(), GRADIENT_MAX.getBlue())); + escape += (contrastRatio(color, Color.BLACK) > contrastRatio(Color.WHITE, color) ? colorTo24BitSGR(Color.BLACK, false) : colorTo24BitSGR(Color.WHITE, false)) + colorTo24BitSGR(color, true); } } private static String colorTo24BitSGR(final Color color, final boolean background) { - return CONTROL + CSI + (background ? BACKGROUND : FOREGROUND) + SEPARATOR + TRUECOLOR + SEPARATOR - + color.getRed() + SEPARATOR + color.getGreen() + SEPARATOR + color.getBlue() + SGR; + return CONTROL + CSI + (background ? BACKGROUND : FOREGROUND) + SEPARATOR + TRUECOLOR + SEPARATOR + color.getRed() + SEPARATOR + color.getGreen() + SEPARATOR + color.getBlue() + SGR; } private static int range(final double normal, final int min, final int max) { @@ -263,12 +224,9 @@ public class CSV { /* https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef */ private static float relativeLuminance(final Color color) { final float[] components = color.getRGBComponents(null); - final float r = components[0] <= 0.03928f ? components[0] / 12.92f - : (float) Math.pow((components[0] + 0.055f) / 1.055f, 2.4f); - final float g = components[1] <= 0.03928f ? components[1] / 12.92f - : (float) Math.pow((components[1] + 0.055f) / 1.055f, 2.4f); - final float b = components[2] <= 0.03928f ? components[2] / 12.92f - : (float) Math.pow((components[2] + 0.055f) / 1.055f, 2.4f); + final float r = components[0] <= 0.03928f ? components[0] / 12.92f : (float) Math.pow((components[0] + 0.055f) / 1.055f, 2.4f); + final float g = components[1] <= 0.03928f ? components[1] / 12.92f : (float) Math.pow((components[1] + 0.055f) / 1.055f, 2.4f); + final float b = components[2] <= 0.03928f ? components[2] / 12.92f : (float) Math.pow((components[2] + 0.055f) / 1.055f, 2.4f); return 0.2126f * r + 0.7152f * g + 0.0722f * b; } }