[FEAT] use Maven a build system root tool

This commit is contained in:
Edouard DUPIN 2024-06-07 09:28:33 +02:00
parent 563cb8957f
commit eb4570dd72
35 changed files with 2380 additions and 1658 deletions

View File

@ -1,37 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<classpath> <classpath>
<classpathentry kind="src" path="resources"/> <classpathentry including="**/*.java" kind="src" output="out/maven/classes" path="src">
<classpathentry kind="src" path="src"/> <attributes>
<classpathentry including="**/*.java" kind="src" output="out/eclipse/classes-test" path="test/src"> <attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="out/maven/test-classes" path="test/src">
<attributes> <attributes>
<attribute name="test" value="true"/> <attribute name="test" value="true"/>
<attribute name="optional" value="true"/> <attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes> </attributes>
</classpathentry> </classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-14"> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21">
<attributes> <attributes>
<attribute name="module" value="true"/> <attribute name="module" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes> </attributes>
</classpathentry> </classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"> <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes> <attributes>
<attribute name="test" value="true"/> <attribute name="maven.pomderived" value="true"/>
</attributes> </attributes>
</classpathentry> </classpathentry>
<classpathentry combineaccessrules="false" kind="src" path="/atriasoft-png-encoder"> <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/>
<attributes> <classpathentry kind="output" path="out/maven/classes"/>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry combineaccessrules="false" kind="src" path="/atriasoft-exml">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry combineaccessrules="false" kind="src" path="/atriasoft-egami">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="out/eclipse/classes"/>
</classpath> </classpath>

View File

@ -1,35 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<projectDescription> <projectDescription>
<name>atriasoft-esvg</name> <name>esvg</name>
<comment></comment> <comment></comment>
<projects> <projects>
<project>atriasoft-esvg</project>
</projects> </projects>
<buildSpec> <buildSpec>
<buildCommand>
<name>org.python.pydev.PyDevBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand> <buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name> <name>org.eclipse.jdt.core.javabuilder</name>
<arguments> <arguments>
</arguments> </arguments>
</buildCommand> </buildCommand>
<buildCommand> <buildCommand>
<name>net.sf.eclipsecs.core.CheckstyleBuilder</name> <name>org.eclipse.m2e.core.maven2Builder</name>
<arguments> <arguments>
</arguments> </arguments>
</buildCommand> </buildCommand>
</buildSpec> </buildSpec>
<natures> <natures>
<nature>org.eclipse.jdt.core.javanature</nature> <nature>org.eclipse.jdt.core.javanature</nature>
<nature>net.sf.eclipsecs.core.CheckstyleNature</nature> <nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures> </natures>
<filteredResources>
<filter>
<id>1646149232192</id>
<name></name>
<type>30</type>
<matcher>
<id>org.eclipse.core.resources.regexFilterMatcher</id>
<arguments>node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
</matcher>
</filter>
</filteredResources>
</projectDescription> </projectDescription>

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -38,7 +38,7 @@ def configure(target, my_module):
'src/org/atriasoft/esvg/Base.java', 'src/org/atriasoft/esvg/Base.java',
'src/org/atriasoft/esvg/Text.java', 'src/org/atriasoft/esvg/Text.java',
'src/org/atriasoft/esvg/RadialGradient.java', 'src/org/atriasoft/esvg/RadialGradient.java',
'src/org/atriasoft/esvg/internal/Log.java', 'src/org/atriasoft/esvg/internal/LOGGER.java',
'src/org/atriasoft/esvg/font/Kerning.java', 'src/org/atriasoft/esvg/font/Kerning.java',
'src/org/atriasoft/esvg/font/Glyph.java', 'src/org/atriasoft/esvg/font/Glyph.java',
'src/org/atriasoft/esvg/Renderer.java', 'src/org/atriasoft/esvg/Renderer.java',

144
pom.xml Normal file
View File

@ -0,0 +1,144 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.atriasoft</groupId>
<artifactId>esvg</artifactId>
<version>0.1.0</version>
<properties>
<maven.compiler.version>3.13.0</maven.compiler.version>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<maven.dependency.version>3.1.1</maven.dependency.version>
</properties>
<repositories>
<repository>
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/org.atriasoft/maven</url>
</repository>
</repositories>
<distributionManagement>
<repository>
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/org.atriasoft/maven</url>
</repository>
<snapshotRepository>
<id>gitea</id>
<url>https://gitea.atria-soft.org/api/packages/org.atriasoft/maven</url>
</snapshotRepository>
</distributionManagement>
<dependencies>
<dependency>
<groupId>org.atriasoft</groupId>
<artifactId>exml</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>org.atriasoft</groupId>
<artifactId>png-encoder</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>org.atriasoft</groupId>
<artifactId>egami</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.11.0-M2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.11.0-M2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.7</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
<resources>
<resource>
<directory>${basedir}/resources</directory>
</resource>
</resources>
<testSourceDirectory>test/src</testSourceDirectory>
<directory>${project.basedir}/out/maven/</directory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.version}</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<!--<encoding>${project.build.sourceEncoding}</encoding>-->
</configuration>
</plugin>
<!-- Create the source bundle -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- junit results -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
<!-- Java-doc generation for stand-alone site -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<show>private</show>
<nohelp>true</nohelp>
</configuration>
</plugin>
</plugins>
</build>
<!-- Generate Java-docs As Part Of Project Reports -->
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<show>public</show>
</configuration>
</plugin>
</plugins>
</reporting>
</project>

View File

@ -7,7 +7,6 @@ open module org.atriasoft.esvg {
exports org.atriasoft.esvg.font; exports org.atriasoft.esvg.font;
exports org.atriasoft.esvg.render; exports org.atriasoft.esvg.render;
requires transitive org.atriasoft.reggol;
requires transitive org.atriasoft.etk; requires transitive org.atriasoft.etk;
requires transitive org.atriasoft.exml; requires transitive org.atriasoft.exml;
requires org.atriasoft.pngencoder; requires org.atriasoft.pngencoder;

View File

@ -2,7 +2,6 @@ package org.atriasoft.esvg;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.Color; import org.atriasoft.etk.Color;
import org.atriasoft.etk.Distance; import org.atriasoft.etk.Distance;
import org.atriasoft.etk.math.FMath; import org.atriasoft.etk.math.FMath;
@ -11,6 +10,8 @@ import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic; import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.etk.util.Pair; import org.atriasoft.etk.util.Pair;
import org.atriasoft.exml.model.XmlElement; import org.atriasoft.exml.model.XmlElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -19,6 +20,7 @@ import org.atriasoft.exml.model.XmlElement;
*/ */
public class Base { public class Base {
static final Logger LOGGER = LoggerFactory.getLogger(Base.class);
public static float kappa90 = 0.5522847493f; //!< proportional lenght to the radius of a bezier handle for 90° arcs. public static float kappa90 = 0.5522847493f; //!< proportional lenght to the radius of a bezier handle for 90° arcs.
@ -30,7 +32,7 @@ public class Base {
} }
posStart += base.length(); posStart += base.length();
if (value.length() < posStart + 2) { if (value.length() < posStart + 2) {
Log.error("Not enought spece in the String to have transform value for ' (' or '()' in '" + value + "'"); LOGGER.error("Not enought spece in the String to have transform value for ' (' or '()' in '" + value + "'");
return ""; return "";
} }
if (value.charAt(posStart) == '(') { if (value.charAt(posStart) == '(') {
@ -39,19 +41,19 @@ public class Base {
} else if (value.charAt(posStart) == ' ' && value.charAt(posStart + 1) == '(') { } else if (value.charAt(posStart) == ' ' && value.charAt(posStart + 1) == '(') {
posStart += 2; posStart += 2;
} else { } else {
Log.error("Can not indexOf ' (' or '(' in '" + value.substring(posStart) + "' for '" + value + "'"); LOGGER.error("Can not indexOf ' (' or '(' in '" + value.substring(posStart) + "' for '" + value + "'");
return ""; return "";
} }
if (value.length() < posStart + 1) { if (value.length() < posStart + 1) {
Log.error("Not enought spece in the String to have transform value for ')' in '" + value + "'"); LOGGER.error("Not enought spece in the String to have transform value for ')' in '" + value + "'");
return ""; return "";
} }
int posEnd = value.indexOf(')', posStart); final int posEnd = value.indexOf(')', posStart);
if (posEnd == -1) { if (posEnd == -1) {
Log.error("Missing element ')' in '" + value + "' for " + base); LOGGER.error("Missing element ')' in '" + value + "' for " + base);
return ""; return "";
} }
Log.verbose("indexOf : '" + value.substring(posStart, posEnd) + "' for " + base); LOGGER.trace("indexOf : '" + value.substring(posStart, posEnd) + "' for " + base);
return value.substring(posStart, posEnd); return value.substring(posStart, posEnd);
} }
@ -83,10 +85,14 @@ public class Base {
* @param level Level of the tree * @param level Level of the tree
*/ */
void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
Log.warning(spacingDist(level) + "DRAW esvg::Base ... ==> No drawing availlable"); LOGGER.warn(spacingDist(level) + "DRAW esvg::Base ... ==> No drawing availlable");
} }
public void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans) { public void drawShapePoints(
final List<List<Vector2f>> out,
final int recurtionMax,
final float threshold,
final Matrix2x3f basicTrans) {
drawShapePoints(out, recurtionMax, threshold, basicTrans, 1); drawShapePoints(out, recurtionMax, threshold, basicTrans, 1);
} }
@ -98,7 +104,12 @@ public class Base {
* @param basicTrans Parant transformation of the environement * @param basicTrans Parant transformation of the environement
* @param level Level of the tree * @param level Level of the tree
*/ */
void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) { void drawShapePoints(
final List<List<Vector2f>> out,
final int recurtionMax,
final float threshold,
final Matrix2x3f basicTrans,
final int level) {
} }
@ -117,22 +128,24 @@ public class Base {
*/ */
Pair<Color, String> parseColor(final String inputData) { Pair<Color, String> parseColor(final String inputData) {
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, inputData.length() - 1); final 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 ..."); LOGGER.error(
"Problem in parsing the color : '" + inputData + "' == > url(XXX) is not supported now ...");
} }
} else { } else {
try { try {
localColor = new Pair<>(Color.valueOf256(inputData), ""); localColor = new Pair<>(Color.valueOf256(inputData), "");
} catch (Exception e) { } catch (final Exception e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
} }
} }
Log.verbose("Parse color : \"" + inputData + "\" == > " + localColor.first + " " + localColor.second); LOGGER.trace("Parse color : \"" + inputData + "\" == > " + localColor.first + " " + localColor.second);
return localColor; return localColor;
} }
@ -142,31 +155,21 @@ public class Base {
* @return standard number of pixels * @return standard number of pixels
*/ */
float parseLength(final String dataInput) { float parseLength(final String dataInput) {
Pair<Float, Distance> value = parseLength2(dataInput); final Pair<Float, Distance> value = parseLength2(dataInput);
Log.verbose(" lenght : '" + value.first + "' => unit=" + value.second); LOGGER.trace(" lenght : '" + value.first + "' => unit=" + value.second);
float fontsize = 20.0f; final float fontsize = 20.0f;
switch (value.second) { return switch (value.second) {
case POURCENT: case POURCENT -> value.first; // / 100.0 * this.paint.viewPort.x();
return value.first;// / 100.0 * this.paint.viewPort.x(); case ELEMENT -> value.first * fontsize;
case ELEMENT: case EX -> value.first / 2.0f * fontsize;
return value.first * fontsize; case PIXEL -> value.first;
case EX: case POINT -> value.first * 1.25f;
return value.first / 2.0f * fontsize; case PC -> value.first * 15.0f;
case PIXEL: case MILLIMETER -> value.first * 3.543307f;
return value.first; case CENTIMETER -> value.first * 35.43307f;
case POINT: case INCH -> value.first * 90.0f;
return value.first * 1.25f; default -> 0.0f;
case PC: };
return value.first * 15.0f;
case MILLIMETER:
return value.first * 3.543307f;
case CENTIMETER:
return value.first * 35.43307f;
case INCH:
return value.first * 90.0f;
default:
return 0.0f;
}
} }
Pair<Float, Distance> parseLength2(String config) { Pair<Float, Distance> parseLength2(String config) {
@ -235,7 +238,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); LOGGER.error("Parse color : " + this.paint.stroke);
} }
content = element.getAttribute("stroke-width", ""); content = element.getAttribute("stroke-width", "");
if (content.length() != 0) { if (content.length() != 0) {
@ -253,7 +256,7 @@ public class Base {
if (content.equals("none")) { if (content.equals("none")) {
// OK, Nothing to do ... // OK, Nothing to do ...
} else { } else {
Log.todo(" 'stroke-dasharray' not implemented ..."); LOGGER.info("TODO 'stroke-dasharray' not implemented ...");
} }
} }
content = element.getAttribute("stroke-linecap", ""); content = element.getAttribute("stroke-linecap", "");
@ -266,7 +269,7 @@ public class Base {
this.paint.lineCap = CapMode.SQUARE; this.paint.lineCap = CapMode.SQUARE;
} else { } else {
this.paint.lineCap = CapMode.BUTT; this.paint.lineCap = CapMode.BUTT;
Log.error("not know stroke-linecap value : '" + content + "', not in [butt,round,square]"); LOGGER.error("not know stroke-linecap value : '" + content + "', not in [butt,round,square]");
} }
} }
content = element.getAttribute("stroke-linejoin", ""); content = element.getAttribute("stroke-linejoin", "");
@ -279,12 +282,12 @@ public class Base {
this.paint.lineJoin = JoinMode.BEVEL; this.paint.lineJoin = JoinMode.BEVEL;
} else { } else {
this.paint.lineJoin = JoinMode.MITER; this.paint.lineJoin = JoinMode.MITER;
Log.error("not know stroke-linejoin value : '" + content + "', not in [miter,round,bevel]"); LOGGER.error("not know stroke-linejoin value : '" + content + "', not in [miter,round,bevel]");
} }
} }
content = element.getAttribute("stroke-miterlimit", ""); content = element.getAttribute("stroke-miterlimit", "");
if (content.length() != 0) { if (content.length() != 0) {
float tmp = parseLength(content); final float tmp = parseLength(content);
this.paint.miterLimit = FMath.max(0.0f, tmp); this.paint.miterLimit = FMath.max(0.0f, tmp);
} }
} }
@ -309,7 +312,7 @@ public class Base {
} else if (content.equals("evenodd")) { } else if (content.equals("evenodd")) {
this.paint.flagEvenOdd = true; this.paint.flagEvenOdd = true;
} else { } else {
Log.error("not know fill-rule value : \"" + content + "\", not in [nonzero,evenodd]"); LOGGER.error("not know fill-rule value : \"" + content + "\", not in [nonzero,evenodd]");
} }
} }
// ---------------- opacity ---------------- // ---------------- opacity ----------------
@ -329,51 +332,56 @@ public class Base {
if (inputString.length() == 0) { if (inputString.length() == 0) {
return; return;
} }
Log.verbose("indexOf transform : '" + inputString + "'"); LOGGER.trace("indexOf transform : '" + inputString + "'");
inputString = inputString.replace(',', ' '); inputString = inputString.replace(',', ' ');
Log.verbose("indexOf transform : '" + inputString + "'"); LOGGER.trace("indexOf transform : '" + inputString + "'");
// need to indexOf elements in order ... // need to indexOf elements in order ...
String data = Base.extractTransformData(inputString, "matrix"); String data = Base.extractTransformData(inputString, "matrix");
if (data.length() != 0) { if (data.length() != 0) {
double[] matrix = FMath.getTableDouble(data, " ", 6); final double[] matrix = FMath.getTableDouble(data, " ", 6);
if (matrix != null) { if (matrix != null) {
this.transformMatrix = new Matrix2x3f(matrix); this.transformMatrix = new Matrix2x3f(matrix);
// indexOf a matrix : simply exit ... // indexOf a matrix : simply exit ...
return; return;
} }
Log.error("Parsing matrix() with wrong data ... '" + data + "'"); LOGGER.error("Parsing matrix() with wrong data ... '" + data + "'");
} }
data = Base.extractTransformData(inputString, "translate"); data = Base.extractTransformData(inputString, "translate");
if (data.length() != 0) { if (data.length() != 0) {
float[] elements = FMath.getTableFloat(data, " ", 2); final float[] elements = FMath.getTableFloat(data, " ", 2);
if (elements != null) { if (elements != null) {
this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createTranslate(new Vector2f(elements[0], elements[1]))); this.transformMatrix = this.transformMatrix
Log.verbose("Translate : " + elements[0] + ", " + elements[1]); .multiply(Matrix2x3f.createTranslate(new Vector2f(elements[0], elements[1])));
LOGGER.trace("Translate : " + elements[0] + ", " + elements[1]);
} else { } else {
float elem = Float.parseFloat(data); final float elem = Float.parseFloat(data);
this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createTranslate(new Vector2f(elem, 0))); this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createTranslate(new Vector2f(elem, 0)));
} }
} }
data = Base.extractTransformData(inputString, "scale"); data = Base.extractTransformData(inputString, "scale");
if (data.length() != 0) { if (data.length() != 0) {
float[] elements = FMath.getTableFloat(data, " ", 2); final float[] elements = FMath.getTableFloat(data, " ", 2);
if (elements != null) { if (elements != null) {
this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createScale(new Vector2f(elements[0], elements[1]))); this.transformMatrix = this.transformMatrix
Log.verbose("Translate : " + elements[0] + ", " + elements[1]); .multiply(Matrix2x3f.createScale(new Vector2f(elements[0], elements[1])));
LOGGER.trace("Translate : " + elements[0] + ", " + elements[1]);
} else { } else {
float elem = Float.parseFloat(data); final float elem = Float.parseFloat(data);
this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createScale(elem)); this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createScale(elem));
} }
} }
data = Base.extractTransformData(inputString, "rotate"); data = Base.extractTransformData(inputString, "rotate");
if (data.length() != 0) { if (data.length() != 0) {
float[] elements = FMath.getTableFloat(data, " ", 3); final float[] elements = FMath.getTableFloat(data, " ", 3);
if (elements != null) { if (elements != null) {
float angle = (float) Math.toRadians(elements[0]); final float angle = (float) Math.toRadians(elements[0]);
this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createTranslate(new Vector2f(-elements[1], -elements[2]))); this.transformMatrix = this.transformMatrix
.multiply(Matrix2x3f.createTranslate(new Vector2f(-elements[1], -elements[2])));
this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createRotate(angle)); this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createRotate(angle));
this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createTranslate(new Vector2f(elements[1], elements[2]))); this.transformMatrix = this.transformMatrix
this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createScale(new Vector2f(elements[0], elements[1]))); .multiply(Matrix2x3f.createTranslate(new Vector2f(elements[1], elements[2])));
this.transformMatrix = this.transformMatrix
.multiply(Matrix2x3f.createScale(new Vector2f(elements[0], elements[1])));
} else { } else {
float elem = Float.parseFloat(data); float elem = Float.parseFloat(data);
elem = (float) Math.toRadians(elem); elem = (float) Math.toRadians(elem);
@ -455,7 +463,7 @@ public class Base {
} }
protected String spacingDist(final int spacing) { protected String spacingDist(final int spacing) {
StringBuilder out = new StringBuilder(); final StringBuilder out = new StringBuilder();
for (int iii = 0; iii < spacing; iii++) { for (int iii = 0; iii < spacing; iii++) {
out.append(" "); out.append(" ");
} }

View File

@ -3,7 +3,6 @@ package org.atriasoft.esvg;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.DynamicColor; import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.PathModel; import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.Point; import org.atriasoft.esvg.render.Point;
@ -14,6 +13,8 @@ import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -22,6 +23,7 @@ import org.atriasoft.exml.model.XmlElement;
*/ */
public class Circle extends Base { public class Circle extends Base {
static final Logger LOGGER = LoggerFactory.getLogger(Circle.class);
private Vector2f position; //!< Position of the Circle private Vector2f position; //!< Position of the Circle
private float radius; //!< Radius of the Circle private float radius; //!< Radius of the Circle
@ -36,41 +38,46 @@ public class Circle extends Base {
} }
private PathModel createPath() { private PathModel createPath() {
PathModel out = new PathModel(); final PathModel out = new PathModel();
out.moveTo(false, this.position.addX(this.radius)); out.moveTo(false, this.position.addX(this.radius));
out.curveTo(false, this.position.add(this.radius, this.radius * Base.kappa90), this.position.add(this.radius * Base.kappa90, this.radius), this.position.addY(this.radius)); out.curveTo(false, this.position.add(this.radius, this.radius * Base.kappa90),
out.curveTo(false, this.position.add(-this.radius * Base.kappa90, this.radius), this.position.add(-this.radius, this.radius * Base.kappa90), this.position.lessX(this.radius)); this.position.add(this.radius * Base.kappa90, this.radius), this.position.addY(this.radius));
out.curveTo(false, this.position.add(-this.radius, -this.radius * Base.kappa90), this.position.add(-this.radius * Base.kappa90, -this.radius), this.position.lessY(this.radius)); out.curveTo(false, this.position.add(-this.radius * Base.kappa90, this.radius),
out.curveTo(false, this.position.add(this.radius * Base.kappa90, -this.radius), this.position.add(this.radius, -this.radius * Base.kappa90), this.position.addX(this.radius)); this.position.add(-this.radius, this.radius * Base.kappa90), this.position.lessX(this.radius));
out.curveTo(false, this.position.add(-this.radius, -this.radius * Base.kappa90),
this.position.add(-this.radius * Base.kappa90, -this.radius), this.position.lessY(this.radius));
out.curveTo(false, this.position.add(this.radius * Base.kappa90, -this.radius),
this.position.add(this.radius, -this.radius * Base.kappa90), this.position.addX(this.radius));
out.close(); out.close();
return out; return out;
} }
@Override @Override
public void display(final int spacing) { public void display(final int spacing) {
Log.debug(spacingDist(spacing) + "Circle " + this.position + " radius=" + this.radius); LOGGER.debug(spacingDist(spacing) + "Circle " + this.position + " radius=" + this.radius);
} }
@Override @Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW esvg::Circle"); LOGGER.trace(spacingDist(level) + "DRAW esvg::Circle");
if (this.radius <= 0.0f) { if (this.radius <= 0.0f) {
Log.verbose(spacingDist(level + 1) + "Too small radius" + this.radius); LOGGER.trace(spacingDist(level + 1) + "Too small radius" + this.radius);
return; return;
} }
PathModel listElement = createPath(); final PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix; Matrix2x3f mtx = this.transformMatrix;
mtx = mtx.multiply(basicTrans); mtx = mtx.multiply(basicTrans);
PointList listPoints = new PointList(); PointList listPoints = new PointList();
listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold()); listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(),
myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx); //listPoints.applyMatrix(mtx);
SegmentList listSegmentFill = new SegmentList(); final SegmentList listSegmentFill = new SegmentList();
SegmentList listSegmentStroke = new SegmentList(); final SegmentList listSegmentStroke = new SegmentList();
Weight tmpFill = new Weight(); final Weight tmpFill = new Weight();
Weight tmpStroke = new Weight(); final Weight tmpStroke = new Weight();
DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx); final DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx);
DynamicColor colorStroke = null; DynamicColor colorStroke = null;
if (this.paint.strokeWidth > 0.0f) { if (this.paint.strokeWidth > 0.0f) {
colorStroke = DynamicColor.createColor(this.paint.stroke, mtx); colorStroke = DynamicColor.createColor(this.paint.stroke, mtx);
@ -85,7 +92,8 @@ public class Circle extends Base {
} }
// check if we need to display stroke: // check if we need to display stroke:
if (colorStroke != null) { if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit); listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap,
this.paint.lineJoin, this.paint.miterLimit);
colorStroke.setViewPort(listSegmentStroke.getViewPort()); colorStroke.setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx); listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
@ -98,17 +106,22 @@ public class Circle extends Base {
} }
@Override @Override
public void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) { public void drawShapePoints(
Log.verbose(spacingDist(level) + "DRAW Shape esvg::Circle"); final List<List<Vector2f>> out,
PathModel listElement = createPath(); final int recurtionMax,
final float threshold,
final Matrix2x3f basicTrans,
final int level) {
LOGGER.trace(spacingDist(level) + "DRAW Shape esvg::Circle");
final PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix; Matrix2x3f mtx = this.transformMatrix;
mtx = mtx.multiply(basicTrans); mtx = mtx.multiply(basicTrans);
PointList listPoints = new PointList(); PointList listPoints = new PointList();
listPoints = listElement.generateListPoints(level, recurtionMax, threshold); listPoints = listElement.generateListPoints(level, recurtionMax, threshold);
listPoints.applyMatrix(mtx); listPoints.applyMatrix(mtx);
for (List<Point> it : listPoints.data) { for (final List<Point> it : listPoints.data) {
List<Vector2f> listPoint = new ArrayList<>(); final List<Vector2f> listPoint = new ArrayList<>();
for (Point itDot : it) { for (final Point itDot : it) {
listPoint.add(itDot.pos); listPoint.add(itDot.pos);
} }
out.add(listPoint); out.add(listPoint);
@ -138,13 +151,13 @@ public class Circle extends Base {
} }
content = element.getAttribute("r", ""); content = element.getAttribute("r", "");
if (content.length() == 0) { if (content.length() == 0) {
Log.error("Circle \"r\" is not present"); LOGGER.error("Circle \"r\" is not present");
return false; return false;
} }
this.radius = parseLength(content); this.radius = parseLength(content);
if (0 > this.radius) { if (0 > this.radius) {
this.radius = 0; this.radius = 0;
Log.error("Circle \"r\" is negative"); LOGGER.error("Circle \"r\" is negative");
return false; return false;
} }
sizeMax.value = new Vector2f(this.position.x() + this.radius, this.position.y() + this.radius); sizeMax.value = new Vector2f(this.position.x() + this.radius, this.position.y() + this.radius);

View File

@ -2,7 +2,7 @@ package org.atriasoft.esvg;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.DynamicColor; import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.PathModel; import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.Point; import org.atriasoft.esvg.render.Point;
@ -13,6 +13,8 @@ import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -21,6 +23,7 @@ import org.atriasoft.exml.model.XmlElement;
*/ */
public class Ellipse extends Base { public class Ellipse extends Base {
static final Logger LOGGER = LoggerFactory.getLogger(Ellipse.class);
private Vector2f c; //!< Center property of the ellipse private Vector2f c; //!< Center property of the ellipse
private Vector2f r; //!< Radius property of the ellipse private Vector2f r; //!< Radius property of the ellipse
@ -35,41 +38,46 @@ public class Ellipse extends Base {
} }
PathModel createPath() { PathModel createPath() {
PathModel out = new PathModel(); final PathModel out = new PathModel();
out.moveTo(false, this.c.add(this.r.x(), 0.0f)); out.moveTo(false, this.c.add(this.r.x(), 0.0f));
out.curveTo(false, this.c.add(this.r.x(), this.r.y() * Base.kappa90), this.c.add(this.r.x() * Base.kappa90, this.r.y()), this.c.add(0.0f, this.r.y())); out.curveTo(false, this.c.add(this.r.x(), this.r.y() * Base.kappa90),
out.curveTo(false, this.c.add(-this.r.x() * Base.kappa90, this.r.y()), this.c.add(-this.r.x(), this.r.y() * Base.kappa90), this.c.add(-this.r.x(), 0.0f)); this.c.add(this.r.x() * Base.kappa90, this.r.y()), this.c.add(0.0f, this.r.y()));
out.curveTo(false, this.c.add(-this.r.x(), -this.r.y() * Base.kappa90), this.c.add(-this.r.x() * Base.kappa90, -this.r.y()), this.c.add(0.0f, -this.r.y())); out.curveTo(false, this.c.add(-this.r.x() * Base.kappa90, this.r.y()),
out.curveTo(false, this.c.add(this.r.x() * Base.kappa90, -this.r.y()), this.c.add(this.r.x(), -this.r.y() * Base.kappa90), this.c.add(this.r.x(), 0.0f)); this.c.add(-this.r.x(), this.r.y() * Base.kappa90), this.c.add(-this.r.x(), 0.0f));
out.curveTo(false, this.c.add(-this.r.x(), -this.r.y() * Base.kappa90),
this.c.add(-this.r.x() * Base.kappa90, -this.r.y()), this.c.add(0.0f, -this.r.y()));
out.curveTo(false, this.c.add(this.r.x() * Base.kappa90, -this.r.y()),
this.c.add(this.r.x(), -this.r.y() * Base.kappa90), this.c.add(this.r.x(), 0.0f));
out.close(); out.close();
return out; return out;
} }
@Override @Override
public void display(final int spacing) { public void display(final int spacing) {
Log.debug(spacingDist(spacing) + "Ellipse c=" + this.c + " r=" + this.r); LOGGER.debug(spacingDist(spacing) + "Ellipse c=" + this.c + " r=" + this.r);
} }
@Override @Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW esvg::Ellipse"); LOGGER.trace(spacingDist(level) + "DRAW esvg::Ellipse");
if (this.r.x() <= 0.0f || this.r.y() <= 0.0f) { if (this.r.x() <= 0.0f || this.r.y() <= 0.0f) {
Log.verbose(spacingDist(level + 1) + "Too small radius" + this.r); LOGGER.trace(spacingDist(level + 1) + "Too small radius" + this.r);
return; return;
} }
PathModel listElement = createPath(); final PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix; Matrix2x3f mtx = this.transformMatrix;
mtx = mtx.multiply(basicTrans); mtx = mtx.multiply(basicTrans);
PointList listPoints = new PointList(); PointList listPoints = new PointList();
listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold()); listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(),
myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx); //listPoints.applyMatrix(mtx);
SegmentList listSegmentFill = new SegmentList(); final SegmentList listSegmentFill = new SegmentList();
SegmentList listSegmentStroke = new SegmentList(); final SegmentList listSegmentStroke = new SegmentList();
Weight tmpFill = new Weight(); final Weight tmpFill = new Weight();
Weight tmpStroke = new Weight(); final Weight tmpStroke = new Weight();
DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx); final DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx);
DynamicColor colorStroke = null; DynamicColor colorStroke = null;
if (this.paint.strokeWidth > 0.0f) { if (this.paint.strokeWidth > 0.0f) {
colorStroke = DynamicColor.createColor(this.paint.stroke, mtx); colorStroke = DynamicColor.createColor(this.paint.stroke, mtx);
@ -84,7 +92,8 @@ public class Ellipse extends Base {
} }
// check if we need to display stroke: // check if we need to display stroke:
if (colorStroke != null) { if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit); listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap,
this.paint.lineJoin, this.paint.miterLimit);
colorStroke.setViewPort(listSegmentStroke.getViewPort()); colorStroke.setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx); listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
@ -97,17 +106,22 @@ public class Ellipse extends Base {
} }
@Override @Override
public void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) { public void drawShapePoints(
Log.verbose(spacingDist(level) + "DRAW Shape esvg::Ellipse"); final List<List<Vector2f>> out,
PathModel listElement = createPath(); final int recurtionMax,
final float threshold,
final Matrix2x3f basicTrans,
final int level) {
LOGGER.trace(spacingDist(level) + "DRAW Shape esvg::Ellipse");
final PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix; Matrix2x3f mtx = this.transformMatrix;
mtx = mtx.multiply(basicTrans); mtx = mtx.multiply(basicTrans);
PointList listPoints; PointList listPoints;
listPoints = listElement.generateListPoints(level, recurtionMax, threshold); listPoints = listElement.generateListPoints(level, recurtionMax, threshold);
listPoints.applyMatrix(mtx); listPoints.applyMatrix(mtx);
for (List<Point> it : listPoints.data) { for (final List<Point> it : listPoints.data) {
List<Vector2f> listPoint = new ArrayList<>(); final List<Vector2f> listPoint = new ArrayList<>();
for (Point itDot : it) { for (final Point itDot : it) {
listPoint.add(itDot.pos); listPoint.add(itDot.pos);
} }
out.add(listPoint); out.add(listPoint);
@ -138,13 +152,13 @@ public class Ellipse extends Base {
} }
content = element.getAttribute("rx", ""); content = element.getAttribute("rx", "");
if (content.length() == 0) { if (content.length() == 0) {
Log.error("Ellipse \"rx\" is not present"); LOGGER.error("Ellipse \"rx\" is not present");
return false; return false;
} }
this.r = this.r.withX(parseLength(content)); this.r = this.r.withX(parseLength(content));
content = element.getAttribute("ry", ""); content = element.getAttribute("ry", "");
if (content.length() == 0) { if (content.length() == 0) {
Log.error("Ellipse \"ry\" is not present"); LOGGER.error("Ellipse \"ry\" is not present");
return false; return false;
} }
this.r = this.r.withY(parseLength(content)); this.r = this.r.withY(parseLength(content));

View File

@ -5,7 +5,6 @@ import java.util.List;
import org.atriasoft.aknot.exception.AknotException; import org.atriasoft.aknot.exception.AknotException;
import org.atriasoft.egami.ImageFloatRGBA; import org.atriasoft.egami.ImageFloatRGBA;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.Uri; import org.atriasoft.etk.Uri;
import org.atriasoft.etk.math.Matrix2x3f; import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
@ -16,8 +15,11 @@ import org.atriasoft.exml.exception.ExmlException;
import org.atriasoft.exml.exception.ExmlNodeDoesNotExist; import org.atriasoft.exml.exception.ExmlNodeDoesNotExist;
import org.atriasoft.exml.model.XmlElement; import org.atriasoft.exml.model.XmlElement;
import org.atriasoft.exml.model.XmlNode; import org.atriasoft.exml.model.XmlNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class EsvgDocument extends Base { public class EsvgDocument extends Base {
static final Logger LOGGER = LoggerFactory.getLogger(EsvgDocument.class);
private boolean loadOK = false; private boolean loadOK = false;
private final List<Base> refList = new ArrayList<>(); private final List<Base> refList = new ArrayList<>();
private Vector2f size = Vector2f.ZERO; private Vector2f size = Vector2f.ZERO;
@ -55,7 +57,7 @@ public class EsvgDocument extends Base {
for (final String it1 : listStyle) { for (final String it1 : listStyle) {
final String[] value = it1.split(":"); final String[] value = it1.split(":");
if (value.length != 2) { if (value.length != 2) {
Log.error("parsing style with a wrong patern : " + it1 + " missing ':'"); LOGGER.error("parsing style with a wrong patern : " + it1 + " missing ':'");
continue; continue;
} }
// TODO Check if the attibute already exist ... // TODO Check if the attibute already exist ...
@ -83,33 +85,38 @@ public class EsvgDocument extends Base {
* Display all the node in the svg file. * Display all the node in the svg file.
*/ */
public void displayDebug() { public void displayDebug() {
Log.debug("Main SVG: size=" + this.size); LOGGER.debug("Main SVG: size=" + this.size);
Log.debug(" refs:"); LOGGER.debug(" refs:");
for (int iii = 0; iii < this.refList.size(); iii++) { for (final Base element : this.refList) {
if (this.refList.get(iii) != null) { if (element != null) {
this.refList.get(iii).display(2); element.display(2);
} }
} }
Log.debug(" Nodes:"); LOGGER.debug(" Nodes:");
for (int iii = 0; iii < this.subElementList.size(); iii++) { for (final Base element : this.subElementList) {
if (this.subElementList.get(iii) != null) { if (element != null) {
this.subElementList.get(iii).display(2); element.display(2);
} }
} }
} }
@Override @Override
protected void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { protected void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
for (int iii = 0; iii < this.subElementList.size(); iii++) { for (final Base element : this.subElementList) {
if (this.subElementList.get(iii) != null) { if (element != null) {
this.subElementList.get(iii).draw(myRenderer, basicTrans); element.draw(myRenderer, basicTrans);
} }
} }
} }
@Override @Override
protected void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) { protected void drawShapePoints(
Log.verbose(spacingDist(level) + "DRAW shape EsvgDocument"); final List<List<Vector2f>> out,
final int recurtionMax,
final float threshold,
final Matrix2x3f basicTrans,
final int level) {
LOGGER.trace(spacingDist(level) + "DRAW shape EsvgDocument");
for (final Base it : this.subElementList) { for (final Base it : this.subElementList) {
if (it != null) { if (it != null) {
it.drawShapePoints(out, recurtionMax, threshold, basicTrans, level + 1); it.drawShapePoints(out, recurtionMax, threshold, basicTrans, level + 1);
@ -134,16 +141,17 @@ public class EsvgDocument extends Base {
if (size.y() <= 0) { if (size.y() <= 0) {
size = size.withY(this.size.y()); size = size.withY(this.size.y());
} }
Log.debug("lineification size " + size); LOGGER.debug("lineification size " + size);
// create the first element matrix modification ... // create the first element matrix modification ...
final Matrix2x3f basicTrans = Matrix2x3f.IDENTITY.multiply(Matrix2x3f.createScale(new Vector2f(size.x() / this.size.x(), size.y() / this.size.y()))); final Matrix2x3f basicTrans = Matrix2x3f.IDENTITY
.multiply(Matrix2x3f.createScale(new Vector2f(size.x() / this.size.x(), size.y() / this.size.y())));
drawShapePoints(out, 10, 0.25f, basicTrans); drawShapePoints(out, 10, 0.25f, basicTrans);
return out; return out;
} }
public Base getReference(final String name) { public Base getReference(final String name) {
if (name.isEmpty()) { if (name.isEmpty()) {
Log.error("request a reference with no name ... "); LOGGER.error("request a reference with no name ... ");
return null; return null;
} }
for (final Base it : this.refList) { for (final Base it : this.refList) {
@ -154,7 +162,7 @@ public class EsvgDocument extends Base {
return it; return it;
} }
} }
Log.error("Can not find reference name : '" + name + "'"); LOGGER.error("Can not find reference name : '" + name + "'");
return null; return null;
} }
@ -277,9 +285,9 @@ public class EsvgDocument extends Base {
pos = parseXmlPosition(root); pos = parseXmlPosition(root);
this.size = parseXmlSize(root); this.size = parseXmlSize(root);
parsePaintAttr(root); parsePaintAttr(root);
Log.verbose("parsed .ROOT trans: " + this.transformMatrix); LOGGER.trace("parsed .ROOT trans: " + this.transformMatrix);
} else { } else {
Log.verbose("Parse Reference section ... (no attibute)"); LOGGER.trace("Parse Reference section ... (no attibute)");
} }
Vector2f maxSize = Vector2f.ZERO; Vector2f maxSize = Vector2f.ZERO;
@ -294,7 +302,7 @@ public class EsvgDocument extends Base {
if (child.getValue().equals("g")) { if (child.getValue().equals("g")) {
elementParser = new Group(this.paint); elementParser = new Group(this.paint);
} else if (child.getValue().equals("a")) { } else if (child.getValue().equals("a")) {
Log.info("Note : 'a' balise is parsed like a g balise ..."); LOGGER.info("Note : 'a' balise is parsed like a g balise ...");
elementParser = new Group(this.paint); elementParser = new Group(this.paint);
} else if (child.getValue().equals("title")) { } else if (child.getValue().equals("title")) {
this.title = "TODO : set the title here ..."; this.title = "TODO : set the title here ...";
@ -317,19 +325,19 @@ public class EsvgDocument extends Base {
elementParser = new Text(this.paint); elementParser = new Text(this.paint);
} else if (child.getValue().equals("radialGradient")) { } else if (child.getValue().equals("radialGradient")) {
if (!isReference) { if (!isReference) {
Log.error("'" + child.getValue() + "' node must not be defined outside a defs Section"); LOGGER.error("'" + child.getValue() + "' node must not be defined outside a defs Section");
continue; continue;
} }
elementParser = new RadialGradient(this.paint); elementParser = new RadialGradient(this.paint);
} else if (child.getValue().equals("linearGradient")) { } else if (child.getValue().equals("linearGradient")) {
if (!isReference) { if (!isReference) {
Log.error("'" + child.getValue() + "' node must not be defined outside a defs Section"); LOGGER.error("'" + child.getValue() + "' node must not be defined outside a defs Section");
continue; continue;
} }
elementParser = new LinearGradient(this.paint); elementParser = new LinearGradient(this.paint);
} else if (child.getValue().equals("defs")) { } else if (child.getValue().equals("defs")) {
if (isReference) { if (isReference) {
Log.error("'" + child.getValue() + "' node must not be defined in a defs Section"); LOGGER.error("'" + child.getValue() + "' node must not be defined in a defs Section");
continue; continue;
} }
final boolean retRefs = parseXMLData(child, true); final boolean retRefs = parseXMLData(child, true);
@ -342,14 +350,15 @@ public class EsvgDocument extends Base {
// Node ignore : generaly inkscape data // Node ignore : generaly inkscape data
continue; continue;
} else { } else {
Log.error("node not suported : '" + child.getValue() + "' must be [title,g,a,path,rect,circle,ellipse,line,polyline,polygon,text,metadata]"); LOGGER.error("node not suported : '" + child.getValue()
+ "' must be [title,g,a,path,rect,circle,ellipse,line,polyline,polygon,text,metadata]");
} }
if (elementParser == null) { if (elementParser == null) {
Log.error("error on node: '" + child.getValue() + "' allocation error or not supported ..."); LOGGER.error("error on node: '" + child.getValue() + "' allocation error or not supported ...");
continue; continue;
} }
if (!elementParser.parseXML(child, this.transformMatrix, size)) { if (!elementParser.parseXML(child, this.transformMatrix, size)) {
Log.error("error on node: '" + child.getValue() + "' Sub Parsing ERROR"); LOGGER.error("error on node: '" + child.getValue() + "' Sub Parsing ERROR");
elementParser = null; elementParser = null;
continue; continue;
} }
@ -393,7 +402,7 @@ public class EsvgDocument extends Base {
size = size.withY((int) this.size.y()); size = size.withY((int) this.size.y());
} }
} }
Log.debug("Generate size " + size); LOGGER.debug("Generate size " + size);
Renderer renderedElement = new Renderer(size, this, visualDebug); Renderer renderedElement = new Renderer(size, this, visualDebug);
// create the first element matrix modification ... // create the first element matrix modification ...
Matrix2x3f basicTrans = Matrix2x3f.IDENTITY.multiply(Matrix2x3f.createScale(new Vector2f(size.x() / this.size.x(), size.y() / this.size.y()))); Matrix2x3f basicTrans = Matrix2x3f.IDENTITY.multiply(Matrix2x3f.createScale(new Vector2f(size.x() / this.size.x(), size.y() / this.size.y())));
@ -424,15 +433,16 @@ public class EsvgDocument extends Base {
} }
} }
if (size.x() <= 0) { if (size.x() <= 0) {
Log.error("Generate size " + size); LOGGER.error("Generate size " + size);
} }
if (size.y() <= 0) { if (size.y() <= 0) {
Log.error("Generate size " + size); LOGGER.error("Generate size " + size);
} }
Log.verbose("Generate size " + size); LOGGER.trace("Generate size " + size);
final Renderer renderedElement = new Renderer(size, this, visualDebug); final Renderer renderedElement = new Renderer(size, this, visualDebug);
// create the first element matrix modification ... // create the first element matrix modification ...
final Matrix2x3f basicTrans = Matrix2x3f.IDENTITY.multiply(Matrix2x3f.createScale(new Vector2f(size.x() / this.size.x(), size.y() / this.size.y()))); final Matrix2x3f basicTrans = Matrix2x3f.IDENTITY
.multiply(Matrix2x3f.createScale(new Vector2f(size.x() / this.size.x(), size.y() / this.size.y())));
draw(renderedElement, basicTrans); draw(renderedElement, basicTrans);
// direct return the generated data ... // direct return the generated data ...

View File

@ -8,7 +8,6 @@ import java.util.Map;
import org.atriasoft.aknot.exception.AknotException; import org.atriasoft.aknot.exception.AknotException;
import org.atriasoft.esvg.font.Glyph; import org.atriasoft.esvg.font.Glyph;
import org.atriasoft.esvg.font.Kerning; import org.atriasoft.esvg.font.Kerning;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.PathModel; import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.RenderingConfig; import org.atriasoft.esvg.render.RenderingConfig;
import org.atriasoft.esvg.render.Weight; import org.atriasoft.esvg.render.Weight;
@ -21,6 +20,8 @@ import org.atriasoft.exml.Exml;
import org.atriasoft.exml.exception.ExmlException; import org.atriasoft.exml.exception.ExmlException;
import org.atriasoft.exml.model.XmlElement; import org.atriasoft.exml.model.XmlElement;
import org.atriasoft.exml.model.XmlNode; import org.atriasoft.exml.model.XmlNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// https://www.w3.org/TR/SVGTiny12/fonts.html // https://www.w3.org/TR/SVGTiny12/fonts.html
@ -77,6 +78,7 @@ import org.atriasoft.exml.model.XmlNode;
*/ */
public class EsvgFont { public class EsvgFont {
static final Logger LOGGER = LoggerFactory.getLogger(EsvgFont.class);
/** /**
* Load the file that might contain the svg * Load the file that might contain the svg
@ -99,19 +101,20 @@ public class EsvgFont {
return null; return null;
} }
if (!(doc instanceof final XmlElement root)) { if (!(doc instanceof final XmlElement root)) {
Log.error("can not load the SVG font ==> wrong root node"); LOGGER.error("can not load the SVG font ==> wrong root node");
return null; return null;
} }
if (!root.existNode("svg") || !(root.getNodeNoExcept("svg") instanceof final XmlElement svgNode)) { if (!root.existNode("svg") || !(root.getNodeNoExcept("svg") instanceof final XmlElement svgNode)) {
Log.error("can not load Node <svg> in svg document"); LOGGER.error("can not load Node <svg> in svg document");
return null; return null;
} }
if (!svgNode.existNode("defs") || !(svgNode.getNodeNoExcept("defs") instanceof final XmlElement defsNode)) { if (!svgNode.existNode("defs") || !(svgNode.getNodeNoExcept("defs") instanceof final XmlElement defsNode)) {
Log.error("can not load Node <defs> in svg document"); LOGGER.error("can not load Node <defs> in svg document");
return null; return null;
} }
if (!defsNode.existNode("font") || !(defsNode.getNodeNoExcept("font") instanceof final XmlElement fontElement)) { if (!defsNode.existNode("font")
Log.error("can not load Node <font> in svg document"); || !(defsNode.getNodeNoExcept("font") instanceof final XmlElement fontElement)) {
LOGGER.error("can not load Node <font> in svg document");
return null; return null;
} }
@ -157,7 +160,7 @@ public class EsvgFont {
for (final XmlNode values : fontElement.getNodes()) { for (final XmlNode values : fontElement.getNodes()) {
if (values.getValue().equals("glyph")) { if (values.getValue().equals("glyph")) {
nbGlyph++; nbGlyph++;
//Log.info("find flyph: " + nbGlyph); //LOGGER.info("find flyph: " + nbGlyph);
final Glyph tmp = Glyph.valueOf(values.toElement(), font); final Glyph tmp = Glyph.valueOf(values.toElement(), font);
if (tmp != null) { if (tmp != null) {
font.glyphs.put(tmp.getUnicodeValue(), tmp); font.glyphs.put(tmp.getUnicodeValue(), tmp);
@ -169,7 +172,7 @@ public class EsvgFont {
} else if (values.getValue().equals("font-face")) { } else if (values.getValue().equals("font-face")) {
// already done ... // already done ...
} else { } else {
Log.warning("unsupported node name :" + values.getValue()); LOGGER.warn("unsupported node name :" + values.getValue());
} }
} }
for (final XmlNode values : fontElement.getNodes()) { for (final XmlNode values : fontElement.getNodes()) {
@ -188,18 +191,18 @@ public class EsvgFont {
final String[] g2Splited = g2.split(","); final String[] g2Splited = g2.split(",");
// create the list of kerning of the next elements // create the list of kerning of the next elements
final List<Kerning> elementsKerning = new ArrayList<>(); final List<Kerning> elementsKerning = new ArrayList<>();
for (int iii = 0; iii < g2Splited.length; iii++) { for (final String element : g2Splited) {
for (final Map.Entry<Integer, Glyph> entry : font.glyphs.entrySet()) { for (final Map.Entry<Integer, Glyph> entry : font.glyphs.entrySet()) {
if (entry.getValue().getName().equals(g2Splited[iii])) { if (entry.getValue().getName().equals(element)) {
elementsKerning.add(new Kerning(offset, entry.getKey())); elementsKerning.add(new Kerning(offset, entry.getKey()));
break; break;
} }
} }
} }
// add it on the // add it on the
for (int iii = 0; iii < g1Splited.length; iii++) { for (final String element : g1Splited) {
for (final Map.Entry<Integer, Glyph> entry : font.glyphs.entrySet()) { for (final Map.Entry<Integer, Glyph> entry : font.glyphs.entrySet()) {
if (entry.getValue().getName().equals(g1Splited[iii])) { if (entry.getValue().getName().equals(element)) {
entry.getValue().addKerning(elementsKerning); entry.getValue().addKerning(elementsKerning);
font.hasKerning = true; font.hasKerning = true;
break; break;
@ -308,7 +311,7 @@ public class EsvgFont {
public int calculateWidth(final String data, final int fontSize, final boolean withKerning) { public int calculateWidth(final String data, final int fontSize, final boolean withKerning) {
final int realSize = calculateFontRealHeight(fontSize); final int realSize = calculateFontRealHeight(fontSize);
final float scale = (float) realSize / (float) this.unitsPerEm; final float scale = (float) realSize / (float) this.unitsPerEm;
//Log.error("scale =" + scale+ " font size = " + fontSize + " realSize=" + realSize); //LOGGER.error("scale =" + scale+ " font size = " + fontSize + " realSize=" + realSize);
float offsetWriting = 0; float offsetWriting = 0;
int lastValue = 0; int lastValue = 0;
for (final char uVal : data.toCharArray()) { for (final char uVal : data.toCharArray()) {
@ -324,7 +327,7 @@ public class EsvgFont {
final float advenceXLocal = glyph.getHorizAdvX() * scale; final float advenceXLocal = glyph.getHorizAdvX() * scale;
offsetWriting += advenceXLocal; offsetWriting += advenceXLocal;
//Log.error("offset X =" + offsetWriting + " + " + advenceXLocal + " " + uVal); //LOGGER.error("offset X =" + offsetWriting + " + " + advenceXLocal + " " + uVal);
} }
return (int) offsetWriting; return (int) offsetWriting;
} }
@ -391,7 +394,8 @@ public class EsvgFont {
} }
final float scale = (float) realSize / (float) this.unitsPerEm; final float scale = (float) realSize / (float) this.unitsPerEm;
final RenderingConfig config = new RenderingConfig(10, 0.25f, 8); final RenderingConfig config = new RenderingConfig(10, 0.25f, 8);
final Matrix2x3f transform = Matrix2x3f.createTranslate(new Vector2f(0, -this.descent)).multiply(Matrix2x3f.createScale(scale)); final Matrix2x3f transform = Matrix2x3f.createTranslate(new Vector2f(0, -this.descent))
.multiply(Matrix2x3f.createScale(scale));
final PathModel model = glyph.getModel(); final PathModel model = glyph.getModel();
if (model == null) { if (model == null) {
return null; return null;
@ -422,17 +426,19 @@ public class EsvgFont {
} }
if (withKerning) { if (withKerning) {
offsetWriting -= glyph.getKerning(lastValue) * scale; offsetWriting -= glyph.getKerning(lastValue) * scale;
Log.info(" ==> kerning offset = " + (glyph.getKerning(lastValue) * scale)); LOGGER.info(" ==> kerning offset = " + (glyph.getKerning(lastValue) * scale));
lastValue = uVal; lastValue = uVal;
} }
final float advenceXLocal = glyph.getHorizAdvX() * scale; final float advenceXLocal = glyph.getHorizAdvX() * scale;
final RenderingConfig config = new RenderingConfig(10, 0.25f, 8); final RenderingConfig config = new RenderingConfig(10, 0.25f, 8);
final Matrix2x3f transform = Matrix2x3f.createTranslate(new Vector2f(0, -this.descent)).multiply(Matrix2x3f.createScale(scale)); final Matrix2x3f transform = Matrix2x3f.createTranslate(new Vector2f(0, -this.descent))
.multiply(Matrix2x3f.createScale(scale));
final PathModel model = glyph.getModel(); final PathModel model = glyph.getModel();
if (model != null) { if (model != null) {
final Weight redered = model.drawFill(calculateWidthRendering((int) uVal, fontSize), transform, 8, config); final Weight redered = model.drawFill(calculateWidthRendering((int) uVal, fontSize), transform, 8,
config);
weight.fusion(redered, (int) offsetWriting, 0); weight.fusion(redered, (int) offsetWriting, 0);
} }
offsetWriting += advenceXLocal; offsetWriting += advenceXLocal;

View File

@ -2,12 +2,13 @@ package org.atriasoft.esvg;
import org.atriasoft.egami.ImageByte; import org.atriasoft.egami.ImageByte;
import org.atriasoft.egami.ToolImage; import org.atriasoft.egami.ToolImage;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.PathModel; import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.etk.Color; import org.atriasoft.etk.Color;
import org.atriasoft.etk.Configs; import org.atriasoft.etk.Configs;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.math.Vector2i; import org.atriasoft.etk.math.Vector2i;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* Graphic context is used to manage dynamic * Graphic context is used to manage dynamic
@ -15,6 +16,7 @@ import org.atriasoft.etk.math.Vector2i;
* *
*/ */
public class GraphicContext { public class GraphicContext {
static final Logger LOGGER = LoggerFactory.getLogger(GraphicContext.class);
private EsvgDocument document = new EsvgDocument(); private EsvgDocument document = new EsvgDocument();
PaintState paintState; PaintState paintState;
private PathModel path = null; private PathModel path = null;
@ -25,7 +27,8 @@ public class GraphicContext {
} }
public Vector2i calculateTextSize(final String data) { public Vector2i calculateTextSize(final String data) {
return FontCache.getFont(Configs.getConfigFonts().getName(), false, false).calculateTextSize(Configs.getConfigFonts().getSize(), data); return FontCache.getFont(Configs.getConfigFonts().getName(), false, false)
.calculateTextSize(Configs.getConfigFonts().getSize(), data);
} }
public void circle(final Vector2f position, final float radius) { public void circle(final Vector2f position, final float radius) {
@ -94,13 +97,14 @@ public class GraphicContext {
public int getTextHeight() { public int getTextHeight() {
return getTextHeight(Configs.getConfigFonts().getSize()); return getTextHeight(Configs.getConfigFonts().getSize());
} }
public int getTextSize() { public int getTextSize() {
return Configs.getConfigFonts().getSize(); return Configs.getConfigFonts().getSize();
} }
public int getTextHeight(final float height) { public int getTextHeight(final float height) {
return FontCache.getFont(Configs.getConfigFonts().getName(), false, false).calculateFontRealHeight((int) height); return FontCache.getFont(Configs.getConfigFonts().getName(), false, false)
.calculateFontRealHeight((int) height);
} }
public void line(final Vector2f origin, final Vector2f destination) { public void line(final Vector2f origin, final Vector2f destination) {
@ -113,7 +117,7 @@ public class GraphicContext {
public void pathLine(final Vector2f pos) { public void pathLine(final Vector2f pos) {
if (this.path == null) { if (this.path == null) {
Log.error("Empty path... Need call pathStart() before"); LOGGER.error("Empty path... Need call pathStart() before");
return; return;
} }
this.path.lineTo(false, pos); this.path.lineTo(false, pos);
@ -121,7 +125,7 @@ public class GraphicContext {
public void pathLineTo(final Vector2f pos) { public void pathLineTo(final Vector2f pos) {
if (this.path == null) { if (this.path == null) {
Log.error("Empty path... Need call pathStart() before"); LOGGER.error("Empty path... Need call pathStart() before");
return; return;
} }
this.path.lineTo(true, pos); this.path.lineTo(true, pos);
@ -130,7 +134,7 @@ public class GraphicContext {
public void pathMove(final Vector2f pos) { public void pathMove(final Vector2f pos) {
if (this.path == null) { if (this.path == null) {
Log.error("Empty path... Need call pathStart() before"); LOGGER.error("Empty path... Need call pathStart() before");
return; return;
} }
this.path.moveTo(false, pos); this.path.moveTo(false, pos);
@ -138,7 +142,7 @@ public class GraphicContext {
public void pathMoveTo(final Vector2f pos) { public void pathMoveTo(final Vector2f pos) {
if (this.path == null) { if (this.path == null) {
Log.error("Empty path... Need call pathStart() before"); LOGGER.error("Empty path... Need call pathStart() before");
return; return;
} }
this.path.moveTo(true, pos); this.path.moveTo(true, pos);
@ -169,7 +173,7 @@ public class GraphicContext {
public void rectangle(final Vector2f position, final Vector2f destination) { public void rectangle(final Vector2f position, final Vector2f destination) {
if (this.path != null) { if (this.path != null) {
Log.error("Path not empty ... Need call pathStart() before"); LOGGER.error("Path not empty ... Need call pathStart() before");
pathStop(); pathStop();
} }
this.document.addElement(new Rectangle(position, destination.less(position), this.paintState.clone())); this.document.addElement(new Rectangle(position, destination.less(position), this.paintState.clone()));
@ -177,7 +181,7 @@ public class GraphicContext {
public void rectangleRounded(final Vector2f position, final Vector2f destination, final Vector2f ruound) { public void rectangleRounded(final Vector2f position, final Vector2f destination, final Vector2f ruound) {
if (this.path != null) { if (this.path != null) {
Log.error("Path not empty ... Need call pathStart() before"); LOGGER.error("Path not empty ... Need call pathStart() before");
pathStop(); pathStop();
} }
this.document.addElement(new Rectangle(position, destination.less(position), ruound, this.paintState.clone())); this.document.addElement(new Rectangle(position, destination.less(position), ruound, this.paintState.clone()));
@ -185,7 +189,7 @@ public class GraphicContext {
public void rectangleRoundedWidth(final Vector2f position, final Vector2f width, final Vector2f ruound) { public void rectangleRoundedWidth(final Vector2f position, final Vector2f width, final Vector2f ruound) {
if (this.path != null) { if (this.path != null) {
Log.error("Path not empty ... Need call pathStart() before"); LOGGER.error("Path not empty ... Need call pathStart() before");
pathStop(); pathStop();
} }
this.document.addElement(new Rectangle(position, width, ruound, this.paintState.clone())); this.document.addElement(new Rectangle(position, width, ruound, this.paintState.clone()));
@ -193,7 +197,7 @@ public class GraphicContext {
public void rectangleWidth(final Vector2f position, final Vector2f width) { public void rectangleWidth(final Vector2f position, final Vector2f width) {
if (this.path != null) { if (this.path != null) {
Log.error("Path not empty ... Need call pathStart() before"); LOGGER.error("Path not empty ... Need call pathStart() before");
pathStop(); pathStop();
} }
this.document.addElement(new Rectangle(position, width, this.paintState.clone())); this.document.addElement(new Rectangle(position, width, this.paintState.clone()));
@ -262,7 +266,8 @@ public class GraphicContext {
} }
public void text(final Vector2f position, final float height, final String data) { public void text(final Vector2f position, final float height, final String data) {
this.document.addElement(new Text(position, Configs.getConfigFonts().getName(), height, data, this.paintState.clone())); this.document.addElement(
new Text(position, Configs.getConfigFonts().getName(), height, data, this.paintState.clone()));
} }
public void text(final Vector2f position, final String data) { public void text(final Vector2f position, final String data) {

View File

@ -3,12 +3,13 @@ package org.atriasoft.esvg;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.internal.Log;
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.util.Dynamic; import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.exml.model.XmlElement; import org.atriasoft.exml.model.XmlElement;
import org.atriasoft.exml.model.XmlNode; import org.atriasoft.exml.model.XmlNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -16,6 +17,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 {
static final Logger LOGGER = LoggerFactory.getLogger(Group.class);
private final List<Base> subElementList = new ArrayList<>(); //!< sub elements ... private final List<Base> subElementList = new ArrayList<>(); //!< sub elements ...
public Group(final PaintState parentPaintState) { public Group(final PaintState parentPaintState) {
@ -24,20 +26,21 @@ public class Group extends Base {
@Override @Override
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 LOGGER.debug(spacingDist(spacing) + "Group (START) fill=" + this.paint.fill.first + "/" + this.paint.fill.second
+ " stroke-width=" + this.paint.strokeWidth); + " stroke=" + this.paint.stroke.first + "/" + this.paint.stroke.second + " stroke-width="
+ this.paint.strokeWidth);
for (final Base it : this.subElementList) { for (final Base it : this.subElementList) {
if (it != null) { if (it != null) {
it.display(spacing + 1); it.display(spacing + 1);
} }
} }
Log.debug(spacingDist(spacing) + "Group (STOP)"); LOGGER.debug(spacingDist(spacing) + "Group (STOP)");
} }
@Override @Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW esvg::group"); LOGGER.trace(spacingDist(level) + "DRAW esvg::group");
for (Base it : this.subElementList) { for (final Base it : this.subElementList) {
if (it != null) { if (it != null) {
it.draw(myRenderer, basicTrans, level + 1); it.draw(myRenderer, basicTrans, level + 1);
} }
@ -45,9 +48,14 @@ public class Group extends Base {
} }
@Override @Override
public void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) { public void drawShapePoints(
Log.verbose(spacingDist(level) + "DRAW shape esvg::group"); final List<List<Vector2f>> out,
for (Base it : this.subElementList) { final int recurtionMax,
final float threshold,
final Matrix2x3f basicTrans,
final int level) {
LOGGER.trace(spacingDist(level) + "DRAW shape esvg::group");
for (final Base it : this.subElementList) {
if (it != null) { if (it != null) {
it.drawShapePoints(out, recurtionMax, threshold, basicTrans, level + 1); it.drawShapePoints(out, recurtionMax, threshold, basicTrans, level + 1);
} }
@ -66,18 +74,18 @@ public class Group extends Base {
pos = parseXmlPosition(element); pos = parseXmlPosition(element);
size = parseXmlSize(element); size = parseXmlSize(element);
parsePaintAttr(element); parsePaintAttr(element);
Log.verbose("parsed G1. trans : " + this.transformMatrix); LOGGER.trace("parsed G1. trans : " + this.transformMatrix);
// add the property of the parrent modifications ... // add the property of the parrent modifications ...
this.transformMatrix = this.transformMatrix.multiply(parentTrans); this.transformMatrix = this.transformMatrix.multiply(parentTrans);
Log.verbose("parsed G2. trans : " + this.transformMatrix); LOGGER.trace("parsed G2. trans : " + this.transformMatrix);
sizeMax.value = Vector2f.ZERO; sizeMax.value = Vector2f.ZERO;
Dynamic<Vector2f> tmpPos = new Dynamic<Vector2f>(Vector2f.ZERO); final Dynamic<Vector2f> tmpPos = new Dynamic<>(Vector2f.ZERO);
// parse all sub node : // parse all sub node :
for (XmlNode it : element.getNodes()) { for (final XmlNode it : element.getNodes()) {
if (!(it instanceof XmlElement child)) { if (!(it instanceof final XmlElement child)) {
// can be a comment ... // can be a comment ...
continue; continue;
} }
@ -103,14 +111,15 @@ public class Group extends Base {
} else if (child.getValue().equals("text")) { } else if (child.getValue().equals("text")) {
elementParser = new Text(this.paint); elementParser = new Text(this.paint);
} else { } else {
Log.error("node not suported : '" + child.getValue() + "' must be [g,a,path,rect,circle,ellipse,line,polyline,polygon,text]"); LOGGER.error("node not suported : '" + child.getValue()
+ "' must be [g,a,path,rect,circle,ellipse,line,polyline,polygon,text]");
} }
if (elementParser == null) { if (elementParser == null) {
Log.error("error on node: '" + child.getValue() + "' allocation error or not supported ..."); LOGGER.error("error on node: '" + child.getValue() + "' allocation error or not supported ...");
continue; continue;
} }
if (!elementParser.parseXML(child, this.transformMatrix, tmpPos)) { if (!elementParser.parseXML(child, this.transformMatrix, tmpPos)) {
Log.error(" error on node: '" + child.getValue() + "' Sub Parsing ERROR"); LOGGER.error(" error on node: '" + child.getValue() + "' Sub Parsing ERROR");
elementParser = null; elementParser = null;
continue; continue;
} }

View File

@ -3,7 +3,6 @@ package org.atriasoft.esvg;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.DynamicColor; import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.PathModel; import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.Point; import org.atriasoft.esvg.render.Point;
@ -14,6 +13,8 @@ import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -21,6 +22,7 @@ import org.atriasoft.exml.model.XmlElement;
* @license MPL v2.0 (see license file) * @license MPL v2.0 (see license file)
*/ */
public class Line extends Base { public class Line extends Base {
static final Logger LOGGER = LoggerFactory.getLogger(Line.class);
private Vector2f startPos = Vector2f.ZERO; //!< Start line position private Vector2f startPos = Vector2f.ZERO; //!< Start line position
private Vector2f stopPos = Vector2f.ZERO; //!< Stop line position private Vector2f stopPos = Vector2f.ZERO; //!< Stop line position
@ -35,7 +37,7 @@ public class Line extends Base {
} }
private PathModel createPath() { private PathModel createPath() {
PathModel out = new PathModel(); final PathModel out = new PathModel();
out.clear(); out.clear();
out.moveTo(false, this.startPos); out.moveTo(false, this.startPos);
out.lineTo(false, this.stopPos); out.lineTo(false, this.stopPos);
@ -45,23 +47,24 @@ public class Line extends Base {
@Override @Override
public void display(final int spacing) { public void display(final int spacing) {
Log.debug(spacingDist(spacing) + "Line " + this.startPos + " to " + this.stopPos); LOGGER.debug(spacingDist(spacing) + "Line " + this.startPos + " to " + this.stopPos);
} }
@Override @Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW esvg::Line"); LOGGER.trace(spacingDist(level) + "DRAW esvg::Line");
PathModel listElement = createPath(); final PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans); final Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
PointList listPoints = new PointList(); PointList listPoints = new PointList();
listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold()); listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(),
SegmentList listSegmentStroke = new SegmentList(); myRenderer.getInterpolationThreshold());
Weight tmpFill = new Weight(); final SegmentList listSegmentStroke = new SegmentList();
Weight tmpStroke = new Weight(); final Weight tmpFill = new Weight();
DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx); final Weight tmpStroke = new Weight();
final DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx);
DynamicColor colorStroke = null; DynamicColor colorStroke = null;
if (this.paint.strokeWidth > 0.0f) { if (this.paint.strokeWidth > 0.0f) {
colorStroke = DynamicColor.createColor(this.paint.stroke, mtx); colorStroke = DynamicColor.createColor(this.paint.stroke, mtx);
@ -70,7 +73,8 @@ public class Line extends Base {
// No background ... // No background ...
// check if we need to display stroke: // check if we need to display stroke:
if (colorStroke != null) { if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit); listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap,
this.paint.lineJoin, this.paint.miterLimit);
colorStroke.setViewPort(listSegmentStroke.getViewPort()); colorStroke.setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx); listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
@ -81,16 +85,21 @@ public class Line extends Base {
} }
@Override @Override
public void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) { public void drawShapePoints(
Log.verbose(spacingDist(level) + "DRAW Shape esvg::Line"); final List<List<Vector2f>> out,
PathModel listElement = createPath(); final int recurtionMax,
Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans); final float threshold,
final Matrix2x3f basicTrans,
final int level) {
LOGGER.trace(spacingDist(level) + "DRAW Shape esvg::Line");
final PathModel listElement = createPath();
final Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
PointList listPoints; PointList listPoints;
listPoints = listElement.generateListPoints(level, recurtionMax, threshold); listPoints = listElement.generateListPoints(level, recurtionMax, threshold);
listPoints.applyMatrix(mtx); listPoints.applyMatrix(mtx);
for (List<Point> it : listPoints.data) { for (final List<Point> it : listPoints.data) {
List<Vector2f> listPoint = new ArrayList<>(); final List<Vector2f> listPoint = new ArrayList<>();
for (Point itDot : it) { for (final Point itDot : it) {
listPoint.add(itDot.pos); listPoint.add(itDot.pos);
} }
out.add(listPoint); out.add(listPoint);

View File

@ -3,7 +3,6 @@ package org.atriasoft.esvg;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.Color; import org.atriasoft.etk.Color;
import org.atriasoft.etk.Dimension2f; import org.atriasoft.etk.Dimension2f;
import org.atriasoft.etk.Distance; import org.atriasoft.etk.Distance;
@ -14,6 +13,8 @@ import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.etk.util.Pair; import org.atriasoft.etk.util.Pair;
import org.atriasoft.exml.model.XmlElement; import org.atriasoft.exml.model.XmlElement;
import org.atriasoft.exml.model.XmlNode; import org.atriasoft.exml.model.XmlNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -22,6 +23,7 @@ import org.atriasoft.exml.model.XmlNode;
*/ */
public class LinearGradient extends Base { public class LinearGradient extends Base {
static final Logger LOGGER = LoggerFactory.getLogger(LinearGradient.class);
private final List<Pair<Float, Color>> data = new ArrayList<>(); //!< gradient position x1 y1 private final List<Pair<Float, Color>> data = new ArrayList<>(); //!< gradient position x1 y1
private String href = ""; //!< gradient position x2 y2 private String href = ""; //!< gradient position x2 y2
private Dimension2f pos1 = new Dimension2f(new Vector2f(50, 50), Distance.POURCENT); private Dimension2f pos1 = new Dimension2f(new Vector2f(50, 50), Distance.POURCENT);
@ -38,15 +40,15 @@ public class LinearGradient extends Base {
@Override @Override
public void display(final int spacing) { public void display(final int spacing) {
Log.debug(spacingDist(spacing) + "LinearGradient " + this.pos1 + " to " + this.pos2); LOGGER.debug(spacingDist(spacing) + "LinearGradient " + this.pos1 + " to " + this.pos2);
for (Pair<Float, Color> it : this.data) { for (final Pair<Float, Color> it : this.data) {
Log.debug(spacingDist(spacing + 1) + "STOP: offset=" + it.first + " color=" + it.second); LOGGER.debug(spacingDist(spacing + 1) + "STOP: offset=" + it.first + " color=" + it.second);
} }
} }
@Override @Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW esvg::LinearGradient"); LOGGER.trace(spacingDist(level) + "DRAW esvg::LinearGradient");
} }
public List<Pair<Float, Color>> getColors(final EsvgDocument document) { public List<Pair<Float, Color>> getColors(final EsvgDocument document) {
@ -54,18 +56,18 @@ public class LinearGradient extends Base {
return this.data; return this.data;
} }
if (document == null) { if (document == null) {
Log.error("Get null input for document"); LOGGER.error("Get null input for document");
return this.data; return this.data;
} }
Base base = document.getReference(this.href); final Base base = document.getReference(this.href);
if (base == null) { if (base == null) {
Log.error("Can not get base : '" + this.href + "'"); LOGGER.error("Can not get base : '" + this.href + "'");
return this.data; return this.data;
} }
if (base instanceof RadialGradient gradientR) { if (base instanceof final RadialGradient gradientR) {
return gradientR.getColors(document); return gradientR.getColors(document);
} }
if (base instanceof LinearGradient gradientL) { if (base instanceof final LinearGradient gradientL) {
return gradientL.getColors(document); return gradientL.getColors(document);
} }
return this.data; return this.data;
@ -113,7 +115,8 @@ public class LinearGradient extends Base {
} else { } else {
this.unit = GradientUnits.GRADIENT_UNITS_OBJECT_BOUNDING_BOX; this.unit = GradientUnits.GRADIENT_UNITS_OBJECT_BOUNDING_BOX;
if (contentX.length() != 0 && contentX != "objectBoundingBox") { if (contentX.length() != 0 && contentX != "objectBoundingBox") {
Log.error("Parsing error of 'gradientUnits' ==> not suported value: '" + contentX + "' not in : {userSpaceOnUse/objectBoundingBox} use objectBoundingBox"); LOGGER.error("Parsing error of 'gradientUnits' ==> not suported value: '" + contentX
+ "' not in : {userSpaceOnUse/objectBoundingBox} use objectBoundingBox");
} }
} }
contentX = element.getAttribute("spreadMethod", ""); contentX = element.getAttribute("spreadMethod", "");
@ -124,7 +127,8 @@ public class LinearGradient extends Base {
} else { } else {
this.spread = SpreadMethod.PAD; this.spread = SpreadMethod.PAD;
if (contentX.length() != 0 && !contentX.equals("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"); LOGGER.error("Parsing error of 'spreadMethod' ==> not suported value: '" + contentX
+ "' not in : {reflect/repeate/pad} use pad");
} }
} }
// note: xlink:href is incompatible with subNode "stop" // note: xlink:href is incompatible with subNode "stop"
@ -133,19 +137,20 @@ public class LinearGradient extends Base {
this.href = this.href.substring(1); this.href = this.href.substring(1);
} }
// parse all sub node : // parse all sub node :
for (XmlNode it : element.getNodes()) { for (final XmlNode it : element.getNodes()) {
if (it instanceof XmlElement child) { if (it instanceof final XmlElement child) {
if (child.getValue().equals("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", "");
if (content.length() != 0) { if (content.length() != 0) {
Pair<Float, Distance> tmp = parseLength2(content); final Pair<Float, Distance> tmp = parseLength2(content);
if (tmp.second == Distance.PIXEL) { if (tmp.second == Distance.PIXEL) {
// special case ==> all time % then no type define ==> % in [0.0 .. 1.0] // special case ==> all time % then no type define ==> % in [0.0 .. 1.0]
offset = tmp.first * 100.0f; offset = tmp.first * 100.0f;
} else if (tmp.second != Distance.POURCENT) { } else if (tmp.second != Distance.POURCENT) {
Log.error("offset : " + content + " res=" + tmp.first + "," + tmp.second + " Not support other than pourcent %"); LOGGER.error("offset : " + content + " res=" + tmp.first + "," + tmp.second
+ " Not support other than pourcent %");
} else { } else {
offset = tmp.first; offset = tmp.first;
} }
@ -153,24 +158,25 @@ public class LinearGradient extends Base {
content = child.getAttribute("stop-color", ""); content = child.getAttribute("stop-color", "");
if (content.length() != 0) { if (content.length() != 0) {
stopColor = parseColor(content).first; stopColor = parseColor(content).first;
Log.verbose(" color : '" + content + "' == > " + stopColor); LOGGER.trace(" color : '" + content + "' == > " + stopColor);
} }
content = child.getAttribute("stop-opacity", ""); content = child.getAttribute("stop-opacity", "");
if (content.length() != 0) { if (content.length() != 0) {
float opacity = parseLength(content); float opacity = parseLength(content);
opacity = FMath.avg(0.0f, opacity, 1.0f); opacity = FMath.avg(0.0f, opacity, 1.0f);
stopColor = stopColor.withA(opacity); stopColor = stopColor.withA(opacity);
Log.verbose(" opacity : '" + content + "' == > " + stopColor); LOGGER.trace(" opacity : '" + content + "' == > " + stopColor);
} }
this.data.add(new Pair<>(offset, stopColor)); this.data.add(new Pair<>(offset, stopColor));
} else { } else {
Log.error(" node not suported : '" + child.getValue() + "' must be [stop]"); LOGGER.error(" node not suported : '" + child.getValue() + "' must be [stop]");
} }
} }
} }
if (this.data.size() != 0) { if (this.data.size() != 0) {
if (!this.href.isEmpty()) { if (!this.href.isEmpty()) {
Log.error(" node can not have an xlink:href element with sub node named: stop ==> removing href"); LOGGER.error(
" node can not have an xlink:href element with sub node named: stop ==> removing href");
this.href = ""; this.href = "";
} }
} }

View File

@ -3,7 +3,6 @@ package org.atriasoft.esvg;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.DynamicColor; import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.PathModel; import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.Point; import org.atriasoft.esvg.render.Point;
@ -15,6 +14,8 @@ import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -22,6 +23,8 @@ import org.atriasoft.exml.model.XmlElement;
* @license MPL v2.0 (see license file) * @license MPL v2.0 (see license file)
*/ */
public class Path extends Base { public class Path extends Base {
static final Logger LOGGER = LoggerFactory.getLogger(Path.class);
private record Command( private record Command(
char cmd, char cmd,
String[] listElem, String[] listElem,
@ -40,33 +43,34 @@ public class Path extends Base {
public static PathModel createPathModel(final String d) { public static PathModel createPathModel(final String d) {
final PathModel out = new PathModel(); final PathModel out = new PathModel();
Log.verbose("Parse Path : \"" + d + "\""); LOGGER.trace("Parse Path : \"" + d + "\"");
final List<String> commandsSplited = Path.splitCommand(d); final List<String> commandsSplited = Path.splitCommand(d);
String[] listDot = null; String[] listDot = null;
// 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(commandsSplited, 0); sss != null; sss = Path.extractCmd(commandsSplited, 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.listElem(); listDot = sss.listElem();
// Log.verbose("Find new command : '" + sss.cmd + "'"); // LOGGER.trace("Find new command : '" + sss.cmd + "'");
// if (listDot != null) { // if (listDot != null) {
// for (int jjj = 0; jjj < listDot.length; jjj++) { // for (int jjj = 0; jjj < listDot.length; jjj++) {
// Log.verbose(" -> '" + listDot[jjj] + "'"); // LOGGER.trace(" -> '" + listDot[jjj] + "'");
// } // }
// } else { // } else {
// Log.verbose(" -> no elements"); // LOGGER.trace(" -> 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)
if (listDot == null) { if (listDot == null) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot); LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
break; break;
} }
if (listDot.length % 2 != 0) { if (listDot.length % 2 != 0) {
Log.warning("the PATH command " + sss.cmd + " must be a multiple of 2"); LOGGER.warn("the PATH command " + sss.cmd + " must be a multiple of 2");
break; break;
} }
// 2 Elements ... // 2 Elements ...
@ -74,22 +78,24 @@ public class Path extends Base {
out.moveTo(relative, new Vector2f(Float.parseFloat(listDot[0]), Float.parseFloat(listDot[1]))); out.moveTo(relative, new Vector2f(Float.parseFloat(listDot[0]), Float.parseFloat(listDot[1])));
} }
for (int iii = 2; iii < listDot.length; iii += 2) { for (int iii = 2; iii < listDot.length; iii += 2) {
out.lineTo(relative, new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1]))); out.lineTo(relative,
new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])));
} }
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)
if (listDot == null) { if (listDot == null) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot); LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
break; break;
} }
if (listDot.length % 2 != 0) { if (listDot.length % 2 != 0) {
Log.warning("the PATH command " + sss.cmd + " must be a multiple of 2"); LOGGER.warn("the PATH command " + sss.cmd + " must be a multiple of 2");
break; break;
} }
for (int iii = 0; iii < listDot.length; iii += 2) { for (int iii = 0; iii < listDot.length; iii += 2) {
out.lineTo(relative, new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1]))); out.lineTo(relative,
new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])));
} }
break; break;
@ -98,11 +104,11 @@ public class Path extends Base {
case 'V': // Vertical Line to (absolute) case 'V': // Vertical Line to (absolute)
// 1 Element ... // 1 Element ...
if (listDot == null) { if (listDot == null) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot); LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
break; break;
} }
for (int iii = 0; iii < listDot.length; iii++) { for (final String element : listDot) {
out.lineToV(relative, Float.parseFloat(listDot[iii])); out.lineToV(relative, Float.parseFloat(element));
} }
break; break;
@ -111,11 +117,11 @@ public class Path extends Base {
case 'H': // Horizantal Line to (absolute) case 'H': // Horizantal Line to (absolute)
// 1 Element ... // 1 Element ...
if (listDot == null) { if (listDot == null) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot); LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
break; break;
} }
for (int iii = 0; iii < listDot.length; iii++) { for (final String element : listDot) {
out.lineToH(relative, Float.parseFloat(listDot[iii])); out.lineToH(relative, Float.parseFloat(element));
} }
break; break;
@ -123,16 +129,18 @@ public class Path extends Base {
relative = true; relative = true;
case 'Q': // Quadratic Bezier curve (absolute) case 'Q': // Quadratic Bezier curve (absolute)
if (listDot == null) { if (listDot == null) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot); LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
break; break;
} }
// 4 Elements ... // 4 Elements ...
if (listDot.length % 4 != 0) { if (listDot.length % 4 != 0) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length + " (must have 4 numbers)"); LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = "
+ listDot.length + " (must have 4 numbers)");
break; break;
} }
for (int iii = 0; iii < listDot.length; iii += 4) { for (int iii = 0; iii < listDot.length; iii += 4) {
out.bezierCurveTo(relative, new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])), out.bezierCurveTo(relative,
new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])),
new Vector2f(Float.parseFloat(listDot[iii + 2]), Float.parseFloat(listDot[iii + 3]))); new Vector2f(Float.parseFloat(listDot[iii + 2]), Float.parseFloat(listDot[iii + 3])));
} }
break; break;
@ -141,17 +149,19 @@ 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)
if (listDot == null) { if (listDot == null) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot); LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
break; break;
} }
// 4 Elements ... // 4 Elements ...
if (listDot.length % 2 != 0) { if (listDot.length % 2 != 0) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length + " (must have 2 numbers)"); LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = "
+ listDot.length + " (must have 2 numbers)");
break; break;
} }
// 2 Elements ... // 2 Elements ...
for (int iii = 0; iii < listDot.length; iii += 2) { for (int iii = 0; iii < listDot.length; iii += 2) {
out.bezierSmoothCurveTo(relative, new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1]))); out.bezierSmoothCurveTo(relative,
new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])));
} }
break; break;
@ -159,16 +169,18 @@ public class Path extends Base {
relative = true; relative = true;
case 'C': // curve to (absolute) case 'C': // curve to (absolute)
if (listDot == null) { if (listDot == null) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot); LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
break; break;
} }
// 6 Elements ... // 6 Elements ...
if (listDot.length % 6 != 0) { if (listDot.length % 6 != 0) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length + "(Must be a multiple of 6)"); LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = "
+ listDot.length + "(Must be a multiple of 6)");
break; break;
} }
for (int iii = 0; iii < listDot.length; iii += 6) { for (int iii = 0; iii < listDot.length; iii += 6) {
out.curveTo(relative, new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])), out.curveTo(relative,
new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])),
new Vector2f(Float.parseFloat(listDot[iii + 2]), Float.parseFloat(listDot[iii + 3])), new Vector2f(Float.parseFloat(listDot[iii + 2]), Float.parseFloat(listDot[iii + 3])),
new Vector2f(Float.parseFloat(listDot[iii + 4]), Float.parseFloat(listDot[iii + 5]))); new Vector2f(Float.parseFloat(listDot[iii + 4]), Float.parseFloat(listDot[iii + 5])));
} }
@ -178,16 +190,18 @@ public class Path extends Base {
relative = true; relative = true;
case 'S': // smooth curve to (absolute) case 'S': // smooth curve to (absolute)
if (listDot == null) { if (listDot == null) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot); LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
break; break;
} }
// 4 Elements ... // 4 Elements ...
if (listDot.length % 4 != 0) { if (listDot.length % 4 != 0) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length + "(Must be a multiple of 4)"); LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = "
+ listDot.length + "(Must be a multiple of 4)");
break; break;
} }
for (int iii = 0; iii < listDot.length; iii += 4) { for (int iii = 0; iii < listDot.length; iii += 4) {
out.smoothCurveTo(relative, new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])), out.smoothCurveTo(relative,
new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])),
new Vector2f(Float.parseFloat(listDot[iii + 2]), Float.parseFloat(listDot[iii + 3]))); new Vector2f(Float.parseFloat(listDot[iii + 2]), Float.parseFloat(listDot[iii + 3])));
} }
break; break;
@ -196,12 +210,13 @@ public class Path extends Base {
relative = true; relative = true;
case 'A': // elliptical Arc (absolute) case 'A': // elliptical Arc (absolute)
if (listDot == null) { if (listDot == null) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot); LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = " + listDot);
break; break;
} }
// 4 element ff,ff f i,i ff,ff Elements ... // 4 element ff,ff f i,i ff,ff Elements ...
if (listDot.length % 7 != 0) { if (listDot.length % 7 != 0) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length); LOGGER.warn("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) {
@ -213,7 +228,9 @@ public class Path extends Base {
if (Integer.parseInt(listDot[iii + 4]) == 0) { if (Integer.parseInt(listDot[iii + 4]) == 0) {
sweepFlag = false; sweepFlag = false;
} }
out.ellipticTo(relative, new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])), Float.parseFloat(listDot[iii + 2]), largeArcFlag, sweepFlag, out.ellipticTo(relative,
new Vector2f(Float.parseFloat(listDot[iii]), Float.parseFloat(listDot[iii + 1])),
Float.parseFloat(listDot[iii + 2]), largeArcFlag, sweepFlag,
new Vector2f(Float.parseFloat(listDot[iii + 5]), Float.parseFloat(listDot[iii + 6]))); new Vector2f(Float.parseFloat(listDot[iii + 5]), Float.parseFloat(listDot[iii + 6])));
} }
break; break;
@ -222,13 +239,14 @@ public class Path extends Base {
case 'Z': // closepath (absolute) case 'Z': // closepath (absolute)
// 0 Element ... // 0 Element ...
if (listDot != null) { if (listDot != null) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length); LOGGER.warn("the PATH command " + sss.cmd + " has not the good number of element = "
+ listDot.length);
break; break;
} }
out.close(relative); out.close(relative);
break; break;
default: default:
Log.error("Unknow error : '" + sss.cmd + "'"); LOGGER.error("Unknow error : '" + sss.cmd + "'");
} }
} }
return out; return out;
@ -237,23 +255,23 @@ 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 List<String> input, final int offset) { private static Command extractCmd(final List<String> input, final int offset) {
if (input.size() <= offset) { if (input.size() <= offset) {
// Log.warning("parse command : END"); // LOGGER.warn("parse command : END");
return null; return null;
} }
// Log.warning("parse command : (rest) " + offset); // LOGGER.warn("parse command : (rest) " + offset);
// for (int iii = offset; iii < input.size(); iii++) { // for (int iii = offset; iii < input.size(); iii++) {
// Log.warning(" -[" + iii + "] '" + input.get(iii) + "'"); // LOGGER.warn(" -[" + iii + "] '" + input.get(iii) + "'");
// } // }
if (input.get(offset).length() != 1) { if (input.get(offset).length() != 1) {
Log.error("Error in the SVG Path : '" + input.get(offset) + "' [" + Integer.toString(offset)); LOGGER.error("Error in the SVG Path : '" + input.get(offset) + "' [" + Integer.toString(offset));
return null; return null;
} }
final char cmd = input.get(offset).charAt(0); final char cmd = input.get(offset).charAt(0);
if (!((cmd <= 'Z' && cmd >= 'A') || (cmd <= 'z' && cmd >= 'a'))) { if (!((cmd <= 'Z' && cmd >= 'A') || (cmd <= 'z' && cmd >= 'a'))) {
Log.error("Error in the SVG Path : '" + cmd + "' [" + Integer.toString(offset)); LOGGER.error("Error in the SVG Path : '" + cmd + "' [" + Integer.toString(offset));
return null; return null;
} }
//Log.verbose("Find command : " + cmd); //LOGGER.trace("Find command : " + cmd);
if (input.size() == offset) { if (input.size() == offset) {
return new Command(cmd, offset + 1); return new Command(cmd, offset + 1);
} }
@ -300,7 +318,7 @@ public class Path extends Base {
isNumber = false; isNumber = false;
out.add(Character.toString(it)); out.add(Character.toString(it));
} else { } else {
Log.error("Can not parse path : '" + it + "'"); LOGGER.error("Can not parse path : '" + it + "'");
} }
} }
final String elements = tmpString.toString(); final String elements = tmpString.toString();
@ -328,12 +346,13 @@ public class Path extends Base {
@Override @Override
void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW esvg::Path"); LOGGER.trace(spacingDist(level) + "DRAW esvg::Path");
final Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans); final Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
PointList listPoints = new PointList(); PointList listPoints = new PointList();
listPoints = this.listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold()); listPoints = this.listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(),
myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx); //listPoints.applyMatrix(mtx);
final SegmentList listSegmentFill = new SegmentList(); final SegmentList listSegmentFill = new SegmentList();
final SegmentList listSegmentStroke = new SegmentList(); final SegmentList listSegmentStroke = new SegmentList();
@ -354,7 +373,8 @@ public class Path extends Base {
} }
// check if we need to display stroke: // check if we need to display stroke:
if (colorStroke != null) { if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit); listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap,
this.paint.lineJoin, this.paint.miterLimit);
colorStroke.setViewPort(listSegmentStroke.getViewPort()); colorStroke.setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx); listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
@ -370,8 +390,13 @@ public class Path extends Base {
} }
@Override @Override
void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) { void drawShapePoints(
Log.verbose(spacingDist(level) + "DRAW Shape esvg::Path"); final List<List<Vector2f>> out,
final int recurtionMax,
final float threshold,
final Matrix2x3f basicTrans,
final int level) {
LOGGER.trace(spacingDist(level) + "DRAW Shape esvg::Path");
final Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans); final Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
@ -400,7 +425,7 @@ public class Path extends Base {
final String elementXML1 = element.getAttribute("d", ""); final String elementXML1 = element.getAttribute("d", "");
if (elementXML1.length() == 0) { if (elementXML1.length() == 0) {
Log.warning("path: missing 'd' attribute or empty"); LOGGER.warn("path: missing 'd' attribute or empty");
return false; return false;
} }
this.listElement = Path.createPathModel(elementXML1); this.listElement = Path.createPathModel(elementXML1);

View File

@ -1,5 +1,8 @@
package org.atriasoft.esvg; package org.atriasoft.esvg;
import java.util.ArrayList;
import java.util.List;
import org.atriasoft.esvg.render.DynamicColor; import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.PathModel; import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.Point; import org.atriasoft.esvg.render.Point;
@ -10,11 +13,8 @@ import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
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.slf4j.Logger;
import java.util.ArrayList; import org.slf4j.LoggerFactory;
import java.util.List;
import org.atriasoft.esvg.internal.Log;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -23,6 +23,7 @@ import org.atriasoft.esvg.internal.Log;
*/ */
public class Polygon extends Base { public class Polygon extends Base {
static final Logger LOGGER = LoggerFactory.getLogger(Polygon.class);
private final List<Vector2f> listPoint = new ArrayList<>(); //!< 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) {
@ -30,7 +31,7 @@ public class Polygon extends Base {
} }
private PathModel createPath() { private PathModel createPath() {
PathModel out = new PathModel(); final PathModel out = new PathModel();
out.moveTo(false, this.listPoint.get(0)); out.moveTo(false, this.listPoint.get(0));
for (int iii = 1; iii < this.listPoint.size(); iii++) { for (int iii = 1; iii < this.listPoint.size(); iii++) {
out.lineTo(false, this.listPoint.get(iii)); out.lineTo(false, this.listPoint.get(iii));
@ -41,25 +42,26 @@ public class Polygon extends Base {
@Override @Override
public void display(final int spacing) { public void display(final int spacing) {
Log.debug(spacingDist(spacing) + "Polygon nbPoint=" + this.listPoint.size()); LOGGER.debug(spacingDist(spacing) + "Polygon nbPoint=" + this.listPoint.size());
} }
@Override @Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW esvg::Polygon"); LOGGER.trace(spacingDist(level) + "DRAW esvg::Polygon");
PathModel listElement = createPath(); final PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans); final Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
PointList listPoints = new PointList(); PointList listPoints = new PointList();
listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold()); listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(),
myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx); //listPoints.applyMatrix(mtx);
SegmentList listSegmentFill = new SegmentList(); final SegmentList listSegmentFill = new SegmentList();
SegmentList listSegmentStroke = new SegmentList(); final SegmentList listSegmentStroke = new SegmentList();
Weight tmpFill = new Weight(); final Weight tmpFill = new Weight();
Weight tmpStroke = new Weight(); final Weight tmpStroke = new Weight();
DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx); final DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx);
DynamicColor colorStroke = null; DynamicColor colorStroke = null;
if (this.paint.strokeWidth > 0.0f) { if (this.paint.strokeWidth > 0.0f) {
colorStroke = DynamicColor.createColor(this.paint.stroke, mtx); colorStroke = DynamicColor.createColor(this.paint.stroke, mtx);
@ -74,7 +76,8 @@ public class Polygon extends Base {
} }
// check if we need to display stroke: // check if we need to display stroke:
if (colorStroke != null) { if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit); listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap,
this.paint.lineJoin, this.paint.miterLimit);
colorStroke.setViewPort(listSegmentStroke.getViewPort()); colorStroke.setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx); listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
@ -87,16 +90,21 @@ public class Polygon extends Base {
} }
@Override @Override
public void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) { public void drawShapePoints(
Log.verbose(spacingDist(level) + "DRAW Shape esvg::Polygon"); final List<List<Vector2f>> out,
PathModel listElement = createPath(); final int recurtionMax,
Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans); final float threshold,
final Matrix2x3f basicTrans,
final int level) {
LOGGER.trace(spacingDist(level) + "DRAW Shape esvg::Polygon");
final PathModel listElement = createPath();
final Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
PointList listPoints; PointList listPoints;
listPoints = listElement.generateListPoints(level, recurtionMax, threshold); listPoints = listElement.generateListPoints(level, recurtionMax, threshold);
listPoints.applyMatrix(mtx); listPoints.applyMatrix(mtx);
for (List<Point> it : listPoints.data) { for (final List<Point> it : listPoints.data) {
List<Vector2f> listPoint = new ArrayList<>(); final List<Vector2f> listPoint = new ArrayList<>();
for (Point itDot : it) { for (final Point itDot : it) {
listPoint.add(itDot.pos); listPoint.add(itDot.pos);
} }
out.add(listPoint); out.add(listPoint);
@ -111,24 +119,24 @@ public class Polygon extends Base {
parseTransform(element); parseTransform(element);
parsePaintAttr(element); parsePaintAttr(element);
Log.verbose("parsed P1. trans: " + this.transformMatrix); LOGGER.trace("parsed P1. trans: " + this.transformMatrix);
// add the property of the parrent modifications ... // add the property of the parrent modifications ...
this.transformMatrix = this.transformMatrix.multiply(parentTrans); this.transformMatrix = this.transformMatrix.multiply(parentTrans);
Log.verbose("parsed P2. trans: " + this.transformMatrix); LOGGER.trace("parsed P2. trans: " + this.transformMatrix);
String sss1 = element.getAttribute("points", ""); final String sss1 = element.getAttribute("points", "");
if (sss1.length() == 0) { if (sss1.length() == 0) {
Log.error("(l "/*+element.Pos()*/ + ") polygon: missing points attribute"); LOGGER.error("(l "/*+element.Pos()*/ + ") polygon: missing points attribute");
return false; return false;
} }
sizeMax.value = Vector2f.ZERO; sizeMax.value = Vector2f.ZERO;
Log.verbose("Parse polyline : '" + sss1 + "'"); LOGGER.trace("Parse polyline : '" + sss1 + "'");
String[] elems = sss1.split(" "); final String[] elems = sss1.split(" ");
for (String elem : elems) { for (final String elem : elems) {
Vector2f pos = Vector2f.valueOf(elem); final Vector2f pos = Vector2f.valueOf(elem);
this.listPoint.add(pos); this.listPoint.add(pos);
sizeMax.value = Vector2f.max(sizeMax.value, pos); sizeMax.value = Vector2f.max(sizeMax.value, pos);
} }

View File

@ -1,5 +1,8 @@
package org.atriasoft.esvg; package org.atriasoft.esvg;
import java.util.ArrayList;
import java.util.List;
import org.atriasoft.esvg.render.DynamicColor; import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.PathModel; import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.Point; import org.atriasoft.esvg.render.Point;
@ -10,11 +13,8 @@ import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
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.slf4j.Logger;
import java.util.ArrayList; import org.slf4j.LoggerFactory;
import java.util.List;
import org.atriasoft.esvg.internal.Log;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -22,6 +22,7 @@ import org.atriasoft.esvg.internal.Log;
* @license MPL v2.0 (see license file) * @license MPL v2.0 (see license file)
*/ */
public class Polyline extends Base { public class Polyline extends Base {
static final Logger LOGGER = LoggerFactory.getLogger(Polyline.class);
private final List<Vector2f> listPoint = new ArrayList<>(); //!< list of all point of the polyline private final List<Vector2f> listPoint = new ArrayList<>(); //!< list of all point of the polyline
public Polyline(final PaintState parentPaintState) { public Polyline(final PaintState parentPaintState) {
@ -29,7 +30,7 @@ public class Polyline extends Base {
} }
private PathModel createPath() { private PathModel createPath() {
PathModel out = new PathModel(); final PathModel out = new PathModel();
out.clear(); out.clear();
out.moveTo(false, this.listPoint.get(0)); out.moveTo(false, this.listPoint.get(0));
for (int iii = 1; iii < this.listPoint.size(); iii++) { for (int iii = 1; iii < this.listPoint.size(); iii++) {
@ -41,25 +42,26 @@ public class Polyline extends Base {
@Override @Override
public void display(final int spacing) { public void display(final int spacing) {
Log.debug(spacingDist(spacing) + "Polyline nbPoint=" + this.listPoint.size()); LOGGER.debug(spacingDist(spacing) + "Polyline nbPoint=" + this.listPoint.size());
} }
@Override @Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW esvg::Polyline"); LOGGER.trace(spacingDist(level) + "DRAW esvg::Polyline");
PathModel listElement = createPath(); final PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans); final Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
PointList listPoints; PointList listPoints;
listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold()); listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(),
myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx); //listPoints.applyMatrix(mtx);
SegmentList listSegmentFill = new SegmentList(); final SegmentList listSegmentFill = new SegmentList();
SegmentList listSegmentStroke = new SegmentList(); final SegmentList listSegmentStroke = new SegmentList();
Weight tmpFill = new Weight(); final Weight tmpFill = new Weight();
Weight tmpStroke = new Weight(); final Weight tmpStroke = new Weight();
DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx); final DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx);
DynamicColor colorStroke = null; DynamicColor colorStroke = null;
if (this.paint.strokeWidth > 0.0f) { if (this.paint.strokeWidth > 0.0f) {
colorStroke = DynamicColor.createColor(this.paint.stroke, mtx); colorStroke = DynamicColor.createColor(this.paint.stroke, mtx);
@ -74,7 +76,8 @@ public class Polyline extends Base {
} }
// check if we need to display stroke: // check if we need to display stroke:
if (colorStroke != null) { if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit); listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap,
this.paint.lineJoin, this.paint.miterLimit);
colorStroke.setViewPort(listSegmentStroke.getViewPort()); colorStroke.setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx); listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
@ -87,16 +90,21 @@ public class Polyline extends Base {
} }
@Override @Override
public void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) { public void drawShapePoints(
Log.verbose(spacingDist(level) + "DRAW Shape esvg::Polyline"); final List<List<Vector2f>> out,
PathModel listElement = createPath(); final int recurtionMax,
Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans); final float threshold,
final Matrix2x3f basicTrans,
final int level) {
LOGGER.trace(spacingDist(level) + "DRAW Shape esvg::Polyline");
final PathModel listElement = createPath();
final Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
PointList listPoints; PointList listPoints;
listPoints = listElement.generateListPoints(level, recurtionMax, threshold); listPoints = listElement.generateListPoints(level, recurtionMax, threshold);
listPoints.applyMatrix(mtx); listPoints.applyMatrix(mtx);
for (List<Point> it : listPoints.data) { for (final List<Point> it : listPoints.data) {
List<Vector2f> listPoint = new ArrayList<>(); final List<Vector2f> listPoint = new ArrayList<>();
for (Point itDot : it) { for (final Point itDot : it) {
listPoint.add(itDot.pos); listPoint.add(itDot.pos);
} }
out.add(listPoint); out.add(listPoint);
@ -116,16 +124,16 @@ public class Polyline extends Base {
// add the property of the parrent modifications ... // add the property of the parrent modifications ...
this.transformMatrix = this.transformMatrix.multiply(parentTrans); this.transformMatrix = this.transformMatrix.multiply(parentTrans);
String sss1 = element.getAttribute("points", ""); final String sss1 = element.getAttribute("points", "");
if (sss1.length() == 0) { if (sss1.length() == 0) {
Log.error("polyline: missing points attribute"); LOGGER.error("polyline: missing points attribute");
return false; return false;
} }
sizeMax.value = Vector2f.ZERO; sizeMax.value = Vector2f.ZERO;
Log.verbose("Parse polyline : '" + sss1 + "'"); LOGGER.trace("Parse polyline : '" + sss1 + "'");
String[] elems = sss1.split(" "); final String[] elems = sss1.split(" ");
for (String elem : elems) { for (final String elem : elems) {
Vector2f pos = Vector2f.valueOf(elem); final Vector2f pos = Vector2f.valueOf(elem);
this.listPoint.add(pos); this.listPoint.add(pos);
sizeMax.value = Vector2f.max(sizeMax.value, pos); sizeMax.value = Vector2f.max(sizeMax.value, pos);
} }

View File

@ -3,7 +3,6 @@ package org.atriasoft.esvg;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.Color; import org.atriasoft.etk.Color;
import org.atriasoft.etk.Dimension1f; import org.atriasoft.etk.Dimension1f;
import org.atriasoft.etk.Dimension2f; import org.atriasoft.etk.Dimension2f;
@ -15,6 +14,8 @@ import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.etk.util.Pair; import org.atriasoft.etk.util.Pair;
import org.atriasoft.exml.model.XmlElement; import org.atriasoft.exml.model.XmlElement;
import org.atriasoft.exml.model.XmlNode; import org.atriasoft.exml.model.XmlNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -22,6 +23,7 @@ import org.atriasoft.exml.model.XmlNode;
* @license MPL v2.0 (see license file) * @license MPL v2.0 (see license file)
*/ */
public class RadialGradient extends Base { public class RadialGradient extends Base {
static final Logger LOGGER = LoggerFactory.getLogger(RadialGradient.class);
private Dimension2f center = new Dimension2f(new Vector2f(50, 50), Distance.POURCENT); //!< gradient position cx cy private Dimension2f center = new Dimension2f(new Vector2f(50, 50), Distance.POURCENT); //!< gradient position cx cy
private final List<Pair<Float, Color>> data = new ArrayList<>(); //!< incompatible with href private final List<Pair<Float, Color>> data = new ArrayList<>(); //!< incompatible with href
private Dimension2f focal = new Dimension2f(new Vector2f(50, 50), Distance.POURCENT); //!< gradient Focal fx fy private Dimension2f focal = new Dimension2f(new Vector2f(50, 50), Distance.POURCENT); //!< gradient Focal fx fy
@ -36,15 +38,16 @@ public class RadialGradient extends Base {
@Override @Override
public void display(final int spacing) { public void display(final int spacing) {
Log.debug(spacingDist(spacing) + "RadialGradient center=" + this.center + " focal=" + this.focal + " radius=" + this.radius); LOGGER.debug(spacingDist(spacing) + "RadialGradient center=" + this.center + " focal=" + this.focal + " radius="
for (Pair<Float, Color> it : this.data) { + this.radius);
Log.debug(spacingDist(spacing + 1) + "STOP: offset=" + it.first + " color=" + it.second); for (final Pair<Float, Color> it : this.data) {
LOGGER.debug(spacingDist(spacing + 1) + "STOP: offset=" + it.first + " color=" + it.second);
} }
} }
@Override @Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW esvg::RadialGradient"); LOGGER.trace(spacingDist(level) + "DRAW esvg::RadialGradient");
} }
public Dimension2f getCenter() { public Dimension2f getCenter() {
@ -56,18 +59,18 @@ public class RadialGradient extends Base {
return this.data; return this.data;
} }
if (document == null) { if (document == null) {
Log.error("Get null input for document"); LOGGER.error("Get null input for document");
return this.data; return this.data;
} }
Base base = document.getReference(this.href); final Base base = document.getReference(this.href);
if (base == null) { if (base == null) {
Log.error("Can not get base : '" + this.href + "'"); LOGGER.error("Can not get base : '" + this.href + "'");
return this.data; return this.data;
} }
if (base instanceof RadialGradient gradientR) { if (base instanceof final RadialGradient gradientR) {
return gradientR.getColors(document); return gradientR.getColors(document);
} }
if (base instanceof LinearGradient gradientL) { if (base instanceof final LinearGradient gradientL) {
return gradientL.getColors(document); return gradientL.getColors(document);
} }
return this.data; return this.data;
@ -118,7 +121,8 @@ public class RadialGradient extends Base {
} else { } else {
this.unit = GradientUnits.GRADIENT_UNITS_OBJECT_BOUNDING_BOX; this.unit = GradientUnits.GRADIENT_UNITS_OBJECT_BOUNDING_BOX;
if (contentX.length() != 0 && contentX != "objectBoundingBox") { if (contentX.length() != 0 && contentX != "objectBoundingBox") {
Log.error("Parsing error of 'gradientUnits' ==> not suported value: '" + contentX + "' not in : {userSpaceOnUse/objectBoundingBox} use objectBoundingBox"); LOGGER.error("Parsing error of 'gradientUnits' ==> not suported value: '" + contentX
+ "' not in : {userSpaceOnUse/objectBoundingBox} use objectBoundingBox");
} }
} }
contentX = element.getAttribute("spreadMethod", ""); contentX = element.getAttribute("spreadMethod", "");
@ -129,7 +133,8 @@ public class RadialGradient extends Base {
} else { } else {
this.spread = SpreadMethod.PAD; this.spread = SpreadMethod.PAD;
if (contentX.length() != 0 && !contentX.equals("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"); LOGGER.error("Parsing error of 'spreadMethod' ==> not suported value: '" + contentX
+ "' not in : {reflect/repeate/pad} use pad");
} }
} }
// note: xlink:href is incompatible with subNode "stop" // note: xlink:href is incompatible with subNode "stop"
@ -138,19 +143,20 @@ public class RadialGradient extends Base {
this.href = this.href.substring(1); this.href = this.href.substring(1);
} }
// parse all sub node : // parse all sub node :
for (XmlNode it : element.getNodes()) { for (final XmlNode it : element.getNodes()) {
if (it instanceof XmlElement child) { if (it instanceof final XmlElement child) {
if (child.getValue().equals("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", "");
if (content.length() != 0) { if (content.length() != 0) {
Pair<Float, Distance> tmp = parseLength2(content); final Pair<Float, Distance> tmp = parseLength2(content);
if (tmp.second == Distance.PIXEL) { if (tmp.second == Distance.PIXEL) {
// special case ==> all time % then no type define ==> % in [0.0 .. 1.0] // special case ==> all time % then no type define ==> % in [0.0 .. 1.0]
offset = tmp.first * 100.0f; offset = tmp.first * 100.0f;
} else if (tmp.second != Distance.POURCENT) { } else if (tmp.second != Distance.POURCENT) {
Log.error("offset : " + content + " res=" + tmp.first + "," + tmp.second + " Not support other than pourcent %"); LOGGER.error("offset : " + content + " res=" + tmp.first + "," + tmp.second
+ " Not support other than pourcent %");
} else { } else {
offset = tmp.first; offset = tmp.first;
} }
@ -158,24 +164,24 @@ public class RadialGradient extends Base {
content = child.getAttribute("stop-color", ""); content = child.getAttribute("stop-color", "");
if (content.length() != 0) { if (content.length() != 0) {
stopColor = parseColor(content).first; stopColor = parseColor(content).first;
Log.verbose(" color : \"" + content + "\" == > " + stopColor); LOGGER.trace(" color : \"" + content + "\" == > " + stopColor);
} }
content = child.getAttribute("stop-opacity", ""); content = child.getAttribute("stop-opacity", "");
if (content.length() != 0) { if (content.length() != 0) {
float opacity = parseLength(content); float opacity = parseLength(content);
opacity = FMath.avg(0.0f, opacity, 1.0f); opacity = FMath.avg(0.0f, opacity, 1.0f);
stopColor = stopColor.withA(opacity); stopColor = stopColor.withA(opacity);
Log.verbose(" opacity : '" + content + "' == > " + stopColor); LOGGER.trace(" opacity : '" + content + "' == > " + stopColor);
} }
this.data.add(new Pair<>(offset, stopColor)); this.data.add(new Pair<>(offset, stopColor));
} else { } else {
Log.error("node not suported : '" + child.getValue() + "' must be [stop]"); LOGGER.error("node not suported : '" + child.getValue() + "' must be [stop]");
} }
} }
} }
if (this.data.size() != 0) { if (this.data.size() != 0) {
if (!this.href.isEmpty()) { if (!this.href.isEmpty()) {
Log.error("node can not have an xlink:href element with sub node named: stop ==> removing href"); LOGGER.error("node can not have an xlink:href element with sub node named: stop ==> removing href");
this.href = ""; this.href = "";
} }
} }

View File

@ -1,20 +1,20 @@
package org.atriasoft.esvg; package org.atriasoft.esvg;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.exml.model.XmlElement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.DynamicColor; import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.PathModel; import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.Point; import org.atriasoft.esvg.render.Point;
import org.atriasoft.esvg.render.PointList; import org.atriasoft.esvg.render.PointList;
import org.atriasoft.esvg.render.SegmentList; import org.atriasoft.esvg.render.SegmentList;
import org.atriasoft.esvg.render.Weight; import org.atriasoft.esvg.render.Weight;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic; import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.exml.model.XmlElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -22,6 +22,7 @@ import org.atriasoft.etk.util.Dynamic;
* @license MPL v2.0 (see license file) * @license MPL v2.0 (see license file)
*/ */
public class Rectangle extends Base { public class Rectangle extends Base {
static final Logger LOGGER = LoggerFactory.getLogger(Rectangle.class);
private Vector2f position = Vector2f.ZERO; //!< position of the rectangle private Vector2f position = Vector2f.ZERO; //!< position of the rectangle
private Vector2f roundedCorner = Vector2f.ZERO; //!< property of the rounded corner private Vector2f roundedCorner = Vector2f.ZERO; //!< property of the rounded corner
private Vector2f size = Vector2f.ZERO; //!< size of the rectangle private Vector2f size = Vector2f.ZERO; //!< size of the rectangle
@ -36,7 +37,8 @@ public class Rectangle extends Base {
this.size = size; this.size = size;
} }
public Rectangle(final Vector2f position, final Vector2f size, final Vector2f roundedCorner, final PaintState parentPaintState) { public Rectangle(final Vector2f position, final Vector2f size, final Vector2f roundedCorner,
final PaintState parentPaintState) {
super(parentPaintState); super(parentPaintState);
this.position = position; this.position = position;
this.size = size; this.size = size;
@ -44,7 +46,7 @@ public class Rectangle extends Base {
} }
private PathModel createPath() { private PathModel createPath() {
PathModel out = new PathModel(); final PathModel out = new PathModel();
out.clear(); out.clear();
if (this.roundedCorner.x() == 0.0f || this.roundedCorner.y() == 0.0f) { if (this.roundedCorner.x() == 0.0f || this.roundedCorner.y() == 0.0f) {
out.moveTo(false, this.position); out.moveTo(false, this.position);
@ -55,16 +57,20 @@ public class Rectangle extends Base {
// Rounded rectangle // Rounded rectangle
out.moveTo(false, this.position.add(this.roundedCorner.x(), 0.0f)); out.moveTo(false, this.position.add(this.roundedCorner.x(), 0.0f));
out.lineToH(true, this.size.x() - this.roundedCorner.x() * 2.0f); out.lineToH(true, this.size.x() - this.roundedCorner.x() * 2.0f);
out.curveTo(true, new Vector2f(this.roundedCorner.x() * Base.kappa90, 0.0f), new Vector2f(this.roundedCorner.x(), this.roundedCorner.y() * (1.0f - Base.kappa90)), out.curveTo(true, new Vector2f(this.roundedCorner.x() * Base.kappa90, 0.0f),
new Vector2f(this.roundedCorner.x(), this.roundedCorner.y() * (1.0f - Base.kappa90)),
new Vector2f(this.roundedCorner.x(), this.roundedCorner.y())); new Vector2f(this.roundedCorner.x(), this.roundedCorner.y()));
out.lineToV(true, this.size.y() - this.roundedCorner.y() * 2.0f); out.lineToV(true, this.size.y() - this.roundedCorner.y() * 2.0f);
out.curveTo(true, new Vector2f(0.0f, this.roundedCorner.y() * Base.kappa90), new Vector2f(-this.roundedCorner.x() * (1.0f - Base.kappa90), this.roundedCorner.y()), out.curveTo(true, new Vector2f(0.0f, this.roundedCorner.y() * Base.kappa90),
new Vector2f(-this.roundedCorner.x() * (1.0f - Base.kappa90), this.roundedCorner.y()),
new Vector2f(-this.roundedCorner.x(), this.roundedCorner.y())); new Vector2f(-this.roundedCorner.x(), this.roundedCorner.y()));
out.lineToH(true, -(this.size.x() - this.roundedCorner.x() * 2.0f)); out.lineToH(true, -(this.size.x() - this.roundedCorner.x() * 2.0f));
out.curveTo(true, new Vector2f(-this.roundedCorner.x() * Base.kappa90, 0.0f), new Vector2f(-this.roundedCorner.x(), -this.roundedCorner.y() * (1.0f - Base.kappa90)), out.curveTo(true, new Vector2f(-this.roundedCorner.x() * Base.kappa90, 0.0f),
new Vector2f(-this.roundedCorner.x(), -this.roundedCorner.y() * (1.0f - Base.kappa90)),
new Vector2f(-this.roundedCorner.x(), -this.roundedCorner.y())); new Vector2f(-this.roundedCorner.x(), -this.roundedCorner.y()));
out.lineToV(true, -(this.size.y() - this.roundedCorner.y() * 2.0f)); out.lineToV(true, -(this.size.y() - this.roundedCorner.y() * 2.0f));
out.curveTo(true, new Vector2f(0.0f, -this.roundedCorner.y() * Base.kappa90), new Vector2f(this.roundedCorner.x() * (1.0f - Base.kappa90), -this.roundedCorner.y()), out.curveTo(true, new Vector2f(0.0f, -this.roundedCorner.y() * Base.kappa90),
new Vector2f(this.roundedCorner.x() * (1.0f - Base.kappa90), -this.roundedCorner.y()),
new Vector2f(this.roundedCorner.x(), -this.roundedCorner.y())); new Vector2f(this.roundedCorner.x(), -this.roundedCorner.y()));
} }
out.close(); out.close();
@ -73,25 +79,28 @@ public class Rectangle extends Base {
@Override @Override
public void display(final int spacing) { public void display(final int spacing) {
Log.debug(spacingDist(spacing) + "Rectangle : pos=" + this.position + " size=" + this.size + " corner=" + this.roundedCorner); LOGGER.debug(spacingDist(spacing) + "Rectangle : pos=" + this.position + " size=" + this.size + " corner="
+ this.roundedCorner);
} }
@Override @Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW esvg::Rectangle: fill=" + this.paint.fill.first + "/" + this.paint.fill.second + " stroke=" + this.paint.stroke.first + "/" + this.paint.stroke.second); LOGGER.trace(spacingDist(level) + "DRAW esvg::Rectangle: fill=" + this.paint.fill.first + "/"
PathModel listElement = createPath(); + this.paint.fill.second + " stroke=" + this.paint.stroke.first + "/" + this.paint.stroke.second);
final PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix; Matrix2x3f mtx = this.transformMatrix;
mtx = mtx.multiply(basicTrans); mtx = mtx.multiply(basicTrans);
listElement.display(2); listElement.display(2);
PointList listPoints = new PointList(); PointList listPoints = new PointList();
listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold()); listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(),
myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx); //listPoints.applyMatrix(mtx);
SegmentList listSegmentFill = new SegmentList(); final SegmentList listSegmentFill = new SegmentList();
SegmentList listSegmentStroke = new SegmentList(); final SegmentList listSegmentStroke = new SegmentList();
Weight tmpFill = new Weight(); final Weight tmpFill = new Weight();
Weight tmpStroke = new Weight(); final Weight tmpStroke = new Weight();
DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx); final DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx);
DynamicColor colorStroke = null; DynamicColor colorStroke = null;
if (this.paint.strokeWidth > 0.0f) { if (this.paint.strokeWidth > 0.0f) {
colorStroke = DynamicColor.createColor(this.paint.stroke, mtx); colorStroke = DynamicColor.createColor(this.paint.stroke, mtx);
@ -106,7 +115,8 @@ public class Rectangle extends Base {
} }
// check if we need to display stroke: // check if we need to display stroke:
if (colorStroke != null) { if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit); listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap,
this.paint.lineJoin, this.paint.miterLimit);
colorStroke.setViewPort(listSegmentStroke.getViewPort()); colorStroke.setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx); listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
@ -120,17 +130,22 @@ public class Rectangle extends Base {
} }
@Override @Override
public void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) { public void drawShapePoints(
Log.verbose(spacingDist(level) + "DRAW Shape esvg::Rectangle"); final List<List<Vector2f>> out,
PathModel listElement = createPath(); final int recurtionMax,
final float threshold,
final Matrix2x3f basicTrans,
final int level) {
LOGGER.trace(spacingDist(level) + "DRAW Shape esvg::Rectangle");
final PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix; Matrix2x3f mtx = this.transformMatrix;
mtx = mtx.multiply(basicTrans); mtx = mtx.multiply(basicTrans);
PointList listPoints; PointList listPoints;
listPoints = listElement.generateListPoints(level, recurtionMax, threshold); listPoints = listElement.generateListPoints(level, recurtionMax, threshold);
listPoints.applyMatrix(mtx); listPoints.applyMatrix(mtx);
for (List<Point> it : listPoints.data) { for (final List<Point> it : listPoints.data) {
List<Vector2f> listPoint = new ArrayList<>(); final List<Vector2f> listPoint = new ArrayList<>();
for (Point itDot : it) { for (final Point itDot : it) {
listPoint.add(itDot.pos); listPoint.add(itDot.pos);
} }
out.add(listPoint); out.add(listPoint);
@ -163,7 +178,8 @@ public class Rectangle extends Base {
if (content.length() != 0) { if (content.length() != 0) {
this.roundedCorner = this.roundedCorner.withY(parseLength(content)); this.roundedCorner = this.roundedCorner.withY(parseLength(content));
} }
sizeMax.value = new Vector2f(this.position.x() + this.size.x() + this.paint.strokeWidth, this.position.y() + this.size.y() + this.paint.strokeWidth); sizeMax.value = new Vector2f(this.position.x() + this.size.x() + this.paint.strokeWidth,
this.position.y() + this.size.y() + this.paint.strokeWidth);
return true; return true;
} }
} }

View File

@ -4,7 +4,6 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.font.Glyph; import org.atriasoft.esvg.font.Glyph;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.DynamicColor; import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.PathModel; import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.PointList; import org.atriasoft.esvg.render.PointList;
@ -16,6 +15,8 @@ import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.exml.model.XmlElement; import org.atriasoft.exml.model.XmlElement;
import org.atriasoft.exml.model.XmlNode; import org.atriasoft.exml.model.XmlNode;
import org.atriasoft.exml.model.XmlText; import org.atriasoft.exml.model.XmlText;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -23,6 +24,7 @@ import org.atriasoft.exml.model.XmlText;
* @license MPL v2.0 (see license file) * @license MPL v2.0 (see license file)
*/ */
public class Text extends Base { public class Text extends Base {
static final Logger LOGGER = LoggerFactory.getLogger(Text.class);
private float fontSize = 42; private float fontSize = 42;
private Vector2f position = Vector2f.ZERO; private Vector2f position = Vector2f.ZERO;
private final List<TextSpan> texts = new ArrayList<>(); private final List<TextSpan> texts = new ArrayList<>();
@ -31,71 +33,79 @@ public class Text extends Base {
super(parentPaintState); super(parentPaintState);
} }
public Text(final Vector2f position, final float fontSize, final String decoratedText, final PaintState parentPaintState) { public Text(final Vector2f position, final float fontSize, final String decoratedText,
final PaintState parentPaintState) {
super(parentPaintState); super(parentPaintState);
this.position = position; this.position = position;
this.fontSize = fontSize; this.fontSize = fontSize;
this.texts.add(new TextSpan(position, decoratedText, FontProperty.DEFAULT_FONT.withSize(fontSize), parentPaintState.clone())); this.texts.add(new TextSpan(position, decoratedText, FontProperty.DEFAULT_FONT.withSize(fontSize),
parentPaintState.clone()));
} }
public Text(final Vector2f position, final String fontName,final float fontSize, final String decoratedText, final PaintState parentPaintState) {
public Text(final Vector2f position, final String fontName, final float fontSize, final String decoratedText,
final PaintState parentPaintState) {
super(parentPaintState); super(parentPaintState);
this.position = position; this.position = position;
this.fontSize = fontSize; this.fontSize = fontSize;
this.texts.add(new TextSpan(position, decoratedText, FontProperty.DEFAULT_FONT.withSize(fontSize).withFontName(fontName), parentPaintState.clone())); this.texts.add(new TextSpan(position, decoratedText,
FontProperty.DEFAULT_FONT.withSize(fontSize).withFontName(fontName), parentPaintState.clone()));
} }
@Override @Override
public void display(final int spacing) { public void display(final int spacing) {
Log.verbose(spacingDist(spacing) + "Text : "); LOGGER.trace(spacingDist(spacing) + "Text : ");
for (TextSpan elem : this.texts) { for (final TextSpan elem : this.texts) {
Log.debug(spacingDist(spacing + 1) + elem.toString()); LOGGER.debug(spacingDist(spacing + 1) + elem.toString());
} }
} }
@Override @Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) { public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW esvg::Text ==> position = " + this.position); LOGGER.trace(spacingDist(level) + "DRAW esvg::Text ==> position = " + this.position);
if (this.texts.size() == 0) { if (this.texts.size() == 0) {
Log.verbose(spacingDist(level + 1) + "No text ..."); LOGGER.trace(spacingDist(level + 1) + "No text ...");
return; return;
} }
boolean withKerning = true; final boolean withKerning = true;
for (TextSpan elem : this.texts) { for (final TextSpan elem : this.texts) {
// get the font or a generic font of the program. // get the font or a generic font of the program.
EsvgFont font = FontCache.getFont(elem.fontState().fontName(), elem.fontState().bold(), elem.fontState().italic()); final EsvgFont font = FontCache.getFont(elem.fontState().fontName(), elem.fontState().bold(),
elem.fontState().italic());
if (font == null) { if (font == null) {
Log.error("Can not get the font :" + elem.fontState()); LOGGER.error("Can not get the font :" + elem.fontState());
return; return;
} }
int realSize = font.calculateFontRealHeight((int) elem.fontState().fontSize()); final int realSize = font.calculateFontRealHeight((int) elem.fontState().fontSize());
float scale = realSize / font.getUnitsPerEm(); final float scale = realSize / font.getUnitsPerEm();
//Log.warning("elem.fontState() =" + elem.fontState()); //LOGGER.warn("elem.fontState() =" + elem.fontState());
//Log.warning("scale =" + scale + " font size = " + elem.fontState().fontSize() + " realSize=" + realSize); //LOGGER.warn("scale =" + scale + " font size = " + elem.fontState().fontSize() + " realSize=" + realSize);
float offsetWriting = 0; float offsetWriting = 0;
int lastValue = 0; int lastValue = 0;
for (char uVal : elem.text().toCharArray()) { for (final char uVal : elem.text().toCharArray()) {
Log.verbose(spacingDist(level) + " elem.position = " + elem.position()); LOGGER.trace(
Glyph glyph = font.getGlyph(uVal); spacingDist(level) + " elem.position = " + elem.position());
final Glyph glyph = font.getGlyph(uVal);
if (glyph == null) { if (glyph == null) {
//lastValue = uVal; //lastValue = uVal;
continue; continue;
} }
if (withKerning) { if (withKerning) {
offsetWriting -= glyph.getKerning(lastValue) * scale; offsetWriting -= glyph.getKerning(lastValue) * scale;
Log.verbose(" ==> kerning offset = " + (glyph.getKerning(lastValue) * scale)); LOGGER.trace(" ==> kerning offset = " + (glyph.getKerning(lastValue) * scale));
lastValue = uVal; lastValue = uVal;
} }
float advenceXLocal = glyph.getHorizAdvX() * scale; final float advenceXLocal = glyph.getHorizAdvX() * scale;
//Matrix2x3f mtx = this.transformMatrix; //Matrix2x3f mtx = this.transformMatrix;
Vector2f tranlate = new Vector2f(elem.position().x() + offsetWriting, elem.position().y() - font.getDescent() * scale); final Vector2f tranlate = new Vector2f(elem.position().x() + offsetWriting,
Log.verbose("translate : " + tranlate); elem.position().y() - font.getDescent() * scale);
Matrix2x3f translateGlyph = Matrix2x3f.createTranslate(tranlate); LOGGER.trace("translate : " + tranlate);
Matrix2x3f scaleGlyph = Matrix2x3f.createScale(new Vector2f(scale, -scale)); final Matrix2x3f translateGlyph = Matrix2x3f.createTranslate(tranlate);
final Matrix2x3f scaleGlyph = Matrix2x3f.createScale(new Vector2f(scale, -scale));
//Matrix2x3f translateGlyph = Matrix2x3f.createTranslate(tranlate).multiply(Matrix2x3f.createScale(scale)); //Matrix2x3f translateGlyph = Matrix2x3f.createTranslate(tranlate).multiply(Matrix2x3f.createScale(scale));
//mtx = translateGlyph.multiply(this.transformMatrix); //mtx = translateGlyph.multiply(this.transformMatrix);
@ -112,17 +122,18 @@ public class Text extends Base {
//Matrix2x3f mtx = this.transformMatrix; //Matrix2x3f mtx = this.transformMatrix;
//mtx = mtx.multiply(basicTrans); //mtx = mtx.multiply(basicTrans);
PathModel listElement = glyph.getModel(); final PathModel listElement = glyph.getModel();
if (listElement != null) { if (listElement != null) {
//-------------------------------------------------- //--------------------------------------------------
// -- Generate Fill weight // -- Generate Fill weight
//-------------------------------------------------- //--------------------------------------------------
PointList listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold()); final PointList listPoints = listElement.generateListPoints(level,
DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx); myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold());
Weight tmpFill = new Weight(); final DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx);
final Weight tmpFill = new Weight();
// Check if we need to display background // Check if we need to display background
if (colorFill != null) { if (colorFill != null) {
SegmentList listSegmentFill = new SegmentList(); final SegmentList listSegmentFill = new SegmentList();
listSegmentFill.createSegmentList(listPoints); listSegmentFill.createSegmentList(listPoints);
colorFill.setViewPort(listSegmentFill.getViewPort()); colorFill.setViewPort(listSegmentFill.getViewPort());
listSegmentFill.applyMatrix(mtx); listSegmentFill.applyMatrix(mtx);
@ -135,27 +146,29 @@ public class Text extends Base {
// -- Generate Stroke weight // -- Generate Stroke weight
//-------------------------------------------------- //--------------------------------------------------
Weight tmpStroke = new Weight(); final Weight tmpStroke = new Weight();
DynamicColor colorStroke = null; DynamicColor colorStroke = null;
if (this.paint.strokeWidth > 0.0f) { if (this.paint.strokeWidth > 0.0f) {
colorStroke = DynamicColor.createColor(this.paint.stroke, mtx); colorStroke = DynamicColor.createColor(this.paint.stroke, mtx);
if (colorStroke == null) { if (colorStroke == null) {
Log.verbose("Color stroke is null: ..."); LOGGER.trace("Color stroke is null: ...");
} else { } else {
// check if we need to display stroke: // check if we need to display stroke:
SegmentList listSegmentStroke = new SegmentList(); final SegmentList listSegmentStroke = new SegmentList();
listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit); listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth,
this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit);
colorStroke.setViewPort(listSegmentStroke.getViewPort()); colorStroke.setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx); listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpStroke.generate(myRenderer.getSize(), myRenderer.getNumberSubScanLine(), listSegmentStroke); tmpStroke.generate(myRenderer.getSize(), myRenderer.getNumberSubScanLine(),
listSegmentStroke);
} }
} }
// add on images: // add on images:
myRenderer.print(tmpFill, colorFill, tmpStroke, colorStroke, this.paint.opacity); myRenderer.print(tmpFill, colorFill, tmpStroke, colorStroke, this.paint.opacity);
} }
offsetWriting += advenceXLocal; offsetWriting += advenceXLocal;
//Log.warning("offset X =" + offsetWriting + " + " + advenceXLocal + " " + uVal); //LOGGER.warn("offset X =" + offsetWriting + " + " + advenceXLocal + " " + uVal);
} }
} }
} }
@ -174,30 +187,30 @@ public class Text extends Base {
this.transformMatrix = this.transformMatrix.multiply(parentTrans); this.transformMatrix = this.transformMatrix.multiply(parentTrans);
boolean italic = false; boolean italic = false;
String fontStyle = element.getAttribute("font-style", "normal"); final String fontStyle = element.getAttribute("font-style", "normal");
if ("italic".equals(fontStyle)) { if ("italic".equals(fontStyle)) {
italic = true; italic = true;
} else if ("normal".equals(fontStyle)) { } else if ("normal".equals(fontStyle)) {
italic = false; italic = false;
} else { } else {
Log.error("can not parse font-style='" + fontStyle + "' support ['normal', 'italic']"); LOGGER.error("can not parse font-style='" + fontStyle + "' support ['normal', 'italic']");
} }
boolean bold = false; boolean bold = false;
String fontWeight = element.getAttribute("font-weight", "normal"); final String fontWeight = element.getAttribute("font-weight", "normal");
if ("bold".equals(fontWeight)) { if ("bold".equals(fontWeight)) {
bold = true; bold = true;
} else if ("normal".equals(fontWeight)) { } else if ("normal".equals(fontWeight)) {
bold = false; bold = false;
} else { } else {
Log.error("can not parse font-weight='" + fontWeight + "' support ['normal', 'bold']"); LOGGER.error("can not parse font-weight='" + fontWeight + "' support ['normal', 'bold']");
} }
String fontFamily = element.getAttribute("font-family", "FreeSans"); String fontFamily = element.getAttribute("font-family", "FreeSans");
if (fontStyle.contains(";")) { if (fontStyle.contains(";")) {
fontFamily = fontFamily.split(";")[0]; fontFamily = fontFamily.split(";")[0];
} }
Log.info("Get font family: '" + fontFamily + "'"); LOGGER.info("Get font family: '" + fontFamily + "'");
float fontSize = parseLength(element.getAttribute("font-size", "50")); final float fontSize = parseLength(element.getAttribute("font-size", "50"));
this.position = Vector2f.ZERO; this.position = Vector2f.ZERO;
String content = element.getAttribute("x", ""); String content = element.getAttribute("x", "");
@ -210,13 +223,14 @@ public class Text extends Base {
} }
// parse all subElement in the Text <TSPAN/> // parse all subElement in the Text <TSPAN/>
for (XmlNode elem : element.getNodes()) { for (final XmlNode elem : element.getNodes()) {
if (elem instanceof XmlElement elementSpan && "tspan".equals(elementSpan.getValue())) { if (elem instanceof final XmlElement elementSpan && "tspan".equals(elementSpan.getValue())) {
} else if (elem instanceof XmlText elementText) { } else if (elem instanceof final XmlText elementText) {
this.texts.add(new TextSpan(this.position, elementText.getValue(), new FontProperty(fontFamily, fontSize, bold, italic), this.paint.clone())); this.texts.add(new TextSpan(this.position, elementText.getValue(),
new FontProperty(fontFamily, fontSize, bold, italic), this.paint.clone()));
} else { } else {
Log.warning("not managed element : " + elem); LOGGER.warn("not managed element : " + elem);
} }
} }
@ -243,7 +257,7 @@ public class Text extends Base {
} }
if (withKerning) { if (withKerning) {
offsetWriting -= glyph.getKerning(lastValue) * scale; offsetWriting -= glyph.getKerning(lastValue) * scale;
Log.info(" ==> kerning offset = " + (glyph.getKerning(lastValue) * scale)); LOGGER.info(" ==> kerning offset = " + (glyph.getKerning(lastValue) * scale));
lastValue = uVal; lastValue = uVal;
} }
@ -269,17 +283,21 @@ record FontProperty(
float fontSize, float fontSize,
boolean bold, boolean bold,
boolean italic) { boolean italic) {
public static final FontProperty DEFAULT_FONT = new FontProperty("FreeSans", 15, false, false); public static final FontProperty DEFAULT_FONT = new FontProperty("FreeSans", 15, false, false);
public FontProperty withSize(final float fontSize) { public FontProperty withSize(final float fontSize) {
return new FontProperty(this.fontName, fontSize, this.bold, this.italic); return new FontProperty(this.fontName, fontSize, this.bold, this.italic);
} }
public FontProperty withFontName(final String fontName) { public FontProperty withFontName(final String fontName) {
return new FontProperty(fontName, this.fontSize, this.bold, this.italic); return new FontProperty(fontName, this.fontSize, this.bold, this.italic);
} }
public FontProperty withBold(final boolean bold) { public FontProperty withBold(final boolean bold) {
return new FontProperty(this.fontName, this.fontSize, bold, this.italic); return new FontProperty(this.fontName, this.fontSize, bold, this.italic);
} }
public FontProperty withSize(final boolean italic) { public FontProperty withSize(final boolean italic) {
return new FontProperty(this.fontName, this.fontSize, this.bold, italic); return new FontProperty(this.fontName, this.fontSize, this.bold, italic);
} }

View File

@ -5,12 +5,14 @@ import java.util.List;
import org.atriasoft.esvg.EsvgFont; import org.atriasoft.esvg.EsvgFont;
import org.atriasoft.esvg.Path; import org.atriasoft.esvg.Path;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.PathModel; import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.exml.model.XmlElement; import org.atriasoft.exml.model.XmlElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Glyph { public class Glyph {
private static final boolean LAZY_MODE = true; private static final boolean LAZY_MODE = true;
static final Logger LOGGER = LoggerFactory.getLogger(Glyph.class);
public static Glyph valueOf(final XmlElement element) { public static Glyph valueOf(final XmlElement element) {
return Glyph.valueOf(element, null); return Glyph.valueOf(element, null);
@ -20,45 +22,45 @@ public class Glyph {
if (element == null) { if (element == null) {
return null; return null;
} }
String name = element.getAttribute("glyph-name", null); final String name = element.getAttribute("glyph-name", null);
Log.verbose("get glyph name = '" + name + "'"); LOGGER.trace("get glyph name = '" + name + "'");
String tmpValue = element.getAttribute("horiz-adv-x", null); final String tmpValue = element.getAttribute("horiz-adv-x", null);
int horizAdvX = font == null ? 100 : font.getHorizAdvX(); int horizAdvX = font == null ? 100 : font.getHorizAdvX();
if (tmpValue != null && tmpValue.length() != 0) { if (tmpValue != null && tmpValue.length() != 0) {
horizAdvX = Integer.parseInt(tmpValue); horizAdvX = Integer.parseInt(tmpValue);
} }
Log.verbose(" horizAdvX= '" + horizAdvX + "'"); LOGGER.trace(" horizAdvX= '" + horizAdvX + "'");
String unicode = element.getAttribute("unicode", null); final String unicode = element.getAttribute("unicode", null);
Log.verbose(" unicode= '" + unicode + "'"); LOGGER.trace(" unicode= '" + unicode + "'");
if (unicode == null) { if (unicode == null) {
Log.debug("Not manage glyph : '" + name + "' (missing unicode value)"); LOGGER.debug("Not manage glyph : '" + name + "' (missing unicode value)");
return null; return null;
} }
String d = element.getAttribute("d", null); final String d = element.getAttribute("d", null);
Log.verbose(" d= '" + d + "'"); LOGGER.trace(" d= '" + d + "'");
int unicodeValue = 0; int unicodeValue = 0;
if (unicode.startsWith("&#x") && unicode.endsWith(";")) { if (unicode.startsWith("&#x") && unicode.endsWith(";")) {
String subElement = unicode.substring(3, unicode.length() - 1); final String subElement = unicode.substring(3, unicode.length() - 1);
if (subElement.indexOf("&") != -1) { if (subElement.indexOf("&") != -1) {
Log.debug("not supported glyph concatenarion" + name + " value='" + unicode + "'"); LOGGER.debug("not supported glyph concatenarion" + name + " value='" + unicode + "'");
return null; return null;
} }
unicodeValue = Integer.parseInt(subElement, 16); unicodeValue = Integer.parseInt(subElement, 16);
} else if (unicode.startsWith("&#") && unicode.endsWith(";")) { } else if (unicode.startsWith("&#") && unicode.endsWith(";")) {
String subElement = unicode.substring(2, unicode.length() - 1); final String subElement = unicode.substring(2, unicode.length() - 1);
if (subElement.indexOf("&") != -1) { if (subElement.indexOf("&") != -1) {
Log.debug("not supported glyph concatenarion" + name + " value='" + unicode + "'"); LOGGER.debug("not supported glyph concatenarion" + name + " value='" + unicode + "'");
return null; return null;
} }
unicodeValue = Integer.parseInt(subElement, 16); unicodeValue = Integer.parseInt(subElement, 16);
} else if (unicode.length() != 1) { } else if (unicode.length() != 1) {
Log.debug("not supported glyph concatenarion" + name + " value='" + unicode + "'"); LOGGER.debug("not supported glyph concatenarion" + name + " value='" + unicode + "'");
return null; return null;
} else { } else {
unicodeValue = unicode.charAt(0); unicodeValue = unicode.charAt(0);
} }
Log.verbose(" unicodeValue= '" + unicodeValue + "'"); LOGGER.trace(" unicodeValue= '" + unicodeValue + "'");
Glyph out = new Glyph(horizAdvX, d, name, unicode, unicodeValue); final Glyph out = new Glyph(horizAdvX, d, name, unicode, unicodeValue);
if (!Glyph.LAZY_MODE) { if (!Glyph.LAZY_MODE) {
// when not in lazy mode we force the parsing of the model, this permit to check the whole font... otherwise many font is really big > 8000 glyph, then it is a waste of time... // when not in lazy mode we force the parsing of the model, this permit to check the whole font... otherwise many font is really big > 8000 glyph, then it is a waste of time...
out.getModel(); out.getModel();
@ -75,7 +77,8 @@ public class Glyph {
private int unicodeValue; private int unicodeValue;
public Glyph(final int horizAdvX, final PathModel model, final String name, final String unicode, final int unicodeValue) { public Glyph(final int horizAdvX, final PathModel model, final String name, final String unicode,
final int unicodeValue) {
this.horizAdvX = horizAdvX; this.horizAdvX = horizAdvX;
this.model = model; this.model = model;
this.path = null; this.path = null;
@ -84,7 +87,8 @@ public class Glyph {
this.unicodeValue = unicodeValue; this.unicodeValue = unicodeValue;
} }
public Glyph(final int horizAdvX, final String path, final String name, final String unicode, final int unicodeValue) { public Glyph(final int horizAdvX, final String path, final String name, final String unicode,
final int unicodeValue) {
this.horizAdvX = horizAdvX; this.horizAdvX = horizAdvX;
this.model = null; this.model = null;
this.path = path; this.path = path;
@ -105,9 +109,10 @@ public class Glyph {
if (unicodeValue == 0) { if (unicodeValue == 0) {
return 0.0f; return 0.0f;
} }
for (Kerning elem : this.kernings) { for (final Kerning elem : this.kernings) {
if (elem.unicode() == unicodeValue) { if (elem.unicode() == unicodeValue) {
Log.verbose("Get kerning between : '" + (char) this.unicodeValue + "' and '" + (char) unicodeValue + "' => " + elem.offset()); LOGGER.trace("Get kerning between : '" + (char) this.unicodeValue + "' and '" + (char) unicodeValue
+ "' => " + elem.offset());
return elem.offset(); return elem.offset();
} }
} }

View File

@ -1,76 +0,0 @@
package org.atriasoft.esvg.internal;
import org.atriasoft.reggol.LogLevel;
import org.atriasoft.reggol.Logger;
public class Log {
private static final boolean FORCE_ALL = false;
private static final String LIB_NAME = "esvg";
private static final String LIB_NAME_DRAW = Logger.getDrawableName(Log.LIB_NAME);
private static final boolean PRINT_CRITICAL = Logger.getNeedPrint(Log.LIB_NAME, LogLevel.CRITICAL);
private static final boolean PRINT_DEBUG = Logger.getNeedPrint(Log.LIB_NAME, LogLevel.DEBUG);
private static final boolean PRINT_ERROR = Logger.getNeedPrint(Log.LIB_NAME, LogLevel.ERROR);
private static final boolean PRINT_INFO = Logger.getNeedPrint(Log.LIB_NAME, LogLevel.INFO);
private static final boolean PRINT_PRINT = Logger.getNeedPrint(Log.LIB_NAME, LogLevel.PRINT);
private static final boolean PRINT_TODO = Logger.getNeedPrint(Log.LIB_NAME, LogLevel.TODO);
private static final boolean PRINT_VERBOSE = Logger.getNeedPrint(Log.LIB_NAME, LogLevel.VERBOSE);
private static final boolean PRINT_WARNING = Logger.getNeedPrint(Log.LIB_NAME, LogLevel.WARNING);
public static void critical(final Exception e, final String data) {
e.printStackTrace();
if (PRINT_CRITICAL || FORCE_ALL) {
Logger.critical(LIB_NAME_DRAW, data + " : " + e.getMessage());
}
}
public static void critical(final String data, final Object... objects) {
if (PRINT_CRITICAL || FORCE_ALL) {
Logger.critical(LIB_NAME_DRAW, data, objects);
}
}
public static void debug(final String data, final Object... objects) {
if (PRINT_DEBUG || FORCE_ALL) {
Logger.debug(LIB_NAME_DRAW, data, objects);
}
}
public static void error(final String data, final Object... objects) {
if (PRINT_ERROR || FORCE_ALL) {
Logger.error(LIB_NAME_DRAW, data, objects);
}
}
public static void info(final String data, final Object... objects) {
if (PRINT_INFO || FORCE_ALL) {
Logger.info(LIB_NAME_DRAW, data, objects);
}
}
public static void print(final String data, final Object... objects) {
if (PRINT_PRINT || FORCE_ALL) {
Logger.print(LIB_NAME_DRAW, data, objects);
}
}
public static void todo(final String data, final Object... objects) {
if (PRINT_TODO || FORCE_ALL) {
Logger.todo(LIB_NAME_DRAW, data, objects);
}
}
public static void verbose(final String data, final Object... objects) {
if (PRINT_VERBOSE || FORCE_ALL) {
Logger.verbose(LIB_NAME_DRAW, data, objects);
}
}
public static void warning(final String data, final Object... objects) {
if (PRINT_WARNING || FORCE_ALL) {
Logger.warning(LIB_NAME_DRAW, data, objects);
}
}
private Log() {}
}

View File

@ -1,12 +1,13 @@
package org.atriasoft.esvg.render; package org.atriasoft.esvg.render;
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;
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.math.Vector2i;
import org.atriasoft.etk.util.Pair; import org.atriasoft.etk.util.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -15,13 +16,15 @@ import org.atriasoft.etk.util.Pair;
*/ */
public interface DynamicColor { public interface DynamicColor {
static final Logger LOGGER = LoggerFactory.getLogger(DynamicColor.class);
public static DynamicColor createColor(final Pair<Color, String> color, final Matrix2x3f mtx) { public static DynamicColor createColor(final Pair<Color, String> color, final Matrix2x3f mtx) {
// Check if need to create a color: // Check if need to create a color:
if (color.first.a() == 0 && color.second.isEmpty()) { if (color.first.a() == 0 && color.second.isEmpty()) {
return null; return null;
} }
if (color.second.isEmpty()) { if (color.second.isEmpty()) {
Log.verbose("use stroke color :" + color); LOGGER.trace("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

@ -8,7 +8,6 @@ import org.atriasoft.esvg.GradientUnits;
import org.atriasoft.esvg.LinearGradient; import org.atriasoft.esvg.LinearGradient;
import org.atriasoft.esvg.RadialGradient; import org.atriasoft.esvg.RadialGradient;
import org.atriasoft.esvg.SpreadMethod; import org.atriasoft.esvg.SpreadMethod;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.Color; import org.atriasoft.etk.Color;
import org.atriasoft.etk.Dimension1f; import org.atriasoft.etk.Dimension1f;
import org.atriasoft.etk.Dimension2f; import org.atriasoft.etk.Dimension2f;
@ -18,15 +17,24 @@ 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.math.Vector2i;
import org.atriasoft.etk.util.Pair; import org.atriasoft.etk.util.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DynamicColorSpecial implements DynamicColor { public class DynamicColorSpecial implements DynamicColor {
protected static Vector2f getIntersect(final Vector2f point1, final Vector2f vect1, final Vector2f point2, final Vector2f vect2) { static final Logger LOGGER = LoggerFactory.getLogger(DynamicColorSpecial.class);
float diviseur = vect1.x() * vect2.y() - vect1.y() * vect2.x();
protected static Vector2f getIntersect(
final Vector2f point1,
final Vector2f vect1,
final Vector2f point2,
final Vector2f vect2) {
final float diviseur = vect1.x() * vect2.y() - vect1.y() * vect2.x();
if (diviseur != 0.0f) { if (diviseur != 0.0f) {
float mmm = (vect1.x() * point1.y() - vect1.x() * point2.y() - vect1.y() * point1.x() + vect1.y() * point2.x()) / diviseur; final float mmm = (vect1.x() * point1.y() - vect1.x() * point2.y() - vect1.y() * point1.x()
+ vect1.y() * point2.x()) / diviseur;
return point2.add(vect2.multiply(mmm)); return point2.add(vect2.multiply(mmm));
} }
Log.error("Get divider / 0.0f"); LOGGER.error("Get divider / 0.0f");
return point2; return point2;
} }
@ -34,11 +42,18 @@ public class DynamicColorSpecial implements DynamicColor {
return DynamicColorSpecial.intersectLineToCircle(pos1, pos2, Vector2f.ZERO); return DynamicColorSpecial.intersectLineToCircle(pos1, pos2, Vector2f.ZERO);
} }
protected static Pair<Vector2f, Vector2f> intersectLineToCircle(final Vector2f pos1, final Vector2f pos2, final Vector2f center) { protected static Pair<Vector2f, Vector2f> intersectLineToCircle(
final Vector2f pos1,
final Vector2f pos2,
final Vector2f center) {
return DynamicColorSpecial.intersectLineToCircle(pos1, pos2, center, 1.0f); return DynamicColorSpecial.intersectLineToCircle(pos1, pos2, center, 1.0f);
} }
protected static Pair<Vector2f, Vector2f> intersectLineToCircle(final Vector2f pos1, final Vector2f pos2, final Vector2f center, final float radius) { protected static Pair<Vector2f, Vector2f> intersectLineToCircle(
final Vector2f pos1,
final Vector2f pos2,
final Vector2f center,
final float radius) {
Vector2f v1; Vector2f v1;
Vector2f v2; Vector2f v2;
//vector2D from point 1 to point 2 //vector2D from point 1 to point 2
@ -46,9 +61,9 @@ public class DynamicColorSpecial implements DynamicColor {
//vector2D from point 1 to the circle's center //vector2D from point 1 to the circle's center
v2 = center.less(pos1); v2 = center.less(pos1);
float dot = v1.dot(v2); final float dot = v1.dot(v2);
Vector2f proj1 = new Vector2f(((dot / (v1.length2())) * v1.x()), ((dot / (v1.length2())) * v1.y())); final Vector2f proj1 = new Vector2f(((dot / (v1.length2())) * v1.x()), ((dot / (v1.length2())) * v1.y()));
Vector2f midpt = pos1.add(proj1); final Vector2f midpt = pos1.add(proj1);
float distToCenter = midpt.less(center).length2(); float distToCenter = midpt.less(center).length2();
if (distToCenter > radius * radius) { if (distToCenter > radius * radius) {
@ -102,35 +117,35 @@ public class DynamicColorSpecial implements DynamicColor {
@Override @Override
public void generate(final EsvgDocument document) { public void generate(final EsvgDocument document) {
if (document == null) { if (document == null) {
Log.error("Get null input for document"); LOGGER.error("Get null input for document");
} }
Base base = document.getReference(this.colorName); final Base base = document.getReference(this.colorName);
if (base == null) { if (base == null) {
Log.error("Can not get base : '" + this.colorName + "'"); LOGGER.error("Can not get base : '" + this.colorName + "'");
return; return;
} }
// Now we can know if we use linear or radial gradient ... // Now we can know if we use linear or radial gradient ...
if (base instanceof LinearGradient gradient) { if (base instanceof final LinearGradient gradient) {
this.linear = true; this.linear = true;
Log.verbose("get for color linear:"); LOGGER.trace("get for color linear:");
gradient.display(2); gradient.display(2);
this.unit = gradient.unit; this.unit = gradient.unit;
this.spread = gradient.spread; this.spread = gradient.spread;
Log.verbose(" viewport = {" + this.viewPort.first + "," + this.viewPort.second + "}"); LOGGER.trace(" viewport = {" + this.viewPort.first + "," + this.viewPort.second + "}");
Vector2f size = this.viewPort.second.less(this.viewPort.first); final Vector2f size = this.viewPort.second.less(this.viewPort.first);
Dimension2f dimPos1 = gradient.getPosition1(); final Dimension2f dimPos1 = gradient.getPosition1();
this.pos1 = dimPos1.getPixel(size); this.pos1 = dimPos1.getPixel(size);
if (dimPos1.getType() == Distance.POURCENT) { if (dimPos1.getType() == Distance.POURCENT) {
this.pos1 = this.pos1.add(this.viewPort.first); this.pos1 = this.pos1.add(this.viewPort.first);
} }
Dimension2f dimPos2 = gradient.getPosition2(); final Dimension2f dimPos2 = gradient.getPosition2();
this.pos2 = dimPos2.getPixel(size); this.pos2 = dimPos2.getPixel(size);
if (dimPos2.getType() == Distance.POURCENT) { if (dimPos2.getType() == Distance.POURCENT) {
this.pos2 = this.pos2.add(this.viewPort.first); this.pos2 = this.pos2.add(this.viewPort.first);
} }
// in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object.. // in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object..
Vector2f delta = this.pos2.less(this.pos1); final Vector2f delta = this.pos2.less(this.pos1);
if (delta.x() < 0.0f) { if (delta.x() < 0.0f) {
this.axeX = new Vector2f(-1.0f, 0.0f); this.axeX = new Vector2f(-1.0f, 0.0f);
} else { } else {
@ -147,41 +162,41 @@ public class DynamicColorSpecial implements DynamicColor {
this.axeX = this.matrix.applyScaleRotation(this.axeX); this.axeX = this.matrix.applyScaleRotation(this.axeX);
this.axeY = this.matrix.applyScaleRotation(this.axeY); this.axeY = this.matrix.applyScaleRotation(this.axeY);
// in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object.. // in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object..
Vector2f intersecX = DynamicColorSpecial.getIntersect(this.pos1, this.axeX, this.pos2, this.axeY); final Vector2f intersecX = DynamicColorSpecial.getIntersect(this.pos1, this.axeX, this.pos2, this.axeY);
Vector2f intersecY = DynamicColorSpecial.getIntersect(this.pos1, this.axeY, this.pos2, this.axeX); final Vector2f intersecY = DynamicColorSpecial.getIntersect(this.pos1, this.axeY, this.pos2, this.axeX);
this.baseSize = new Vector2f((this.pos1.less(intersecX)).length(), (this.pos1.less(intersecY)).length()); this.baseSize = new Vector2f((this.pos1.less(intersecX)).length(), (this.pos1.less(intersecY)).length());
// get all the colors // get all the colors
this.data = gradient.getColors(document); this.data = gradient.getColors(document);
} else { } else {
this.linear = false; this.linear = false;
if (!(base instanceof RadialGradient gradient)) { if (!(base instanceof final RadialGradient gradient)) {
Log.error("Can not cast in a linear gradient: '" + this.colorName + "' ==> wrong type"); LOGGER.error("Can not cast in a linear gradient: '" + this.colorName + "' ==> wrong type");
return; return;
} }
Log.verbose("get for color Radial:"); LOGGER.trace("get for color Radial:");
gradient.display(2); gradient.display(2);
this.unit = gradient.unit; this.unit = gradient.unit;
this.spread = gradient.spread; this.spread = gradient.spread;
Log.verbose(" viewport = {" + this.viewPort.first + "," + this.viewPort.second + "}"); LOGGER.trace(" viewport = {" + this.viewPort.first + "," + this.viewPort.second + "}");
Vector2f size = this.viewPort.second.less(this.viewPort.first); final Vector2f size = this.viewPort.second.less(this.viewPort.first);
Dimension2f dimCenter = gradient.getCenter(); final Dimension2f dimCenter = gradient.getCenter();
Vector2f center = dimCenter.getPixel(size); Vector2f center = dimCenter.getPixel(size);
if (dimCenter.getType() == Distance.POURCENT) { if (dimCenter.getType() == Distance.POURCENT) {
center = center.add(this.viewPort.first); center = center.add(this.viewPort.first);
} }
Dimension2f dimFocal = gradient.getFocal(); final Dimension2f dimFocal = gradient.getFocal();
Vector2f focal = dimFocal.getPixel(size); Vector2f focal = dimFocal.getPixel(size);
if (dimFocal.getType() == Distance.POURCENT) { if (dimFocal.getType() == Distance.POURCENT) {
focal = focal.add(this.viewPort.first); focal = focal.add(this.viewPort.first);
} }
Dimension1f dimRadius = gradient.getRadius(); final Dimension1f dimRadius = gradient.getRadius();
// in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object).. // in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object)..
if (center == focal) { if (center == focal) {
this.centerIsFocal = true; this.centerIsFocal = true;
this.pos2 = new Vector2f(dimRadius.getPixel(size.x()), dimRadius.getPixel(size.y())); this.pos2 = new Vector2f(dimRadius.getPixel(size.x()), dimRadius.getPixel(size.y()));
this.pos2 = this.pos2.add(center); this.pos2 = this.pos2.add(center);
Vector2f delta = center.less(this.pos2); final Vector2f delta = center.less(this.pos2);
if (delta.x() < 0.0f) { if (delta.x() < 0.0f) {
this.axeX = new Vector2f(-1.0f, 0.0f); this.axeX = new Vector2f(-1.0f, 0.0f);
} else { } else {
@ -198,7 +213,8 @@ public class DynamicColorSpecial implements DynamicColor {
this.axeX = center.less(focal).safeNormalize(); this.axeX = center.less(focal).safeNormalize();
this.axeY = new Vector2f(this.axeX.y(), -this.axeX.x()); this.axeY = new Vector2f(this.axeX.y(), -this.axeX.x());
this.pos2 = this.axeX.multiply(dimRadius.getPixel(size.x())).add(this.axeY.multiply(dimRadius.getPixel(size.y()))); this.pos2 = this.axeX.multiply(dimRadius.getPixel(size.x()))
.add(this.axeY.multiply(dimRadius.getPixel(size.y())));
this.pos2 = this.pos2.add(center); this.pos2 = this.pos2.add(center);
this.pos1 = center; this.pos1 = center;
} }
@ -209,20 +225,21 @@ public class DynamicColorSpecial implements DynamicColor {
this.axeX = this.matrix.applyScaleRotation(this.axeX); this.axeX = this.matrix.applyScaleRotation(this.axeX);
this.axeY = this.matrix.applyScaleRotation(this.axeY); this.axeY = this.matrix.applyScaleRotation(this.axeY);
// in the basic version of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object.. // in the basic version of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object..
Vector2f intersecX = DynamicColorSpecial.getIntersect(this.pos1, this.axeX, this.pos2, this.axeY); final Vector2f intersecX = DynamicColorSpecial.getIntersect(this.pos1, this.axeX, this.pos2, this.axeY);
Vector2f intersecY = DynamicColorSpecial.getIntersect(this.pos1, this.axeY, this.pos2, this.axeX); final Vector2f intersecY = DynamicColorSpecial.getIntersect(this.pos1, this.axeY, this.pos2, this.axeX);
this.baseSize = new Vector2f((intersecX.less(this.pos1)).length(), (intersecY.less(this.pos1)).length()); this.baseSize = new Vector2f((intersecX.less(this.pos1)).length(), (intersecY.less(this.pos1)).length());
if (!this.centerIsFocal) { if (!this.centerIsFocal) {
this.focalLength = (center.less(this.matrix.multiply(focal))).length(); this.focalLength = (center.less(this.matrix.multiply(focal))).length();
if (this.focalLength >= this.baseSize.x()) { if (this.focalLength >= this.baseSize.x()) {
Log.debug("Change position of the Focal ... ==> set it inside the circle"); LOGGER.debug("Change position of the Focal ... ==> set it inside the circle");
this.focalLength = this.baseSize.x() * 0.999998f; this.focalLength = this.baseSize.x() * 0.999998f;
this.clipOut = true; this.clipOut = true;
} else { } else {
this.clipOut = false; this.clipOut = false;
} }
} }
Log.verbose("baseSize=" + this.baseSize + " this.pos1=" + this.pos1 + " dim=" + dimCenter + " this.focal=" + this.focal + " this.pos2=" + this.pos2 + " dim=" + dimRadius); LOGGER.trace("baseSize=" + this.baseSize + " this.pos1=" + this.pos1 + " dim=" + dimCenter
+ " this.focal=" + this.focal + " this.pos2=" + this.pos2 + " dim=" + dimRadius);
// get all the colors // get all the colors
this.data = gradient.getColors(document); this.data = gradient.getColors(document);
} }
@ -242,12 +259,13 @@ public class DynamicColorSpecial implements DynamicColor {
private Color getColorLinear(final Vector2i pos) { private Color getColorLinear(final Vector2i pos) {
float ratio = 0.0f; float ratio = 0.0f;
if (this.unit == GradientUnits.GRADIENT_UNITS_USER_SPACE_ON_USE) { if (this.unit == GradientUnits.GRADIENT_UNITS_USER_SPACE_ON_USE) {
Vector2f vectorBase = this.pos2.less(this.pos1); final Vector2f vectorBase = this.pos2.less(this.pos1);
Vector2f vectorOrtho = new Vector2f(vectorBase.y(), -vectorBase.x()); final Vector2f vectorOrtho = new Vector2f(vectorBase.y(), -vectorBase.x());
Vector2f intersec = DynamicColorSpecial.getIntersect(this.pos1, vectorBase, new Vector2f(pos.x(), pos.y()), vectorOrtho); final Vector2f intersec = DynamicColorSpecial.getIntersect(this.pos1, vectorBase,
float baseSize = vectorBase.length(); new Vector2f(pos.x(), pos.y()), vectorOrtho);
Vector2f vectorBaseDraw = intersec.less(this.pos1); final float baseSize = vectorBase.length();
float baseDraw = vectorBaseDraw.length(); final Vector2f vectorBaseDraw = intersec.less(this.pos1);
final float baseDraw = vectorBaseDraw.length();
ratio = baseDraw / baseSize; ratio = baseDraw / baseSize;
switch (this.spread) { switch (this.spread) {
default: default:
@ -275,10 +293,12 @@ public class DynamicColorSpecial implements DynamicColor {
} }
} else { } else {
// in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object.. // in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object..
Vector2f intersecX = DynamicColorSpecial.getIntersect(this.pos1, this.axeX, new Vector2f(pos.x(), pos.y()), this.axeY); final Vector2f intersecX = DynamicColorSpecial.getIntersect(this.pos1, this.axeX,
Vector2f intersecY = DynamicColorSpecial.getIntersect(this.pos1, this.axeY, new Vector2f(pos.x(), pos.y()), this.axeX); new Vector2f(pos.x(), pos.y()), this.axeY);
Vector2f vectorBaseDrawX = intersecX.less(this.pos1); final Vector2f intersecY = DynamicColorSpecial.getIntersect(this.pos1, this.axeY,
Vector2f vectorBaseDrawY = intersecY.less(this.pos1); new Vector2f(pos.x(), pos.y()), this.axeX);
final Vector2f vectorBaseDrawX = intersecX.less(this.pos1);
final Vector2f vectorBaseDrawY = intersecY.less(this.pos1);
float baseDrawX = vectorBaseDrawX.length(); float baseDrawX = vectorBaseDrawX.length();
float baseDrawY = vectorBaseDrawY.length(); float baseDrawY = vectorBaseDrawY.length();
if (this.axeX.dot(vectorBaseDrawX) < 0) { if (this.axeX.dot(vectorBaseDrawX) < 0) {
@ -289,7 +309,8 @@ public class DynamicColorSpecial implements DynamicColor {
} }
if (this.baseSize.x() + this.baseSize.y() != 0.0f) { if (this.baseSize.x() + this.baseSize.y() != 0.0f) {
if (this.baseSize.x() != 0.0f && this.baseSize.y() != 0.0f) { if (this.baseSize.x() != 0.0f && this.baseSize.y() != 0.0f) {
ratio = (baseDrawX * this.baseSize.y() + baseDrawY * this.baseSize.x()) / (this.baseSize.x() * this.baseSize.y() * 2.0f); ratio = (baseDrawX * this.baseSize.y() + baseDrawY * this.baseSize.x())
/ (this.baseSize.x() * this.baseSize.y() * 2.0f);
} else if (this.baseSize.x() != 0.0f) { } else if (this.baseSize.x() != 0.0f) {
ratio = baseDrawX / this.baseSize.x(); ratio = baseDrawX / this.baseSize.x();
} else { } else {
@ -328,10 +349,15 @@ public class DynamicColorSpecial implements DynamicColor {
if (ratio <= this.data.get(iii).first * 0.01f) { if (ratio <= this.data.get(iii).first * 0.01f) {
float localRatio = ratio - this.data.get(iii - 1).first * 0.01f; float localRatio = ratio - this.data.get(iii - 1).first * 0.01f;
localRatio = localRatio / ((this.data.get(iii).first - this.data.get(iii - 1).first) * 0.01f); localRatio = localRatio / ((this.data.get(iii).first - this.data.get(iii - 1).first) * 0.01f);
return new Color(this.data.get(iii - 1).second.r() * (1.0 - localRatio) + this.data.get(iii).second.r() * localRatio, return new Color(
this.data.get(iii - 1).second.g() * (1.0 - localRatio) + this.data.get(iii).second.g() * localRatio, this.data.get(iii - 1).second.r() * (1.0 - localRatio)
this.data.get(iii - 1).second.b() * (1.0 - localRatio) + this.data.get(iii).second.b() * localRatio, + this.data.get(iii).second.r() * localRatio,
this.data.get(iii - 1).second.a() * (1.0 - localRatio) + this.data.get(iii).second.a() * localRatio); this.data.get(iii - 1).second.g() * (1.0 - localRatio)
+ this.data.get(iii).second.g() * localRatio,
this.data.get(iii - 1).second.b() * (1.0 - localRatio)
+ this.data.get(iii).second.b() * localRatio,
this.data.get(iii - 1).second.a() * (1.0 - localRatio)
+ this.data.get(iii).second.a() * localRatio);
} }
} }
return Color.GREEN; return Color.GREEN;
@ -340,10 +366,12 @@ public class DynamicColorSpecial implements DynamicColor {
private Color getColorRadial(final Vector2i pos) { private Color getColorRadial(final Vector2i pos) {
float ratio = 0.0f; float ratio = 0.0f;
// in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object).. // in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object)..
Vector2f intersecX = DynamicColorSpecial.getIntersect(this.pos1, this.axeX, new Vector2f(pos.x(), pos.y()), this.axeY); final Vector2f intersecX = DynamicColorSpecial.getIntersect(this.pos1, this.axeX,
Vector2f intersecY = DynamicColorSpecial.getIntersect(this.pos1, this.axeY, new Vector2f(pos.x(), pos.y()), this.axeX); new Vector2f(pos.x(), pos.y()), this.axeY);
Vector2f vectorBaseDrawX = intersecX.less(this.pos1); final Vector2f intersecY = DynamicColorSpecial.getIntersect(this.pos1, this.axeY,
Vector2f vectorBaseDrawY = intersecY.less(this.pos1); new Vector2f(pos.x(), pos.y()), this.axeX);
final Vector2f vectorBaseDrawX = intersecX.less(this.pos1);
final Vector2f vectorBaseDrawY = intersecY.less(this.pos1);
float baseDrawX = vectorBaseDrawX.length(); float baseDrawX = vectorBaseDrawX.length();
float baseDrawY = vectorBaseDrawY.length(); float baseDrawY = vectorBaseDrawY.length();
// specal case when focal == center (this is faster ...) // specal case when focal == center (this is faster ...)
@ -376,15 +404,16 @@ public class DynamicColorSpecial implements DynamicColor {
if (this.clipOut && baseDrawX <= -1.0f) { if (this.clipOut && baseDrawX <= -1.0f) {
ratio = 1.0f; ratio = 1.0f;
} else { } else {
float tmpLength = -this.focalLength / this.baseSize.x(); final float tmpLength = -this.focalLength / this.baseSize.x();
Vector2f focalCenter = new Vector2f(tmpLength, 0.0f); final Vector2f focalCenter = new Vector2f(tmpLength, 0.0f);
Vector2f currentPoint = new Vector2f(baseDrawX, baseDrawY); final Vector2f currentPoint = new Vector2f(baseDrawX, baseDrawY);
if (focalCenter == currentPoint) { if (focalCenter == currentPoint) {
ratio = 0.0f; ratio = 0.0f;
} else { } else {
Pair<Vector2f, Vector2f> positions = DynamicColorSpecial.intersectLineToCircle(focalCenter, currentPoint); final Pair<Vector2f, Vector2f> positions = DynamicColorSpecial.intersectLineToCircle(focalCenter,
float lenghtBase = currentPoint.less(focalCenter).length(); currentPoint);
float lenghtBorder1 = positions.first.less(focalCenter).length(); final float lenghtBase = currentPoint.less(focalCenter).length();
final float lenghtBorder1 = positions.first.less(focalCenter).length();
//float lenghtBorder2 = positions.second.less(focalCenter).length(); //float lenghtBorder2 = positions.second.less(focalCenter).length();
ratio = lenghtBase / lenghtBorder1; ratio = lenghtBase / lenghtBorder1;
} }
@ -418,10 +447,15 @@ public class DynamicColorSpecial implements DynamicColor {
if (ratio <= this.data.get(iii).first * 0.01f) { if (ratio <= this.data.get(iii).first * 0.01f) {
float localRatio = ratio - this.data.get(iii - 1).first * 0.01f; float localRatio = ratio - this.data.get(iii - 1).first * 0.01f;
localRatio = localRatio / ((this.data.get(iii).first - this.data.get(iii - 1).first) * 0.01f); localRatio = localRatio / ((this.data.get(iii).first - this.data.get(iii - 1).first) * 0.01f);
return new Color(this.data.get(iii - 1).second.r() * (1.0 - localRatio) + this.data.get(iii).second.r() * localRatio, return new Color(
this.data.get(iii - 1).second.g() * (1.0 - localRatio) + this.data.get(iii).second.g() * localRatio, this.data.get(iii - 1).second.r() * (1.0 - localRatio)
this.data.get(iii - 1).second.b() * (1.0 - localRatio) + this.data.get(iii).second.b() * localRatio, + this.data.get(iii).second.r() * localRatio,
this.data.get(iii - 1).second.a() * (1.0 - localRatio) + this.data.get(iii).second.a() * localRatio); this.data.get(iii - 1).second.g() * (1.0 - localRatio)
+ this.data.get(iii).second.g() * localRatio,
this.data.get(iii - 1).second.b() * (1.0 - localRatio)
+ this.data.get(iii).second.b() * localRatio,
this.data.get(iii - 1).second.a() * (1.0 - localRatio)
+ this.data.get(iii).second.a() * localRatio);
} }
} }
return Color.GREEN; return Color.GREEN;

View File

@ -5,11 +5,12 @@ import java.util.List;
import org.atriasoft.esvg.CapMode; import org.atriasoft.esvg.CapMode;
import org.atriasoft.esvg.JoinMode; import org.atriasoft.esvg.JoinMode;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.math.FMath; import org.atriasoft.etk.math.FMath;
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.math.Vector2i;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -18,29 +19,41 @@ import org.atriasoft.etk.math.Vector2i;
*/ */
public class PathModel { public class PathModel {
private static void interpolateCubicBezier(final List<Point> listPoint, final int recurtionMax, final float threshold, final Vector2f pos1, final Vector2f pos2, final Vector2f pos3, static final Logger LOGGER = LoggerFactory.getLogger(PathModel.class);
final Vector2f pos4, final int level, final PointType type) {
private static void interpolateCubicBezier(
final List<Point> listPoint,
final int recurtionMax,
final float threshold,
final Vector2f pos1,
final Vector2f pos2,
final Vector2f pos3,
final Vector2f pos4,
final int level,
final PointType type) {
if (level > recurtionMax) { if (level > recurtionMax) {
return; return;
} }
Vector2f pos12 = pos1.add(pos2).multiply(0.5f); final Vector2f pos12 = pos1.add(pos2).multiply(0.5f);
Vector2f pos23 = pos2.add(pos3).multiply(0.5f); final Vector2f pos23 = pos2.add(pos3).multiply(0.5f);
Vector2f pos34 = pos3.add(pos4).multiply(0.5f); final Vector2f pos34 = pos3.add(pos4).multiply(0.5f);
Vector2f delta = pos4.less(pos1); final Vector2f delta = pos4.less(pos1);
float distance2 = Math.abs(((pos2.x() - pos4.x()) * delta.y() - (pos2.y() - pos4.y()) * delta.x())); final float distance2 = Math.abs(((pos2.x() - pos4.x()) * delta.y() - (pos2.y() - pos4.y()) * delta.x()));
float distance3 = Math.abs(((pos3.x() - pos4.x()) * delta.y() - (pos3.y() - pos4.y()) * delta.x())); final float distance3 = Math.abs(((pos3.x() - pos4.x()) * delta.y() - (pos3.y() - pos4.y()) * delta.x()));
if ((distance2 + distance3) * (distance2 + distance3) < threshold * delta.length2()) { if ((distance2 + distance3) * (distance2 + distance3) < threshold * delta.length2()) {
listPoint.add(new Point(pos4, type)); listPoint.add(new Point(pos4, type));
return; return;
} }
Vector2f pos123 = pos12.add(pos23).multiply(0.5f); final Vector2f pos123 = pos12.add(pos23).multiply(0.5f);
Vector2f pos234 = pos23.add(pos34).multiply(0.5f); final Vector2f pos234 = pos23.add(pos34).multiply(0.5f);
Vector2f pos1234 = pos123.add(pos234).multiply(0.5f); final Vector2f pos1234 = pos123.add(pos234).multiply(0.5f);
PathModel.interpolateCubicBezier(listPoint, recurtionMax, threshold, pos1, pos12, pos123, pos1234, level + 1, PointType.interpolation); PathModel.interpolateCubicBezier(listPoint, recurtionMax, threshold, pos1, pos12, pos123, pos1234, level + 1,
PathModel.interpolateCubicBezier(listPoint, recurtionMax, threshold, pos1234, pos234, pos34, pos4, level + 1, type); PointType.interpolation);
PathModel.interpolateCubicBezier(listPoint, recurtionMax, threshold, pos1234, pos234, pos34, pos4, level + 1,
type);
} }
/** /**
@ -95,20 +108,24 @@ public class PathModel {
} }
public void display(final int spacing) { public void display(final int spacing) {
Log.warning(PathModel.spacingDist(spacing) + "Path"); LOGGER.warn(PathModel.spacingDist(spacing) + "Path");
for (Element it : this.listElement) { for (final Element it : this.listElement) {
if (it == null) { if (it == null) {
continue; continue;
} }
Log.warning(PathModel.spacingDist(spacing + 1) + it); LOGGER.warn(PathModel.spacingDist(spacing + 1) + it);
} }
} }
public Weight drawFill(final Vector2i size, final Matrix2x3f basicTrans, final int level, final RenderingConfig config) { public Weight drawFill(
final Vector2i size,
final Matrix2x3f basicTrans,
final int level,
final RenderingConfig config) {
PointList listPoints = new PointList(); PointList listPoints = new PointList();
listPoints = generateListPoints(level, config.recurtionMax(), config.interpolationThreshold()); listPoints = generateListPoints(level, config.recurtionMax(), config.interpolationThreshold());
SegmentList listSegment = new SegmentList(); final SegmentList listSegment = new SegmentList();
Weight weight = new Weight(); final Weight weight = new Weight();
// Check if we need to display background // Check if we need to display background
listSegment.createSegmentList(listPoints); listSegment.createSegmentList(listPoints);
listSegment.applyMatrix(basicTrans); listSegment.applyMatrix(basicTrans);
@ -117,11 +134,16 @@ public class PathModel {
return weight; return weight;
} }
public Weight drawStroke(final Vector2i size, final Matrix2x3f basicTrans, final int level, final float strokeWidth, final RenderingConfig config) { public Weight drawStroke(
final Vector2i size,
final Matrix2x3f basicTrans,
final int level,
final float strokeWidth,
final RenderingConfig config) {
PointList listPoints = new PointList(); PointList listPoints = new PointList();
listPoints = generateListPoints(level, config.recurtionMax(), config.interpolationThreshold()); listPoints = generateListPoints(level, config.recurtionMax(), config.interpolationThreshold());
SegmentList listSegment = new SegmentList(); final SegmentList listSegment = new SegmentList();
Weight weight = new Weight(); final Weight weight = new Weight();
// Check if we need to display background // Check if we need to display background
listSegment.createSegmentListStroke(listPoints, strokeWidth, CapMode.BUTT, JoinMode.MITER, 4.0f); listSegment.createSegmentListStroke(listPoints, strokeWidth, CapMode.BUTT, JoinMode.MITER, 4.0f);
listSegment.applyMatrix(basicTrans); listSegment.applyMatrix(basicTrans);
@ -130,7 +152,13 @@ public class PathModel {
return weight; return weight;
} }
public void ellipticTo(final boolean relative, final Vector2f radius, final float angle, final boolean largeArcFlag, final boolean sweepFlag, final Vector2f pos) { public void ellipticTo(
final boolean relative,
final Vector2f radius,
final float angle,
final boolean largeArcFlag,
final boolean sweepFlag,
final Vector2f pos) {
this.listElement.add(new ElementElliptic(relative, radius, angle, largeArcFlag, sweepFlag, pos)); this.listElement.add(new ElementElliptic(relative, radius, angle, largeArcFlag, sweepFlag, pos));
} }
@ -143,22 +171,23 @@ public class PathModel {
} }
public PointList generateListPoints(final int level, final int recurtionMax, final float threshold) { public PointList generateListPoints(final int level, final int recurtionMax, final float threshold) {
Log.verbose(PathModel.spacingDist(level) + "Generate List Points ... from a path"); LOGGER.trace(PathModel.spacingDist(level) + "Generate List Points ... from a path");
PointList out = new PointList(); final PointList out = new PointList();
List<Point> tmpListPoint = new ArrayList<>(); List<Point> tmpListPoint = new ArrayList<>();
Vector2f lastPosition = Vector2f.ZERO; Vector2f lastPosition = Vector2f.ZERO;
Vector2f lastAngle = Vector2f.ZERO; Vector2f lastAngle = Vector2f.ZERO;
// Foreach element, we move in the path: // Foreach element, we move in the path:
for (Element it : this.listElement) { for (final Element it : this.listElement) {
if (it == null) { if (it == null) {
continue; continue;
} }
Log.verbose(PathModel.spacingDist(level + 1) + " Draw : " + it.toString()); LOGGER.trace(PathModel.spacingDist(level + 1) + " Draw : " + it.toString());
switch (it.getType()) { switch (it.getType()) {
case STOP: case STOP:
if (tmpListPoint.size() != 0) { if (tmpListPoint.size() != 0) {
if (tmpListPoint.size() == 0) { if (tmpListPoint.size() == 0) {
Log.warning(PathModel.spacingDist(level + 1) + " Request path stop of not starting path ..."); LOGGER.warn(
PathModel.spacingDist(level + 1) + " Request path stop of not starting path ...");
} else { } else {
tmpListPoint.get(tmpListPoint.size() - 1).setEndPath(); tmpListPoint.get(tmpListPoint.size() - 1).setEndPath();
out.addList(tmpListPoint); out.addList(tmpListPoint);
@ -171,14 +200,17 @@ public class PathModel {
case CLOSE: case CLOSE:
if (tmpListPoint.size() != 0) { if (tmpListPoint.size() != 0) {
if (tmpListPoint.size() == 0) { if (tmpListPoint.size() == 0) {
Log.warning(PathModel.spacingDist(level + 1) + " Request path close of not starting path ..."); LOGGER.warn(
PathModel.spacingDist(level + 1) + " Request path close of not starting path ...");
} else { } else {
// find the previous tart of the path ... // find the previous tart of the path ...
tmpListPoint.get(0).type = PointType.join; tmpListPoint.get(0).type = PointType.join;
// 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(); final 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) {
Log.verbose(" Remove point Z property : " + tmpListPoint.get(tmpListPoint.size() - 1).pos + " with delta=" + delta); LOGGER.trace(" Remove point Z property : "
+ tmpListPoint.get(tmpListPoint.size() - 1).pos + " with delta=" + delta);
tmpListPoint.remove(tmpListPoint.size() - 1); tmpListPoint.remove(tmpListPoint.size() - 1);
} }
out.addList(tmpListPoint); out.addList(tmpListPoint);
@ -244,14 +276,15 @@ public class PathModel {
if (tmpListPoint.size() == 0) { if (tmpListPoint.size() == 0) {
tmpListPoint.add(new Point(lastPosition, PointType.join)); tmpListPoint.add(new Point(lastPosition, PointType.join));
} { } {
Vector2f lastPosStore = lastPosition; final Vector2f lastPosStore = lastPosition;
if (!it.getRelative()) { if (!it.getRelative()) {
lastPosition = Vector2f.ZERO; lastPosition = Vector2f.ZERO;
} }
Vector2f pos1 = lastPosition.add(it.getPos1()); final Vector2f pos1 = lastPosition.add(it.getPos1());
Vector2f pos2 = lastPosition.add(it.getPos2()); final Vector2f pos2 = lastPosition.add(it.getPos2());
Vector2f pos = lastPosition.add(it.getPos()); final Vector2f pos = lastPosition.add(it.getPos());
PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, lastPosStore, pos1, pos2, pos, 0, PointType.join); PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, lastPosStore, pos1, pos2,
pos, 0, PointType.join);
lastPosition = pos; lastPosition = pos;
lastAngle = pos2; lastAngle = pos2;
} }
@ -261,15 +294,16 @@ public class PathModel {
if (tmpListPoint.size() == 0) { if (tmpListPoint.size() == 0) {
tmpListPoint.add(new Point(lastPosition, PointType.join)); tmpListPoint.add(new Point(lastPosition, PointType.join));
} { } {
Vector2f lastPosStore = lastPosition; final Vector2f lastPosStore = lastPosition;
if (!it.getRelative()) { if (!it.getRelative()) {
lastPosition = Vector2f.ZERO; lastPosition = Vector2f.ZERO;
} }
Vector2f pos2 = lastPosition.add(it.getPos2()); final Vector2f pos2 = lastPosition.add(it.getPos2());
Vector2f pos = lastPosition.add(it.getPos()); final Vector2f pos = lastPosition.add(it.getPos());
// generate Pos 1 // generate Pos 1
Vector2f pos1 = lastPosStore.multiply(2.0f).less(lastAngle); final Vector2f pos1 = lastPosStore.multiply(2.0f).less(lastAngle);
PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, lastPosStore, pos1, pos2, pos, 0, PointType.join); PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, lastPosStore, pos1, pos2,
pos, 0, PointType.join);
lastPosition = pos; lastPosition = pos;
lastAngle = pos2; lastAngle = pos2;
} }
@ -279,16 +313,17 @@ public class PathModel {
if (tmpListPoint.size() == 0) { if (tmpListPoint.size() == 0) {
tmpListPoint.add(new Point(lastPosition, PointType.join)); tmpListPoint.add(new Point(lastPosition, PointType.join));
} { } {
Vector2f lastPosStore = lastPosition; final Vector2f lastPosStore = lastPosition;
if (!it.getRelative()) { if (!it.getRelative()) {
lastPosition = Vector2f.ZERO; lastPosition = Vector2f.ZERO;
} }
Vector2f pos = lastPosition.add(it.getPos()); final Vector2f pos = lastPosition.add(it.getPos());
Vector2f tmp1 = lastPosition.add(it.getPos1()); final Vector2f tmp1 = lastPosition.add(it.getPos1());
// generate pos1 and pos2 // generate pos1 and pos2
Vector2f pos1 = lastPosStore.add(tmp1.less(lastPosStore).multiply(0.666666666f)); final Vector2f pos1 = lastPosStore.add(tmp1.less(lastPosStore).multiply(0.666666666f));
Vector2f pos2 = pos.add(tmp1.less(pos).multiply(0.666666666f)); final Vector2f pos2 = pos.add(tmp1.less(pos).multiply(0.666666666f));
PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, lastPosStore, pos1, pos2, pos, 0, PointType.join); PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, lastPosStore, pos1, pos2,
pos, 0, PointType.join);
lastPosition = pos; lastPosition = pos;
lastAngle = tmp1; lastAngle = tmp1;
} }
@ -298,16 +333,17 @@ public class PathModel {
if (tmpListPoint.size() == 0) { if (tmpListPoint.size() == 0) {
tmpListPoint.add(new Point(lastPosition, PointType.join)); tmpListPoint.add(new Point(lastPosition, PointType.join));
} { } {
Vector2f lastPosStore = lastPosition; final Vector2f lastPosStore = lastPosition;
if (!it.getRelative()) { if (!it.getRelative()) {
lastPosition = Vector2f.ZERO; lastPosition = Vector2f.ZERO;
} }
Vector2f pos = lastPosition.add(it.getPos()); final Vector2f pos = lastPosition.add(it.getPos());
Vector2f tmp1 = lastPosStore.multiply(2.0f).less(lastAngle); final Vector2f tmp1 = lastPosStore.multiply(2.0f).less(lastAngle);
// generate pos1 and pos2 // generate pos1 and pos2
Vector2f pos1 = lastPosStore.add(tmp1.less(lastPosStore).multiply(0.666666666f)); final Vector2f pos1 = lastPosStore.add(tmp1.less(lastPosStore).multiply(0.666666666f));
Vector2f pos2 = pos.add(tmp1.less(pos).multiply(0.66666666f)); final Vector2f pos2 = pos.add(tmp1.less(pos).multiply(0.66666666f));
PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, lastPosStore, pos1, pos2, pos, 0, PointType.join); PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, lastPosStore, pos1, pos2,
pos, 0, PointType.join);
lastPosition = pos; lastPosition = pos;
lastAngle = tmp1; lastAngle = tmp1;
} }
@ -317,25 +353,28 @@ public class PathModel {
if (tmpListPoint.size() == 0) { if (tmpListPoint.size() == 0) {
tmpListPoint.add(new Point(lastPosition, PointType.join)); tmpListPoint.add(new Point(lastPosition, PointType.join));
} { } {
ElementElliptic tmpIt = (ElementElliptic) it; final ElementElliptic tmpIt = (ElementElliptic) it;
Log.todo(PathModel.spacingDist(level + 1) + " Elliptic arc: radius=" + tmpIt.getPos1()); LOGGER.info(
Log.todo(PathModel.spacingDist(level + 1) + " angle=" + tmpIt.angle); "TODO:" + PathModel.spacingDist(level + 1) + " Elliptic arc: radius=" + tmpIt.getPos1());
Log.todo(PathModel.spacingDist(level + 1) + " this.largeArcFlag=" + tmpIt.largeArcFlag); LOGGER.info("TODO:" + PathModel.spacingDist(level + 1) + " angle=" + tmpIt.angle);
Log.todo(PathModel.spacingDist(level + 1) + " this.sweepFlag=" + tmpIt.sweepFlag); LOGGER.info("TODO:" + PathModel.spacingDist(level + 1) + " this.largeArcFlag="
+ tmpIt.largeArcFlag);
LOGGER.info("TODO:" + PathModel.spacingDist(level + 1) + " this.sweepFlag="
+ tmpIt.sweepFlag);
Vector2f lastPosStore = lastPosition; final Vector2f lastPosStore = lastPosition;
if (!it.getRelative()) { if (!it.getRelative()) {
lastPosition = Vector2f.ZERO; lastPosition = Vector2f.ZERO;
} }
Vector2f pos = lastPosition.add(it.getPos()); final Vector2f pos = lastPosition.add(it.getPos());
float rotationX = tmpIt.angle * ((float) Math.PI / 180.0f); final float rotationX = tmpIt.angle * ((float) Math.PI / 180.0f);
Vector2f radius = tmpIt.getPos1(); Vector2f radius = tmpIt.getPos1();
//this.debugInformation.addSegment(lastPosStore, pos); //this.debugInformation.addSegment(lastPosStore, pos);
Vector2f delta = lastPosStore.less(pos); Vector2f delta = lastPosStore.less(pos);
float ddd = delta.length(); float ddd = delta.length();
if (ddd < 1e-6f || radius.x() < 1e-6f || radius.y() < 1e-6f) { if (ddd < 1e-6f || radius.x() < 1e-6f || radius.y() < 1e-6f) {
Log.warning("Degenerate arc in Line"); LOGGER.warn("Degenerate arc in Line");
if (tmpListPoint.size() == 0) { if (tmpListPoint.size() == 0) {
tmpListPoint.add(new Point(lastPosition, PointType.join)); tmpListPoint.add(new Point(lastPosition, PointType.join));
} }
@ -345,18 +384,21 @@ public class PathModel {
// http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
// procedure describe here : http://www.w3.org/TR/SVG11/implnote.html#ArcConversionCenterToEndpoint // procedure describe here : http://www.w3.org/TR/SVG11/implnote.html#ArcConversionCenterToEndpoint
// Compute delta' // Compute delta'
Matrix2x3f matrixRotationCenter = Matrix2x3f.createRotate(-rotationX); final Matrix2x3f matrixRotationCenter = Matrix2x3f.createRotate(-rotationX);
Vector2f deltaPrim = matrixRotationCenter.multiply(delta.multiply(0.5f)); final Vector2f deltaPrim = matrixRotationCenter.multiply(delta.multiply(0.5f));
ddd = (deltaPrim.x() * deltaPrim.x()) / (radius.x() * radius.x()) + (deltaPrim.y() * deltaPrim.y()) / (radius.y() * radius.y()); ddd = (deltaPrim.x() * deltaPrim.x()) / (radius.x() * radius.x())
+ (deltaPrim.y() * deltaPrim.y()) / (radius.y() * radius.y());
if (ddd > 1.0f) { if (ddd > 1.0f) {
ddd = (float) Math.sqrt(ddd); ddd = (float) Math.sqrt(ddd);
radius = radius.multiply(ddd); radius = radius.multiply(ddd);
} }
// Compute center' // Compute center'
float sss = 0.0f; float sss = 0.0f;
float ssa = radius.x() * radius.x() * radius.y() * radius.y() - radius.x() * radius.x() * deltaPrim.y() * deltaPrim.y() float ssa = radius.x() * radius.x() * radius.y() * radius.y()
- radius.x() * radius.x() * deltaPrim.y() * deltaPrim.y()
- radius.y() * radius.y() * deltaPrim.x() * deltaPrim.x(); - radius.y() * radius.y() * deltaPrim.x() * deltaPrim.x();
float ssb = radius.x() * radius.x() * deltaPrim.y() * deltaPrim.y() + radius.y() * radius.y() * deltaPrim.x() * deltaPrim.x(); final float ssb = radius.x() * radius.x() * deltaPrim.y() * deltaPrim.y()
+ radius.y() * radius.y() * deltaPrim.x() * deltaPrim.x();
if (ssa < 0.0f) { if (ssa < 0.0f) {
ssa = 0.0f; ssa = 0.0f;
} }
@ -366,19 +408,21 @@ public class PathModel {
if (tmpIt.largeArcFlag == tmpIt.sweepFlag) { if (tmpIt.largeArcFlag == tmpIt.sweepFlag) {
sss *= -1.0f; sss *= -1.0f;
} }
Vector2f centerPrime = new Vector2f(sss * radius.x() * deltaPrim.y() / radius.y(), sss * -radius.y() * deltaPrim.x() / radius.x()); final Vector2f centerPrime = new Vector2f(sss * radius.x() * deltaPrim.y() / radius.y(),
sss * -radius.y() * deltaPrim.x() / radius.x());
// Compute center from center' // Compute center from center'
Matrix2x3f matrix = Matrix2x3f.createRotate(rotationX); final Matrix2x3f matrix = Matrix2x3f.createRotate(rotationX);
Vector2f center = lastPosStore.multiply(pos).multiply(0.5f).add(matrix.multiply(centerPrime)); final Vector2f center = lastPosStore.multiply(pos).multiply(0.5f)
.add(matrix.multiply(centerPrime));
//this.debugInformation.addSegment(center-Vector2f(3.0,3.0), center+Vector2f(3.0,3.0)); //this.debugInformation.addSegment(center-Vector2f(3.0,3.0), center+Vector2f(3.0,3.0));
// this.debugInformation.addSegment(center-Vector2f(3.0,-3.0), center+Vector2f(3.0,-3.0)); // this.debugInformation.addSegment(center-Vector2f(3.0,-3.0), center+Vector2f(3.0,-3.0));
// Calculate theta1, and delta theta. // Calculate theta1, and delta theta.
Vector2f vectorA = deltaPrim.less(centerPrime).devide(radius); final Vector2f vectorA = deltaPrim.less(centerPrime).devide(radius);
Vector2f vectorB = deltaPrim.add(centerPrime).devide(radius.multiply(-1.0f)); final Vector2f vectorB = deltaPrim.add(centerPrime).devide(radius.multiply(-1.0f));
//this.debugInformation.addSegment(center, center+vectorA*radius.x()); //this.debugInformation.addSegment(center, center+vectorA*radius.x());
//this.debugInformation.addSegment(center, center+vectorB*radius.y()); //this.debugInformation.addSegment(center, center+vectorB*radius.y());
// Initial angle // Initial angle
float theta1 = PathModel.vectorAngle(new Vector2f(1.0f, 0.0f), vectorA); final float theta1 = PathModel.vectorAngle(new Vector2f(1.0f, 0.0f), vectorA);
// Delta angle // Delta angle
float deltaTheta = PathModel.vectorAngle(vectorA, vectorB); float deltaTheta = PathModel.vectorAngle(vectorA, vectorB);
// special case of invert angle... // special case of invert angle...
@ -397,9 +441,9 @@ public class PathModel {
matrix.translate(center); matrix.translate(center);
// Split arc into max 90 degree segments. // Split arc into max 90 degree segments.
// The loop assumes an iteration per end point (including start and end), this +1. // The loop assumes an iteration per end point (including start and end), this +1.
int ndivs = (int) (Math.abs(deltaTheta) / ((float) Math.PI * 0.5f)) + 1; final int ndivs = (int) (Math.abs(deltaTheta) / ((float) Math.PI * 0.5f)) + 1;
float hda = (deltaTheta / ndivs) * 0.5f; final float hda = (deltaTheta / ndivs) * 0.5f;
float kappa = (float) Math.abs(4.0f / 3.0f * (1.0f - Math.cos(hda)) / Math.sin(hda)); float kappa = (float) Math.abs(4.0f / 3.0f * (1.0f - Math.cos(hda)) / Math.sin(hda));
if (deltaTheta < 0.0f) { if (deltaTheta < 0.0f) {
kappa = -kappa; kappa = -kappa;
@ -407,21 +451,24 @@ public class PathModel {
Vector2f pointPosPrevious = Vector2f.ZERO; Vector2f pointPosPrevious = Vector2f.ZERO;
Vector2f tangentPrevious = Vector2f.ZERO; Vector2f tangentPrevious = Vector2f.ZERO;
for (int iii = 0; iii <= ndivs; ++iii) { for (int iii = 0; iii <= ndivs; ++iii) {
float a = theta1 + deltaTheta * ((float) iii / (float) ndivs); final float a = theta1 + deltaTheta * ((float) iii / (float) ndivs);
delta = new Vector2f(FMath.cos(a), FMath.sin(a)); delta = new Vector2f(FMath.cos(a), FMath.sin(a));
// position // position
Vector2f pointPos = matrix.multiply(new Vector2f(delta.x() * radius.x(), delta.y() * radius.y())); final Vector2f pointPos = matrix
.multiply(new Vector2f(delta.x() * radius.x(), delta.y() * radius.y()));
// tangent // tangent
Vector2f tangent = matrix.applyScaleRotation(new Vector2f(-delta.y() * radius.x() * kappa, delta.x() * radius.y() * kappa)); final Vector2f tangent = matrix.applyScaleRotation(
new Vector2f(-delta.y() * radius.x() * kappa, delta.x() * radius.y() * kappa));
if (iii > 0) { if (iii > 0) {
Vector2f zlastPosStore = lastPosition; final Vector2f zlastPosStore = lastPosition;
if (!it.getRelative()) { if (!it.getRelative()) {
lastPosition = Vector2f.ZERO; lastPosition = Vector2f.ZERO;
} }
Vector2f zpos1 = pointPosPrevious.add(tangentPrevious); final Vector2f zpos1 = pointPosPrevious.add(tangentPrevious);
Vector2f zpos2 = pointPos.less(tangent); final Vector2f zpos2 = pointPos.less(tangent);
Vector2f zpos = pointPos; final Vector2f zpos = pointPos;
PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, zlastPosStore, zpos1, zpos2, zpos, 0, PointType.join); PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, zlastPosStore,
zpos1, zpos2, zpos, 0, PointType.join);
lastPosition = zpos; lastPosition = zpos;
lastAngle = zpos2; lastAngle = zpos2;
} }
@ -433,13 +480,13 @@ public class PathModel {
} }
break; break;
default: default:
Log.error(PathModel.spacingDist(level + 1) + " Unknow PATH commant (internal error)"); LOGGER.error(PathModel.spacingDist(level + 1) + " Unknow PATH commant (internal error)");
break; break;
} }
} }
// special case : No request end of path ==> open path: // special case : No request end of path ==> open path:
if (tmpListPoint.size() != 0) { if (tmpListPoint.size() != 0) {
Log.verbose("Auto-end PATH"); LOGGER.trace("Auto-end PATH");
tmpListPoint.get(tmpListPoint.size() - 1).setEndPath(); tmpListPoint.get(tmpListPoint.size() - 1).setEndPath();
out.addList(tmpListPoint); out.addList(tmpListPoint);
tmpListPoint = new ArrayList<>(); tmpListPoint = new ArrayList<>();

View File

@ -1,7 +1,8 @@
package org.atriasoft.esvg.render; package org.atriasoft.esvg.render;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -10,6 +11,7 @@ import org.atriasoft.etk.math.Vector2f;
*/ */
public class Point { public class Point {
static final Logger LOGGER = LoggerFactory.getLogger(Point.class);
public Vector2f delta = Vector2f.ZERO; public Vector2f delta = Vector2f.ZERO;
public float len = 0; public float len = 0;
public Vector2f miterAxe = Vector2f.ZERO; public Vector2f miterAxe = Vector2f.ZERO;
@ -43,12 +45,12 @@ public class Point {
void setEndPath() { void setEndPath() {
if (this.type == PointType.interpolation) { if (this.type == PointType.interpolation) {
Log.warning("Request stop path of an interpolate Point"); LOGGER.warn("Request stop path of an interpolate Point");
this.type = PointType.stop; this.type = PointType.stop;
return; return;
} }
if (this.type == PointType.stop) { if (this.type == PointType.stop) {
Log.warning("Request stop path of an STOP Point"); LOGGER.warn("Request stop path of an STOP Point");
return; return;
} }
if (this.type == PointType.start) { if (this.type == PointType.start) {

View File

@ -3,12 +3,14 @@ package org.atriasoft.esvg.render;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.internal.Log;
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.util.Pair; import org.atriasoft.etk.util.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PointList { public class PointList {
static final Logger LOGGER = LoggerFactory.getLogger(PointList.class);
public List<List<Point>> data = new ArrayList<>(); public List<List<Point>> data = new ArrayList<>();
public PointList() { public PointList() {
@ -21,28 +23,28 @@ public class PointList {
} }
public void applyMatrix(final Matrix2x3f transformationMatrix) { public void applyMatrix(final Matrix2x3f transformationMatrix) {
for (List<Point> it : this.data) { for (final List<Point> it : this.data) {
for (Point val : it) { for (final Point val : it) {
val.pos = transformationMatrix.multiply(val.pos); val.pos = transformationMatrix.multiply(val.pos);
} }
} }
} }
public void display() { public void display() {
Log.verbose(" Display list of points : size=" + this.data.size()); LOGGER.trace(" Display list of points : size=" + this.data.size());
for (List<Point> it : this.data) { for (final List<Point> it : this.data) {
Log.verbose(" Find List " + it.size() + " members"); LOGGER.trace(" Find List " + it.size() + " members");
for (int iii = 0; iii < it.size(); ++iii) { for (int iii = 0; iii < it.size(); ++iii) {
Point elem = it.get(iii); final Point elem = it.get(iii);
Log.verbose(" [" + iii + "] Find " + elem.type + " " + elem.pos); LOGGER.trace(" [" + iii + "] Find " + elem.type + " " + elem.pos);
} }
} }
} }
public Pair<Vector2f, Vector2f> getViewPort() { public Pair<Vector2f, Vector2f> getViewPort() {
Pair<Vector2f, Vector2f> out = new Pair<>(Vector2f.MAX_VALUE, Vector2f.MIN_VALUE); Pair<Vector2f, Vector2f> out = new Pair<>(Vector2f.MAX_VALUE, Vector2f.MIN_VALUE);
for (List<Point> it : this.data) { for (final List<Point> it : this.data) {
for (Point it2 : it) { for (final Point it2 : it) {
out = new Pair<>(Vector2f.min(out.first, it2.pos), Vector2f.max(out.second, it2.pos)); out = new Pair<>(Vector2f.min(out.first, it2.pos), Vector2f.max(out.second, it2.pos));
} }
} }

View File

@ -4,14 +4,15 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.CapMode;
import org.atriasoft.esvg.JoinMode;
import org.atriasoft.etk.math.FMath;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic; 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.slf4j.Logger;
import org.atriasoft.etk.math.Matrix2x3f; import org.slf4j.LoggerFactory;
import org.atriasoft.esvg.CapMode;
import org.atriasoft.esvg.JoinMode;
import org.atriasoft.esvg.internal.Log;
/** @file /** @file
* @author Edouard DUPIN * @author Edouard DUPIN
@ -20,13 +21,20 @@ import org.atriasoft.esvg.internal.Log;
*/ */
public class SegmentList { public class SegmentList {
static Vector2f getIntersect(final Vector2f point1, final Vector2f vect1, final Vector2f point2, final Vector2f vect2) { static final Logger LOGGER = LoggerFactory.getLogger(SegmentList.class);
float diviseur = vect1.x() * vect2.y() - vect1.y() * vect2.x();
static Vector2f getIntersect(
final Vector2f point1,
final Vector2f vect1,
final Vector2f point2,
final Vector2f vect2) {
final float diviseur = vect1.x() * vect2.y() - vect1.y() * vect2.x();
if (diviseur != 0.0f) { if (diviseur != 0.0f) {
float mmm = (vect1.x() * point1.y() - vect1.x() * point2.y() - vect1.y() * point1.x() + vect1.y() * point2.x()) / diviseur; final float mmm = (vect1.x() * point1.y() - vect1.x() * point2.y() - vect1.y() * point1.x()
+ vect1.y() * point2.x()) / diviseur;
return point2.add(vect2.multiply(mmm)); return point2.add(vect2.multiply(mmm));
} }
Log.error("Get divider / 0.0f"); LOGGER.error("Get divider / 0.0f");
return point2; return point2;
} }
@ -55,16 +63,16 @@ public class SegmentList {
} }
public void applyMatrix(final Matrix2x3f transformationMatrix) { public void applyMatrix(final Matrix2x3f transformationMatrix) {
for (Segment it : this.data) { for (final Segment it : this.data) {
it.applyMatrix(transformationMatrix); it.applyMatrix(transformationMatrix);
} }
} }
public void clearHorizontals() { public void clearHorizontals() {
// TODO Auto-generated method stub // TODO Auto-generated method stub
Iterator<Segment> itr = this.data.iterator(); final Iterator<Segment> itr = this.data.iterator();
while (itr.hasNext()) { while (itr.hasNext()) {
Segment seg = itr.next(); final Segment seg = itr.next();
if (seg.p0.y() == seg.p1.y()) { if (seg.p0.y() == seg.p1.y()) {
itr.remove(); itr.remove();
} }
@ -72,7 +80,7 @@ public class SegmentList {
} }
public void createSegmentList(final PointList listPoint) { public void createSegmentList(final PointList listPoint) {
for (List<Point> it : listPoint.data) { for (final List<Point> it : listPoint.data) {
// Build Segments // Build Segments
for (int iii = 0, jjj = it.size() - 1; iii < it.size(); jjj = iii++) { for (int iii = 0, jjj = it.size() - 1; iii < it.size(); jjj = iii++) {
addSegment(it.get(jjj), it.get(iii)); addSegment(it.get(jjj), it.get(iii));
@ -80,8 +88,13 @@ public class SegmentList {
} }
} }
public void createSegmentListStroke(final PointList listPoint, final float width, final CapMode cap, final JoinMode join, final float miterLimit) { public void createSegmentListStroke(
for (List<Point> itListPoint : listPoint.data) { final PointList listPoint,
final float width,
final CapMode cap,
final JoinMode join,
final float miterLimit) {
for (final List<Point> itListPoint : listPoint.data) {
// generate for every point all the orthogonal elements // generate for every point all the orthogonal elements
// //
// normal edge * end path // normal edge * end path
@ -96,29 +109,31 @@ public class SegmentList {
// . * * . * * * * * * * * * * * * * // . * * . * * * * * * * * * * * * *
// * * // * *
// * * // * *
for (int idPevious = itListPoint.size() - 1, idCurrent = 0, idNext = 1; idCurrent < itListPoint.size(); idPevious = idCurrent++, idNext++) { for (int idPevious = itListPoint.size() - 1, idCurrent = 0, idNext = 1; idCurrent < itListPoint.size();
idPevious = idCurrent++, idNext++) {
if (idNext == itListPoint.size()) { if (idNext == itListPoint.size()) {
idNext = 0; idNext = 0;
} }
if (itListPoint.get(idCurrent).type == PointType.join || itListPoint.get(idCurrent).type == PointType.interpolation) { if (itListPoint.get(idCurrent).type == PointType.join
|| itListPoint.get(idCurrent).type == PointType.interpolation) {
if (idPevious < 0) { if (idPevious < 0) {
Log.error("an error occure a previous ID is < 0.... "); LOGGER.error("an error occure a previous ID is < 0.... ");
continue; continue;
} }
if (idNext >= itListPoint.size()) { if (idNext >= itListPoint.size()) {
Log.error("an error occure a next ID is >= nbPoint len .... "); LOGGER.error("an error occure a next ID is >= nbPoint len .... ");
continue; continue;
} }
//Log.debug("JOIN : id : prev/curr/next : " + idPevious + "/" + idCurrent + "/" + idNext); //LOGGER.debug("JOIN : id : prev/curr/next : " + idPevious + "/" + idCurrent + "/" + idNext);
//Log.debug("JOIN : val : prev/curr/next : " + itListPoint.get(idPevious).pos + "/" + itListPoint.get(idCurrent).pos + "/" + itListPoint.get(idNext).pos); //LOGGER.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); //LOGGER.debug("JOIN : vecA : " + 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); //LOGGER.debug("JOIN : vecB : " + vecB);
vecB = vecB.safeNormalize(); vecB = vecB.safeNormalize();
Vector2f vecC = vecA.less(vecB); Vector2f vecC = vecA.less(vecB);
//Log.debug("JOIN : vecC : " + vecC); //LOGGER.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());
@ -134,7 +149,7 @@ public class SegmentList {
vecB = itListPoint.get(idCurrent).pos.less(itListPoint.get(idPevious).pos); vecB = itListPoint.get(idCurrent).pos.less(itListPoint.get(idPevious).pos);
vecB = 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); //LOGGER.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);
@ -144,7 +159,7 @@ public class SegmentList {
itListPoint.get(idCurrent).orthoAxeNext = itListPoint.get(idCurrent).miterAxe; itListPoint.get(idCurrent).orthoAxeNext = itListPoint.get(idCurrent).miterAxe;
} else if (itListPoint.get(idCurrent).type == PointType.stop) { } else if (itListPoint.get(idCurrent).type == PointType.stop) {
if (idPevious < 0) { if (idPevious < 0) {
Log.error("an error occure a previous ID is < 0.... "); LOGGER.error("an error occure a previous ID is < 0.... ");
continue; continue;
} }
itListPoint.get(idCurrent).posPrevious = itListPoint.get(idPevious).pos; itListPoint.get(idCurrent).posPrevious = itListPoint.get(idPevious).pos;
@ -154,25 +169,27 @@ public class SegmentList {
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;
} else { } else {
Log.todo("Unsupported type of point ...."); LOGGER.info("TODO: Unsupported type of point ....");
} }
} }
// create segment list: // create segment list:
boolean haveStartLine = false; boolean haveStartLine = false;
Dynamic<Vector2f> leftPoint = new Dynamic<Vector2f>(Vector2f.ZERO); final Dynamic<Vector2f> leftPoint = new Dynamic<>(Vector2f.ZERO);
Dynamic<Vector2f> rightPoint = new Dynamic<Vector2f>(Vector2f.ZERO); final Dynamic<Vector2f> rightPoint = new Dynamic<>(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); final Point it = itListPoint.get(itListPoint.size() - 1);
// Calculate the perpendicular axis ... // Calculate the perpendicular axis ...
leftPoint.value = it.pos.add(it.orthoAxePrevious.multiply(width * 0.5f)); leftPoint.value = it.pos.add(it.orthoAxePrevious.multiply(width * 0.5f));
rightPoint.value = 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.value = SegmentList.getIntersect(leftPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe); leftPoint.value = SegmentList.getIntersect(leftPoint.value, it.pos.less(it.posPrevious), it.pos,
rightPoint.value = SegmentList.getIntersect(rightPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe); 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 perpendicular axis ... // Calculate the perpendicular axis ...
leftPoint.value = it.pos.add(it.orthoAxePrevious.multiply(width * 0.5f)); leftPoint.value = it.pos.add(it.orthoAxePrevious.multiply(width * 0.5f));
@ -180,12 +197,14 @@ public class SegmentList {
// project on the miter Axis ... // project on the miter Axis ...
switch (join) { switch (join) {
case MITER: { case MITER: {
Vector2f left = SegmentList.getIntersect(leftPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe); final Vector2f left = SegmentList.getIntersect(leftPoint.value,
Vector2f right = SegmentList.getIntersect(rightPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe); it.pos.less(it.posPrevious), it.pos, it.miterAxe);
final 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; final float limitRight = (left.less(it.pos)).length() / width * 2.0f;
float limitLeft = (right.less(it.pos)).length() / width * 2.0f; final float limitLeft = (right.less(it.pos)).length() / width * 2.0f;
Log.verbose(" miter Limit: " + limitRight + " " + limitLeft + " <= " + miterLimit); LOGGER.trace(" miter Limit: " + limitRight + " " + limitLeft + " <= " + miterLimit);
if (limitRight <= miterLimit && limitLeft <= miterLimit) { if (limitRight <= miterLimit && limitLeft <= miterLimit) {
leftPoint.value = left; leftPoint.value = left;
rightPoint.value = right; rightPoint.value = right;
@ -194,14 +213,16 @@ public class SegmentList {
} }
case ROUND: case ROUND:
case BEVEL: { case BEVEL: {
Vector2f axePrevious = (it.pos.less(it.posPrevious)).safeNormalize(); final Vector2f axePrevious = (it.pos.less(it.posPrevious)).safeNormalize();
Vector2f axeNext = (it.posNext.less(it.pos)).safeNormalize(); final Vector2f axeNext = (it.posNext.less(it.pos)).safeNormalize();
float cross = axePrevious.cross(axeNext); final float cross = axePrevious.cross(axeNext);
if (cross > 0.0f) { if (cross > 0.0f) {
rightPoint.value = SegmentList.getIntersect(rightPoint.value, 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.value = it.pos.add(it.orthoAxeNext.multiply(width * 0.5f)); leftPoint.value = it.pos.add(it.orthoAxeNext.multiply(width * 0.5f));
} else { } else {
leftPoint.value = SegmentList.getIntersect(leftPoint.value, 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.value = it.pos.less(it.orthoAxeNext.multiply(width * 0.5f)); rightPoint.value = it.pos.less(it.orthoAxeNext.multiply(width * 0.5f));
} }
break; break;
@ -210,106 +231,112 @@ public class SegmentList {
break; break;
} }
} else { } else {
Log.error("Start list point with a join, but last lement is not a join"); LOGGER.error("Start list point with a join, but last lement is not a join");
} }
} }
} }
for (Point it : itListPoint) { for (final Point it : itListPoint) {
switch (it.type) { switch (it.type) {
case single: case single:
// just do nothing .... // just do nothing ....
Log.verbose("Find Single " + it.pos); LOGGER.trace("Find Single " + it.pos);
break; break;
case start: case start:
Log.verbose("Find Start " + it.pos); LOGGER.trace("Find Start " + it.pos);
if (haveStartLine) { if (haveStartLine) {
// close previous : // close previous :
Log.warning(" find a non close path ..."); LOGGER.warn(" find a non close path ...");
addSegment(leftPoint.value, rightPoint.value); addSegment(leftPoint.value, rightPoint.value);
} }
haveStartLine = true; haveStartLine = true;
startStopPoint(leftPoint, rightPoint, it, cap, width, true); startStopPoint(leftPoint, rightPoint, it, cap, width, true);
break; break;
case stop: case stop:
Log.verbose("Find Stop " + it.pos); LOGGER.trace("Find Stop " + it.pos);
if (!haveStartLine) { if (!haveStartLine) {
Log.warning("find close path without start part ..."); LOGGER.warn("find close path without start part ...");
break; break;
} }
haveStartLine = false; haveStartLine = false;
startStopPoint(leftPoint, rightPoint, it, cap, width, false); startStopPoint(leftPoint, rightPoint, it, cap, width, false);
break; break;
case interpolation: { case interpolation: {
Log.verbose("Find interpolation " + it.pos); LOGGER.trace("Find interpolation " + it.pos);
Vector2f left = SegmentList.getIntersect(leftPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe); final Vector2f left = SegmentList.getIntersect(leftPoint.value, it.pos.less(it.posPrevious),
Vector2f right = SegmentList.getIntersect(rightPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe); it.pos, it.miterAxe);
final 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.value, left); addSegment(leftPoint.value, left);
Log.verbose(" segment :" + leftPoint + " . " + left); LOGGER.trace(" segment :" + leftPoint + " . " + left);
addSegment(right, rightPoint.value); addSegment(right, rightPoint.value);
Log.verbose(" segment :" + right + " . " + rightPoint); LOGGER.trace(" segment :" + right + " . " + rightPoint);
leftPoint.value = left; leftPoint.value = left;
rightPoint.value = right; rightPoint.value = right;
} }
break; break;
case join: case join:
Log.verbose("Find join " + it.pos); LOGGER.trace("Find join " + it.pos);
switch (join) { switch (join) {
case MITER: { case MITER: {
Vector2f left = SegmentList.getIntersect(leftPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe); final Vector2f left = SegmentList.getIntersect(leftPoint.value,
Vector2f right = SegmentList.getIntersect(rightPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe); it.pos.less(it.posPrevious), it.pos, it.miterAxe);
final 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; final float limitRight = left.less(it.pos).length() / width * 2.0f;
float limitLeft = right.less(it.pos).length() / width * 2.0f; final float limitLeft = right.less(it.pos).length() / width * 2.0f;
Log.verbose(" miter Limit: " + limitRight + " " + limitLeft + " <= " + miterLimit); LOGGER.trace(" 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.value, left); addSegment(leftPoint.value, left);
Log.verbose(" segment :" + leftPoint + " . " + left); LOGGER.trace(" segment :" + leftPoint + " . " + left);
addSegment(right, rightPoint.value); addSegment(right, rightPoint.value);
Log.verbose(" segment :" + right + " . " + rightPoint); LOGGER.trace(" segment :" + right + " . " + rightPoint);
leftPoint.value = left; leftPoint.value = left;
rightPoint.value = right; rightPoint.value = right;
break; break;
} }
Log.verbose(" Find miter Limit ... ==> create BEVEL"); LOGGER.trace(" Find miter Limit ... ==> create BEVEL");
} }
case ROUND: case ROUND:
case BEVEL: { case BEVEL: {
Vector2f axePrevious = (it.pos.less(it.posPrevious)).safeNormalize(); final Vector2f axePrevious = (it.pos.less(it.posPrevious)).safeNormalize();
Vector2f axeNext = (it.posNext.less(it.pos)).safeNormalize(); final Vector2f axeNext = (it.posNext.less(it.pos)).safeNormalize();
float cross = axePrevious.cross(axeNext); final float cross = axePrevious.cross(axeNext);
if (cross > 0.0f) { if (cross > 0.0f) {
Vector2f right = SegmentList.getIntersect(rightPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe); final Vector2f right = SegmentList.getIntersect(rightPoint.value,
Vector2f left1 = it.pos.add(it.orthoAxePrevious.multiply(width * 0.5f)); it.pos.less(it.posPrevious), it.pos, it.miterAxe);
Vector2f left2 = it.pos.add(it.orthoAxeNext.multiply(width * 0.5f)); final Vector2f left1 = it.pos.add(it.orthoAxePrevious.multiply(width * 0.5f));
final Vector2f left2 = it.pos.add(it.orthoAxeNext.multiply(width * 0.5f));
//Draw from previous point: //Draw from previous point:
addSegment(leftPoint.value, left1); addSegment(leftPoint.value, left1);
Log.verbose(" segment :" + leftPoint + " . " + left1); LOGGER.trace(" segment :" + leftPoint + " . " + left1);
if (join != JoinMode.ROUND) { if (join != JoinMode.ROUND) {
// Miter and bevel: // Miter and bevel:
addSegment(left1, left2); addSegment(left1, left2);
Log.verbose(" segment :" + left1 + " . " + left2); LOGGER.trace(" segment :" + left1 + " . " + left2);
} else { } else {
createSegmentListStroke(left1, left2, it.pos, width, false); createSegmentListStroke(left1, left2, it.pos, width, false);
} }
addSegment(right, rightPoint.value); addSegment(right, rightPoint.value);
Log.verbose(" segment :" + right + " . " + rightPoint); LOGGER.trace(" segment :" + right + " . " + rightPoint);
leftPoint.value = left2; leftPoint.value = left2;
rightPoint.value = right; rightPoint.value = right;
} else { } else {
Vector2f left = SegmentList.getIntersect(leftPoint.value, it.pos.less(it.posPrevious), it.pos, it.miterAxe); final Vector2f left = SegmentList.getIntersect(leftPoint.value,
Vector2f right1 = it.pos.less(it.orthoAxePrevious.multiply(width * 0.5f)); it.pos.less(it.posPrevious), it.pos, it.miterAxe);
Vector2f right2 = it.pos.less(it.orthoAxeNext.multiply(width * 0.5f)); final Vector2f right1 = it.pos.less(it.orthoAxePrevious.multiply(width * 0.5f));
final Vector2f right2 = it.pos.less(it.orthoAxeNext.multiply(width * 0.5f));
//Draw from previous point: //Draw from previous point:
addSegment(leftPoint.value, left); addSegment(leftPoint.value, left);
Log.verbose(" segment :" + leftPoint + " . " + left); LOGGER.trace(" segment :" + leftPoint + " . " + left);
addSegment(right1, rightPoint.value); addSegment(right1, rightPoint.value);
Log.verbose(" segment :" + right1 + " . " + rightPoint); LOGGER.trace(" segment :" + right1 + " . " + rightPoint);
if (join != JoinMode.ROUND) { if (join != JoinMode.ROUND) {
// Miter and bevel: // Miter and bevel:
addSegment(right2, right1); addSegment(right2, right1);
Log.verbose(" segment :" + right2 + " . " + right1); LOGGER.trace(" segment :" + right2 + " . " + right1);
} else { } else {
createSegmentListStroke(right1, right2, it.pos, width, true); createSegmentListStroke(right1, right2, it.pos, width, true);
} }
@ -330,15 +357,21 @@ public class SegmentList {
} }
private void createSegmentListStroke(final Vector2f point1, final Vector2f point2, final Vector2f center, final float width, final boolean isStart) { private void createSegmentListStroke(
final Vector2f point1,
final Vector2f point2,
final Vector2f center,
final float width,
final boolean isStart) {
int nbDot = (int) width; int nbDot = (int) width;
if (nbDot <= 2) { if (nbDot <= 2) {
nbDot = 2; nbDot = 2;
} }
float angleToDraw = FMath.acos((point1.less(center)).safeNormalize().dot((point2.less(center)).safeNormalize())); final float angleToDraw = FMath
float baseAngle = angleToDraw / nbDot; .acos((point1.less(center)).safeNormalize().dot((point2.less(center)).safeNormalize()));
final float baseAngle = angleToDraw / nbDot;
float iii; float iii;
Vector2f axe = (point1.less(center)).safeNormalize(); final Vector2f axe = (point1.less(center)).safeNormalize();
Vector2f ppp1 = point1; Vector2f ppp1 = point1;
@ -350,68 +383,74 @@ public class SegmentList {
} else { } else {
tmpMat = Matrix2x3f.createRotate(iii); tmpMat = Matrix2x3f.createRotate(iii);
} }
Vector2f axeRotate = tmpMat.multiply(axe); final Vector2f axeRotate = tmpMat.multiply(axe);
ppp2 = center.add(axeRotate.multiply(width * 0.5f)); ppp2 = center.add(axeRotate.multiply(width * 0.5f));
if (isStart) { if (isStart) {
addSegment(ppp2, ppp1); addSegment(ppp2, ppp1);
Log.verbose(" segment :" + ppp2 + " . " + ppp1); LOGGER.trace(" segment :" + ppp2 + " . " + ppp1);
} else { } else {
addSegment(ppp1, ppp2); addSegment(ppp1, ppp2);
Log.verbose(" segment :" + ppp1 + " . " + ppp2); LOGGER.trace(" segment :" + ppp1 + " . " + ppp2);
} }
ppp1 = ppp2; ppp1 = ppp2;
} }
if (isStart) { if (isStart) {
addSegment(point2, ppp1); addSegment(point2, ppp1);
Log.verbose(" segment :" + point2 + " . " + ppp1); LOGGER.trace(" segment :" + point2 + " . " + ppp1);
} else { } else {
addSegment(ppp1, point2); addSegment(ppp1, point2);
Log.verbose(" segment :" + ppp1 + " . " + point2); LOGGER.trace(" segment :" + ppp1 + " . " + point2);
} }
} }
public Pair<Vector2f, Vector2f> getViewPort() { public Pair<Vector2f, Vector2f> getViewPort() {
Pair<Vector2f, Vector2f> out = new Pair<>(Vector2f.MAX_VALUE, Vector2f.MIN_VALUE); Pair<Vector2f, Vector2f> out = new Pair<>(Vector2f.MAX_VALUE, Vector2f.MIN_VALUE);
for (Segment it : this.data) { for (final Segment it : this.data) {
out = new Pair<>(Vector2f.min(out.first, it.p0, it.p1), Vector2f.max(out.second, it.p0, it.p1)); out = new Pair<>(Vector2f.min(out.first, it.p0, it.p1), Vector2f.max(out.second, it.p0, it.p1));
} }
return out; return out;
} }
private void startStopPoint(final Dynamic<Vector2f> leftPoint, final Dynamic<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)); final Vector2f left = point.pos.add(point.miterAxe.multiply(width * 0.5f));
Vector2f right = point.pos.less(point.miterAxe.multiply(width * 0.5f)); final 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.value, left); addSegment(leftPoint.value, left);
Log.verbose(" segment :" + leftPoint + " . " + left); LOGGER.trace(" segment :" + leftPoint + " . " + left);
addSegment(right, rightPoint.value); addSegment(right, rightPoint.value);
Log.verbose(" segment :" + right + " . " + rightPoint); LOGGER.trace(" segment :" + right + " . " + rightPoint);
} }
leftPoint.value = left; leftPoint.value = left;
rightPoint.value = right; rightPoint.value = right;
} }
if (!isStart) { if (!isStart) {
addSegment(leftPoint.value, rightPoint.value); addSegment(leftPoint.value, rightPoint.value);
Log.verbose(" segment :" + leftPoint + " . " + rightPoint); LOGGER.trace(" segment :" + leftPoint + " . " + rightPoint);
} else { } else {
addSegment(rightPoint.value, leftPoint.value); addSegment(rightPoint.value, leftPoint.value);
Log.verbose(" segment :" + rightPoint + " . " + leftPoint); LOGGER.trace(" segment :" + rightPoint + " . " + leftPoint);
} }
break; break;
case ROUND: { case ROUND: {
if (!isStart) { if (!isStart) {
Vector2f left = point.pos.add(point.miterAxe.multiply(width * 0.5f)); final Vector2f left = point.pos.add(point.miterAxe.multiply(width * 0.5f));
Vector2f right = point.pos.less(point.miterAxe.multiply(width * 0.5f)); final 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.value, left); addSegment(leftPoint.value, left);
Log.verbose(" segment :" + leftPoint + " . " + left); LOGGER.trace(" segment :" + leftPoint + " . " + left);
addSegment(right, rightPoint.value); addSegment(right, rightPoint.value);
Log.verbose(" segment :" + right + " . " + rightPoint); LOGGER.trace(" segment :" + right + " . " + rightPoint);
} }
leftPoint.value = left; leftPoint.value = left;
rightPoint.value = right; rightPoint.value = right;
@ -434,30 +473,30 @@ public class SegmentList {
} }
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));
Matrix2x3f tmpMat = Matrix2x3f.createTranslate(nextAxe.safeNormalize().multiply(width * -0.5f)); final Matrix2x3f tmpMat = Matrix2x3f.createTranslate(nextAxe.safeNormalize().multiply(width * -0.5f));
left = tmpMat.multiply(left); left = tmpMat.multiply(left);
right = tmpMat.multiply(right); right = tmpMat.multiply(right);
if (!isStart) { if (!isStart) {
//Draw from previous point: //Draw from previous point:
addSegment(leftPoint.value, left); addSegment(leftPoint.value, left);
Log.verbose(" segment :" + leftPoint + " . " + left); LOGGER.trace(" segment :" + leftPoint + " . " + left);
addSegment(right, rightPoint.value); addSegment(right, rightPoint.value);
Log.verbose(" segment :" + right + " . " + rightPoint); LOGGER.trace(" segment :" + right + " . " + rightPoint);
} }
leftPoint.value = left; leftPoint.value = left;
rightPoint.value = right; rightPoint.value = right;
if (!isStart) { if (!isStart) {
addSegment(leftPoint.value, rightPoint.value); addSegment(leftPoint.value, rightPoint.value);
Log.verbose(" segment :" + leftPoint + " . " + rightPoint); LOGGER.trace(" segment :" + leftPoint + " . " + rightPoint);
} else { } else {
addSegment(rightPoint.value, leftPoint.value); addSegment(rightPoint.value, leftPoint.value);
Log.verbose(" segment :" + rightPoint + " . " + leftPoint); LOGGER.trace(" segment :" + rightPoint + " . " + leftPoint);
} }
Log.verbose(" segment :" + leftPoint + " . " + rightPoint); LOGGER.trace(" segment :" + leftPoint + " . " + rightPoint);
} }
break; break;
default: default:
Log.error(" Undefined CAP TYPE"); LOGGER.error(" Undefined CAP TYPE");
break; break;
} }
} }

View File

@ -4,14 +4,16 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.math.FMath; import org.atriasoft.etk.math.FMath;
import org.atriasoft.etk.math.Vector2f; import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.math.Vector2i; import org.atriasoft.etk.math.Vector2i;
import org.atriasoft.etk.util.ArraysTools; import org.atriasoft.etk.util.ArraysTools;
import org.atriasoft.etk.util.Pair; import org.atriasoft.etk.util.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Weight { public class Weight {
static final Logger LOGGER = LoggerFactory.getLogger(Weight.class);
private float[][] data = null; private float[][] data = null;
private Vector2i size; private Vector2i size;
@ -40,7 +42,8 @@ public class Weight {
public void fusion(final Weight redered, final int offsetXXX, final int offsetYYY) { public void fusion(final Weight redered, final int offsetXXX, final int offsetYYY) {
for (int yyy = 0; yyy < redered.getHeight(); yyy++) { for (int yyy = 0; yyy < redered.getHeight(); yyy++) {
for (int xxx = 0; xxx < redered.getWidth(); xxx++) { for (int xxx = 0; xxx < redered.getWidth(); xxx++) {
this.data[offsetYYY + yyy][offsetXXX + xxx] = FMath.avg(0.0f, this.data[offsetYYY + yyy][offsetXXX + xxx] + redered.get(xxx, yyy), 1.0f); this.data[offsetYYY + yyy][offsetXXX + xxx] = FMath.avg(0.0f,
this.data[offsetYYY + yyy][offsetXXX + xxx] + redered.get(xxx, yyy), 1.0f);
} }
} }
@ -50,10 +53,10 @@ public class Weight {
resize(size); resize(size);
// for each lines: // for each lines:
for (int yyy = 0; yyy < size.y(); ++yyy) { for (int yyy = 0; yyy < size.y(); ++yyy) {
Log.verbose("Weighting ... " + yyy + " / " + size.y()); LOGGER.trace("Weighting ... " + yyy + " / " + size.y());
// Reduce the number of lines in the subsampling parsing: // Reduce the number of lines in the subsampling parsing:
List<Segment> availlableSegmentPixel = new ArrayList<Segment>(); final List<Segment> availlableSegmentPixel = new ArrayList<>();
for (Segment it : listSegment.data) { for (final Segment it : listSegment.data) {
if (it.p0.y() < yyy + 1 && it.p1.y() > (yyy)) { if (it.p0.y() < yyy + 1 && it.p1.y() > (yyy)) {
availlableSegmentPixel.add(it); availlableSegmentPixel.add(it);
} }
@ -61,20 +64,21 @@ public class Weight {
if (availlableSegmentPixel.size() == 0) { if (availlableSegmentPixel.size() == 0) {
continue; continue;
} }
Log.verbose(" Find Basic segments " + availlableSegmentPixel.size()); LOGGER.trace(" Find Basic segments " + availlableSegmentPixel.size());
// This represent the pondaration on the subSampling // This represent the pondaration on the subSampling
float deltaSize = 1.0f / subSamplingCount; final float deltaSize = 1.0f / subSamplingCount;
for (int kkk = 0; kkk < subSamplingCount; ++kkk) { for (int kkk = 0; kkk < subSamplingCount; ++kkk) {
Log.verbose(" Scanline ... " + kkk + " / " + subSamplingCount); LOGGER.trace(" Scanline ... " + kkk + " / " + subSamplingCount);
Scanline scanline = new Scanline(size.x()); final Scanline scanline = new Scanline(size.x());
//find all the segment that cross the middle of the line of the center of the pixel line: //find all the segment that cross the middle of the line of the center of the pixel line:
float subSamplingCenterPos = yyy + deltaSize * 0.5f + deltaSize * kkk; final float subSamplingCenterPos = yyy + deltaSize * 0.5f + deltaSize * kkk;
List<Segment> availlableSegment = new ArrayList<>(); final List<Segment> availlableSegment = new ArrayList<>();
// find in the subList ... // find in the subList ...
for (Segment it : availlableSegmentPixel) { for (final Segment it : availlableSegmentPixel) {
if (it.p0.y() <= subSamplingCenterPos && it.p1.y() > subSamplingCenterPos) { if (it.p0.y() <= subSamplingCenterPos && it.p1.y() > subSamplingCenterPos) {
// check if we not get 2 identical lines: // check if we not get 2 identical lines:
if (availlableSegment.size() > 0 && availlableSegment.get(availlableSegment.size() - 1).p1 == it.p0 if (availlableSegment.size() > 0
&& availlableSegment.get(availlableSegment.size() - 1).p1 == it.p0
&& availlableSegment.get(availlableSegment.size() - 1).direction == it.direction) { && availlableSegment.get(availlableSegment.size() - 1).direction == it.direction) {
// we not add this point in this case to prevent double count of the same point. // we not add this point in this case to prevent double count of the same point.
} else { } else {
@ -82,24 +86,24 @@ public class Weight {
} }
} }
} }
Log.verbose(" Availlable Segment " + availlableSegment.size()); LOGGER.trace(" Availlable Segment " + availlableSegment.size());
if (availlableSegment.size() == 0) { if (availlableSegment.size() == 0) {
continue; continue;
} }
for (Segment it : availlableSegment) { for (final Segment it : availlableSegment) {
Log.verbose(" Availlable Segment " + it.p0 + " . " + it.p1 + " dir=" + it.direction); LOGGER.trace(" Availlable Segment " + it.p0 + " . " + it.p1 + " dir=" + it.direction);
} }
// x position, angle // x position, angle
List<Pair<Float, Integer>> listPosition = new ArrayList<>(); final List<Pair<Float, Integer>> listPosition = new ArrayList<>();
for (Segment it : availlableSegment) { for (final Segment it : availlableSegment) {
Vector2f delta = it.p0.less(it.p1); final Vector2f delta = it.p0.less(it.p1);
// x = coefficent*y+bbb; // x = coefficent*y+bbb;
float coefficient = delta.x() / delta.y(); final float coefficient = delta.x() / delta.y();
float bbb = it.p0.x() - coefficient * it.p0.y(); final float bbb = it.p0.x() - coefficient * it.p0.y();
float xpos = coefficient * subSamplingCenterPos + bbb; final float xpos = coefficient * subSamplingCenterPos + bbb;
listPosition.add(new Pair<Float, Integer>(xpos, it.direction)); listPosition.add(new Pair<>(xpos, it.direction));
} }
Log.verbose(" List position " + listPosition.size()); LOGGER.trace(" List position " + listPosition.size());
// now we order position of the xPosition: // now we order position of the xPosition:
Collections.sort(listPosition, (e1, e2) -> ((int) (e1.first - e2.first))); Collections.sort(listPosition, (e1, e2) -> ((int) (e1.first - e2.first)));
@ -111,25 +115,25 @@ public class Weight {
// * current pos // * current pos
// * pos ... // * pos ...
// TODO Code the Odd/even and non-zero ... // TODO Code the Odd/even and non-zero ...
for (Pair<Float, Integer> it : listPosition) { for (final Pair<Float, Integer> it : listPosition) {
if (currentPos != it.first.intValue()) { if (currentPos != it.first.intValue()) {
// fill to the new pos -1: // fill to the new pos -1:
float endValue = FMath.min(1.0f, FMath.abs(lastState)) * deltaSize; final float endValue = FMath.min(1.0f, FMath.abs(lastState)) * deltaSize;
for (int iii = currentPos + 1; iii < it.first.intValue(); ++iii) { for (int iii = currentPos + 1; iii < it.first.intValue(); ++iii) {
scanline.set(iii, endValue); scanline.set(iii, endValue);
} }
currentPos = it.first.intValue(); currentPos = it.first.intValue();
currentValue = endValue; currentValue = endValue;
} }
int oldState = lastState; final int oldState = lastState;
lastState += it.second; lastState += it.second;
if (oldState == 0) { if (oldState == 0) {
// nothing to draw before ... // nothing to draw before ...
float ratio = 1.0f - (it.first - it.first.intValue()); final float ratio = 1.0f - (it.first - it.first.intValue());
currentValue += ratio * deltaSize; currentValue += ratio * deltaSize;
} else if (lastState == 0) { } else if (lastState == 0) {
// something new to draw ... // something new to draw ...
float ratio = 1.0f - (it.first - it.first.intValue()); final float ratio = 1.0f - (it.first - it.first.intValue());
currentValue -= ratio * deltaSize; currentValue -= ratio * deltaSize;
} else { } else {
// nothing to do ... // nothing to do ...
@ -142,7 +146,7 @@ public class Weight {
// if the counter is not at 0 ==> fill if to the end with full value ... 2.0 // if the counter is not at 0 ==> fill if to the end with full value ... 2.0
if (lastState != 0) { if (lastState != 0) {
// just past the last state to the end of the image ... // just past the last state to the end of the image ...
Log.error("end of Path whith no end ... " + currentPos + " . " + size.x()); LOGGER.error("end of Path whith no end ... " + currentPos + " . " + size.x());
for (int xxx = currentPos; xxx < size.x(); ++xxx) { for (int xxx = currentPos; xxx < size.x(); ++xxx) {
scanline.set(xxx, 100.0f); scanline.set(xxx, 100.0f);
} }
@ -184,11 +188,11 @@ public class Weight {
public void resize(final Vector2i size) { public void resize(final Vector2i size) {
this.size = size; this.size = size;
if (this.size.x() <= 0) { if (this.size.x() <= 0) {
Log.error("Error in the Weight size : " + this.size); LOGGER.error("Error in the Weight size : " + this.size);
this.size = this.size.withX(1); this.size = this.size.withX(1);
} }
if (this.size.y() <= 0) { if (this.size.y() <= 0) {
Log.error("Error in the Weight size : " + this.size); LOGGER.error("Error in the Weight size : " + this.size);
this.size = this.size.withY(1); this.size = this.size.withY(1);
} }
this.data = new float[this.size.y()][this.size.x()]; this.data = new float[this.size.y()][this.size.x()];

View File

@ -1,36 +1,37 @@
package test.atriasoft.esvg; package test.atriasoft.esvg;
import org.atriasoft.egami.ImageFloatRGBA;
import org.atriasoft.egami.Image; import org.atriasoft.egami.Image;
import org.atriasoft.egami.ImageFloatRGBA;
import org.atriasoft.esvg.EsvgDocument; import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.Weight; import org.atriasoft.esvg.render.Weight;
import org.atriasoft.etk.Color; import org.atriasoft.etk.Color;
import org.atriasoft.etk.Uri; import org.atriasoft.etk.Uri;
import org.atriasoft.etk.math.Vector2i; import org.atriasoft.etk.math.Vector2i;
import org.atriasoft.pngencoder.PngEncoder; import org.atriasoft.pngencoder.PngEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ConfigTest { public class ConfigTest {
static final Logger LOGGER = LoggerFactory.getLogger(ConfigTest.class);
public static final String BASE_PATH = "./testResult/";//"~/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) {
Image data = doc.renderImageFloatRGBA(null, ConfigTest.VISUAL_DEBUG); final Image data = doc.renderImageFloatRGBA(null, ConfigTest.VISUAL_DEBUG);
if (data == null) { if (data == null) {
Log.critical("No data generated ..."); LOGGER.error("No data generated ...");
} }
Log.warning("Save file in " + uri.getPath()); LOGGER.warn("Save file in " + uri.getPath());
byte[] outElem = new PngEncoder().withBufferedImage(data).withCompressionLevel(9).toBytes(); final byte[] outElem = new PngEncoder().withBufferedImage(data).withCompressionLevel(9).toBytes();
Log.warning("outsize = " + outElem.length); LOGGER.warn("outsize = " + outElem.length);
new PngEncoder().withBufferedImage(data).withCompressionLevel(9).toFile(uri.getPath()); new PngEncoder().withBufferedImage(data).withCompressionLevel(9).toFile(uri.getPath());
} }
public static void generateAnImage(final Weight weight, final Uri uri) { public static void generateAnImage(final Weight weight, final Uri uri) {
ImageFloatRGBA image = new ImageFloatRGBA(weight.getWidth() + 2, weight.getHeight() + 2); final ImageFloatRGBA image = new ImageFloatRGBA(weight.getWidth() + 2, weight.getHeight() + 2);
for (int yyy = 0; yyy < weight.getHeight(); yyy++) { for (int yyy = 0; yyy < weight.getHeight(); yyy++) {
for (int xxx = 0; xxx < weight.getWidth(); xxx++) { for (int xxx = 0; xxx < weight.getWidth(); xxx++) {
float elem = weight.get(new Vector2i(xxx, yyy)); final float elem = weight.get(new Vector2i(xxx, yyy));
image.setColorFloat(xxx, yyy, 1.0f, 1.0f, 1.0f, elem); image.setColorFloat(xxx, yyy, 1.0f, 1.0f, 1.0f, elem);
} }
} }
@ -42,9 +43,9 @@ public class ConfigTest {
image.setColor(xxx, 0, Color.ORANGE); image.setColor(xxx, 0, Color.ORANGE);
image.setColor(xxx, weight.getHeight() + 1, Color.ORANGE); image.setColor(xxx, weight.getHeight() + 1, Color.ORANGE);
} }
Log.warning("Save file in " + uri.getPath()); LOGGER.warn("Save file in " + uri.getPath());
byte[] outElem = new PngEncoder().withBufferedImage(image).withCompressionLevel(9).toBytes(); final byte[] outElem = new PngEncoder().withBufferedImage(image).withCompressionLevel(9).toBytes();
Log.warning("outsize = " + outElem.length); LOGGER.warn("outsize = " + outElem.length);
new PngEncoder().withBufferedImage(image).withCompressionLevel(9).toFile(uri.getPath()); new PngEncoder().withBufferedImage(image).withCompressionLevel(9).toFile(uri.getPath());
} }

View File

@ -2,140 +2,187 @@ 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.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
class TestCap { class TestCap {
@Test @Test
public void testTestCapButt() { public void testTestCapButt() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" final String data = """
+ " <polyline points='20,75 80,75' stroke='green' stroke-width='20' fill='none' stroke-linecap='butt'/>" <?xml version='1.0' encoding='UTF-8' standalone='no'?>\
+ " <polyline points='80,25 20,25' stroke='orange' stroke-width='20' fill='none' stroke-linecap='butt'/>" + "</svg>"; <svg height='100' width='100'>\
EsvgDocument doc = new EsvgDocument(); <polyline points='20,75 80,75' stroke='green' stroke-width='20' fill='none' stroke-linecap='butt'/>\
<polyline points='80,25 20,25' stroke='orange' stroke-width='20' fill='none' stroke-linecap='butt'/>\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapbutt.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapbutt.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapbutt.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapbutt.png"));
} }
@Test @Test
public void testTestCapButtDiag1() { public void testTestCapButtDiag1() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" final String data = """
+ " <polyline points='20,20 80,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='butt'/>" <?xml version='1.0' encoding='UTF-8' standalone='no'?>\
+ " <polyline points='80,20 20,80' stroke='orange' stroke-width='20' fill='none' stroke-linecap='butt'/>" + "</svg>"; <svg height='100' width='100'>\
EsvgDocument doc = new EsvgDocument(); <polyline points='20,20 80,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='butt'/>\
<polyline points='80,20 20,80' stroke='orange' stroke-width='20' fill='none' stroke-linecap='butt'/>\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapbuttDiag1.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapbuttDiag1.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapbuttDiag1.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapbuttDiag1.png"));
} }
@Test @Test
public void testTestCapButtDiag2() { public void testTestCapButtDiag2() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" final String data = """
+ " <polyline points='20,80 80,20' stroke='green' stroke-width='20' fill='none' stroke-linecap='butt'/>" <?xml version='1.0' encoding='UTF-8' standalone='no'?>\
+ " <polyline points='80,80 20,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='butt'/>" + "</svg>"; <svg height='100' width='100'>\
EsvgDocument doc = new EsvgDocument(); <polyline points='20,80 80,20' stroke='green' stroke-width='20' fill='none' stroke-linecap='butt'/>\
<polyline points='80,80 20,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='butt'/>\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapbuttDiag2.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapbuttDiag2.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapbuttDiag2.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapbuttDiag2.png"));
} }
@Test @Test
public void testTestCapButtVert() { public void testTestCapButtVert() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" final String data = """
+ " <polyline points='25,20 25,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='butt'/>" <?xml version='1.0' encoding='UTF-8' standalone='no'?>\
+ " <polyline points='75,80 75,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='butt'/>" + "</svg>"; <svg height='100' width='100'>\
EsvgDocument doc = new EsvgDocument(); <polyline points='25,20 25,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='butt'/>\
<polyline points='75,80 75,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='butt'/>\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapbuttVert.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapbuttVert.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapbuttVert.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapbuttVert.png"));
} }
@Test @Test
public void testTestCapRound() { public void testTestCapRound() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" final String data = """
+ " <polyline points='20,75 80,75' stroke='green' stroke-width='20' fill='none' stroke-linecap='round'/>" <?xml version='1.0' encoding='UTF-8' standalone='no'?>\
+ " <polyline points='80,25 20,25' stroke='orange' stroke-width='20' fill='none' stroke-linecap='round'/>" + "</svg>"; <svg height='100' width='100'>\
EsvgDocument doc = new EsvgDocument(); <polyline points='20,75 80,75' stroke='green' stroke-width='20' fill='none' stroke-linecap='round'/>\
<polyline points='80,25 20,25' stroke='orange' stroke-width='20' fill='none' stroke-linecap='round'/>\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapround.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapround.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapround.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapround.png"));
} }
@Test @Test
public void testTestCapRoundDiag1() { public void testTestCapRoundDiag1() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" final String data = """
+ " <polyline points='20,20 80,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='round'/>" <?xml version='1.0' encoding='UTF-8' standalone='no'?>\
+ " <polyline points='80,20 20,80' stroke='orange' stroke-width='20' fill='none' stroke-linecap='round'/>" + "</svg>"; <svg height='100' width='100'>\
EsvgDocument doc = new EsvgDocument(); <polyline points='20,20 80,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='round'/>\
<polyline points='80,20 20,80' stroke='orange' stroke-width='20' fill='none' stroke-linecap='round'/>\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCaproundDiag1.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCaproundDiag1.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCaproundDiag1.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCaproundDiag1.png"));
} }
@Test @Test
public void testTestCapRoundDiag2() { public void testTestCapRoundDiag2() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" final String data = """
+ " <polyline points='20,80 80,20' stroke='green' stroke-width='20' fill='none' stroke-linecap='round'/>" <?xml version='1.0' encoding='UTF-8' standalone='no'?>\
+ " <polyline points='80,80 20,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='round'/>" + "</svg>"; <svg height='100' width='100'>\
EsvgDocument doc = new EsvgDocument(); <polyline points='20,80 80,20' stroke='green' stroke-width='20' fill='none' stroke-linecap='round'/>\
<polyline points='80,80 20,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='round'/>\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCaproundDiag2.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCaproundDiag2.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCaproundDiag2.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCaproundDiag2.png"));
} }
@Test @Test
public void testTestCapRoundVert() { public void testTestCapRoundVert() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" final String data = """
+ " <polyline points='25,20 25,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='round'/>" <?xml version='1.0' encoding='UTF-8' standalone='no'?>\
+ " <polyline points='75,80 75,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='round'/>" + "</svg>"; <svg height='100' width='100'>\
EsvgDocument doc = new EsvgDocument(); <polyline points='25,20 25,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='round'/>\
<polyline points='75,80 75,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='round'/>\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCaproundVert.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCaproundVert.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCaproundVert.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCaproundVert.png"));
} }
@Test @Test
public void testTestCapSquare() { public void testTestCapSquare() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" final String data = """
+ " <polyline points='20,75 80,75' stroke='green' stroke-width='20' fill='none' stroke-linecap='square'/>" <?xml version='1.0' encoding='UTF-8' standalone='no'?>\
+ " <polyline points='80,25 20,25' stroke='orange' stroke-width='20' fill='none' stroke-linecap='square'/>" + "</svg>"; <svg height='100' width='100'>\
EsvgDocument doc = new EsvgDocument(); <polyline points='20,75 80,75' stroke='green' stroke-width='20' fill='none' stroke-linecap='square'/>\
<polyline points='80,25 20,25' stroke='orange' stroke-width='20' fill='none' stroke-linecap='square'/>\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapsquare.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapsquare.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapsquare.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapsquare.png"));
} }
@Test @Test
public void testTestCapSquareDiag1() { public void testTestCapSquareDiag1() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" final String data = """
+ " <polyline points='20,20 80,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='square'/>" <?xml version='1.0' encoding='UTF-8' standalone='no'?>\
+ " <polyline points='80,20 20,80' stroke='orange' stroke-width='20' fill='none' stroke-linecap='square'/>" + "</svg>"; <svg height='100' width='100'>\
EsvgDocument doc = new EsvgDocument(); <polyline points='20,20 80,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='square'/>\
<polyline points='80,20 20,80' stroke='orange' stroke-width='20' fill='none' stroke-linecap='square'/>\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapsquareDiag1.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapsquareDiag1.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapsquareDiag1.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapsquareDiag1.png"));
} }
@Test @Test
public void testTestCapSquareDiag2() { public void testTestCapSquareDiag2() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" final String data = """
+ " <polyline points='20,80 80,20' stroke='green' stroke-width='20' fill='none' stroke-linecap='square'/>" <?xml version='1.0' encoding='UTF-8' standalone='no'?>\
+ " <polyline points='80,80 20,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='square'/>" + "</svg>"; <svg height='100' width='100'>\
EsvgDocument doc = new EsvgDocument(); <polyline points='20,80 80,20' stroke='green' stroke-width='20' fill='none' stroke-linecap='square'/>\
<polyline points='80,80 20,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='square'/>\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapsquareDiag2.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapsquareDiag2.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapsquareDiag2.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapsquareDiag2.png"));
} }
@Test @Test
public void testTestCapSquareVert() { public void testTestCapSquareVert() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" final String data = """
+ " <polyline points='25,20 25,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='square'/>" <?xml version='1.0' encoding='UTF-8' standalone='no'?>\
+ " <polyline points='75,80 75,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='square'/>" + "</svg>"; <svg height='100' width='100'>\
EsvgDocument doc = new EsvgDocument(); <polyline points='25,20 25,80' stroke='green' stroke-width='20' fill='none' stroke-linecap='square'/>\
<polyline points='75,80 75,20' stroke='orange' stroke-width='20' fill='none' stroke-linecap='square'/>\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapsquareVert.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCapsquareVert.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapsquareVert.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCapsquareVert.png"));
} }
} }

View File

@ -2,37 +2,50 @@ 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.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
class TestCircle { class TestCircle {
@Test @Test
public void testTestCircleFill() { public void testTestCircleFill() throws RuntimeException {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" + " <circle cx='50' cy='50' r='40' fill='red' />" + "</svg>"; final String data = """
EsvgDocument doc = new EsvgDocument(); <?xml version='1.0' encoding='UTF-8' standalone='no'?>\
<svg height='100' width='100'>\
<circle cx='50' cy='50' r='40' fill='red' />\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCirclefill.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCirclefill.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCirclefill.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCirclefill.png"));
} }
@Test @Test
public void testTestCircleFillandstroke() { public void testTestCircleFillandstroke() throws RuntimeException {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" + " <circle cx='50' cy='50' r='40' stroke='green' stroke-width='3' fill='red' />" final String data = """
+ "</svg>"; <?xml version='1.0' encoding='UTF-8' standalone='no'?>\
EsvgDocument doc = new EsvgDocument(); <svg height='100' width='100'>\
<circle cx='50' cy='50' r='40' stroke='green' stroke-width='3' fill='red' />\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCirclefillandstroke.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCirclefillandstroke.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCirclefillandstroke.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCirclefillandstroke.png"));
} }
@Test @Test
public void testTestCircleStroke() { public void testTestCircleStroke() throws RuntimeException {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" + " <circle cx='50' cy='50' r='40' stroke='green' stroke-width='3' />" + "</svg>"; final String data = """
EsvgDocument doc = new EsvgDocument(); <?xml version='1.0' encoding='UTF-8' standalone='no'?>\
<svg height='100' width='100'>\
<circle cx='50' cy='50' r='40' stroke='green' stroke-width='3' />\
</svg>""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCirclestroke.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestCirclestroke.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCirclestroke.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestCirclestroke.png"));
} }
} }

View File

@ -2,7 +2,6 @@ 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.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -10,251 +9,405 @@ class TestGradientLinear {
@Test @Test
public void testTestGradientLinearDiag1() { public void testTestGradientLinearDiag1() {
//@formatter:off //@formatter:off
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" final String data = """
+ "<svg height='100' width='100'>\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <defs>\n" <svg height='100' width='100'>
+ " <linearGradient id='grad2' x1='0%' y1='0%' x2='100%' y2='100%'>\n" <defs>
+ " <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />\n" <linearGradient id='grad2' x1='0%' y1='0%' x2='100%' y2='100%'>
+ " <stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n" <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />
+ " <stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n" <stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
+ " <stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />\n" <stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
+ " </linearGradient>\n" <stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />
+ " </defs>\n" </linearGradient>
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n" </defs>
+ "</svg>\n"; <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />
</svg>
""";
//@formatter:on //@formatter:on
EsvgDocument doc = new EsvgDocument(); final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag1.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag1.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag1.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag1.png"));
} }
@Test @Test
public void testTestGradientLinearDiag1Partiel() { public void testTestGradientLinearDiag1Partiel() {
//@formatter:off //@formatter:off
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" final String data = """
+ "<svg height='100' width='100'>\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <defs>\n" <svg height='100' width='100'>
+ " <linearGradient id='grad2' x1='40%' y1='40%' x2='70%' y2='70%'>\n" <defs>
+ " <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n" <linearGradient id='grad2' x1='40%' y1='40%' x2='70%' y2='70%'>
+ " <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n" <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
+ " </linearGradient>\n" <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
+ " </defs>\n" </linearGradient>
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n" </defs>
+ "</svg>\n"; <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />
</svg>
""";
//@formatter:on //@formatter:on
EsvgDocument doc = new EsvgDocument(); final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag1Partiel.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag1Partiel.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag1Partiel.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag1Partiel.png"));
} }
@Test @Test
public void testTestGradientLinearDiag2() { public void testTestGradientLinearDiag2() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <linearGradient id='grad2' x1='0%' y1='100%' x2='100%' y2='0%'>\n" + " <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <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'>
+ " <stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />\n" + " </linearGradient>\n" + " </defs>\n" <defs>
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n" + "</svg>\n"; <linearGradient id='grad2' x1='0%' y1='100%' x2='100%' y2='0%'>
EsvgDocument doc = new EsvgDocument(); <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />
<stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2.png"));
} }
@Test @Test
public void testTestGradientLinearDiag2Rotate0() { public void testTestGradientLinearDiag2Rotate0() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <linearGradient id='grad2' x1='0%' y1='50%' x2='100%' y2='50%'>\n" + " <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <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'>
+ " <stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />\n" + " </linearGradient>\n" + " </defs>\n" <defs>
+ " <ellipse transform='rotate (30 50 50)' cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n" + "</svg>\n"; <linearGradient id='grad2' x1='0%' y1='50%' x2='100%' y2='50%'>
EsvgDocument doc = new EsvgDocument(); <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />
<stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse transform='rotate (30 50 50)' cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2Rotate0.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2Rotate0.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2Rotate0.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2Rotate0.png"));
} }
@Test @Test
public void testTestGradientLinearDiag2Rotate1() { public void testTestGradientLinearDiag2Rotate1() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <linearGradient id='grad2' x1='0%' y1='100%' x2='100%' y2='0%'>\n" + " <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <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'>
+ " <stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />\n" + " </linearGradient>\n" + " </defs>\n" <defs>
+ " <ellipse transform='rotate (45 50 50)' cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n" + "</svg>\n"; <linearGradient id='grad2' x1='0%' y1='100%' x2='100%' y2='0%'>
EsvgDocument doc = new EsvgDocument(); <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />
<stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse transform='rotate (45 50 50)' cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2Rotate1.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2Rotate1.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2Rotate1.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2Rotate1.png"));
} }
@Test @Test
public void testTestGradientLinearDiag2Rotate2() { public void testTestGradientLinearDiag2Rotate2() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <linearGradient id='grad2' x1='0%' y1='100%' x2='100%' y2='0%'>\n" + " <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <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'>
+ " <stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />\n" + " </linearGradient>\n" + " </defs>\n" <defs>
+ " <ellipse transform='rotate (-45 50 50)' cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n" + "</svg>\n"; <linearGradient id='grad2' x1='0%' y1='100%' x2='100%' y2='0%'>
EsvgDocument doc = new EsvgDocument(); <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />
<stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse transform='rotate (-45 50 50)' cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2Rotate2.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2Rotate2.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2Rotate2.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2Rotate2.png"));
} }
@Test @Test
public void testTestGradientLinearDiag2scale() { public void testTestGradientLinearDiag2scale() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <linearGradient id='grad2' x1='0%' y1='100%' x2='100%' y2='0%'>\n" + " <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <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'>
+ " <stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />\n" + " </linearGradient>\n" + " </defs>\n" <defs>
+ " <ellipse transform='scale (0.5 2.0) translate (10,-25)' cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n" + "</svg>\n"; <linearGradient id='grad2' x1='0%' y1='100%' x2='100%' y2='0%'>
EsvgDocument doc = new EsvgDocument(); <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />
<stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse transform='scale (0.5 2.0) translate (10,-25)' cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2scale.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri
.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2scale.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2scale.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLineardiag2scale.png"));
} }
@Test @Test
public void testTestGradientLinearHorizontal() { public void testTestGradientLinearHorizontal() {
//@formatter:off //@formatter:off
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" final String data = """
+ "<svg height='100' width='100'>\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <defs>\n" <svg height='100' width='100'>
+ " <linearGradient id='grad1' x1='0%' y1='0%' x2='100%' y2='0%'>\n" <defs>
+ " <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />\n" <linearGradient id='grad1' x1='0%' y1='0%' x2='100%' y2='0%'>
+ " <stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n" <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />
+ " <stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n" <stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
+ " <stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />\n" <stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
+ " </linearGradient>\n" <stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />
+ " </defs>\n" </linearGradient>
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" </defs>
+ "</svg>\n"; <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
//@formatter:on //@formatter:on
EsvgDocument doc = new EsvgDocument(); final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearhorizontal.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri
.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearhorizontal.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearhorizontal.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearhorizontal.png"));
} }
@Test @Test
public void testTestGradientLinearInternalHref() { public void testTestGradientLinearInternalHref() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" + " <linearGradient id='grad2Values'>\n" final String data = """
+ " <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" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <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" <svg height='100' width='100'>
+ " </linearGradient>\n" + " <linearGradient id='grad2' x1='0%' y1='100%' x2='100%' y2='0%' xlink:href='#grad2Values' />\n" + " </defs>\n" <defs>
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n" + "</svg>\n"; <linearGradient id='grad2Values'>
EsvgDocument doc = new EsvgDocument(); <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />
<stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />
</linearGradient>
<linearGradient id='grad2' x1='0%' y1='100%' x2='100%' y2='0%' xlink:href='#grad2Values' />
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearinternalHref.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientLinearinternalHref.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearinternalHref.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearinternalHref.png"));
} }
@Test @Test
public void testTestGradientLinearUnitBoxspreadNone() { public void testTestGradientLinearUnitBoxspreadNone() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <linearGradient id='grad2' x1='40%' y1='40%' x2='60%' y2='60%'>\n" + " <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n" + " </linearGradient>\n" + " </defs>\n" <svg height='100' width='100'>
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>\n" + "</svg>\n"; <defs>
EsvgDocument doc = new EsvgDocument(); <linearGradient id='grad2' x1='40%' y1='40%' x2='60%' y2='60%'>
<stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadNone.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadNone.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadNone.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadNone.png"));
} }
@Test @Test
public void testTestGradientLinearUnitBoxspreadPad() { public void testTestGradientLinearUnitBoxspreadPad() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <linearGradient id='grad2' x1='40%' y1='40%' x2='60%' y2='60%' spreadMethod='pad'>\n" + " <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n" + " </linearGradient>\n" + " </defs>\n" <svg height='100' width='100'>
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>\n" + "</svg>\n"; <defs>
EsvgDocument doc = new EsvgDocument(); <linearGradient id='grad2' x1='40%' y1='40%' x2='60%' y2='60%' spreadMethod='pad'>
<stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadPad.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadPad.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadPad.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadPad.png"));
} }
@Test @Test
public void testTestGradientLinearUnitBoxspreadReflect() { public void testTestGradientLinearUnitBoxspreadReflect() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <linearGradient id='grad2' x1='40%' y1='40%' x2='60%' y2='60%' spreadMethod='reflect'>\n" + " <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n" + " </linearGradient>\n" + " </defs>\n" <svg height='100' width='100'>
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>\n" + "</svg>\n"; <defs>
EsvgDocument doc = new EsvgDocument(); <linearGradient id='grad2' x1='40%' y1='40%' x2='60%' y2='60%' spreadMethod='reflect'>
<stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadReflect.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadReflect.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadReflect.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadReflect.png"));
} }
@Test @Test
public void testTestGradientLinearUnitBoxspreadRepeat() { public void testTestGradientLinearUnitBoxspreadRepeat() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <linearGradient id='grad2' x1='40%' y1='40%' x2='60%' y2='60%' spreadMethod='repeat'>\n" + " <stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n" + " </linearGradient>\n" + " </defs>\n" <svg height='100' width='100'>
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>\n" + "</svg>\n"; <defs>
EsvgDocument doc = new EsvgDocument(); <linearGradient id='grad2' x1='40%' y1='40%' x2='60%' y2='60%' spreadMethod='repeat'>
<stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadRepeat.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadRepeat.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadRepeat.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitBoxspreadRepeat.png"));
} }
@Test @Test
public void testTestGradientLinearUnitUserspreadNone() { public void testTestGradientLinearUnitUserspreadNone() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <linearGradient id='grad2' x1='45' y1='45' x2='55' y2='55' gradientUnits='userSpaceOnUse'>\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <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" <svg height='100' width='100'>
+ " </linearGradient>\n" + " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>\n" + "</svg>\n"; <defs>
EsvgDocument doc = new EsvgDocument(); <linearGradient id='grad2' x1='45' y1='45' x2='55' y2='55' gradientUnits='userSpaceOnUse'>
<stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadNone.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadNone.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadNone.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadNone.png"));
} }
@Test @Test
public void testTestGradientLinearUnitUserspreadPad() { public void testTestGradientLinearUnitUserspreadPad() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <linearGradient id='grad2' x1='45' y1='45' x2='55' y2='55' spreadMethod='pad' gradientUnits='userSpaceOnUse' >\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <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" <svg height='100' width='100'>
+ " </linearGradient>\n" + " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>\n" + "</svg>\n"; <defs>
EsvgDocument doc = new EsvgDocument(); <linearGradient id='grad2' x1='45' y1='45' x2='55' y2='55' spreadMethod='pad' gradientUnits='userSpaceOnUse' >
<stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadPad.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadPad.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadPad.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadPad.png"));
} }
@Test @Test
public void testTestGradientLinearUnitUserspreadReflect() { public void testTestGradientLinearUnitUserspreadReflect() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <linearGradient id='grad2' x1='45' y1='45' x2='55' y2='55' spreadMethod='reflect' gradientUnits='userSpaceOnUse' >\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <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" <svg height='100' width='100'>
+ " </linearGradient>\n" + " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>\n" + "</svg>\n"; <defs>
EsvgDocument doc = new EsvgDocument(); <linearGradient id='grad2' x1='45' y1='45' x2='55' y2='55' spreadMethod='reflect' gradientUnits='userSpaceOnUse' >
<stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadReflect.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadReflect.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadReflect.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadReflect.png"));
} }
@Test @Test
public void testTestGradientLinearUnitUserspreadRepeate() { public void testTestGradientLinearUnitUserspreadRepeate() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <linearGradient id='grad2' x1='45' y1='45' x2='55' y2='55' spreadMethod='repeat' gradientUnits='userSpaceOnUse' >\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <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" <svg height='100' width='100'>
+ " </linearGradient>\n" + " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>\n" + "</svg>\n"; <defs>
EsvgDocument doc = new EsvgDocument(); <linearGradient id='grad2' x1='45' y1='45' x2='55' y2='55' spreadMethod='repeat' gradientUnits='userSpaceOnUse' >
<stop offset='0%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)'/>
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadRepeate.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadRepeate.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadRepeate.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearunitUserspreadRepeate.png"));
} }
@Test @Test
public void testTestGradientLinearVertical() { public void testTestGradientLinearVertical() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <linearGradient id='grad2' x1='0%' y1='0%' x2='0%' y2='100%'>\n" + " <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <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'>
+ " <stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />\n" + " </linearGradient>\n" + " </defs>\n" <defs>
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n" + "</svg>\n"; <linearGradient id='grad2' x1='0%' y1='0%' x2='0%' y2='100%'>
EsvgDocument doc = new EsvgDocument(); <stop offset='0%' style='stop-color:rgb(255,0,0);stop-opacity:1' />
<stop offset='45%' style='stop-color:rgb(0,255,0);stop-opacity:1' />
<stop offset='55%' style='stop-color:rgb(0,0,255);stop-opacity:1' />
<stop offset='100%' style='stop-color:rgb(255,0,255);stop-opacity:1' />
</linearGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearvertical.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri
.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientLinearvertical.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearvertical.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientLinearvertical.png"));
} }
} }

View File

@ -2,217 +2,387 @@ 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.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
class TestGradientRadial { class TestGradientRadial {
@Test @Test
public void testTestGradientRadialCircle() { public void testTestGradientRadialCircle() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <radialGradient id='grad1' cx='50%' cy='50%' r='50%' fx='50%' fy='50%'>\n" + " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n" + " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" <svg height='100' width='100'>
+ " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n" + " </defs>\n" <defs>
+ " <ellipse cx='50' cy='50' rx='50' ry='50' fill='url(#grad1)' />\n" + "</svg>\n"; <radialGradient id='grad1' cx='50%' cy='50%' r='50%' fx='50%' fy='50%'>
EsvgDocument doc = new EsvgDocument(); <stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='50' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialcircle.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialcircle.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialcircle.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialcircle.png"));
} }
@Test @Test
public void testTestGradientRadialFull() { public void testTestGradientRadialFull() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <radialGradient id='grad1' cx='50%' cy='50%' r='50%' fx='50%' fy='50%'>\n" + " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n" + " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" <svg height='100' width='100'>
+ " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n" + " </defs>\n" <defs>
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n"; <radialGradient id='grad1' cx='50%' cy='50%' r='50%' fx='50%' fy='50%'>
EsvgDocument doc = new EsvgDocument(); <stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialfull.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialfull.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialfull.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialfull.png"));
} }
@Test @Test
public void testTestGradientRadialPartial() { public void testTestGradientRadialPartial() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <radialGradient id='grad2' cx='20%' cy='30%' r='30%' fx='50%' fy='50%'>\n" + " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n" + " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" <svg height='100' width='100'>
+ " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n" + " </defs>\n" <defs>
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n" + "</svg>\n"; <radialGradient id='grad2' cx='20%' cy='30%' r='30%' fx='50%' fy='50%'>
EsvgDocument doc = new EsvgDocument(); <stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialpartial.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri
.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialpartial.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialpartial.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialpartial.png"));
} }
@Test @Test
public void testTestGradientRadialUnitBoxspreadNone() { public void testTestGradientRadialUnitBoxspreadNone() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <radialGradient id='grad1' cx='50%' cy='50%' r='10%' fx='50%' fy='50%'>\n" + " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n" + " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" <svg height='100' width='100'>
+ " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n" + " </defs>\n" <defs>
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n"; <radialGradient id='grad1' cx='50%' cy='50%' r='10%' fx='50%' fy='50%'>
EsvgDocument doc = new EsvgDocument(); <stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadNone.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadNone.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadNone.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadNone.png"));
} }
@Test @Test
public void testTestGradientRadialUnitBoxspreadPad() { public void testTestGradientRadialUnitBoxspreadPad() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <radialGradient id='grad1' cx='50%' cy='50%' r='10%' fx='50%' fy='50%' spreadMethod='pad'>\n" + " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n" + " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" <svg height='100' width='100'>
+ " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n" + " </defs>\n" <defs>
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n"; <radialGradient id='grad1' cx='50%' cy='50%' r='10%' fx='50%' fy='50%' spreadMethod='pad'>
EsvgDocument doc = new EsvgDocument(); <stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadPad.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadPad.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadPad.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadPad.png"));
} }
@Test @Test
public void testTestGradientRadialUnitBoxspreadReflect() { public void testTestGradientRadialUnitBoxspreadReflect() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <radialGradient id='grad1' cx='50%' cy='50%' r='10%' fx='50%' fy='50%' spreadMethod='reflect'>\n" + " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n" + " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" <svg height='100' width='100'>
+ " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n" + " </defs>\n" <defs>
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n"; <radialGradient id='grad1' cx='50%' cy='50%' r='10%' fx='50%' fy='50%' spreadMethod='reflect'>
EsvgDocument doc = new EsvgDocument(); <stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadReflect.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadReflect.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadReflect.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadReflect.png"));
} }
@Test @Test
public void testTestGradientRadialUnitBoxspreadRepeat() { public void testTestGradientRadialUnitBoxspreadRepeat() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <radialGradient id='grad1' cx='50%' cy='50%' r='10%' fx='50%' fy='50%' spreadMethod='repeat'>\n" + " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n" + " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" <svg height='100' width='100'>
+ " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n" + " </defs>\n" <defs>
+ " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n"; <radialGradient id='grad1' cx='50%' cy='50%' r='10%' fx='50%' fy='50%' spreadMethod='repeat'>
EsvgDocument doc = new EsvgDocument(); <stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadRepeat.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadRepeat.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadRepeat.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitBoxspreadRepeat.png"));
} }
@Test @Test
public void testTestGradientRadialUnitUserspreadNone() { public void testTestGradientRadialUnitUserspreadNone() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <radialGradient id='grad1' cx='50' cy='50' r='10' fx='50' fy='50%' gradientUnits='userSpaceOnUse' >\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" + " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n" <svg height='100' width='100'>
+ " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" + " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n" <defs>
+ " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n"; <radialGradient id='grad1' cx='50' cy='50' r='10' fx='50' fy='50%' gradientUnits='userSpaceOnUse' >
EsvgDocument doc = new EsvgDocument(); <stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadNone.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadNone.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadNone.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadNone.png"));
} }
@Test @Test
public void testTestGradientRadialUnitUserspreadPad() { public void testTestGradientRadialUnitUserspreadPad() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <radialGradient id='grad1' cx='50' cy='50' r='10' fx='50' fy='50' spreadMethod='pad' gradientUnits='userSpaceOnUse' >\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" + " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n" <svg height='100' width='100'>
+ " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" + " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n" <defs>
+ " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n"; <radialGradient id='grad1' cx='50' cy='50' r='10' fx='50' fy='50' spreadMethod='pad' gradientUnits='userSpaceOnUse' >
EsvgDocument doc = new EsvgDocument(); <stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadPad.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadPad.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadPad.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadPad.png"));
} }
@Test @Test
public void testTestGradientRadialUnitUserspreadPadunCenter() { public void testTestGradientRadialUnitUserspreadPadunCenter() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <radialGradient id='grad1' cx='50' cy='50' r='24' fx='40' fy='40' spreadMethod='pad' gradientUnits='userSpaceOnUse' >\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" + " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n" <svg height='100' width='100'>
+ " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" + " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n" <defs>
+ " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n"; <radialGradient id='grad1' cx='50' cy='50' r='24' fx='40' fy='40' spreadMethod='pad' gradientUnits='userSpaceOnUse' >
EsvgDocument doc = new EsvgDocument(); <stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadPadunCenter.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadPadunCenter.png")); () -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadPadunCenter.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc,
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadPadunCenter.png"));
} }
@Test @Test
public void testTestGradientRadialUnitUserspreadReflect() { public void testTestGradientRadialUnitUserspreadReflect() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <radialGradient id='grad1' cx='50' cy='50' r='10' fx='50' fy='50' spreadMethod='reflect' gradientUnits='userSpaceOnUse' >\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" + " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n" <svg height='100' width='100'>
+ " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" + " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n" <defs>
+ " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n"; <radialGradient id='grad1' cx='50' cy='50' r='10' fx='50' fy='50' spreadMethod='reflect' gradientUnits='userSpaceOnUse' >
EsvgDocument doc = new EsvgDocument(); <stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadReflect.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(
() -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadReflect.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadReflect.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadReflect.png"));
} }
@Test @Test
public void testTestGradientRadialUnitUserspreadReflectunCenter() { public void testTestGradientRadialUnitUserspreadReflectunCenter() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <radialGradient id='grad1' cx='50' cy='50' r='24' fx='40' fy='40' spreadMethod='reflect' gradientUnits='userSpaceOnUse' >\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" + " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n" <svg height='100' width='100'>
+ " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" + " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n" <defs>
+ " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n"; <radialGradient id='grad1' cx='50' cy='50' r='24' fx='40' fy='40' spreadMethod='reflect' gradientUnits='userSpaceOnUse' >
EsvgDocument doc = new EsvgDocument(); <stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadReflectunCenter.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadReflectunCenter.png")); new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadReflectunCenter.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc,
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadReflectunCenter.png"));
} }
@Test @Test
public void testTestGradientRadialUnitUserspreadRepeat() { public void testTestGradientRadialUnitUserspreadRepeat() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <radialGradient id='grad1' cx='50' cy='50' r='10' fx='50' fy='50' spreadMethod='repeat' gradientUnits='userSpaceOnUse' >\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" + " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n" <svg height='100' width='100'>
+ " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" + " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n" <defs>
+ " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n"; <radialGradient id='grad1' cx='50' cy='50' r='10' fx='50' fy='50' spreadMethod='repeat' gradientUnits='userSpaceOnUse' >
EsvgDocument doc = new EsvgDocument(); <stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeat.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeat.svg"), data.replace("'", "\"")));
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeat.png")); ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeat.png"));
} }
@Test @Test
public void testTestGradientRadialUnitUserspreadRepeatout() { public void testTestGradientRadialUnitUserspreadRepeatout() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <radialGradient id='grad1' cx='50' cy='50' r='24' fx='20' fy='40' spreadMethod='reflect' gradientUnits='userSpaceOnUse' >\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" + " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n" <svg height='100' width='100'>
+ " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" + " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n" <defs>
+ " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n"; <radialGradient id='grad1' cx='50' cy='50' r='24' fx='20' fy='40' spreadMethod='reflect' gradientUnits='userSpaceOnUse' >
EsvgDocument doc = new EsvgDocument(); <stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeatout.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeatout.png")); () -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeatout.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc,
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeatout.png"));
} }
@Test @Test
public void testTestGradientRadialUnitUserspreadRepeatunCenter() { public void testTestGradientRadialUnitUserspreadRepeatunCenter() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <radialGradient id='grad1' cx='50' cy='50' r='24' fx='40' fy='40' spreadMethod='repeat' gradientUnits='userSpaceOnUse' >\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" + " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n" <svg height='100' width='100'>
+ " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" + " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n" <defs>
+ " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n"; <radialGradient id='grad1' cx='50' cy='50' r='24' fx='40' fy='40' spreadMethod='repeat' gradientUnits='userSpaceOnUse' >
EsvgDocument doc = new EsvgDocument(); <stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeatunCenter.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeatunCenter.png")); () -> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeatunCenter.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc,
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeatunCenter.png"));
} }
@Test @Test
public void testTestGradientRadialUnitUserspreadRepeatunCenter2() { public void testTestGradientRadialUnitUserspreadRepeatunCenter2() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n" + "<svg height='100' width='100'>\n" + " <defs>\n" final String data = """
+ " <radialGradient id='grad1' cx='50' cy='50' r='24' fx='60' fy='60' spreadMethod='repeat' gradientUnits='userSpaceOnUse' >\n" <?xml version='1.0' encoding='UTF-8' standalone='no'?>
+ " <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n" + " <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n" <svg height='100' width='100'>
+ " <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n" + " <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n" + " </radialGradient>\n" <defs>
+ " </defs>\n" + " <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n" + "</svg>\n"; <radialGradient id='grad1' cx='50' cy='50' r='24' fx='60' fy='60' spreadMethod='repeat' gradientUnits='userSpaceOnUse' >
EsvgDocument doc = new EsvgDocument(); <stop offset='0%' style='stop-color:orange;stop-opacity:1' />
<stop offset='45%' style='stop-color:red;stop-opacity:1' />
<stop offset='55%' style='stop-color:blue;stop-opacity:1' />
<stop offset='100%' style='stop-color:green;stop-opacity:1' />
</radialGradient>
</defs>
<ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />
</svg>
""";
final EsvgDocument doc = new EsvgDocument();
doc.parse(data); doc.parse(data);
Assertions.assertDoesNotThrow(()-> Uri.writeAll(new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeatunCenter2.svg"), data.replace("'", "\""))); Assertions.assertDoesNotThrow(() -> Uri.writeAll(
ConfigTest.generateAnImage(doc, new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeatunCenter2.png")); new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeatunCenter2.svg"),
data.replace("'", "\"")));
ConfigTest.generateAnImage(doc,
new Uri(ConfigTest.BASE_PATH + "TestGradientRadialunitUserspreadRepeatunCenter2.png"));
} }
} }