[DEBUG] generation is opk, except the gradiant reflect that have some errors.

This commit is contained in:
Edouard DUPIN 2021-04-06 01:10:39 +02:00
parent 9a8e73d883
commit fb91ff5cbf
16 changed files with 362 additions and 260 deletions

View File

@ -67,7 +67,7 @@ public class Base {
Base(final PaintState parentPaintState) { Base(final PaintState parentPaintState) {
// copy the parent painting properties ... // copy the parent painting properties ...
this.paint = parentPaintState; this.paint = parentPaintState.clone();
} }
void display(final int spacing) {} void display(final int spacing) {}
@ -119,14 +119,14 @@ public class Base {
Pair<Color, String> localColor = new Pair<>(Color.WHITE, ""); Pair<Color, String> localColor = new Pair<>(Color.WHITE, "");
if (inputData.length() > 4 && inputData.charAt(0) == 'u' && inputData.charAt(1) == 'r' && inputData.charAt(2) == 'l' && inputData.charAt(3) == '(') { if (inputData.length() > 4 && inputData.charAt(0) == 'u' && inputData.charAt(1) == 'r' && inputData.charAt(2) == 'l' && inputData.charAt(3) == '(') {
if (inputData.charAt(4) == '#') { if (inputData.charAt(4) == '#') {
String color = inputData.substring(5); String color = inputData.substring(5, inputData.length() - 1);
localColor = new Pair<>(Color.NONE, color); localColor = new Pair<>(Color.NONE, color);
} else { } else {
Log.error("Problem in parsing the color : '" + inputData + "' == > url(XXX) is not supported now ..."); Log.error("Problem in parsing the color : '" + inputData + "' == > url(XXX) is not supported now ...");
} }
} else { } else {
try { try {
localColor = new Pair<>(Color.valueOf(inputData), ""); localColor = new Pair<>(Color.valueOf256(inputData), "");
} catch (Exception e) { } catch (Exception e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
@ -169,50 +169,48 @@ public class Base {
} }
} }
Pair<Float, Distance> parseLength2(final String dataInput) { Pair<Float, Distance> parseLength2(String config) {
Log.verbose(" lenght : '" + dataInput + "'");
float n = Float.parseFloat(dataInput); Distance type = Distance.PIXEL;
String unit = ""; if (config.endsWith("%")) {
for (int iii = 0; iii < dataInput.length(); ++iii) { type = Distance.POURCENT;
if ((dataInput.charAt(iii) >= '0' && dataInput.charAt(iii) <= '9') || dataInput.charAt(iii) == '+' || dataInput.charAt(iii) == '-' || dataInput.charAt(iii) == '.') { config = config.substring(0, config.length() - 1);
continue; } else if (config.endsWith("px")) {
} type = Distance.PIXEL;
unit = dataInput.substring(iii); config = config.substring(0, config.length() - 2);
break; } else if (config.endsWith("ft")) {
type = Distance.FOOT;
config = config.substring(0, config.length() - 2);
} else if (config.endsWith("in")) {
type = Distance.INCH;
config = config.substring(0, config.length() - 2);
} else if (config.endsWith("km")) {
type = Distance.KILOMETER;
config = config.substring(0, config.length() - 2);
} else if (config.endsWith("mm")) {
type = Distance.MILLIMETER;
config = config.substring(0, config.length() - 2);
} else if (config.endsWith("cm")) {
type = Distance.CENTIMETER;
config = config.substring(0, config.length() - 2);
} else if (config.endsWith("m")) {
type = Distance.METER;
config = config.substring(0, config.length() - 1);
} else if (config.endsWith("em")) {
type = Distance.ELEMENT;
config = config.substring(0, config.length() - 2);
} else if (config.endsWith("ex")) {
type = Distance.EX;
config = config.substring(0, config.length() - 2);
} else if (config.endsWith("pt")) {
type = Distance.POINT;
config = config.substring(0, config.length() - 2);
} else if (config.endsWith("pc")) {
type = Distance.PC;
config = config.substring(0, config.length() - 2);
} }
Log.verbose(" lenght : '" + n + "' => unit=" + unit); final float tmp = Float.parseFloat(config);
// note : ";" is for the parsing of the style elements ... return new Pair<>(tmp, type);
if (unit.length() == 0) {
return new Pair<>(n, Distance.PIXEL);
}
if (unit.charAt(0) == '%') { // xxx %
return new Pair<>(n, Distance.POURCENT);
}
if (unit.charAt(0) == 'e' && unit.charAt(1) == 'm') { // xxx em
return new Pair<>(n, Distance.ELEMENT);
}
if (unit.charAt(0) == 'e' && unit.charAt(1) == 'x') { // xxx ex
return new Pair<>(n, Distance.EX);
}
if (unit.charAt(0) == 'p' && unit.charAt(1) == 'x') { // xxx px
return new Pair<>(n, Distance.PIXEL);
}
if (unit.charAt(0) == 'p' && unit.charAt(1) == 't') { // xxx pt
return new Pair<>(n, Distance.POINT);
}
if (unit.charAt(0) == 'p' && unit.charAt(1) == 'c') { // xxx pc
return new Pair<>(n, Distance.PC);
}
if (unit.charAt(0) == 'm' && unit.charAt(1) == 'm') { // xxx mm
return new Pair<>(n, Distance.MILLIMETER);
}
if (unit.charAt(0) == 'c' && unit.charAt(1) == 'm') { // xxx cm
return new Pair<>(n, Distance.CENTIMETER);
}
if (unit.charAt(0) == 'i' && unit.charAt(1) == 'n') { // xxx in
return new Pair<>(n, Distance.INCH);
}
return new Pair<>(0.0f, Distance.PIXEL);
} }
/** /**
@ -237,6 +235,7 @@ public class Base {
} else { } else {
if (content.length() != 0) { if (content.length() != 0) {
this.paint.stroke = parseColor(content); this.paint.stroke = parseColor(content);
Log.error("Parse color : " + this.paint.stroke);
} }
content = element.getAttribute("stroke-width", ""); content = element.getAttribute("stroke-width", "");
if (content.length() != 0) { if (content.length() != 0) {

View File

@ -133,7 +133,7 @@ public class EsvgDocument extends Base {
} }
public Base getReference(final String name) { public Base getReference(final String name) {
if (name == "") { if (name.isEmpty()) {
Log.error("request a reference with no name ... "); Log.error("request a reference with no name ... ");
return null; return null;
} }
@ -141,7 +141,7 @@ public class EsvgDocument extends Base {
if (it == null) { if (it == null) {
continue; continue;
} }
if (it.getId() == name) { if (it.getId().equals(name)) {
return it; return it;
} }
} }

View File

@ -1,5 +1,6 @@
package org.atriasoft.esvg; package org.atriasoft.esvg;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.internal.Log; import org.atriasoft.esvg.internal.Log;
@ -15,7 +16,7 @@ import org.atriasoft.exml.model.XmlNode;
* @license MPL v2.0 (see license file) * @license MPL v2.0 (see license file)
*/ */
public class Group extends Base { public class Group extends Base {
private List<Base> subElementList; //!< sub elements ... private final List<Base> subElementList = new ArrayList<>(); //!< sub elements ...
public Group(final PaintState parentPaintState) { public Group(final PaintState parentPaintState) {
super(parentPaintState); super(parentPaintState);
@ -25,7 +26,7 @@ public class Group extends Base {
public void display(final int spacing) { public void display(final int spacing) {
Log.debug(spacingDist(spacing) + "Group (START) fill=" + this.paint.fill.first + "/" + this.paint.fill.second + " stroke=" + this.paint.stroke.first + "/" + this.paint.stroke.second Log.debug(spacingDist(spacing) + "Group (START) fill=" + this.paint.fill.first + "/" + this.paint.fill.second + " stroke=" + this.paint.stroke.first + "/" + this.paint.stroke.second
+ " stroke-width=" + this.paint.strokeWidth); + " stroke-width=" + this.paint.strokeWidth);
for (Base it : this.subElementList) { for (final Base it : this.subElementList) {
if (it != null) { if (it != null) {
it.display(spacing + 1); it.display(spacing + 1);
} }

View File

@ -50,7 +50,7 @@ public class LinearGradient extends Base {
} }
public List<Pair<Float, Color>> getColors(final EsvgDocument document) { public List<Pair<Float, Color>> getColors(final EsvgDocument document) {
if (this.href == "") { if (this.href.isEmpty()) {
return this.data; return this.data;
} }
if (document == null) { if (document == null) {
@ -99,16 +99,16 @@ public class LinearGradient extends Base {
String contentX = element.getAttribute("x1", ""); String contentX = element.getAttribute("x1", "");
String contentY = element.getAttribute("y1", ""); String contentY = element.getAttribute("y1", "");
if (contentX != "" && contentY != "") { if (!contentX.isEmpty() && !contentY.isEmpty()) {
this.pos1 = new Dimension(new Vector2f(Float.parseFloat(contentX), Float.parseFloat(contentY))); this.pos1 = Dimension.valueOf(contentX, contentY);
} }
contentX = element.getAttribute("x2", ""); contentX = element.getAttribute("x2", "");
contentY = element.getAttribute("y2", ""); contentY = element.getAttribute("y2", "");
if (contentX != "" && contentY != "") { if (!contentX.isEmpty() && !contentY.isEmpty()) {
this.pos2 = new Dimension(new Vector2f(Float.parseFloat(contentX), Float.parseFloat(contentY))); this.pos2 = Dimension.valueOf(contentX, contentY);
} }
contentX = element.getAttribute("gradientUnits", ""); contentX = element.getAttribute("gradientUnits", "");
if (contentX == "userSpaceOnUse") { if (contentX.equals("userSpaceOnUse")) {
this.unit = GradientUnits.gradientUnitsuserSpaceOnUse; this.unit = GradientUnits.gradientUnitsuserSpaceOnUse;
} else { } else {
this.unit = GradientUnits.gradientUnitsobjectBoundingBox; this.unit = GradientUnits.gradientUnitsobjectBoundingBox;
@ -117,13 +117,13 @@ public class LinearGradient extends Base {
} }
} }
contentX = element.getAttribute("spreadMethod", ""); contentX = element.getAttribute("spreadMethod", "");
if (contentX == "reflect") { if (contentX.equals("reflect")) {
this.spread = SpreadMethod.REFLECT; this.spread = SpreadMethod.REFLECT;
} else if (contentX == "repeat") { } else if (contentX.equals("repeat")) {
this.spread = SpreadMethod.REPEAT; this.spread = SpreadMethod.REPEAT;
} else { } else {
this.spread = SpreadMethod.PAD; this.spread = SpreadMethod.PAD;
if (contentX.length() != 0 && contentX != "pad") { if (contentX.length() != 0 && !contentX.equals("pad")) {
Log.error("Parsing error of 'spreadMethod' ==> not suported value: '" + contentX + "' not in : {reflect/repeate/pad} use pad"); Log.error("Parsing error of 'spreadMethod' ==> not suported value: '" + contentX + "' not in : {reflect/repeate/pad} use pad");
} }
} }
@ -135,7 +135,7 @@ public class LinearGradient extends Base {
// parse all sub node : // parse all sub node :
for (XmlNode it : element.getNodes()) { for (XmlNode it : element.getNodes()) {
if (it instanceof XmlElement child) { if (it instanceof XmlElement child) {
if (child.getValue() == "stop") { if (child.getValue().equals("stop")) {
float offset = 100; float offset = 100;
Color stopColor = Color.NONE; Color stopColor = Color.NONE;
String content = child.getAttribute("offset", ""); String content = child.getAttribute("offset", "");
@ -169,7 +169,7 @@ public class LinearGradient extends Base {
} }
} }
if (this.data.size() != 0) { if (this.data.size() != 0) {
if (this.href != "") { if (!this.href.isEmpty()) {
Log.error(" node can not have an xlink:href element with sub node named: stop ==> removing href"); Log.error(" node can not have an xlink:href element with sub node named: stop ==> removing href");
this.href = ""; this.href = "";
} }

View File

@ -29,4 +29,20 @@ public class PaintState {
this.miterLimit = 4.0f; this.miterLimit = 4.0f;
this.opacity = 1.0f; this.opacity = 1.0f;
} }
@Override
protected PaintState clone() {
PaintState out = new PaintState();
out.fill = this.fill;
out.stroke = this.stroke;
out.strokeWidth = this.strokeWidth;
out.viewPort = this.viewPort;
out.flagEvenOdd = this.flagEvenOdd;
out.lineJoin = this.lineJoin;
out.lineCap = this.lineCap;
out.miterLimit = this.miterLimit;
out.opacity = this.opacity;
return out;
}
} }

View File

@ -12,6 +12,7 @@ import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.SegmentList; import org.atriasoft.esvg.render.SegmentList;
import org.atriasoft.etk.math.Matrix2x3f; import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.math.Vector2i;
import org.atriasoft.etk.util.Dynamic; import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.exml.model.XmlElement; import org.atriasoft.exml.model.XmlElement;
import org.atriasoft.exml.parser.Tools; import org.atriasoft.exml.parser.Tools;
@ -24,11 +25,11 @@ import org.atriasoft.exml.parser.Tools;
public class Path extends Base { public class Path extends Base {
private record Command( private record Command(
char cmd, char cmd,
float[] listDot, String[] listElem,
int offset) { int offset) {
Command(final char cmd, final float[] listDot, final int offset) { Command(final char cmd, final String[] listElem, final int offset) {
this.cmd = cmd; this.cmd = cmd;
this.listDot = listDot; this.listElem = listElem;
this.offset = offset; this.offset = offset;
} }
@ -42,7 +43,7 @@ public class Path extends Base {
StringBuilder out = new StringBuilder(input.length()); StringBuilder out = new StringBuilder(input.length());
boolean haveSpace = false; boolean haveSpace = false;
for (char it : input.toCharArray()) { for (char it : input.toCharArray()) {
if (it == ' ' || it == '\t' || it == '\t' || it == '\r') { if (it == ' ' || it == '\t' || it == '\r') {
haveSpace = true; haveSpace = true;
} else { } else {
if (haveSpace) { if (haveSpace) {
@ -56,52 +57,48 @@ public class Path extends Base {
} }
//return the next char position ... (after 'X' or NULL) //return the next char position ... (after 'X' or NULL)
private static Command extractCmd(final char[] input, final int offset) { private static Command extractCmd(final List<String> input, final int offset) {
if (input[offset] == '\0') { if (input.size() <= offset) {
// Log.warning("parse command : END");
return null; return null;
} }
char cmd = '\0'; // Log.warning("parse command : (rest) " + offset);
if (!((input[offset] <= 'Z' && input[offset] >= 'A') || (input[offset] <= 'z' && input[offset] >= 'a'))) { // for (int iii = offset; iii < input.size(); iii++) {
Log.error("Error in the SVG Path : '" + input + "' [" + offset); // Log.warning(" -[" + iii + "] '" + input.get(iii) + "'");
// }
if (input.get(offset).length() != 1) {
Log.error("Error in the SVG Path : '" + input.get(offset) + "' [" + offset);
return null; return null;
} }
cmd = input[0]; char cmd = input.get(offset).charAt(0);
Log.verbose("Find command : " + cmd); if (!((cmd <= 'Z' && cmd >= 'A') || (cmd <= 'z' && cmd >= 'a'))) {
if (input[offset + 1] == '\0') { Log.error("Error in the SVG Path : '" + cmd + "' [" + offset);
return null;
}
//Log.verbose("Find command : " + cmd);
if (input.size() == offset) {
return new Command(cmd, offset + 1); return new Command(cmd, offset + 1);
} }
StringBuilder tmpData = new StringBuilder();
List<String> elements = new ArrayList<>();
int iii; int iii;
for (iii = offset; iii < input.length; iii++) { for (iii = offset + 1; iii < input.size(); iii++) {
if (Tools.checkNumber(input[iii], iii == offset)) { char startElem = input.get(iii).charAt(0);
tmpData.append(input[iii]); if ((startElem <= 'Z' && startElem >= 'A') || (startElem <= 'z' && startElem >= 'a')) {
continue; // find end of elements
break;
} }
elements.add(tmpData.toString());
tmpData.setLength(0);
if (input[iii] == ' ' || input[iii] == '\t' || input[iii] == '\n' || input[iii] == '\r' || input[iii] == ',' || input[iii] == ';') {
continue;
}
break;
} }
float[] outputList = new float[elements.size()]; int length = iii - (offset + 1);
int jjj = 0; if (length == 0) {
for (String ekems : elements) { return new Command(cmd, null, iii + 1);
outputList[jjj++] = Float.parseFloat(ekems);
} }
// remove after white space... String[] outputList = new String[length];
for (; iii < input.length; iii++) { for (int jjj = 0; jjj < length; jjj++) {
if (input[iii] == ' ' || input[iii] == '\t' || input[iii] == '\n' || input[iii] == '\r') { outputList[jjj] = input.get(offset + 1 + jjj);
continue;
}
break;
} }
return new Command(cmd, outputList, offset + 1); return new Command(cmd, outputList, iii);
} }
public PathModel listElement; public PathModel listElement = new PathModel();
public Path(final PaintState parentPaintState) { public Path(final PaintState parentPaintState) {
super(parentPaintState); super(parentPaintState);
@ -190,41 +187,47 @@ public class Path extends Base {
return false; return false;
} }
Log.verbose("Parse Path : \"" + elementXML1 + "\""); Log.verbose("Parse Path : \"" + elementXML1 + "\"");
List<String> commandsSplited = splitCommand(elementXML1);
float[] listDot = null; String[] listDot = null;
elementXML1 = Path.cleanBadSpaces(elementXML1);
char[] elementXML = elementXML1.toCharArray();
// TODO REWORK this, can be done with a simple split and search in a list... // TODO REWORK this, can be done with a simple split and search in a list...
for (Command sss = Path.extractCmd(elementXML, 0); sss != null; sss = Path.extractCmd(elementXML, sss.offset())) { for (Command sss = Path.extractCmd(commandsSplited, 0); sss != null; sss = Path.extractCmd(commandsSplited, sss.offset())) {
boolean relative = false; boolean relative = false;
listDot = sss.listDot(); listDot = sss.listElem();
Log.error("Find new command : '" + sss.cmd + "'");
if (listDot != null) {
for (int jjj = 0; jjj < listDot.length; jjj++) {
Log.error(" -> '" + listDot[jjj] + "'");
}
} else {
Log.error(" -> no elements");
}
switch (sss.cmd) { switch (sss.cmd) {
case 'm': // Move to (relative) case 'm': // Move to (relative)
relative = true; relative = true;
case 'M': // Move to (absolute) case 'M': // Move to (absolute)
// 2 Elements ... if (listDot == null) {
if (listDot.length % 2 != 0) { Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length);
break; break;
} }
if (listDot.length >= 2) { // 2 Elements ...
this.listElement.moveTo(relative, new Vector2f(listDot[0], listDot[1])); if (listDot.length >= 1) {
this.listElement.moveTo(relative, Vector2f.valueOf(listDot[0]));
} }
for (int iii = 2; iii < listDot.length; iii += 2) { for (int iii = 1; iii < listDot.length; iii++) {
this.listElement.lineTo(relative, new Vector2f(listDot[iii], listDot[iii + 1])); this.listElement.lineTo(relative, Vector2f.valueOf(listDot[iii]));
} }
break; break;
case 'l': // Line to (relative) case 'l': // Line to (relative)
relative = true; relative = true;
case 'L': // Line to (absolute) case 'L': // Line to (absolute)
// 2 Elements ... if (listDot == null) {
if (listDot.length % 2 != 0) { Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length);
break; break;
} }
for (int iii = 0; iii < listDot.length; iii += 2) { for (int iii = 0; iii < listDot.length; iii++) {
this.listElement.lineTo(relative, new Vector2f(listDot[iii], listDot[iii + 1])); this.listElement.lineTo(relative, Vector2f.valueOf(listDot[iii]));
} }
break; break;
@ -232,12 +235,12 @@ public class Path extends Base {
relative = true; relative = true;
case 'V': // Vertical Line to (absolute) case 'V': // Vertical Line to (absolute)
// 1 Element ... // 1 Element ...
if (listDot.length == 0) { if (listDot == null) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length); Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
break; break;
} }
for (int iii = 0; iii < listDot.length; iii += 1) { for (int iii = 0; iii < listDot.length; iii++) {
this.listElement.lineToV(relative, listDot[iii]); this.listElement.lineToV(relative, Float.parseFloat(listDot[iii]));
} }
break; break;
@ -245,25 +248,29 @@ public class Path extends Base {
relative = true; relative = true;
case 'H': // Horizantal Line to (absolute) case 'H': // Horizantal Line to (absolute)
// 1 Element ... // 1 Element ...
if (listDot.length == 0) { if (listDot == null) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length); Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
break; break;
} }
for (int iii = 0; iii < listDot.length; iii += 1) { for (int iii = 0; iii < listDot.length; iii++) {
this.listElement.lineToH(relative, listDot[iii]); this.listElement.lineToH(relative, Float.parseFloat(listDot[iii]));
} }
break; break;
case 'q': // Quadratic Bezier curve (relative) case 'q': // Quadratic Bezier curve (relative)
relative = true; relative = true;
case 'Q': // Quadratic Bezier curve (absolute) case 'Q': // Quadratic Bezier curve (absolute)
if (listDot == null) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
break;
}
// 4 Elements ... // 4 Elements ...
if (listDot.length % 4 != 0) { if (listDot.length % 2 != 0) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length); Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length);
break; break;
} }
for (int iii = 0; iii < listDot.length; iii += 4) { for (int iii = 0; iii < listDot.length; iii += 2) {
this.listElement.bezierCurveTo(relative, new Vector2f(listDot[iii], listDot[iii + 1]), new Vector2f(listDot[iii + 2], listDot[iii + 3])); this.listElement.bezierCurveTo(relative, Vector2f.valueOf(listDot[iii]), Vector2f.valueOf(listDot[iii + 1]));
} }
break; break;
@ -271,68 +278,75 @@ public class Path extends Base {
relative = true; relative = true;
case 'T': // smooth quadratic Bezier curve to (absolute) case 'T': // smooth quadratic Bezier curve to (absolute)
// 2 Elements ... // 2 Elements ...
if (listDot.length % 2 != 0) { for (int iii = 0; iii < listDot.length; iii++) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length); this.listElement.bezierSmoothCurveTo(relative, Vector2f.valueOf(listDot[iii]));
break;
}
for (int iii = 0; iii < listDot.length; iii += 2) {
this.listElement.bezierSmoothCurveTo(relative, new Vector2f(listDot[iii], listDot[iii + 1]));
} }
break; break;
case 'c': // curve to (relative) case 'c': // curve to (relative)
relative = true; relative = true;
case 'C': // curve to (absolute) case 'C': // curve to (absolute)
if (listDot == null) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
break;
}
// 6 Elements ... // 6 Elements ...
if (listDot.length % 6 != 0) { if (listDot.length % 3 != 0) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length); Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length);
break; break;
} }
for (int iii = 0; iii < listDot.length; iii += 6) { for (int iii = 0; iii < listDot.length; iii += 3) {
this.listElement.curveTo(relative, new Vector2f(listDot[iii], listDot[iii + 1]), new Vector2f(listDot[iii + 2], listDot[iii + 3]), this.listElement.curveTo(relative, Vector2f.valueOf(listDot[iii]), Vector2f.valueOf(listDot[iii + 1]), Vector2f.valueOf(listDot[iii + 2]));
new Vector2f(listDot[iii + 4], listDot[iii + 5]));
} }
break; break;
case 's': // smooth curve to (relative) case 's': // smooth curve to (relative)
relative = true; relative = true;
case 'S': // smooth curve to (absolute) case 'S': // smooth curve to (absolute)
if (listDot == null) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
break;
}
// 4 Elements ... // 4 Elements ...
if (listDot.length % 4 != 0) { if (listDot.length % 2 != 0) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length); Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length);
break; break;
} }
for (int iii = 0; iii < listDot.length; iii += 4) { for (int iii = 0; iii < listDot.length; iii += 2) {
this.listElement.smoothCurveTo(relative, new Vector2f(listDot[iii], listDot[iii + 1]), new Vector2f(listDot[iii + 2], listDot[iii + 3])); this.listElement.smoothCurveTo(relative, Vector2f.valueOf(listDot[iii]), Vector2f.valueOf(listDot[iii + 1]));
} }
break; break;
case 'a': // elliptical Arc (relative) case 'a': // elliptical Arc (relative)
relative = true; relative = true;
case 'A': // elliptical Arc (absolute) case 'A': // elliptical Arc (absolute)
// 7 Elements ... if (listDot == null) {
if (listDot.length % 7 != 0) { Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
break;
}
// 4 element ff,ff f i,i ff,ff Elements ...
if (listDot.length % 4 != 0) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length); Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length);
break; break;
} }
for (int iii = 0; iii < listDot.length; iii += 7) { for (int iii = 0; iii < listDot.length; iii += 7) {
boolean largeArcFlag = true; boolean largeArcFlag = true;
boolean sweepFlag = true; boolean sweepFlag = true;
if (listDot[iii + 3] == 0.0f) { Vector2i tmp = Vector2i.valueOf(listDot[iii + 2]);
if (tmp.x() == 0) {
largeArcFlag = false; largeArcFlag = false;
} }
if (listDot[iii + 4] == 0.0f) { if (tmp.y() == 0) {
sweepFlag = false; sweepFlag = false;
} }
this.listElement.ellipticTo(relative, new Vector2f(listDot[iii], listDot[iii + 1]), listDot[iii + 2], largeArcFlag, sweepFlag, this.listElement.ellipticTo(relative, Vector2f.valueOf(listDot[iii]), Float.parseFloat(listDot[iii + 1]), largeArcFlag, sweepFlag, Vector2f.valueOf(listDot[iii + 3]));
new Vector2f(listDot[iii + 5], listDot[iii + 6]));
} }
break; break;
case 'z': // closepath (relative) case 'z': // closepath (relative)
relative = true; relative = true;
case 'Z': // closepath (absolute) case 'Z': // closepath (absolute)
// 0 Element ... // 0 Element ...
if (listDot.length != 0) { if (listDot != null) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length); Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length);
break; break;
} }
@ -346,4 +360,45 @@ public class Path extends Base {
return true; return true;
} }
List<String> splitCommand(final String data) {
List<String> out = new ArrayList<>();
StringBuilder tmpString = new StringBuilder(20);
boolean isText = false;
boolean isNumber = false;
for (char it : data.toCharArray()) {
if (it == ' ' || it == '\t' || it == '\r') {
String elements = tmpString.toString();
if (!elements.isEmpty()) {
out.add(elements);
}
tmpString.setLength(0);
isText = false;
isNumber = false;
} else if (Tools.checkNumber(it, true) || it == ',' || it == '.') {
if (isText) {
out.add(tmpString.toString());
tmpString.setLength(0);
}
isText = false;
isNumber = true;
tmpString.append(it);
} else if ((it <= 'Z' && it >= 'A') || (it <= 'z' && it >= 'a')) {
if (isNumber) {
out.add(tmpString.toString());
tmpString.setLength(0);
}
isText = true;
isNumber = false;
tmpString.append(it);
} else {
Log.error("Can not parse path : '" + it + "'");
}
}
String elements = tmpString.toString();
if (!elements.isEmpty()) {
out.add(elements);
}
return out;
}
} }

View File

@ -23,7 +23,7 @@ import org.atriasoft.esvg.internal.Log;
*/ */
public class Polygon extends Base { public class Polygon extends Base {
private List<Vector2f> listPoint; //!< list of all point of the polygone private final List<Vector2f> listPoint = new ArrayList<>(); //!< list of all point of the polygone
public Polygon(final PaintState parentPaintState) { public Polygon(final PaintState parentPaintState) {
super(parentPaintState); super(parentPaintState);

View File

@ -52,7 +52,7 @@ public class RadialGradient extends Base {
} }
public List<Pair<Float, Color>> getColors(final EsvgDocument document) { public List<Pair<Float, Color>> getColors(final EsvgDocument document) {
if (this.href == "") { if (this.href.isEmpty()) {
return this.data; return this.data;
} }
if (document == null) { if (document == null) {
@ -100,20 +100,20 @@ public class RadialGradient extends Base {
String contentX = element.getAttribute("cx", ""); String contentX = element.getAttribute("cx", "");
String contentY = element.getAttribute("cy", ""); String contentY = element.getAttribute("cy", "");
if (contentX != "" && contentY != "") { if (!contentX.isEmpty() && !contentY.isEmpty()) {
this.center = new Dimension(new Vector2f(Float.parseFloat(contentX), Float.parseFloat(contentY))); this.center = Dimension.valueOf(contentX, contentY);
} }
contentX = element.getAttribute("r", ""); contentX = element.getAttribute("r", "");
if (contentX != "") { if (contentX != "") {
this.radius = new Dimension1D(Float.parseFloat(contentX)); this.radius = Dimension1D.valueOf(contentX);
} }
contentX = element.getAttribute("fx", ""); contentX = element.getAttribute("fx", "");
contentY = element.getAttribute("fy", ""); contentY = element.getAttribute("fy", "");
if (contentX != "" && contentY != "") { if (!contentX.isEmpty() && !contentY.isEmpty()) {
this.focal = new Dimension(new Vector2f(Float.parseFloat(contentX), Float.parseFloat(contentY))); this.focal = Dimension.valueOf(contentX, contentY);
} }
contentX = element.getAttribute("gradientUnits", ""); contentX = element.getAttribute("gradientUnits", "");
if (contentX == "userSpaceOnUse") { if (contentX.equals("userSpaceOnUse")) {
this.unit = GradientUnits.gradientUnitsuserSpaceOnUse; this.unit = GradientUnits.gradientUnitsuserSpaceOnUse;
} else { } else {
this.unit = GradientUnits.gradientUnitsobjectBoundingBox; this.unit = GradientUnits.gradientUnitsobjectBoundingBox;
@ -122,13 +122,13 @@ public class RadialGradient extends Base {
} }
} }
contentX = element.getAttribute("spreadMethod", ""); contentX = element.getAttribute("spreadMethod", "");
if (contentX == "reflect") { if (contentX.equals("reflect")) {
this.spread = SpreadMethod.REFLECT; this.spread = SpreadMethod.REFLECT;
} else if (contentX == "repeat") { } else if (contentX.equals("repeat")) {
this.spread = SpreadMethod.REPEAT; this.spread = SpreadMethod.REPEAT;
} else { } else {
this.spread = SpreadMethod.PAD; this.spread = SpreadMethod.PAD;
if (contentX.length() != 0 && contentX != "pad") { if (contentX.length() != 0 && !contentX.equals("pad")) {
Log.error("Parsing error of 'spreadMethod' ==> not suported value: '" + contentX + "' not in : {reflect/repeate/pad} use pad"); Log.error("Parsing error of 'spreadMethod' ==> not suported value: '" + contentX + "' not in : {reflect/repeate/pad} use pad");
} }
} }
@ -140,7 +140,7 @@ public class RadialGradient extends Base {
// parse all sub node : // parse all sub node :
for (XmlNode it : element.getNodes()) { for (XmlNode it : element.getNodes()) {
if (it instanceof XmlElement child) { if (it instanceof XmlElement child) {
if (child.getValue() == "stop") { if (child.getValue().equals("stop")) {
float offset = 100; float offset = 100;
Color stopColor = Color.NONE; Color stopColor = Color.NONE;
String content = child.getAttribute("offset", ""); String content = child.getAttribute("offset", "");
@ -174,7 +174,7 @@ public class RadialGradient extends Base {
} }
} }
if (this.data.size() != 0) { if (this.data.size() != 0) {
if (this.href != "") { if (!this.href.isEmpty()) {
Log.error("node can not have an xlink:href element with sub node named: stop ==> removing href"); Log.error("node can not have an xlink:href element with sub node named: stop ==> removing href");
this.href = ""; this.href = "";
} }

View File

@ -22,7 +22,7 @@ import org.atriasoft.etk.util.ArraysTools;
*/ */
public class Renderer { public class Renderer {
private static final boolean DEBUG_MODE = true; private static final boolean DEBUG_MODE = false;
protected Color[][] buffer; // for debug protected Color[][] buffer; // for debug
protected EsvgDocument document; // for debug protected EsvgDocument document; // for debug
@ -205,8 +205,8 @@ public class Renderer {
Color intermediateColor = mergeColor(intermediateColorFill, intermediateColorStroke); Color intermediateColor = mergeColor(intermediateColorFill, intermediateColorStroke);
intermediateColor = intermediateColor.withA(intermediateColor.a() * opacity); intermediateColor = intermediateColor.withA(intermediateColor.a() * opacity);
if (Renderer.DEBUG_MODE) { if (Renderer.DEBUG_MODE) {
for (int deltaY = 0; deltaY < this.factor; ++deltaY) { for (int deltaY = 0; deltaY < this.factor; deltaY++) {
for (int deltaX = 0; deltaX < this.factor; ++deltaX) { for (int deltaX = 0; deltaX < this.factor; deltaX++) {
int idx = xxx * this.factor + deltaX; int idx = xxx * this.factor + deltaX;
int idy = yyy * this.factor + deltaY; int idy = yyy * this.factor + deltaY;
this.buffer[idy][idx] = mergeColor(this.buffer[idy][idx], intermediateColor); this.buffer[idy][idx] = mergeColor(this.buffer[idy][idx], intermediateColor);
@ -257,9 +257,9 @@ public class Renderer {
public void setSize(final Vector2i size) { public void setSize(final Vector2i size) {
this.size = size; this.size = size;
if (Renderer.DEBUG_MODE) { if (Renderer.DEBUG_MODE) {
this.buffer = new Color[this.size.x()][this.size.y()]; this.buffer = new Color[this.size.y()][this.size.x()];
} else { } else {
this.buffer = new Color[this.size.x() * this.factor][this.size.y() * this.factor]; this.buffer = new Color[this.size.y() * this.factor][this.size.x() * this.factor];
} }
ArraysTools.fill2(this.buffer, Color.NONE); ArraysTools.fill2(this.buffer, Color.NONE);
} }

View File

@ -5,6 +5,7 @@ import org.atriasoft.etk.util.Pair;
import org.atriasoft.etk.math.Matrix2x3f; import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.esvg.EsvgDocument; import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.Color; import org.atriasoft.etk.Color;
/** @file /** @file
@ -20,6 +21,7 @@ public interface DynamicColor {
return null; return null;
} }
if (color.second.isEmpty()) { if (color.second.isEmpty()) {
Log.error("use stroke color :" + color);
return new DynamicColorUni(color.first); return new DynamicColorUni(color.first);
} }
return new DynamicColorSpecial(color.second, mtx); return new DynamicColorSpecial(color.second, mtx);

View File

@ -65,7 +65,7 @@ public class DynamicColorSpecial implements DynamicColor {
distToIntersection = FMath.sqrt(radius * radius - distToCenter * distToCenter); distToIntersection = FMath.sqrt(radius * radius - distToCenter * distToCenter);
} }
// normalize... // normalize...
v1.safeNormalize(); v1 = v1.safeNormalize();
v1 = v1.multiply(distToIntersection); v1 = v1.multiply(distToIntersection);
return new Pair<>(midpt.add(v1), midpt.less(v1)); return new Pair<>(midpt.add(v1), midpt.less(v1));
} }
@ -396,7 +396,7 @@ public class DynamicColorSpecial implements DynamicColor {
// nothing to do ... // nothing to do ...
break; break;
case REFLECT: case REFLECT:
ratio -= ((int) (ratio) >> 1) + 1; ratio -= (((int) (ratio)) >> 1) + 1;
if (ratio > 1.0f) { if (ratio > 1.0f) {
ratio = 2.0f - ratio; ratio = 2.0f - ratio;
} }

View File

@ -149,8 +149,8 @@ public class PathModel {
// Remove the last point if it is the same position... // Remove the last point if it is the same position...
Vector2f delta = (tmpListPoint.get(0).pos.less(tmpListPoint.get(tmpListPoint.size() - 1).pos)).abs(); Vector2f delta = (tmpListPoint.get(0).pos.less(tmpListPoint.get(tmpListPoint.size() - 1).pos)).abs();
if (delta.x() <= 0.00001 && delta.y() <= 0.00001) { if (delta.x() <= 0.00001 && delta.y() <= 0.00001) {
tmpListPoint.remove(tmpListPoint.size() - 1);
Log.verbose(" Remove point Z property : " + tmpListPoint.get(tmpListPoint.size() - 1).pos + " with delta=" + delta); Log.verbose(" Remove point Z property : " + tmpListPoint.get(tmpListPoint.size() - 1).pos + " with delta=" + delta);
tmpListPoint.remove(tmpListPoint.size() - 1);
} }
out.addList(tmpListPoint); out.addList(tmpListPoint);
tmpListPoint = new ArrayList<>(); tmpListPoint = new ArrayList<>();

View File

@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.etk.util.Pair; import org.atriasoft.etk.util.Pair;
import org.atriasoft.etk.math.FMath; import org.atriasoft.etk.math.FMath;
import org.atriasoft.etk.math.Matrix2x3f; import org.atriasoft.etk.math.Matrix2x3f;
@ -50,8 +51,10 @@ public class SegmentList {
this.data.add(new Segment(pos0.pos, pos1.pos)); this.data.add(new Segment(pos0.pos, pos1.pos));
} }
// TODO is it really needed...
void addSegment(final Vector2f pos0, final Vector2f pos1) { void addSegment(final Vector2f pos0, final Vector2f pos1) {
if (pos0.y() == pos1.y()) {
return;
}
this.data.add(new Segment(pos0, pos1)); this.data.add(new Segment(pos0, pos1));
} }
@ -77,7 +80,7 @@ public class SegmentList {
// normal edge * end path // normal edge * end path
// (mitter) * | * * * * * * * * * * * * * * // (mitter) * | * * * * * * * * * * * * * *
// * |<--*----this | * // * |<--*----this | *
// * | * this -.| * // * | * this -->| *
// * * * | * // * * * | *
// * . | . * . . . . . . . . * * // * . | . * . . . . . . . . * *
// * . | . * | * // * . | . * | *
@ -103,32 +106,32 @@ public class SegmentList {
//Log.debug("JOIN : val : prev/curr/next : " + itListPoint.get(idPevious).pos + "/" + itListPoint.get(idCurrent).pos + "/" + itListPoint.get(idNext).pos); //Log.debug("JOIN : val : prev/curr/next : " + itListPoint.get(idPevious).pos + "/" + itListPoint.get(idCurrent).pos + "/" + itListPoint.get(idNext).pos);
Vector2f vecA = itListPoint.get(idCurrent).pos.less(itListPoint.get(idPevious).pos); Vector2f vecA = itListPoint.get(idCurrent).pos.less(itListPoint.get(idPevious).pos);
//Log.debug("JOIN : vecA : " + vecA); //Log.debug("JOIN : vecA : " + vecA);
vecA.safeNormalize(); vecA = vecA.safeNormalize();
Vector2f vecB = itListPoint.get(idNext).pos.less(itListPoint.get(idCurrent).pos); Vector2f vecB = itListPoint.get(idNext).pos.less(itListPoint.get(idCurrent).pos);
//Log.debug("JOIN : vecB : " + vecB); //Log.debug("JOIN : vecB : " + vecB);
vecB.safeNormalize(); vecB = vecB.safeNormalize();
Vector2f vecC = vecA.less(vecB); Vector2f vecC = vecA.less(vecB);
//Log.debug("JOIN : vecC : " + vecC); //Log.debug("JOIN : vecC : " + vecC);
if (vecC.isZero()) { if (vecC.isZero()) {
// special case: 1 line ... // special case: 1 line ...
itListPoint.get(idCurrent).miterAxe = new Vector2f(vecA.y(), vecA.x()); itListPoint.get(idCurrent).miterAxe = new Vector2f(vecA.y(), vecA.x());
} else { } else {
vecC.safeNormalize(); vecC = vecC.safeNormalize();
itListPoint.get(idCurrent).miterAxe = vecC; itListPoint.get(idCurrent).miterAxe = vecC;
} }
itListPoint.get(idCurrent).posPrevious = itListPoint.get(idPevious).pos; itListPoint.get(idCurrent).posPrevious = itListPoint.get(idPevious).pos;
itListPoint.get(idCurrent).posNext = itListPoint.get(idNext).pos; itListPoint.get(idCurrent).posNext = itListPoint.get(idNext).pos;
vecB = itListPoint.get(idNext).pos.less(itListPoint.get(idCurrent).pos); vecB = itListPoint.get(idNext).pos.less(itListPoint.get(idCurrent).pos);
vecB.safeNormalize(); vecB = vecB.safeNormalize();
itListPoint.get(idCurrent).orthoAxeNext = new Vector2f(vecB.y(), -vecB.x()); itListPoint.get(idCurrent).orthoAxeNext = new Vector2f(vecB.y(), -vecB.x());
vecB = itListPoint.get(idCurrent).pos.less(itListPoint.get(idPevious).pos); vecB = itListPoint.get(idCurrent).pos.less(itListPoint.get(idPevious).pos);
vecB.safeNormalize(); vecB = vecB.safeNormalize();
itListPoint.get(idCurrent).orthoAxePrevious = new Vector2f(vecB.y(), -vecB.x()); itListPoint.get(idCurrent).orthoAxePrevious = new Vector2f(vecB.y(), -vecB.x());
//Log.debug("JOIN : miterAxe " + itListPoint.get(idCurrent).miterAxe); //Log.debug("JOIN : miterAxe " + itListPoint.get(idCurrent).miterAxe);
} else if (itListPoint.get(idCurrent).type == PointType.start) { } else if (itListPoint.get(idCurrent).type == PointType.start) {
itListPoint.get(idCurrent).posNext = itListPoint.get(idNext).pos; itListPoint.get(idCurrent).posNext = itListPoint.get(idNext).pos;
Vector2f vecB = itListPoint.get(idNext).pos.less(itListPoint.get(idCurrent).pos); Vector2f vecB = itListPoint.get(idNext).pos.less(itListPoint.get(idCurrent).pos);
vecB.safeNormalize(); vecB = vecB.safeNormalize();
itListPoint.get(idCurrent).miterAxe = new Vector2f(vecB.y(), -vecB.x()); itListPoint.get(idCurrent).miterAxe = new Vector2f(vecB.y(), -vecB.x());
itListPoint.get(idCurrent).orthoAxePrevious = itListPoint.get(idCurrent).miterAxe; itListPoint.get(idCurrent).orthoAxePrevious = itListPoint.get(idCurrent).miterAxe;
itListPoint.get(idCurrent).orthoAxeNext = itListPoint.get(idCurrent).miterAxe; itListPoint.get(idCurrent).orthoAxeNext = itListPoint.get(idCurrent).miterAxe;
@ -139,7 +142,7 @@ public class SegmentList {
} }
itListPoint.get(idCurrent).posPrevious = itListPoint.get(idPevious).pos; itListPoint.get(idCurrent).posPrevious = itListPoint.get(idPevious).pos;
Vector2f vecA = itListPoint.get(idCurrent).pos.less(itListPoint.get(idPevious).pos); Vector2f vecA = itListPoint.get(idCurrent).pos.less(itListPoint.get(idPevious).pos);
vecA.safeNormalize(); vecA = vecA.safeNormalize();
itListPoint.get(idCurrent).miterAxe = new Vector2f(vecA.y(), -vecA.x()); itListPoint.get(idCurrent).miterAxe = new Vector2f(vecA.y(), -vecA.x());
itListPoint.get(idCurrent).orthoAxePrevious = itListPoint.get(idCurrent).miterAxe; itListPoint.get(idCurrent).orthoAxePrevious = itListPoint.get(idCurrent).miterAxe;
itListPoint.get(idCurrent).orthoAxeNext = itListPoint.get(idCurrent).miterAxe; itListPoint.get(idCurrent).orthoAxeNext = itListPoint.get(idCurrent).miterAxe;
@ -150,35 +153,35 @@ public class SegmentList {
// create segment list: // create segment list:
boolean haveStartLine = false; boolean haveStartLine = false;
Vector2f leftPoint = Vector2f.ZERO; Dynamic<Vector2f> leftPoint = new Dynamic<Vector2f>(Vector2f.ZERO);
Vector2f rightPoint = Vector2f.ZERO; Dynamic<Vector2f> rightPoint = new Dynamic<Vector2f>(Vector2f.ZERO);
if (itListPoint.size() > 0) { if (itListPoint.size() > 0) {
if (itListPoint.get(0).type == PointType.join) { if (itListPoint.get(0).type == PointType.join) {
Point it = itListPoint.get(itListPoint.size() - 1); Point it = itListPoint.get(itListPoint.size() - 1);
// Calculate the perpendiculary axis ... // Calculate the perpendicular axis ...
leftPoint = it.pos.add(it.orthoAxePrevious.multiply(width * 0.5f)); leftPoint.value = it.pos.add(it.orthoAxePrevious.multiply(width * 0.5f));
rightPoint = it.pos.less(it.orthoAxePrevious.multiply(width * 0.5f)); rightPoint.value = it.pos.less(it.orthoAxePrevious.multiply(width * 0.5f));
// cyclic path... // cyclic path...
if (it.type == PointType.interpolation) { if (it.type == PointType.interpolation) {
leftPoint = SegmentList.getIntersect(leftPoint, it.pos.less(it.posPrevious), it.pos, it.miterAxe); leftPoint.value = SegmentList.getIntersect(leftPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
rightPoint = SegmentList.getIntersect(rightPoint, it.pos.less(it.posPrevious), it.pos, it.miterAxe); rightPoint.value = SegmentList.getIntersect(rightPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
} else if (it.type == PointType.join) { } else if (it.type == PointType.join) {
// Calculate the perpendiculary axis ... // Calculate the perpendicular axis ...
leftPoint = it.pos.add(it.orthoAxePrevious.multiply(width * 0.5f)); leftPoint.value = it.pos.add(it.orthoAxePrevious.multiply(width * 0.5f));
rightPoint = it.pos.less(it.orthoAxePrevious.multiply(width * 0.5f)); rightPoint.value = it.pos.less(it.orthoAxePrevious.multiply(width * 0.5f));
// project on the miter Axis ... // project on the miter Axis ...
switch (join) { switch (join) {
case MITER: { case MITER: {
Vector2f left = SegmentList.getIntersect(leftPoint, it.pos.less(it.posPrevious), it.pos, it.miterAxe); Vector2f left = SegmentList.getIntersect(leftPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
Vector2f right = SegmentList.getIntersect(rightPoint, it.pos.less(it.posPrevious), it.pos, it.miterAxe); Vector2f right = SegmentList.getIntersect(rightPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
// Check the miter limit: // Check the miter limit:
float limitRight = (left.less(it.pos)).length() / width * 2.0f; float limitRight = (left.less(it.pos)).length() / width * 2.0f;
float limitLeft = (right.less(it.pos)).length() / width * 2.0f; float limitLeft = (right.less(it.pos)).length() / width * 2.0f;
Log.verbose(" miter Limit: " + limitRight + " " + limitLeft + " <= " + miterLimit); Log.verbose(" miter Limit: " + limitRight + " " + limitLeft + " <= " + miterLimit);
if (limitRight <= miterLimit && limitLeft <= miterLimit) { if (limitRight <= miterLimit && limitLeft <= miterLimit) {
leftPoint = left; leftPoint.value = left;
rightPoint = right; rightPoint.value = right;
break; break;
} }
} }
@ -188,11 +191,11 @@ public class SegmentList {
Vector2f axeNext = (it.posNext.less(it.pos)).safeNormalize(); Vector2f axeNext = (it.posNext.less(it.pos)).safeNormalize();
float cross = axePrevious.cross(axeNext); float cross = axePrevious.cross(axeNext);
if (cross > 0.0f) { if (cross > 0.0f) {
rightPoint = SegmentList.getIntersect(rightPoint, it.pos.less(it.posPrevious), it.pos, it.miterAxe); rightPoint.value = SegmentList.getIntersect(rightPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
leftPoint = it.pos.add(it.orthoAxeNext.multiply(width * 0.5f)); leftPoint.value = it.pos.add(it.orthoAxeNext.multiply(width * 0.5f));
} else { } else {
leftPoint = SegmentList.getIntersect(leftPoint, it.pos.less(it.posPrevious), it.pos, it.miterAxe); leftPoint.value = SegmentList.getIntersect(leftPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
rightPoint = it.pos.less(it.orthoAxeNext.multiply(width * 0.5f)); rightPoint.value = it.pos.less(it.orthoAxeNext.multiply(width * 0.5f));
} }
break; break;
} }
@ -215,7 +218,7 @@ public class SegmentList {
if (haveStartLine) { if (haveStartLine) {
// close previous : // close previous :
Log.warning(" find a non close path ..."); Log.warning(" find a non close path ...");
addSegment(leftPoint, rightPoint); addSegment(leftPoint.value, rightPoint.value);
} }
haveStartLine = true; haveStartLine = true;
startStopPoint(leftPoint, rightPoint, it, cap, width, true); startStopPoint(leftPoint, rightPoint, it, cap, width, true);
@ -231,35 +234,35 @@ public class SegmentList {
break; break;
case interpolation: { case interpolation: {
Log.verbose("Find interpolation " + it.pos); Log.verbose("Find interpolation " + it.pos);
Vector2f left = SegmentList.getIntersect(leftPoint, it.pos.less(it.posPrevious), it.pos, it.miterAxe); Vector2f left = SegmentList.getIntersect(leftPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
Vector2f right = SegmentList.getIntersect(rightPoint, it.pos.less(it.posPrevious), it.pos, it.miterAxe); Vector2f right = SegmentList.getIntersect(rightPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
//Draw from previous point: //Draw from previous point:
addSegment(leftPoint, left); addSegment(leftPoint.value, left);
Log.verbose(" segment :" + leftPoint + " . " + left); Log.verbose(" segment :" + leftPoint + " . " + left);
addSegment(right, rightPoint); addSegment(right, rightPoint.value);
Log.verbose(" segment :" + right + " . " + rightPoint); Log.verbose(" segment :" + right + " . " + rightPoint);
leftPoint = left; leftPoint.value = left;
rightPoint = right; rightPoint.value = right;
} }
break; break;
case join: case join:
Log.verbose("Find join " + it.pos); Log.verbose("Find join " + it.pos);
switch (join) { switch (join) {
case MITER: { case MITER: {
Vector2f left = SegmentList.getIntersect(leftPoint, it.pos.less(it.posPrevious), it.pos, it.miterAxe); Vector2f left = SegmentList.getIntersect(leftPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
Vector2f right = SegmentList.getIntersect(rightPoint, it.pos.less(it.posPrevious), it.pos, it.miterAxe); Vector2f right = SegmentList.getIntersect(rightPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
// Check the miter limit: // Check the miter limit:
float limitRight = left.less(it.pos).length() / width * 2.0f; float limitRight = left.less(it.pos).length() / width * 2.0f;
float limitLeft = right.less(it.pos).length() / width * 2.0f; float limitLeft = right.less(it.pos).length() / width * 2.0f;
Log.verbose(" miter Limit: " + limitRight + " " + limitLeft + " <= " + miterLimit); Log.verbose(" miter Limit: " + limitRight + " " + limitLeft + " <= " + miterLimit);
if (limitRight <= miterLimit && limitLeft <= miterLimit) { if (limitRight <= miterLimit && limitLeft <= miterLimit) {
//Draw from previous point: //Draw from previous point:
addSegment(leftPoint, left); addSegment(leftPoint.value, left);
Log.verbose(" segment :" + leftPoint + " . " + left); Log.verbose(" segment :" + leftPoint + " . " + left);
addSegment(right, rightPoint); addSegment(right, rightPoint.value);
Log.verbose(" segment :" + right + " . " + rightPoint); Log.verbose(" segment :" + right + " . " + rightPoint);
leftPoint = left; leftPoint.value = left;
rightPoint = right; rightPoint.value = right;
break; break;
} }
Log.verbose(" Find miter Limit ... ==> create BEVEL"); Log.verbose(" Find miter Limit ... ==> create BEVEL");
@ -270,11 +273,11 @@ public class SegmentList {
Vector2f axeNext = (it.posNext.less(it.pos)).safeNormalize(); Vector2f axeNext = (it.posNext.less(it.pos)).safeNormalize();
float cross = axePrevious.cross(axeNext); float cross = axePrevious.cross(axeNext);
if (cross > 0.0f) { if (cross > 0.0f) {
Vector2f right = SegmentList.getIntersect(rightPoint, it.pos.less(it.posPrevious), it.pos, it.miterAxe); Vector2f right = SegmentList.getIntersect(rightPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
Vector2f left1 = it.pos.add(it.orthoAxePrevious.multiply(width * 0.5f)); Vector2f left1 = it.pos.add(it.orthoAxePrevious.multiply(width * 0.5f));
Vector2f left2 = it.pos.add(it.orthoAxeNext.multiply(width * 0.5f)); Vector2f left2 = it.pos.add(it.orthoAxeNext.multiply(width * 0.5f));
//Draw from previous point: //Draw from previous point:
addSegment(leftPoint, left1); addSegment(leftPoint.value, left1);
Log.verbose(" segment :" + leftPoint + " . " + left1); Log.verbose(" segment :" + leftPoint + " . " + left1);
if (join != JoinMode.ROUND) { if (join != JoinMode.ROUND) {
// Miter and bevel: // Miter and bevel:
@ -283,18 +286,18 @@ public class SegmentList {
} else { } else {
createSegmentListStroke(left1, left2, it.pos, width, false); createSegmentListStroke(left1, left2, it.pos, width, false);
} }
addSegment(right, rightPoint); addSegment(right, rightPoint.value);
Log.verbose(" segment :" + right + " . " + rightPoint); Log.verbose(" segment :" + right + " . " + rightPoint);
leftPoint = left2; leftPoint.value = left2;
rightPoint = right; rightPoint.value = right;
} else { } else {
Vector2f left = SegmentList.getIntersect(leftPoint, it.pos.less(it.posPrevious), it.pos, it.miterAxe); Vector2f left = SegmentList.getIntersect(leftPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
Vector2f right1 = it.pos.less(it.orthoAxePrevious.multiply(width * 0.5f)); Vector2f right1 = it.pos.less(it.orthoAxePrevious.multiply(width * 0.5f));
Vector2f right2 = it.pos.less(it.orthoAxeNext.multiply(width * 0.5f)); Vector2f right2 = it.pos.less(it.orthoAxeNext.multiply(width * 0.5f));
//Draw from previous point: //Draw from previous point:
addSegment(leftPoint, left); addSegment(leftPoint.value, left);
Log.verbose(" segment :" + leftPoint + " . " + left); Log.verbose(" segment :" + leftPoint + " . " + left);
addSegment(right1, rightPoint); addSegment(right1, rightPoint.value);
Log.verbose(" segment :" + right1 + " . " + rightPoint); Log.verbose(" segment :" + right1 + " . " + rightPoint);
if (join != JoinMode.ROUND) { if (join != JoinMode.ROUND) {
// Miter and bevel: // Miter and bevel:
@ -303,8 +306,8 @@ public class SegmentList {
} else { } else {
createSegmentListStroke(right1, right2, it.pos, width, true); createSegmentListStroke(right1, right2, it.pos, width, true);
} }
leftPoint = left; leftPoint.value = left;
rightPoint = right2; rightPoint.value = right2;
} }
} }
break; break;
@ -369,26 +372,26 @@ public class SegmentList {
return out; return out;
} }
private void startStopPoint(Vector2f leftPoint, Vector2f rightPoint, final Point point, final CapMode cap, final float width, final boolean isStart) { private void startStopPoint(final Dynamic<Vector2f> leftPoint, final Dynamic<Vector2f> rightPoint, final Point point, final CapMode cap, final float width, final boolean isStart) {
switch (cap) { switch (cap) {
case BUTT: { case BUTT: {
Vector2f left = point.pos.add(point.miterAxe.multiply(width * 0.5f)); Vector2f left = point.pos.add(point.miterAxe.multiply(width * 0.5f));
Vector2f right = point.pos.less(point.miterAxe.multiply(width * 0.5f)); Vector2f right = point.pos.less(point.miterAxe.multiply(width * 0.5f));
if (!isStart) { if (!isStart) {
//Draw from previous point: //Draw from previous point:
addSegment(leftPoint, left); addSegment(leftPoint.value, left);
Log.verbose(" segment :" + leftPoint + " . " + left); Log.verbose(" segment :" + leftPoint + " . " + left);
addSegment(right, rightPoint); addSegment(right, rightPoint.value);
Log.verbose(" segment :" + right + " . " + rightPoint); Log.verbose(" segment :" + right + " . " + rightPoint);
} }
leftPoint = left; leftPoint.value = left;
rightPoint = right; rightPoint.value = right;
} }
if (!isStart) { if (!isStart) {
addSegment(leftPoint, rightPoint); addSegment(leftPoint.value, rightPoint.value);
Log.verbose(" segment :" + leftPoint + " . " + rightPoint); Log.verbose(" segment :" + leftPoint + " . " + rightPoint);
} else { } else {
addSegment(rightPoint, leftPoint); addSegment(rightPoint.value, leftPoint.value);
Log.verbose(" segment :" + rightPoint + " . " + leftPoint); Log.verbose(" segment :" + rightPoint + " . " + leftPoint);
} }
break; break;
@ -398,21 +401,21 @@ public class SegmentList {
Vector2f right = point.pos.less(point.miterAxe.multiply(width * 0.5f)); Vector2f right = point.pos.less(point.miterAxe.multiply(width * 0.5f));
if (!isStart) { if (!isStart) {
//Draw from previous point: //Draw from previous point:
addSegment(leftPoint, left); addSegment(leftPoint.value, left);
Log.verbose(" segment :" + leftPoint + " . " + left); Log.verbose(" segment :" + leftPoint + " . " + left);
addSegment(right, rightPoint); addSegment(right, rightPoint.value);
Log.verbose(" segment :" + right + " . " + rightPoint); Log.verbose(" segment :" + right + " . " + rightPoint);
} }
leftPoint = left; leftPoint.value = left;
rightPoint = right; rightPoint.value = right;
} }
int nbDot = (int) width; int nbDot = (int) width;
if (nbDot <= 2) { if (nbDot <= 2) {
nbDot = 2; nbDot = 2;
} }
leftPoint = point.pos.add(point.miterAxe.multiply(width * 0.5f)); leftPoint.value = point.pos.add(point.miterAxe.multiply(width * 0.5f));
rightPoint = point.pos.less(point.miterAxe.multiply(width * 0.5f)); rightPoint.value = point.pos.less(point.miterAxe.multiply(width * 0.5f));
createSegmentListStroke(leftPoint, rightPoint, point.pos, width, isStart); createSegmentListStroke(leftPoint.value, rightPoint.value, point.pos, width, isStart);
} }
break; break;
case SQUARE: { case SQUARE: {
@ -428,21 +431,19 @@ public class SegmentList {
left = tmpMat.multiply(left); left = tmpMat.multiply(left);
right = tmpMat.multiply(right); right = tmpMat.multiply(right);
if (!isStart) { if (!isStart) {
if (!isStart) { //Draw from previous point:
//Draw from previous point: addSegment(leftPoint.value, left);
addSegment(leftPoint, left); Log.verbose(" segment :" + leftPoint + " . " + left);
Log.verbose(" segment :" + leftPoint + " . " + left); addSegment(right, rightPoint.value);
addSegment(right, rightPoint); Log.verbose(" segment :" + right + " . " + rightPoint);
Log.verbose(" segment :" + right + " . " + rightPoint);
}
} }
leftPoint = left; leftPoint.value = left;
rightPoint = right; rightPoint.value = right;
if (!isStart) { if (!isStart) {
addSegment(leftPoint, rightPoint); addSegment(leftPoint.value, rightPoint.value);
Log.verbose(" segment :" + leftPoint + " . " + rightPoint); Log.verbose(" segment :" + leftPoint + " . " + rightPoint);
} else { } else {
addSegment(rightPoint, leftPoint); addSegment(rightPoint.value, leftPoint.value);
Log.verbose(" segment :" + rightPoint + " . " + leftPoint); Log.verbose(" segment :" + rightPoint + " . " + leftPoint);
} }
Log.verbose(" segment :" + leftPoint + " . " + rightPoint); Log.verbose(" segment :" + leftPoint + " . " + rightPoint);

View File

@ -10,11 +10,14 @@ import org.atriasoft.etk.Uri;
import com.pngencoder.PngEncoder; import com.pngencoder.PngEncoder;
public class ConfigTest { public class ConfigTest {
public static final String BASE_PATH = "./";//"~/dev/workspace-game/atriasoft/esvg/"; public static final String BASE_PATH = "./testResult/";//"~/dev/workspace-game/atriasoft/esvg/";
public static final boolean VISUAL_DEBUG = true; public static final boolean VISUAL_DEBUG = true;
public static void generateAnImage(final EsvgDocument doc, final Uri uri) { public static void generateAnImage(final EsvgDocument doc, final Uri uri) {
Color[][] data = doc.renderImageFloatRGBA(null, ConfigTest.VISUAL_DEBUG); Color[][] data = doc.renderImageFloatRGBA(null, ConfigTest.VISUAL_DEBUG);
if (data.length == 0) {
Log.critical("No data generated ...");
}
BufferedImage bufferedImage = new BufferedImage(data[0].length, data.length, BufferedImage.TYPE_INT_ARGB); BufferedImage bufferedImage = new BufferedImage(data[0].length, data.length, BufferedImage.TYPE_INT_ARGB);
for (int yyy = 0; yyy < data.length; yyy++) { for (int yyy = 0; yyy < data.length; yyy++) {
for (int xxx = 0; xxx < data[yyy].length; xxx++) { for (int xxx = 0; xxx < data[yyy].length; xxx++) {

View File

@ -7,11 +7,20 @@ import org.junit.jupiter.api.Test;
class TestGradientLinear { class TestGradientLinear {
@Test @Test
public void testTestGradientLinearDiag1() { public void testTestGradientLinearDiag1() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" //@formatter:off
+ " <linearGradient id='grad2' x1='0%' y1='0%' x2='100%' y2='100%'>\n" + " <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />\n" String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
+ " <stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n" + " <stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n" + "<svg height='100' width='100'>\n"
+ " <stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />\n" + " </linearGradient>\n" + " </defs>\n" + " <defs>\n"
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n" + "</svg>\n"; + " <linearGradient id='grad2' x1='0%' y1='0%' x2='100%' y2='100%'>\n"
+ " <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />\n"
+ " <stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n"
+ " <stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
+ " <stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />\n"
+ " </linearGradient>\n"
+ " </defs>\n"
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n"
+ "</svg>\n";
//@formatter:on
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag1.svg"), data.replace("'", "\"")); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag1.svg"), data.replace("'", "\""));
@ -20,10 +29,18 @@ class TestGradientLinear {
@Test @Test
public void testTestGradientLinearDiag1Partiel() { public void testTestGradientLinearDiag1Partiel() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" //@formatter:off
+ " <linearGradient id='grad2' x1='40%' y1='40%' x2='70%' y2='70%'>\n" + " <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n" String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
+ " <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n" + " </linearGradient>\n" + " </defs>\n" + "<svg height='100' width='100'>\n"
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n" + "</svg>\n"; + " <defs>\n"
+ " <linearGradient id='grad2' x1='40%' y1='40%' x2='70%' y2='70%'>\n"
+ " <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n"
+ " <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
+ " </linearGradient>\n"
+ " </defs>\n"
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n"
+ "</svg>\n";
//@formatter:on
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag1Partiel.svg"), data.replace("'", "\"")); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag1Partiel.svg"), data.replace("'", "\""));
@ -97,11 +114,20 @@ class TestGradientLinear {
@Test @Test
public void testTestGradientLinearHorizontal() { public void testTestGradientLinearHorizontal() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" //@formatter:off
+ " <linearGradient id='grad1' x1='0%' y1='0%' x2='100%' y2='0%'>\n" + " <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />\n" String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
+ " <stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n" + " <stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n" + "<svg height='100' width='100'>\n"
+ " <stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />\n" + " </linearGradient>\n" + " </defs>\n" + " <defs>\n"
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n"; + " <linearGradient id='grad1' x1='0%' y1='0%' x2='100%' y2='0%'>\n"
+ " <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />\n"
+ " <stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n"
+ " <stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
+ " <stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />\n"
+ " </linearGradient>\n"
+ " </defs>\n"
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n"
+ "</svg>\n";
//@formatter:on
EsvgDocument doc = new EsvgDocument(); EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearhorizontal.svg"), data.replace("'", "\"")); Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearhorizontal.svg"), data.replace("'", "\""));

View File

@ -2,10 +2,9 @@ package test.atriasoft.esvg;
import org.atriasoft.esvg.EsvgDocument; import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Uri; import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Test;
class TestStyle { class TestStyle {
@Test
public void testTestExternWorddown() { public void testTestExternWorddown() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<!-- Created with Inkscape (http://www.inkscape.org/) -.\n" + "\n" + "<svg\n" String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<!-- Created with Inkscape (http://www.inkscape.org/) -.\n" + "\n" + "<svg\n"
+ " xmlns:dc='http://purl.org/dc/elements/1.1/'\n" + " xmlns:cc='http://creativecommons.org/ns#'\n" + " xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'\n" + " xmlns:dc='http://purl.org/dc/elements/1.1/'\n" + " xmlns:cc='http://creativecommons.org/ns#'\n" + " xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'\n"