Lightpen on
Build and Test j3270 / Build JAR & Run Tests (push) Successful in 1m8s

This commit is contained in:
2026-08-24 16:55:38 +00:00
parent e28b7dc30a
commit d2bdb9bb0a
4 changed files with 70 additions and 32 deletions
@@ -35,9 +35,9 @@ public class GocaDecoder {
private int charHeight = 16;
private int charSet = 0;
private int arcParamP = 1;
private int arcParamQ = 1;
private int arcParamQ = 0;
private int arcParamR = 0;
private int arcParamS = 0;
private int arcParamS = 1;
private ProgramSymbolManager programSymbolManager;
@@ -832,48 +832,70 @@ public class GocaDecoder {
int centerX = curX;
int centerY = curY;
// For absolute variants, read the center point from data
if (!fromCurPos && pos + 4 <= off + len) {
centerX = readCoord(data, pos);
centerY = readCoord(data, pos + 2);
pos += 4;
}
double sweepFraction = 1.0;
if (!isFull && pos + 2 <= off + len) {
byte intPart = data[pos];
double fracPart = (data[pos + 1] & 0xFF) / 256.0;
sweepFraction = intPart + (intPart >= 0 ? fracPart : -fracPart);
// Read the multiplier (integer.fraction format)
double multiplier = 1.0;
if (pos + 2 <= off + len) {
int intPart = data[pos]; // signed byte
int fracPart = data[pos + 1] & 0xFF;
multiplier = intPart + fracPart / 256.0;
if (multiplier == 0.0) multiplier = 1.0;
pos += 2;
}
int pxCenter = plane.mapX(centerX);
int pyCenter = plane.mapY(centerY);
int pxCur = plane.mapX(curX);
int pyCur = plane.mapY(curY);
// Compute semi-axes from arc parameters scaled by multiplier
// P,Q and R,S are conjugate semi-diameter vectors
double pScaled = arcParamP * multiplier;
double qScaled = arcParamQ * multiplier;
double rScaled = arcParamR * multiplier;
double sScaled = arcParamS * multiplier;
double radius = Math.sqrt(Math.pow(pxCur - pxCenter, 2) + Math.pow(pyCur - pyCenter, 2));
int rx = (int) Math.round(radius);
int ry = rx;
if (rx <= 0) {
rx = 10;
ry = 10;
// Semi-axis lengths in GOCA coordinate space
double semiAxis1 = Math.sqrt(pScaled * pScaled + qScaled * qScaled);
double semiAxis2 = Math.sqrt(rScaled * rScaled + sScaled * sScaled);
if (semiAxis1 < 1.0) semiAxis1 = 1.0;
if (semiAxis2 < 1.0) semiAxis2 = 1.0;
// Map to pixel space
int rx = Math.abs(plane.mapX((int) Math.round(semiAxis1)) - plane.mapX(0));
int ry = Math.abs(plane.mapY(0) - plane.mapY((int) Math.round(semiAxis2)));
if (rx <= 0) rx = 1;
if (ry <= 0) ry = 1;
// For partial arcs, read sweep start and sweep angle
double startAngleDeg = 0.0;
double sweepAngleDeg = 360.0;
if (!isFull && pos + 4 <= off + len) {
// Sweep start: integer.fraction of full revolution
int startInt = data[pos];
int startFrac = data[pos + 1] & 0xFF;
startAngleDeg = (startInt + startFrac / 256.0) * 360.0;
pos += 2;
// Sweep angle: integer.fraction of full revolution
int sweepInt = data[pos];
int sweepFrac = data[pos + 1] & 0xFF;
sweepAngleDeg = (sweepInt + sweepFrac / 256.0) * 360.0;
} else if (!isFull) {
// No sweep data — default to full circle
sweepAngleDeg = 360.0;
}
double startAngleRad = Math.atan2(pyCenter - pyCur, pxCur - pxCenter);
double startAngleDeg = Math.toDegrees(startAngleRad);
if (startAngleDeg < 0) startAngleDeg += 360.0;
double sweepAngleDeg = isFull ? 360.0 : (sweepFraction * 360.0);
System.out.println("processArc: center=(" + centerX + "," + centerY + ") mult=" + multiplier
+ " P=" + arcParamP + " Q=" + arcParamQ + " R=" + arcParamR + " S=" + arcParamS
+ " rx=" + rx + " ry=" + ry + " start=" + startAngleDeg + " sweep=" + sweepAngleDeg
+ " isFull=" + isFull);
plane.drawArc(pxCenter, pyCenter, rx, ry, startAngleDeg, sweepAngleDeg,
plane.drawArc(plane.mapX(centerX), plane.mapY(centerY), rx, ry, startAngleDeg, sweepAngleDeg,
curColor, lineType, lineWidth, isFull);
// Arc ends at the end of the sweep
double endAngleRad = Math.toRadians(startAngleDeg + sweepAngleDeg);
int pxEnd = (int) Math.round(pxCenter + rx * Math.cos(endAngleRad));
int pyEnd = (int) Math.round(pyCenter - ry * Math.sin(endAngleRad));
curX = plane.unmapX(pxEnd);
curY = plane.unmapY(pyEnd);
curX = centerX;
curY = centerY;
}
private void processFillet(byte[] data, int off, int len, boolean fromCurPos) {
@@ -357,16 +357,20 @@ public class InputProcessor {
*/
public boolean lightPenSelect(int address) {
if (screen == null || !screen.isFormatted()) {
System.out.println("LP: screen null or unformatted");
return false;
}
int size = screen.getRows() * screen.getCols();
int faPos = screen.findFieldAttribute(address);
if (faPos < 0) {
System.out.println("LP: no FA found for addr=" + address);
return false;
}
ExtendedAttribute faCell = screen.getCell(faPos);
int fa = faCell.fa & 0xFF;
System.out.println("LP: addr=" + address + " faPos=" + faPos + " fa=0x" + String.format("%02X", fa)
+ " selectable=" + org.lib3270j.protocol.DS3270Constants.faIsSelectable(fa));
if (!org.lib3270j.protocol.DS3270Constants.faIsSelectable(fa)) {
return false;
}