Fixed #2138 Missing morphshapes (incorrect holes calculation)

Fixed #2138 Mask layer was visible when did not contain a masked layer
This commit is contained in:
Jindra Petřík
2023-12-09 11:22:28 +01:00
parent 74ce252dad
commit 81d0c67e31
12 changed files with 650 additions and 92 deletions

View File

@@ -237,7 +237,7 @@ public class XFLConverter {
/**
* Adds "(depth xxx)" to layer name
*/
private final boolean DEBUG_EXPORT_LAYER_DEPTHS = false;
private final boolean DEBUG_EXPORT_LAYER_DEPTHS = true;
private static final DecimalFormat EDGE_DECIMAL_FORMAT = new DecimalFormat("0.#", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
@@ -4217,6 +4217,29 @@ public class XFLConverter {
index++;
}
}
if (index == parentIndex + 1) {
//put at least one empty layer as masked, otherwise the mask layer will be visible
writer.writeStartElement("DOMLayer", new String[]{
"name", "Layer " + (index + 1),
"color", randomOutlineColor(),
"parentLayerIndex", "" + parentIndex,
"locked", "true"
});
writer.writeStartElement("frames");
writer.writeStartElement("DOMFrame");
writer.writeAttribute("index", 0);
writer.writeAttribute("duration", lastFrame + 1);
writer.writeAttribute("keyMode", KEY_MODE_NORMAL);
writer.writeStartElement("elements");
writer.writeEndElement(); //elements
writer.writeEndElement(); //DOMFrame
writer.writeEndElement(); //frames
writer.writeEndElement(); //DOMLayer
index++;
}
for (int i = clipFrame; i <= lastFrame; i++) {
depthToFramesList.get(po.getDepth()).remove((Integer) i);
}

View File

@@ -64,8 +64,67 @@ public class MorphShapeFixer extends ShapeFixer {
mergeWithSamePrefix(shapes, fillStyles0, fillStyles1, lineStyles);
clearDuplicatePathsNextToEachOther(shapes, fillStyles0, lineStyles);
fixHolesAndAntiClockwise(shapes, fillStyles0, fillStyles1, lineStyles, layers);
mergeSamePathsWithOppositeFillstyles(shapes, fillStyles0, fillStyles1, lineStyles, layers);
}
/**
* shape 1 [FS0:A, FS1:-, LS:n], shape 2 [FS0:-, FS1:B, LS:n]
* => shape 1 [FS0:A, FS1:B], remove shape 2
* @param shapes
* @param fillStyles0
* @param fillStyles1
* @param lineStyles
* @param layers
*/
private void mergeSamePathsWithOppositeFillstyles(
List<List<BezierEdge>> shapes,
List<Integer> fillStyles0,
List<Integer> fillStyles1,
List<Integer> lineStyles,
List<Integer> layers
) {
for (int i1 = 0; i1 < shapes.size(); i1++) {
for (int i2 = 0; i2 < shapes.size(); i2++) {
if (i1 == i2) {
continue;
}
if (layers.get(i1) != layers.get(i2)) {
continue;
}
if (lineStyles.get(i1) != lineStyles.get(i2)) {
continue;
}
if (!shapes.get(i1).equals(shapes.get(i2))) {
continue;
}
boolean doRemove = false;
if (
fillStyles0.get(i1) != 0 && fillStyles1.get(i1) == 0
&& fillStyles1.get(i2) != 0 && fillStyles0.get(i2) == 0
) {
fillStyles1.set(i1, fillStyles1.get(i2));
doRemove = true;
} else if (
fillStyles1.get(i1) != 0 && fillStyles0.get(i1) == 0
&& fillStyles0.get(i2) != 0 && fillStyles1.get(i2) == 0
) {
fillStyles0.set(i1, fillStyles0.get(i2));
doRemove = true;
}
if (doRemove) {
shapes.remove(i2);
fillStyles0.remove(i2);
fillStyles1.remove(i2);
lineStyles.remove(i2);
layers.remove(i2);
i2--;
}
}
}
}
private boolean isEmptyPath(List<BezierEdge> path) {
for (BezierEdge be : path) {
if (!be.isEmpty()) {

View File

@@ -95,94 +95,15 @@ public class ShapeFixer {
List<LINESTYLEARRAY> lineStyleLayers
) {
}
public List<ShapeRecordAdvanced> fix(
List<SHAPERECORD> records,
int shapeNum,
FILLSTYLEARRAY baseFillStyles,
LINESTYLEARRAY baseLineStyles
private void detectOverlappingEdges(
List<List<BezierEdge>> shapes,
List<Integer> fillStyles0,
List<Integer> fillStyles1,
List<Integer> lineStyles,
List<Integer> layers
) {
List<List<BezierEdge>> shapes = new ArrayList<>();
List<BezierEdge> currentShape = new ArrayList<>();
List<Integer> fillStyles0 = new ArrayList<>();
List<Integer> fillStyles1 = new ArrayList<>();
List<Integer> lineStyles = new ArrayList<>();
List<Integer> layers = new ArrayList<>();
List<FILLSTYLEARRAY> fillStyleLayers = new ArrayList<>();
List<LINESTYLEARRAY> lineStyleLayers = new ArrayList<>();
int fillStyle0 = 0;
int fillStyle1 = 0;
int lineStyle = 0;
int layer = -1;
int x = 0;
int y = 0;
for (SHAPERECORD rec : records) {
if (rec instanceof StyleChangeRecord) {
StyleChangeRecord scr = (StyleChangeRecord) rec;
if (scr.stateMoveTo
|| scr.stateNewStyles
|| scr.stateFillStyle0
|| scr.stateFillStyle1
|| scr.stateLineStyle) {
if (!currentShape.isEmpty()) {
shapes.add(currentShape);
fillStyles0.add(fillStyle0);
fillStyles1.add(fillStyle1);
lineStyles.add(lineStyle);
layers.add(layer);
currentShape = new ArrayList<>();
}
}
if (scr.stateNewStyles) {
layer++;
fillStyle0 = 0;
fillStyle1 = 0;
lineStyle = 0;
fillStyleLayers.add(scr.fillStyles);
lineStyleLayers.add(scr.lineStyles);
}
if (scr.stateFillStyle0) {
fillStyle0 = scr.fillStyle0;
}
if (scr.stateFillStyle1) {
fillStyle1 = scr.fillStyle1;
}
if (scr.stateLineStyle) {
lineStyle = scr.lineStyle;
}
}
if (rec instanceof StraightEdgeRecord) {
int x2 = rec.changeX(x);
int y2 = rec.changeY(y);
BezierEdge be = new BezierEdge(x, y, x2, y2);
currentShape.add(be);
}
if (rec instanceof CurvedEdgeRecord) {
CurvedEdgeRecord cer = (CurvedEdgeRecord) rec;
int cx = x + cer.controlDeltaX;
int cy = y + cer.controlDeltaY;
int ax = cx + cer.anchorDeltaX;
int ay = cy + cer.anchorDeltaY;
BezierEdge be = new BezierEdge(x, y, cx, cy, ax, ay);
currentShape.add(be);
}
if (rec instanceof EndShapeRecord) {
if (!currentShape.isEmpty()) {
shapes.add(currentShape);
fillStyles0.add(fillStyle0);
fillStyles1.add(fillStyle1);
lineStyles.add(lineStyle);
layers.add(layer);
currentShape = new ArrayList<>();
}
}
x = rec.changeX(x);
y = rec.changeY(y);
}
beforeHandle(shapeNum, shapes, fillStyles0, fillStyles1, lineStyles, layers, baseFillStyles, baseLineStyles, fillStyleLayers, lineStyleLayers);
//------------------- detecting overlapping edges --------------------
List<BezierPair> splittedPairs = new ArrayList<>();
@@ -190,7 +111,7 @@ public class ShapeFixer {
//int oldpct = 0;
loopi1:
for (int i1 = 0; i1 < shapes.size(); i1++) {
layer = layers.get(i1);
int layer = layers.get(i1);
/*if (i1 % 10 == 0) {
int pct = i1 * 100 / shapes.size();
if (oldpct != pct) {
@@ -397,10 +318,102 @@ public class ShapeFixer {
}
}
}
}
private void splitToLayers(
List<SHAPERECORD> records,
List<List<BezierEdge>> shapes,
List<Integer> fillStyles0,
List<Integer> fillStyles1,
List<Integer> lineStyles,
List<Integer> layers,
List<FILLSTYLEARRAY> fillStyleLayers,
List<LINESTYLEARRAY> lineStyleLayers
) {
List<BezierEdge> currentShape = new ArrayList<>();
int fillStyle0 = 0;
int fillStyle1 = 0;
int lineStyle = 0;
int layer = -1;
int x = 0;
int y = 0;
for (SHAPERECORD rec : records) {
if (rec instanceof StyleChangeRecord) {
StyleChangeRecord scr = (StyleChangeRecord) rec;
if (scr.stateMoveTo
|| scr.stateNewStyles
|| scr.stateFillStyle0
|| scr.stateFillStyle1
|| scr.stateLineStyle) {
if (!currentShape.isEmpty()) {
shapes.add(currentShape);
fillStyles0.add(fillStyle0);
fillStyles1.add(fillStyle1);
lineStyles.add(lineStyle);
layers.add(layer);
currentShape = new ArrayList<>();
}
}
if (scr.stateNewStyles) {
layer++;
fillStyle0 = 0;
fillStyle1 = 0;
lineStyle = 0;
fillStyleLayers.add(scr.fillStyles);
lineStyleLayers.add(scr.lineStyles);
}
if (scr.stateFillStyle0) {
fillStyle0 = scr.fillStyle0;
}
if (scr.stateFillStyle1) {
fillStyle1 = scr.fillStyle1;
}
if (scr.stateLineStyle) {
lineStyle = scr.lineStyle;
}
}
if (rec instanceof StraightEdgeRecord) {
int x2 = rec.changeX(x);
int y2 = rec.changeY(y);
BezierEdge be = new BezierEdge(x, y, x2, y2);
currentShape.add(be);
}
if (rec instanceof CurvedEdgeRecord) {
CurvedEdgeRecord cer = (CurvedEdgeRecord) rec;
int cx = x + cer.controlDeltaX;
int cy = y + cer.controlDeltaY;
int ax = cx + cer.anchorDeltaX;
int ay = cy + cer.anchorDeltaY;
BezierEdge be = new BezierEdge(x, y, cx, cy, ax, ay);
currentShape.add(be);
}
if (rec instanceof EndShapeRecord) {
if (!currentShape.isEmpty()) {
shapes.add(currentShape);
fillStyles0.add(fillStyle0);
fillStyles1.add(fillStyle1);
lineStyles.add(lineStyle);
layers.add(layer);
currentShape = new ArrayList<>();
}
}
x = rec.changeX(x);
y = rec.changeY(y);
}
}
private List<ShapeRecordAdvanced> combineLayers(
List<List<BezierEdge>> shapes,
List<Integer> fillStyles0,
List<Integer> fillStyles1,
List<Integer> lineStyles,
List<Integer> layers,
List<FILLSTYLEARRAY> fillStyleLayers,
List<LINESTYLEARRAY> lineStyleLayers
) {
List<ShapeRecordAdvanced> ret = new ArrayList<>();
layer = -1;
int layer = -1;
double dx = 0;
double dy = 0;
for (int i = 0; i < shapes.size(); i++) {
@@ -446,6 +459,29 @@ public class ShapeFixer {
return ret;
}
public List<ShapeRecordAdvanced> fix(
List<SHAPERECORD> records,
int shapeNum,
FILLSTYLEARRAY baseFillStyles,
LINESTYLEARRAY baseLineStyles
) {
List<List<BezierEdge>> shapes = new ArrayList<>();
List<Integer> fillStyles0 = new ArrayList<>();
List<Integer> fillStyles1 = new ArrayList<>();
List<Integer> lineStyles = new ArrayList<>();
List<Integer> layers = new ArrayList<>();
List<FILLSTYLEARRAY> fillStyleLayers = new ArrayList<>();
List<LINESTYLEARRAY> lineStyleLayers = new ArrayList<>();
splitToLayers(records, shapes, fillStyles0, fillStyles1, lineStyles, layers, fillStyleLayers, lineStyleLayers);
beforeHandle(shapeNum, shapes, fillStyles0, fillStyles1, lineStyles, layers, baseFillStyles, baseLineStyles, fillStyleLayers, lineStyleLayers);
detectOverlappingEdges(shapes, fillStyles0, fillStyles1, lineStyles, layers);
return combineLayers(shapes, fillStyles0, fillStyles1, lineStyles, layers, fillStyleLayers, lineStyleLayers);
}
private ShapeRecordAdvanced bezierToAdvancedRecord(BezierEdge be) {
if (be.points.size() == 2) {
StraightEdgeRecordAdvanced ser = new StraightEdgeRecordAdvanced();