[DEV] rewrite all ==> nee to test now ...

This commit is contained in:
Edouard DUPIN 2021-04-04 15:26:24 +02:00
parent aa7a62bae3
commit 0065451367
124 changed files with 6762 additions and 9422 deletions

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<fileset-config file-format-version="1.2.0" simple-config="true" sync-formatter="false">
<fileset name="all" enabled="true" check-config-name="ewol" local="false">
<fileset name="all" enabled="true" check-config-name="Ewol" local="false">
<file-match-pattern match-pattern="." include-pattern="true"/>
</fileset>
</fileset-config>

View File

@ -21,12 +21,17 @@
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry combineaccessrules="false" kind="src" path="/atriasoft-etk">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry combineaccessrules="false" kind="src" path="/scenarium-logger">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry combineaccessrules="false" kind="src" path="/atriasoft-etk">
<classpathentry combineaccessrules="false" kind="src" path="/atriasoft-exml">
<attributes>
<attribute name="module" value="true"/>
</attributes>

View File

@ -1,14 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Checkstyle//DTD Check Configuration 1.3//EN" "https://checkstyle.org/dtds/configuration_1_3.dtd">
<!DOCTYPE module PUBLIC "-//Checkstyle//DTD Check Configuration 1.3//EN" "https://checkstyle.org/dtds/configuration13.dtd">
<!--
This configuration file was written by the eclipse-cs plugin configuration editor
-->
-.
<!--
Checkstyle-Configuration: Marc Checks
Description:
Checkstyle configuration that checks the sun coding conventions.
-->
-.
<module name="Checker">
<property name="severity" value="error"/>
<property name="fileExtensions" value="java, properties, xml"/>

View File

@ -1,106 +1,106 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="2">
<profile kind="CleanUpProfile" name="EWOL" version="2">
<setting id="cleanup.use_autoboxing" value="false"/>
<setting id="cleanup.always_use_this_for_non_static_method_access" value="false"/>
<setting id="cleanup.remove_trailing_whitespaces_ignore_empty" value="false"/>
<setting id="cleanup.format_source_code_changes_only" value="false"/>
<setting id="cleanup.remove_redundant_semicolons" value="false"/>
<setting id="cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class" value="true"/>
<setting id="cleanup.useless_continue" value="false"/>
<setting id="cleanup.remove_redundant_type_arguments" value="true"/>
<setting id="cleanup.remove_unused_imports" value="true"/>
<setting id="cleanup.break_loop" value="false"/>
<setting id="cleanup.pull_up_assignment" value="false"/>
<setting id="cleanup.useautoboxing" value="false"/>
<setting id="cleanup.alwaysusethisfornonstaticmethodaccess" value="false"/>
<setting id="cleanup.removetrailingwhitespacesignoreempty" value="false"/>
<setting id="cleanup.formatsourcecodechangesonly" value="false"/>
<setting id="cleanup.removeredundantsemicolons" value="false"/>
<setting id="cleanup.qualifystaticmemberaccessesthroughsubtypeswithdeclaringclass" value="true"/>
<setting id="cleanup.uselesscontinue" value="false"/>
<setting id="cleanup.removeredundanttypearguments" value="true"/>
<setting id="cleanup.removeunusedimports" value="true"/>
<setting id="cleanup.breakloop" value="false"/>
<setting id="cleanup.pullupassignment" value="false"/>
<setting id="cleanup.stringbuilder" value="false"/>
<setting id="cleanup.no_super" value="false"/>
<setting id="cleanup.arrays_fill" value="false"/>
<setting id="cleanup.use_lambda" value="true"/>
<setting id="cleanup.simplify_lambda_expression_and_method_ref" value="false"/>
<setting id="cleanup.always_use_blocks" value="true"/>
<setting id="cleanup.sort_members_all" value="false"/>
<setting id="cleanup.nosuper" value="false"/>
<setting id="cleanup.arraysfill" value="false"/>
<setting id="cleanup.uselambda" value="true"/>
<setting id="cleanup.simplifylambdaexpressionandmethodref" value="false"/>
<setting id="cleanup.alwaysuseblocks" value="true"/>
<setting id="cleanup.sortmembersall" value="false"/>
<setting id="cleanup.instanceof" value="false"/>
<setting id="cleanup.add_missing_annotations" value="true"/>
<setting id="cleanup.precompile_regex" value="false"/>
<setting id="cleanup.always_use_this_for_non_static_field_access" value="true"/>
<setting id="cleanup.boolean_literal" value="false"/>
<setting id="cleanup.always_use_parentheses_in_expressions" value="false"/>
<setting id="cleanup.sort_members" value="false"/>
<setting id="cleanup.remove_unused_local_variables" value="false"/>
<setting id="cleanup.add_missing_deprecated_annotations" value="true"/>
<setting id="cleanup.no_string_creation" value="false"/>
<setting id="cleanup.use_unboxing" value="false"/>
<setting id="cleanup.use_blocks_only_for_return_and_throw" value="false"/>
<setting id="cleanup.if_condition" value="false"/>
<setting id="cleanup.remove_trailing_whitespaces" value="true"/>
<setting id="cleanup.map_cloning" value="false"/>
<setting id="cleanup.add_serial_version_id" value="true"/>
<setting id="cleanup.try_with_resource" value="false"/>
<setting id="cleanup.use_this_for_non_static_method_access" value="false"/>
<setting id="cleanup.use_this_for_non_static_method_access_only_if_necessary" value="true"/>
<setting id="cleanup.make_local_variable_final" value="false"/>
<setting id="cleanup.add_missing_methods" value="false"/>
<setting id="cleanup.qualify_static_member_accesses_with_declaring_class" value="true"/>
<setting id="cleanup.add_missing_override_annotations" value="true"/>
<setting id="cleanup.use_blocks" value="true"/>
<setting id="cleanup.collection_cloning" value="false"/>
<setting id="cleanup.convert_to_enhanced_for_loop_if_loop_var_used" value="false"/>
<setting id="cleanup.make_variable_declarations_final" value="true"/>
<setting id="cleanup.remove_unused_private_types" value="true"/>
<setting id="cleanup.qualify_static_method_accesses_with_declaring_class" value="false"/>
<setting id="cleanup.organize_imports" value="true"/>
<setting id="cleanup.lazy_logical_operator" value="false"/>
<setting id="cleanup.bitwise_conditional_expression" value="false"/>
<setting id="cleanup.add_all" value="false"/>
<setting id="cleanup.use_directly_map_method" value="false"/>
<setting id="cleanup.qualify_static_field_accesses_with_declaring_class" value="false"/>
<setting id="cleanup.add_generated_serial_version_id" value="false"/>
<setting id="cleanup.primitive_serialization" value="false"/>
<setting id="cleanup.comparison_statement" value="false"/>
<setting id="cleanup.insert_inferred_type_arguments" value="false"/>
<setting id="cleanup.make_private_fields_final" value="true"/>
<setting id="cleanup.useless_return" value="false"/>
<setting id="cleanup.use_this_for_non_static_field_access_only_if_necessary" value="false"/>
<setting id="cleanup.remove_trailing_whitespaces_all" value="true"/>
<setting id="cleanup.remove_unnecessary_array_creation" value="false"/>
<setting id="cleanup.remove_private_constructors" value="true"/>
<setting id="cleanup.make_parameters_final" value="false"/>
<setting id="cleanup.ternary_operator" value="false"/>
<setting id="cleanup.merge_conditional_blocks" value="false"/>
<setting id="cleanup.convert_to_enhanced_for_loop" value="false"/>
<setting id="cleanup.remove_unused_private_fields" value="true"/>
<setting id="cleanup.never_use_blocks" value="false"/>
<setting id="cleanup.remove_redundant_modifiers" value="false"/>
<setting id="cleanup.redundant_falling_through_block_end" value="false"/>
<setting id="cleanup.addmissingannotations" value="true"/>
<setting id="cleanup.precompileregex" value="false"/>
<setting id="cleanup.alwaysusethisfornonstaticfieldaccess" value="true"/>
<setting id="cleanup.booleanliteral" value="false"/>
<setting id="cleanup.alwaysuseparenthesesinexpressions" value="false"/>
<setting id="cleanup.sortmembers" value="false"/>
<setting id="cleanup.removeunusedlocalvariables" value="false"/>
<setting id="cleanup.addmissingdeprecatedannotations" value="true"/>
<setting id="cleanup.nostringcreation" value="false"/>
<setting id="cleanup.useunboxing" value="false"/>
<setting id="cleanup.useblocksonlyforreturnandthrow" value="false"/>
<setting id="cleanup.ifcondition" value="false"/>
<setting id="cleanup.removetrailingwhitespaces" value="true"/>
<setting id="cleanup.mapcloning" value="false"/>
<setting id="cleanup.addserialversionid" value="true"/>
<setting id="cleanup.trywithresource" value="false"/>
<setting id="cleanup.usethisfornonstaticmethodaccess" value="false"/>
<setting id="cleanup.usethisfornonstaticmethodaccessonlyifnecessary" value="true"/>
<setting id="cleanup.makelocalvariablefinal" value="false"/>
<setting id="cleanup.addmissingmethods" value="false"/>
<setting id="cleanup.qualifystaticmemberaccesseswithdeclaringclass" value="true"/>
<setting id="cleanup.addmissingoverrideannotations" value="true"/>
<setting id="cleanup.useblocks" value="true"/>
<setting id="cleanup.collectioncloning" value="false"/>
<setting id="cleanup.converttoenhancedforloopifloopvarused" value="false"/>
<setting id="cleanup.makevariabledeclarationsfinal" value="true"/>
<setting id="cleanup.removeunusedprivatetypes" value="true"/>
<setting id="cleanup.qualifystaticmethodaccesseswithdeclaringclass" value="false"/>
<setting id="cleanup.organizeimports" value="true"/>
<setting id="cleanup.lazylogicaloperator" value="false"/>
<setting id="cleanup.bitwiseconditionalexpression" value="false"/>
<setting id="cleanup.addall" value="false"/>
<setting id="cleanup.usedirectlymapmethod" value="false"/>
<setting id="cleanup.qualifystaticfieldaccesseswithdeclaringclass" value="false"/>
<setting id="cleanup.addgeneratedserialversionid" value="false"/>
<setting id="cleanup.primitiveserialization" value="false"/>
<setting id="cleanup.comparisonstatement" value="false"/>
<setting id="cleanup.insertinferredtypearguments" value="false"/>
<setting id="cleanup.makeprivatefieldsfinal" value="true"/>
<setting id="cleanup.uselessreturn" value="false"/>
<setting id="cleanup.usethisfornonstaticfieldaccessonlyifnecessary" value="false"/>
<setting id="cleanup.removetrailingwhitespacesall" value="true"/>
<setting id="cleanup.removeunnecessaryarraycreation" value="false"/>
<setting id="cleanup.removeprivateconstructors" value="true"/>
<setting id="cleanup.makeparametersfinal" value="false"/>
<setting id="cleanup.ternaryoperator" value="false"/>
<setting id="cleanup.mergeconditionalblocks" value="false"/>
<setting id="cleanup.converttoenhancedforloop" value="false"/>
<setting id="cleanup.removeunusedprivatefields" value="true"/>
<setting id="cleanup.neveruseblocks" value="false"/>
<setting id="cleanup.removeredundantmodifiers" value="false"/>
<setting id="cleanup.redundantfallingthroughblockend" value="false"/>
<setting id="cleanup.switch" value="false"/>
<setting id="cleanup.number_suffix" value="false"/>
<setting id="cleanup.remove_unnecessary_nls_tags" value="true"/>
<setting id="cleanup.convert_to_switch_expressions" value="false"/>
<setting id="cleanup.use_this_for_non_static_field_access" value="true"/>
<setting id="cleanup.add_missing_nls_tags" value="false"/>
<setting id="cleanup.qualify_static_member_accesses_through_instances_with_declaring_class" value="true"/>
<setting id="cleanup.remove_unnecessary_casts" value="true"/>
<setting id="cleanup.objects_equals" value="false"/>
<setting id="cleanup.convert_functional_interfaces" value="true"/>
<setting id="cleanup.format_source_code" value="true"/>
<setting id="cleanup.else_if" value="true"/>
<setting id="cleanup.add_default_serial_version_id" value="true"/>
<setting id="cleanup.remove_unused_private_methods" value="true"/>
<setting id="cleanup.make_type_abstract_if_missing_method" value="false"/>
<setting id="cleanup.numbersuffix" value="false"/>
<setting id="cleanup.removeunnecessarynlstags" value="true"/>
<setting id="cleanup.converttoswitchexpressions" value="false"/>
<setting id="cleanup.usethisfornonstaticfieldaccess" value="true"/>
<setting id="cleanup.addmissingnlstags" value="false"/>
<setting id="cleanup.qualifystaticmemberaccessesthroughinstanceswithdeclaringclass" value="true"/>
<setting id="cleanup.removeunnecessarycasts" value="true"/>
<setting id="cleanup.objectsequals" value="false"/>
<setting id="cleanup.convertfunctionalinterfaces" value="true"/>
<setting id="cleanup.formatsourcecode" value="true"/>
<setting id="cleanup.elseif" value="true"/>
<setting id="cleanup.adddefaultserialversionid" value="true"/>
<setting id="cleanup.removeunusedprivatemethods" value="true"/>
<setting id="cleanup.maketypeabstractifmissingmethod" value="false"/>
<setting id="cleanup.join" value="false"/>
<setting id="cleanup.embedded_if" value="false"/>
<setting id="cleanup.use_anonymous_class_creation" value="false"/>
<setting id="cleanup.add_missing_override_annotations_interface_methods" value="true"/>
<setting id="cleanup.remove_unused_private_members" value="false"/>
<setting id="cleanup.strictly_equal_or_different" value="false"/>
<setting id="cleanup.never_use_parentheses_in_expressions" value="true"/>
<setting id="cleanup.push_down_negation" value="false"/>
<setting id="cleanup.evaluate_nullable" value="false"/>
<setting id="cleanup.use_parentheses_in_expressions" value="true"/>
<setting id="cleanup.embeddedif" value="false"/>
<setting id="cleanup.useanonymousclasscreation" value="false"/>
<setting id="cleanup.addmissingoverrideannotationsinterfacemethods" value="true"/>
<setting id="cleanup.removeunusedprivatemembers" value="false"/>
<setting id="cleanup.strictlyequalordifferent" value="false"/>
<setting id="cleanup.neveruseparenthesesinexpressions" value="true"/>
<setting id="cleanup.pushdownnegation" value="false"/>
<setting id="cleanup.evaluatenullable" value="false"/>
<setting id="cleanup.useparenthesesinexpressions" value="true"/>
<setting id="cleanup.hash" value="false"/>
<setting id="cleanup.double_negation" value="false"/>
<setting id="cleanup.overridden_assignment" value="false"/>
<setting id="cleanup.correct_indentation" value="true"/>
<setting id="cleanup.use_var" value="false"/>
<setting id="cleanup.doublenegation" value="false"/>
<setting id="cleanup.overriddenassignment" value="false"/>
<setting id="cleanup.correctindentation" value="true"/>
<setting id="cleanup.usevar" value="false"/>
</profile>
</profiles>

View File

@ -1,390 +1,390 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="20">
<profile kind="CodeFormatterProfile" name="EWOL" version="20">
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enuthis.declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enuthis.constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafterellipsis" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercommainenuthis.declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecommainallocationexpression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parenthesespositionsinforstatment" value="commonlines"/>
<setting id="org.eclipse.jdt.core.formatter.comment.newlinesatblockboundaries" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercommainconstructordeclarationparameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insertnewlineforparameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertnewlineafterannotationonpackage" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebetweenemptyparensinenuthis.constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeclosingpareninwhile" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebetweenemptyparensinannotationtypememberdeclaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.formatjavadoccomments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enuthis.constant_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_with_spaces" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enuthis.constant" value="48"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
<setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_frothis.starting_position" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_record_components" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_logical_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enuthis.constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.keep_enuthis.constant_declaration_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_shift_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_loops" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enuthis.constant" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.text_block_indentation" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enuthis.constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_annotations" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="2147483647"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_not_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enuthis.constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enuthis.declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enuthis.declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_tag_description" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_constructor" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enuthis.declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_string_concatenation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enuthis.constant_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_shift_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_shift_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_additive_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_relational_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_logical_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enuthis.constants" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="200"/>
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_method_body_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enuthis.constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_additive_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_relational_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_relational_operator" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_additive_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enuthis.declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_additive_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_shift_operator" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.keep_code_block_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parenthesespositionsinenuthis.constantdeclaration" value="commonlines"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftersemicoloninfor" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignwithspaces" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.continuationindentation" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.numberofblanklinesbeforecodeblock" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecommainswitchcaseexpressions" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blanklinesafterpackage" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercommainmultiplelocaldeclarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforargumentsinenuthis.constant" value="48"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafteropeninganglebracketinparameterizedtypereference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indentroottags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.wrapbeforeoroperatormulticatch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.enablingtag" value="@formatter:on"/>
<setting id="org.eclipse.jdt.core.formatter.comment.countlinelengthfrothis.startingposition" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforrecordcomponents" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforthrowsclauseinmethoddeclaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insertnewlineafterannotationonparameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrapbeforemultiplicativeoperator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keepthenstatementonsameline" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercommainexplicitconstructorcallarguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafterprefixoperator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeclosingbraceinarrayinitializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafteropeninganglebracketintypearguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertnewlineafterannotationonmethod" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforparameterizedtypereferences" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforlogicaloperator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeclosingpareninparenthesizedexpression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keepannotationdeclarationononeline" value="onelineifempty"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeclosingpareninrecorddeclaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertnewlineafterannotationonenuthis.constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftermultiplicativeoperator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafterandintypeparameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebetweenemptyparensinmethodinvocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafterassignmentoperator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningbraceintypedeclaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafteropeningpareninfor" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.preservewhitespacebetweencodeandlinecomments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insertnewlineafterannotationonlocalvariable" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blanklinesbeforeabstractmethod" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.keepenuthis.constantdeclarationononeline" value="onelineifempty"/>
<setting id="org.eclipse.jdt.core.formatter.alignvariabledeclarationsoncolumns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeclosingpareninmethodinvocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforuniontypeinmulticatch" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.numberofblanklinesatbeginningofmethodbody" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.keepelsestatementonsameline" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parenthesespositionsincatchclause" value="commonlines"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercommainparameterizedtypereference" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecommainarrayinitializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecommainannotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforargumentsinexplicitconstructorcall" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentformultiplicativeoperator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.keepanonymoustypedeclarationononeline" value="onelineifempty"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercommainswitchcaseexpressions" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrapbeforeshiftoperator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indentbodydeclarationscomparetoannotationdeclarationheader" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.bracepositionforblock" value="endofline"/>
<setting id="org.eclipse.jdt.core.formatter.numberofblanklinesatendofcodeblock" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforebitwiseoperator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.putemptystatementonnewline" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforparametersinconstructordeclaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentfortypeparameters" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforcompactloops" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clearblanklinesinblockcomment" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keepsimpleforbodyonsameline" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insertnewlineatendoffileifmissing" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercommainarrayinitializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeunaryoperator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.formatlinecommentstartingonfirstcolumn" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parenthesespositionsinannotation" value="commonlines"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeellipsis" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforesemicolonintryresources" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercoloninassert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforannotationsonenuthis.constant" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeandintypeparameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafteropeningpareninparenthesizedexpression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.textblockindentation" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.aligntypemembersoncolumns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforassignment" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentformodulestatements" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indentbodydeclarationscomparetotypeheader" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebetweenemptyparensinmethoddeclaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.aligntagsnamesdescriptions" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafteropeningpareninenuthis.constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keepifthenbodyblockononeline" value="onelineifempty"/>
<setting id="org.eclipse.jdt.core.formatter.blanklinesbeforefirstclassbodydeclaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insertnewlinebeforeclosingbraceinarrayinitializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecommainconstructordeclarationparameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.formatguardianclauseononeline" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningpareninif" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignassignmentstatementsoncolumns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.bracepositionforblockincase" value="endofline"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeclosingpareninconstructordeclaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforconditionalexpressionchain" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.comment.formatheader" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentfortypeannotations" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforargumentsinallocationexpression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.wrapbeforeassertionmessageoperator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeclosingpareninswitch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentformethoddeclaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignfieldsgroupingblanklines" value="2147483647"/>
<setting id="org.eclipse.jdt.core.formatter.comment.newlinesatjavadocboundaries" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforbitwiseoperator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.bracepositionforannotationtypedeclaration" value="endofline"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecoloninfor" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforresourcesintry" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforselectorinmethodinvocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.neverindentblockcommentsonfirstcolumn" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafteropeningpareninsynchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercommainallocationexpression" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.formatsourcecode" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningbraceinarrayinitializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blanklinesbeforefield" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafteratinannotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blanklinesbeforemethod" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforsuperclassintypedeclaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeparenthesizedexpressioninthrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafternotoperator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertnewlineaftertypeannotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafteropeningbraceinarrayinitializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningpareninparenthesizedexpression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.formathtml" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafteratinannotationtypedeclaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parenthesespositionsinmethoddelcaration" value="commonlines"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforcompactif" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indentemptylines" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentfortypearguments" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafterunaryoperator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningpareninenuthis.constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforargumentsinannotation" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecommainenuthis.declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforannotationsonpackage" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.indentswitchstatementscomparetoswitch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insertnewlinebeforeelseinifstatement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeassignmentoperator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertnewlineafterlabel" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indentbodydeclarationscomparetoenuthis.declarationheader" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecoloninconditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecommainmethoddeclarationparameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeclosingparenincast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafterarrowinswitchcase" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertnewlinebeforewhileindostatement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningbracketinarraytypereference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indentbodydeclarationscomparetorecordheader" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeclosinganglebracketinparameterizedtypereference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertnewlineafteropeningbraceinarrayinitializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indentbreakscomparetocases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeclosingpareninmethoddeclaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrapbeforebitwiseoperator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafteropeningparenintry" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforelambdaarrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafteropeningpareninmethoddeclaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indenttagdescription" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keepimpleifononeline" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.bracepositionforrecordconstructor" value="endofline"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningbraceinenuthis.declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebetweenbracketsinarraytypereference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeninganglebracketintypeparameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforstringconcatenation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforesemicoloninfor" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningbracketinarrayallocationexpression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentformultiplefields" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercommainenuthis.constantarguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeprefixoperator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.bracepositionforarrayinitializer" value="endofline"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeshiftoperator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningbraceinmethoddeclaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercommaintypeparameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeclosingparenincatch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftershiftoperator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebetweenemptybracesinarrayinitializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecommainmultiplelocaldeclarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keepsimpledowhilebodyonsameline" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningbraceinannotationtypedeclaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecommainrecordcomponents" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrapouterexpressionswhennested" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafterclosingparenincast" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningpareninsynchronized" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningpareninannotationtypememberdeclaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforexpressionsinforloopheader" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.wrapbeforeadditiveoperator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keepsimplegettersetterononeline" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafteropeningpareninwhile" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafteropeninganglebracketintypeparameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforestringconcatenation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafterlambdaarrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.joinlinesincomments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningpareninrecorddeclaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafterrelationaloperator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecommainmultiplefielddeclarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blanklinesbetweenimportgroups" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeatinannotationtypedeclaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafterlogicaloperator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parenthesespositionsinmethodinvocation" value="commonlines"/>
<setting id="org.eclipse.jdt.core.formatter.blanklinesafterimports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insertnewlinebeforeroottags" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parenthesespositionsinrecorddeclaration" value="commonlines"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecommainmethoddeclarationthrows" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parenthesespositionsinswitchstatement" value="commonlines"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafterpostfixoperator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercommainforincrements" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercommaintypearguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafterarrowinswitchdefault" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecommainforinits" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.disablingtag" value="@formatter:off"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforenuthis.constants" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.blanklinesbeforeimports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.numberofblanklinesatendofmethodbody" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.parenthesespositionsinifwhilestatement" value="commonlines"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafterclosingbraceinblock" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeparenthesizedexpressioninreturn" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforearrowinswitchcase" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertnewlineafterannotationonfield" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blanklinesbetweentypedeclarations" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeclosingpareninfor" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafteropeningparenincatch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafteropeningpareninswitch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningbraceinanonymoustypedeclaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.neverindentlinecommentsonfirstcolumn" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercommainforinits" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indentstatementscomparetoblock" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.bracepositionforanonymoustypedeclaration" value="endofline"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforequestioninwildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningpareninannotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecommainmethodinvocationarguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningbraceinswitch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.aligntagsdescriptionsgrouped" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.comment.linelength" value="200"/>
<setting id="org.eclipse.jdt.core.formatter.useonofftags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keepmethodbodyononeline" value="onelineifempty"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebetweenemptybracketsinarrayallocationexpression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keeploopbodyblockononeline" value="onelineifempty"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningbraceinenuthis.constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.bracepositionformethoddeclaration" value="endofline"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercoloninfor" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keeptypedeclarationononeline" value="onelineifempty"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafterclosinganglebracketintypearguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforadditiveoperator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercommainmultiplefielddeclarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningbraceinrecordconstructor" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforerelationaloperator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercommainsuperinterfaces" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keeprecorddeclarationononeline" value="onelineifempty"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecolonindefault" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafterquestioninconditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.bracepositionforconstructordeclaration" value="endofline"/>
<setting id="org.eclipse.jdt.core.formatter.bracepositionforlambdabody" value="endofline"/>
<setting id="org.eclipse.jdt.core.formatter.compactelseif" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecommaintypeparameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningparenincatch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningpareninmethodinvocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercommainmethodinvocationarguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforargumentsinmethodinvocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforthrowsclauseinconstructordeclaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insertnewlinebeforecatchintrystatement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningparenintry" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforannotationsonparameter" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clearblanklinesinjavadoccomment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforrelationaloperator" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforexpressionsinarrayinitializer" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.numberofemptylinestopreserve" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercolonincase" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafteradditiveoperator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeclosingpareninif" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecommaintypearguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafterstringconcatenation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.formatlinecomments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.bracepositionforrecorddeclaration" value="endofline"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercoloninlabeledstatement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.numberofblanklinesaftercodeblock" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforsuperinterfacesintypedeclaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforconditionalexpression" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.insertnewlineafterannotationontype" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforannotationsontype" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningbraceinblock" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforannotationsonlocalvariable" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.bracepositionforenuthis.declaration" value="endofline"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforearrowinswitchdefault" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insertnewlinebetweendifferenttags" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeadditiveoperator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafteropeningpareninmethodinvocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningpareninwhile" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.joinwrappedlines" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebetweenemptyparensinconstructordeclaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforannotationsonfield" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.wrapbeforeconditionaloperator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indentswitchstatementscomparetocases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeclosingbracketinarrayallocationexpression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeclosingpareninsynchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforshiftoperator" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.usetabsonlyforleadingindentations" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parenthesespositionsintryclause" value="commonlines"/>
<setting id="org.eclipse.jdt.core.formatter.keepcodeblockononeline" value="onelineifempty"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercommainconstructordeclarationthrows" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercommainrecordcomponents" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enuthis.declaration" value="33"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assertion_message" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_logical_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration" value="33"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_relational_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_logical_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enuthis.constant_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_enuthis.declaration_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enuthis.constant" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enuthis.constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enuthis.constant_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafterbitwiseoperator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafteropeningbracketinarrayreference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercoloninconditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeclosingparenintry" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftersemicolonintryresources" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.continuationindentationforarrayinitializer" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafterquestioninwildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafteropeningpareninrecorddeclaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforsuperinterfacesinenuthis.declaration" value="33"/>
<setting id="org.eclipse.jdt.core.formatter.wrapbeforeassignmentoperator" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecoloninlabeledstatement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.bracepositionforswitch" value="endofline"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecommainsuperinterfaces" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercommainmethoddeclarationparameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafterclosinganglebracketintypeparameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keeplambdabodyblockononeline" value="onelineifempty"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforannotationsonmethod" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecommainparameterizedtypereference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keeprecordconstructorononeline" value="onelineifempty"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningbraceinrecorddeclaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keepemptyarrayinitializerononeline" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforassertionmessage" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningpareninconstructordeclaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blanklinesbeforenewchunk" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafteropeningbracketinarrayallocationexpression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafteropeningpareninconstructordeclaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeninganglebracketinparameterizedtypereference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeclosinganglebracketintypearguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecoloninassert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blanklinesbeforemembertype" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforelogicaloperator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforargumentsinqualifiedallocationexpression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforsuperinterfacesinrecorddeclaration" value="33"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafteropeningpareninif" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforesemicolon" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrapbeforerelationaloperator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforepostfixoperator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeninganglebracketintypearguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafteropeningparenincast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.formatblockcomments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignmentforparametersinmethoddeclaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercommainmethoddeclarationthrows" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blanklinesafterlastclassbodydeclaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.indentstatementscomparetobody" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keepsimplewhilebodyonsameline" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.wrapbeforelogicaloperator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.blanklinesbetweenstatementgroupinswitch" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeclosingbracketinarrayreference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceaftercommainannotation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecommainenuthis.constantarguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parenthesespositionsinlambdadeclaration" value="commonlines"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecolonincase" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningbracketinarrayreference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keepenuthis.declarationononeline" value="onelineifempty"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningpareninmethoddeclaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.bracepositionforenuthis.constant" value="endofline"/>
<setting id="org.eclipse.jdt.core.formatter.bracepositionfortypedeclaration" value="endofline"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforemultiplicativeoperator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blanklinesbeforepackage" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningpareninfor" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecommainforincrements" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeclosingpareninenuthis.constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecommainexplicitconstructorcallarguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeclosingpareninannotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indentbodydeclarationscomparetoenuthis.constantheader" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningbraceinconstructordeclaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforecommainconstructordeclarationthrows" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeclosinganglebracketintypeparameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforequestioninconditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indentparameterdescription" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.numberofblanklinesatbeginningofcodeblock" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insertnewlinebeforefinallyintrystatement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="tab"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_string_concatenation" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.wrapbeforestringconcatenation" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="200"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspaceafteropeningpareninannotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insertspacebeforeopeningpareninswitch" value="insert"/>
</profile>
</profiles>

66
TestExternworddown.svg Normal file
View File

@ -0,0 +1,66 @@
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<!-- Created with Inkscape (http://www.inkscape.org/) -.
<svg
xmlns:dc='http://purl.org/dc/elements/1.1/'
xmlns:cc='http://creativecommons.org/ns#'
xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'
xmlns:svg='http://www.w3.org/2000/svg'
xmlns='http://www.w3.org/2000/svg'
xmlns:sodipodi='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd'
xmlns:inkscape='http://www.inkscape.org/namespaces/inkscape'
id='svg3411'
version='1.1'
inkscape:version='0.91 r13725'
width='100'
height='100'
viewBox='0 0 100 100'
sodipodi:docname='ArtTime20.svg'>
<metadata
id='metadata3417'>
<rdf:RDF>
<cc:Work
rdf:about=''>
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource='http://purl.org/dc/dcmitype/StillImage' />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id='defs3415' />
<sodipodi:namedview
pagecolor='#ffffff'
bordercolor='#666666'
borderopacity='1'
objecttolerance='10'
gridtolerance='10'
guidetolerance='10'
inkscape:pageopacity='0'
inkscape:pageshadow='2'
inkscape:window-width='1600'
inkscape:window-height='836'
id='namedview3413'
showgrid='true'
inkscape:zoom='7.1484076'
inkscape:cx='32.846023'
inkscape:cy='55.531879'
inkscape:window-x='0'
inkscape:window-y='27'
inkscape:window-maximized='1'
inkscape:current-layer='svg3411'>
<inkscape:grid
type='xygrid'
id='grid3423' />
</sodipodi:namedview>
<g
id='g4311'
transform='translate(2.6978375,-4.244742)'>
<path
inkscape:connector-curvature='0'
id='path4228'
d='m 42.01082,10 c 0,2.666667 0,5.333333 0,8 1.666667,0 3.333333,0 5,0 0,-2.666667 0,-5.333333 0,-8 1.666667,0 3.333333,0 5,0 0,2.666667 0,5.333333 0,8'
style='fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' />
</g>
</svg>

View File

@ -8,4 +8,5 @@ open module org.atriasoft.esvg {
requires transitive io.scenarium.logger;
requires transitive org.atriasoft.etk;
requires transitive org.atriasoft.exml;
}

View File

@ -1,413 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/debug.hpp>
#include <esvg/Base.hpp>
#include <cmath>
const float esvg::kappa90(0.5522847493f);
esvg::Base::Base(PaintState _parentPaintState) {
// copy the parent painting properties ...
this.paint = _parentPaintState;
}
etk::String extractTransformData(const etk::String& _value, const etk::String& _base) {
size_t posStart = _value.find(_base);
if (posStart == etk::String::npos) {
// Not find element is a normal case ...
return "";
}
posStart += _base.size();
if (_value.size() < posStart+2) {
Log.error("Not enought spece in the String to have transform value for ' (' or '()' in '" << _value << "'");
return "";
}
if (_value[posStart] == '(') {
// normal SVG does not support this case ...
posStart++;
} else if ( _value[posStart] == ' '
&& _value[posStart+1] == '(') {
posStart+=2;
} else {
Log.error("Can not find ' (' or '(' in '" << &_value[posStart] << "' for '" << _value << "'");
return "";
}
if (_value.size() < posStart+1) {
Log.error("Not enought spece in the String to have transform value for ')' in '" << _value << "'");
return "";
}
size_t posEnd = _value.find(')', posStart);
if (posEnd == etk::String::npos) {
Log.error("Missing element ')' in '" << _value << "' for " << _base);
return "";
}
Log.verbose("Find : '" << etk::String(_value.begin()+posStart, _value.begin()+posEnd) << "' for " << _base);
return etk::String(_value.begin()+posStart, _value.begin()+posEnd);
}
void esvg::Base::parseTransform(const exml::Element& _element) {
if (_element.exist() == false) {
return;
}
etk::String inputString = _element.attributes["transform"];
if (inputString.size() == 0) {
return;
}
Log.verbose("find transform : \"" << inputString << "\"");
for (size_t iii=0; iii<inputString.size(); iii++) {
if (inputString[iii] == ',') {
inputString[iii] = ' ';
}
}
Log.verbose("find transform : \"" << inputString << "\"");
// need to find elements in order ...
etk::String data = extractTransformData(inputString, "matrix");
if (data.size() != 0) {
double matrix[6];
if (sscanf(data.c_str(), "%lf %lf %lf %lf %lf %lf", &matrix[0], &matrix[1], &matrix[2], &matrix[3], &matrix[4], &matrix[5]) == 6) {
this.transformMatrix = mat2x3(matrix);
// find a matrix : simply exit ...
return;
} else {
Log.error("Parsing matrix() with wrong data ... '" << data << "'");
}
}
data = extractTransformData(inputString, "translate");
if (data.size() != 0) {
float xxx, yyy;
if (sscanf(data.c_str(), "%f %f", &xxx, &yyy) == 2) {
this.transformMatrix *= etk::mat2x3Translate(Vector2f(xxx, yyy));
Log.verbose("Translate : " << xxx << ", " << yyy);
} else if (sscanf(data.c_str(), "%f", &xxx) == 1) {
this.transformMatrix *= etk::mat2x3Translate(Vector2f(xxx, 0));
Log.verbose("Translate : " << xxx << ", " << 0);
} else {
Log.error("Parsing translate() with wrong data ... '" << data << "'");
}
}
data = extractTransformData(inputString, "scale");
if (data.size() != 0) {
float xxx, yyy;
if (sscanf(data.c_str(), "%f %f", &xxx, &yyy) == 2) {
this.transformMatrix *= etk::mat2x3Scale(Vector2f(xxx, yyy));
Log.verbose("Scale : " << xxx << ", " << yyy);
} else if (sscanf(data.c_str(), "%f", &xxx) == 1) {
this.transformMatrix *= etk::mat2x3Scale(xxx);
Log.verbose("Scale : " << xxx << ", " << xxx);
} else {
Log.error("Parsing scale() with wrong data ... '" << data << "'");
}
}
data = extractTransformData(inputString, "rotate");
if (data.size() != 0) {
float angle, xxx, yyy;
if (sscanf(data.c_str(), "%f %f %f", &angle, &xxx, &yyy) == 3) {
angle = angle / 180 * M_PI;
this.transformMatrix *= etk::mat2x3Translate(Vector2f(-xxx, -yyy));
this.transformMatrix *= etk::mat2x3Rotate(angle);
this.transformMatrix *= etk::mat2x3Translate(Vector2f(xxx, yyy));
} else if (sscanf(data.c_str(), "%f", &angle) == 1) {
angle = angle / 180 * M_PI;
Log.verbose("rotate : " << angle << "rad, " << (angle/M_PI*180) << "°");
this.transformMatrix *= etk::mat2x3Rotate(angle);
} else {
Log.error("Parsing rotate() with wrong data ... '" << data << "'");
}
}
data = extractTransformData(inputString, "skewX");
if (data.size() != 0) {
float angle;
if (sscanf(data.c_str(), "%f", &angle) == 1) {
angle = angle / 180 * M_PI;
Log.verbose("skewX : " << angle << "rad, " << (angle/M_PI*180) << "°");
this.transformMatrix *= etk::mat2x3Skew(Vector2f(angle, 0.0f));
} else {
Log.error("Parsing skewX() with wrong data ... '" << data << "'");
}
}
data = extractTransformData(inputString, "skewY");
if (data.size() != 0) {
float angle;
if (sscanf(data.c_str(), "%f", &angle) == 1) {
angle = angle / 180 * M_PI;
Log.verbose("skewY : " << angle << "rad, " << (angle/M_PI*180) << "°");
this.transformMatrix *= etk::mat2x3Skew(Vector2f(0.0f, angle));
} else {
Log.error("Parsing skewY() with wrong data ... '" << data << "'");
}
}
}
void esvg::Base::parsePosition(const exml::Element& _element, Vector2f &_pos, Vector2f &_size) {
_pos.setValue(0,0);
_size.setValue(0,0);
if (_element.exist() == false) {
return;
}
etk::String content = _element.attributes["x"];
if (content.size()!=0) {
_pos.setX(parseLength(content));
}
content = _element.attributes["y"];
if (content.size()!=0) {
_pos.setY(parseLength(content));
}
content = _element.attributes["width"];
if (content.size()!=0) {
_size.setX(parseLength(content));
}
content = _element.attributes["height"];
if (content.size()!=0) {
_size.setY(parseLength(content));
}
}
Pair<float, enum esvg::distance> esvg::Base::parseLength2(const etk::String& _dataInput) {
Log.verbose(" lenght : '" << _dataInput << "'");
float n = _dataInput.to<float>();
etk::String unit;
for (size_t iii=0; iii<_dataInput.size(); ++iii) {
if( (_dataInput[iii]>='0' && _dataInput[iii]<='9')
|| _dataInput[iii]=='+'
|| _dataInput[iii]=='-'
|| _dataInput[iii]=='.') {
continue;
}
unit = etk::String(_dataInput, iii);
break;
}
Log.verbose(" lenght : '" << n << "' => unit=" << unit);
// note : ";" is for the parsing of the style elements ...
if(unit.size() == 0) {
return etk::makePair(n, esvg::distance_pixel);
} else if (unit[0] == '%') { // xxx %
return etk::makePair(n, esvg::distance_pourcent);
} else if ( unit[0] == 'e'
&& unit[1] == 'm') { // xxx em
return etk::makePair(n, esvg::distance_element);
} else if ( unit[0] == 'e'
&& unit[1] == 'x') { // xxx ex
return etk::makePair(n, esvg::distance_ex);
} else if ( unit[0] == 'p'
&& unit[1] == 'x') { // xxx px
return etk::makePair(n, esvg::distance_pixel);
} else if ( unit[0] == 'p'
&& unit[1] == 't') { // xxx pt
return etk::makePair(n, esvg::distance_point);
} else if ( unit[0] == 'p'
&& unit[1] == 'c') { // xxx pc
return etk::makePair(n, esvg::distance_pc);
} else if ( unit[0] == 'm'
&& unit[1] == 'm') { // xxx mm
return etk::makePair(n, esvg::distance_millimeter);
} else if ( unit[0] == 'c'
&& unit[1] == 'm') { // xxx cm
return etk::makePair(n, esvg::distance_centimeter);
} else if ( unit[0] == 'i'
&& unit[1] == 'n') { // xxx in
return etk::makePair(n, esvg::distance_inch);
}
return etk::makePair(0.0f, esvg::distance_pixel);
}
float esvg::Base::parseLength(const etk::String& _dataInput) {
Pair<float, enum esvg::distance> value = parseLength2(_dataInput);
Log.verbose(" lenght : '" << value.first << "' => unit=" << value.second);
float font_size = 20.0f;
switch (value.second) {
case esvg::distance_pourcent:
return value.first;// / 100.0 * this.paint.viewPort.x();
case esvg::distance_element:
return value.first * font_size;
case esvg::distance_ex:
return value.first / 2.0f * font_size;
case esvg::distance_pixel:
return value.first;
case esvg::distance_point:
return value.first * 1.25f;
case esvg::distance_pc:
return value.first * 15.0f;
case esvg::distance_millimeter:
return value.first * 3.543307f;
case esvg::distance_centimeter:
return value.first * 35.43307f;
case esvg::distance_inch:
return value.first * 90.0f;
}
return 0.0f;
}
void esvg::Base::parsePaintAttr(const exml::Element& _element) {
if (_element.exist() == false) {
return;
}
/*
boolean fillNone = false;
boolean strokeNone = false;
*/
etk::String content;
// ---------------- get unique ID ----------------
this.id = _element.attributes["id"];
// ---------------- stroke ----------------
content = _element.attributes["stroke"];
if (content == "none") {
this.paint.stroke = Pair<etk::Color<float,4>, etk::String>(etk::color::none, "");
} else {
if (content.size()!=0) {
this.paint.stroke = parseColor(content);
}
content = _element.attributes["stroke-width"];
if (content.size()!=0) {
this.paint.strokeWidth = parseLength(content);
}
content = _element.attributes["stroke-opacity"];
if (content.size()!=0) {
float opacity = parseLength(content);
opacity = etk::avg(0.0f, opacity, 1.0f);
this.paint.stroke.first.setA(opacity);
}
content = _element.attributes["stroke-dasharray"];
if (content.size()!=0) {
if (content == "none" ) {
// OK, Nothing to do ...
} else {
Log.todo(" 'stroke-dasharray' not implemented ...");
}
}
content = _element.attributes["stroke-linecap"];
if (content.size()!=0) {
if (content == "butt" ) {
this.paint.lineCap = esvg::cap_butt;
} else if (content == "round" ) {
this.paint.lineCap = esvg::cap_round;
} else if (content == "square" ) {
this.paint.lineCap = esvg::cap_square;
} else {
this.paint.lineCap = esvg::cap_butt;
Log.error("not know stroke-linecap value : \"" << content << "\", not in [butt,round,square]");
}
}
content = _element.attributes["stroke-linejoin"];
if (content.size()!=0) {
if (content == "miter" ) {
this.paint.lineJoin = esvg::join_miter;
} else if (content == "round" ) {
this.paint.lineJoin = esvg::join_round;
} else if (content == "bevel" ) {
this.paint.lineJoin = esvg::join_bevel;
} else {
this.paint.lineJoin = esvg::join_miter;
Log.error("not know stroke-linejoin value : \"" << content << "\", not in [miter,round,bevel]");
}
}
content = _element.attributes["stroke-miterlimit"];
if (content.size()!=0) {
float tmp = parseLength(content);
this.paint.miterLimit = etk::max(0.0f, tmp);
}
}
// ---------------- FILL ----------------
content = _element.attributes["fill"];
if (content == "none") {
this.paint.fill = Pair<etk::Color<float,4>, etk::String>(etk::color::none, "");
} else {
if (content.size()!=0) {
this.paint.fill = parseColor(content);
}
content = _element.attributes["fill-opacity"];
if (content.size()!=0) {
float opacity = parseLength(content);
opacity = etk::avg(0.0f, opacity, 1.0f);
this.paint.fill.first.setA(opacity);
}
content = _element.attributes["fill-rule"];
if (content.size()!=0) {
if (content == "nonzero") {
this.paint.flagEvenOdd = false;
} else if (content == "evenodd" ) {
this.paint.flagEvenOdd = true;
} else {
Log.error("not know fill-rule value : \"" << content << "\", not in [nonzero,evenodd]");
}
}
// ---------------- opacity ----------------
content = _element.attributes["opacity"];
if (content.size()!=0) {
this.paint.opacity = parseLength(content);
this.paint.opacity = etk::avg(0.0f, this.paint.opacity, 1.0f);
}
}
}
Pair<etk::Color<float,4>, etk::String> esvg::Base::parseColor(const etk::String& _inputData) {
Pair<etk::Color<float,4>, etk::String> localColor(etk::color::white, "");
if( _inputData.size() > 4
&& _inputData[0] == 'u'
&& _inputData[1] == 'r'
&& _inputData[2] == 'l'
&& _inputData[3] == '(') {
if (_inputData[4] == '#') {
etk::String color(_inputData.begin() + 5, _inputData.end()-1);
localColor = Pair<etk::Color<float,4>, etk::String>(etk::color::none, color);
} else {
Log.error("Problem in parsing the color : \"" << _inputData << "\" == > url(XXX) is not supported now ...");
}
} else {
localColor = Pair<etk::Color<float,4>, etk::String>(_inputData, "");
}
Log.verbose("Parse color : \"" << _inputData << "\" == > " << localColor.first << " " << localColor.second);
return localColor;
}
boolean esvg::Base::parseXML(const exml::Element& _element, mat2x3& _parentTrans, Vector2f& _sizeMax) {
// TODO : UNDERSTAND why nothing is done here ...
// Parse basic elements (ID...):
this.id = _element.attributes["id"];
_sizeMax = Vector2f(0.0f, 0.0f);
return false;
}
const char * esvg::Base::spacingDist(int _spacing) {
static const char *tmpValue = " ";
if (_spacing>20) {
_spacing = 20;
}
return tmpValue + 20*4 - _spacing*4;
}
void esvg::Base::draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int _level) {
Log.warning(spacingDist(_level) << "DRAW esvg::Base ... ==> No drawing availlable");
}
const etk::String& esvg::Base::getId() const {
return this.id;
}
void esvg::Base::setId(const etk::String& _newId) {
// TODO : Check if it is UNIQUE ...
this.id = _newId;
}
void esvg::Base::drawShapePoints(List<etk::Vector<Vector2f>>& _out,
int _recurtionMax,
float _threshold,
mat2x3& _basicTrans,
int _level) {
}

View File

@ -1,83 +1,107 @@
package org.atriasoft.esvg;
import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.Color;
import org.atriasoft.etk.Distance;
import org.atriasoft.etk.math.FMath;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.etk.util.Pair;
import org.atriasoft.exml.model.XmlElement;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
class Base {
public static float kappa90; //!< proportional lenght to the radius of a bezier handle for 90° arcs.
public class Base {
public static float kappa90 = 0.5522847493f; //!< proportional lenght to the radius of a bezier handle for 90° arcs.
private static String extractTransformData(final String value, final String base) {
int posStart = value.indexOf(base);
if (posStart == -1) {
// Not indexOf element is a normal case ...
return "";
}
posStart += base.length();
if (value.length() < posStart + 2) {
Log.error("Not enought spece in the String to have transform value for ' (' or '()' in '" + value + "'");
return "";
}
if (value.charAt(posStart) == '(') {
// normal SVG does not support this case ...
posStart++;
} else if (value.charAt(posStart) == ' ' && value.charAt(posStart + 1) == '(') {
posStart += 2;
} else {
Log.error("Can not indexOf ' (' or '(' in '" + value.substring(posStart) + "' for '" + value + "'");
return "";
}
if (value.length() < posStart + 1) {
Log.error("Not enought spece in the String to have transform value for ')' in '" + value + "'");
return "";
}
int posEnd = value.indexOf(')', posStart);
if (posEnd == -1) {
Log.error("Missing element ')' in '" + value + "' for " + base);
return "";
}
Log.verbose("indexOf : '" + value.substring(posStart, posEnd) + "' for " + base);
return value.substring(posStart, posEnd);
}
protected String id; //!< unique ID of the element.
protected PaintState paint;
protected mat2x3 transformMatrix; //!< specific render of the curent element
protected String spacingDist(int _spacing);
protected Matrix2x3f transformMatrix; //!< specific render of the curent element
public Base() {};
public Base() {
this.paint = new PaintState();
}
Base(PaintState _parentPaintState);
Base(final PaintState parentPaintState) {
// copy the parent painting properties ...
this.paint = parentPaintState;
}
/**
* parse all the element needed in the basic node
* @param _element standart XML node
* @return true if no problem arrived
*/
boolean parseXML(const exml::Element& _element, mat2x3& _parentTrans, Vector2f& _sizeMax);
void display(final int spacing) {}
void draw(final Renderer myRenderer, final Matrix2x3f basicTrans) {
draw(myRenderer, basicTrans, 1);
}
/**
* Draw the form in the renderer
* @param _myRenderer Renderer engine
* @param _basicTrans Parant transformation of the environement
* @param _level Level of the tree
* @param myRenderer Renderer engine
* @param basicTrans Parant transformation of the environement
* @param level Level of the tree
*/
void draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int _level=1);
void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
Log.warning(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) {
drawShapePoints(out, recurtionMax, threshold, basicTrans, 1);
}
/**
* Draw rhe shape with all points
* @param _out where the lines are added
* @param _recurtionMax interpolation recurtion max
* @param _threshold threshold to stop recurtion
* @param _basicTrans Parant transformation of the environement
* @param _level Level of the tree
* @param out where the lines are added
* @param recurtionMax interpolation recurtion max
* @param threshold threshold to stop recurtion
* @param basicTrans Parant transformation of the environement
* @param level Level of the tree
*/
void drawShapePoints(final List<List<Vector2f>> _out,
final int _recurtionMax,
final float _threshold,
final mat2x3 _basicTrans,
final int _level=1);
void display(final int _spacing) {};
void parseTransform(const exml::Element& _element);
/**
* parse x, y, width, height attribute of the xml node
* @param _element XML node
* @param _pos parsed position
* @param _size parsed dimention
*/
void parsePosition(const exml::Element& _element, Vector2f &_pos, Vector2f &_size);
/**
* parse a lenght of the xml element
* @param _dataInput Data C String with the printed lenght
* @return standard number of pixels
*/
float parseLength(const etk::String& _dataInput);
Pair<float, enum esvg::distance> parseLength2(const etk::String& _dataInput);
/**
* parse a Painting attribute of a specific node
* @param _element Basic node of the XML that might be parsed
*/
void parsePaintAttr(exml::Element _element);
/**
* parse a color specification from the svg file
* @param _inputData Data C String with the xml definition
* @return The parsed color (color used and the link if needed)
*/
Pair<Color, String> parseColor(String _inputData);
protected String id; //!< unique ID of the element.
void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) {
}
/**
* Get the ID of the Element
* @return UniqueId in the svg file
@ -85,11 +109,360 @@ class Base {
public String getId() {
return this.id;
}
/**
* parse a color specification from the svg file
* @param inputData Data C String with the xml definition
* @return The parsed color (color used and the link if needed)
*/
Pair<Color, String> parseColor(final String inputData) {
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.charAt(4) == '#') {
String color = inputData.substring(5);
localColor = new Pair<>(Color.NONE, color);
} else {
Log.error("Problem in parsing the color : '" + inputData + "' == > url(XXX) is not supported now ...");
}
} else {
try {
localColor = new Pair<>(Color.valueOf(inputData), "");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Log.verbose("Parse color : \"" + inputData + "\" == > " + localColor.first + " " + localColor.second);
return localColor;
}
/**
* parse a lenght of the xml element
* @param dataInput Data C String with the printed lenght
* @return standard number of pixels
*/
float parseLength(final String dataInput) {
Pair<Float, Distance> value = parseLength2(dataInput);
Log.verbose(" lenght : '" + value.first + "' => unit=" + value.second);
float fontsize = 20.0f;
switch (value.second) {
case POURCENT:
return value.first;// / 100.0 * this.paint.viewPort.x();
case ELEMENT:
return value.first * fontsize;
case EX:
return value.first / 2.0f * fontsize;
case PIXEL:
return value.first;
case POINT:
return value.first * 1.25f;
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(final String dataInput) {
Log.verbose(" lenght : '" + dataInput + "'");
float n = Float.parseFloat(dataInput);
String unit = "";
for (int iii = 0; iii < dataInput.length(); ++iii) {
if ((dataInput.charAt(iii) >= '0' && dataInput.charAt(iii) <= '9') || dataInput.charAt(iii) == '+' || dataInput.charAt(iii) == '-' || dataInput.charAt(iii) == '.') {
continue;
}
unit = dataInput.substring(iii);
break;
}
Log.verbose(" lenght : '" + n + "' => unit=" + unit);
// note : ";" is for the parsing of the style elements ...
if (unit.length() == 0) {
return new Pair<>(n, Distance.PIXEL);
}
if (unit.charAt(0) == '%') { // xxx %
return new Pair<>(n, Distance.POURCENT);
}
if (unit.charAt(0) == 'e' && unit.charAt(1) == 'm') { // xxx em
return new Pair<>(n, Distance.ELEMENT);
}
if (unit.charAt(0) == 'e' && unit.charAt(1) == 'x') { // xxx ex
return new Pair<>(n, Distance.EX);
}
if (unit.charAt(0) == 'p' && unit.charAt(1) == 'x') { // xxx px
return new Pair<>(n, Distance.PIXEL);
}
if (unit.charAt(0) == 'p' && unit.charAt(1) == 't') { // xxx pt
return new Pair<>(n, Distance.POINT);
}
if (unit.charAt(0) == 'p' && unit.charAt(1) == 'c') { // xxx pc
return new Pair<>(n, Distance.PC);
}
if (unit.charAt(0) == 'm' && unit.charAt(1) == 'm') { // xxx mm
return new Pair<>(n, Distance.MILLIMETER);
}
if (unit.charAt(0) == 'c' && unit.charAt(1) == 'm') { // xxx cm
return new Pair<>(n, Distance.CENTIMETER);
}
if (unit.charAt(0) == 'i' && unit.charAt(1) == 'n') { // xxx in
return new Pair<>(n, Distance.INCH);
}
return new Pair<>(0.0f, Distance.PIXEL);
}
/**
* parse a Painting attribute of a specific node
* @param element Basic node of the XML that might be parsed
*/
void parsePaintAttr(final XmlElement element) {
if (element == null) {
return;
}
/*
boolean fillNone = false;
boolean strokeNone = false;
*/
String content;
// ---------------- get unique ID ----------------
this.id = element.getAttribute("id", "");
// ---------------- stroke ----------------
content = element.getAttribute("stroke", "");
if (content == "none") {
this.paint.stroke = new Pair<>(Color.NONE, "");
} else {
if (content.length() != 0) {
this.paint.stroke = parseColor(content);
}
content = element.getAttribute("stroke-width", "");
if (content.length() != 0) {
this.paint.strokeWidth = parseLength(content);
}
content = element.getAttribute("stroke-opacity", "");
if (content.length() != 0) {
float opacity = parseLength(content);
opacity = FMath.avg(0.0f, opacity, 1.0f);
this.paint.stroke = this.paint.stroke.withFirst(this.paint.stroke.first.withA(opacity));
}
content = element.getAttribute("stroke-dasharray", "");
if (content.length() != 0) {
if (content == "none") {
// OK, Nothing to do ...
} else {
Log.todo(" 'stroke-dasharray' not implemented ...");
}
}
content = element.getAttribute("stroke-linecap", "");
if (content.length() != 0) {
if (content == "butt") {
this.paint.lineCap = CapMode.BUTT;
} else if (content == "round") {
this.paint.lineCap = CapMode.ROUND;
} else if (content == "square") {
this.paint.lineCap = CapMode.SQUARE;
} else {
this.paint.lineCap = CapMode.BUTT;
Log.error("not know stroke-linecap value : '" + content + "', not in [butt,round,square]");
}
}
content = element.getAttribute("stroke-linejoin", "");
if (content.length() != 0) {
if (content == "miter") {
this.paint.lineJoin = JoinMode.MITER;
} else if (content == "round") {
this.paint.lineJoin = JoinMode.ROUND;
} else if (content == "bevel") {
this.paint.lineJoin = JoinMode.BEVEL;
} else {
this.paint.lineJoin = JoinMode.MITER;
Log.error("not know stroke-linejoin value : '" + content + "', not in [miter,round,bevel]");
}
}
content = element.getAttribute("stroke-miterlimit", "");
if (content.length() != 0) {
float tmp = parseLength(content);
this.paint.miterLimit = FMath.max(0.0f, tmp);
}
}
// ---------------- FILL ----------------
content = element.getAttribute("fill", "");
if (content == "none") {
this.paint.fill = new Pair<>(Color.NONE, "");
} else {
if (content.length() != 0) {
this.paint.fill = parseColor(content);
}
content = element.getAttribute("fill-opacity", "");
if (content.length() != 0) {
float opacity = parseLength(content);
opacity = FMath.avg(0.0f, opacity, 1.0f);
this.paint.fill = this.paint.fill.withFirst(this.paint.fill.first.withA(opacity));
}
content = element.getAttribute("fill-rule", "");
if (content.length() != 0) {
if (content == "nonzero") {
this.paint.flagEvenOdd = false;
} else if (content == "evenodd") {
this.paint.flagEvenOdd = true;
} else {
Log.error("not know fill-rule value : \"" + content + "\", not in [nonzero,evenodd]");
}
}
// ---------------- opacity ----------------
content = element.getAttribute("opacity", "");
if (content.length() != 0) {
this.paint.opacity = parseLength(content);
this.paint.opacity = FMath.avg(0.0f, this.paint.opacity, 1.0f);
}
}
}
protected void parseTransform(final XmlElement element) {
if (element == null) {
return;
}
String inputString = element.getAttribute("transform", "");
if (inputString.length() == 0) {
return;
}
Log.verbose("indexOf transform : '" + inputString + "'");
inputString = inputString.replace(',', ' ');
Log.verbose("indexOf transform : '" + inputString + "'");
// need to indexOf elements in order ...
String data = Base.extractTransformData(inputString, "matrix");
if (data.length() != 0) {
double[] matrix = FMath.getTableDouble(data, " ", 6);
if (matrix != null) {
this.transformMatrix = new Matrix2x3f(matrix);
// indexOf a matrix : simply exit ...
return;
}
Log.error("Parsing matrix() with wrong data ... '" + data + "'");
}
data = Base.extractTransformData(inputString, "translate");
if (data.length() != 0) {
float[] elements = FMath.getTableFloat(data, " ", 2);
if (elements != null) {
this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createTranslate(new Vector2f(elements[0], elements[1])));
Log.verbose("Translate : " + elements[0] + ", " + elements[1]);
} else {
float elem = Float.parseFloat(data);
this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createTranslate(new Vector2f(elem, 0)));
}
}
data = Base.extractTransformData(inputString, "scale");
if (data.length() != 0) {
float[] elements = FMath.getTableFloat(data, " ", 2);
if (elements != null) {
this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createScale(new Vector2f(elements[0], elements[1])));
Log.verbose("Translate : " + elements[0] + ", " + elements[1]);
} else {
float elem = Float.parseFloat(data);
this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createScale(elem));
}
}
data = Base.extractTransformData(inputString, "rotate");
if (data.length() != 0) {
float[] elements = FMath.getTableFloat(data, " ", 3);
if (elements != null) {
float angle = elements[0] / 180 * FMath.PI;
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.createTranslate(new Vector2f(elements[1], elements[2])));
this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createScale(new Vector2f(elements[0], elements[1])));
} else {
float elem = Float.parseFloat(data);
float angle = elem / 180 * FMath.PI;
Log.verbose("rotate : " + angle + "rad, " + (angle / FMath.PI * 180) + "0");
this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createRotate(elem));
}
}
data = Base.extractTransformData(inputString, "skewX");
if (data.length() != 0) {
float angle = Float.parseFloat(data);
angle = angle / 180 * FMath.PI;
Log.verbose("skewX : " + angle + "rad, " + (angle / FMath.PI * 180) + "0");
this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createSkew(new Vector2f(angle, 0.0f)));
}
data = Base.extractTransformData(inputString, "skewY");
if (data.length() != 0) {
float angle = Float.parseFloat(data);
angle = angle / 180 * FMath.PI;
Log.verbose("skewY : " + angle + "rad, " + (angle / FMath.PI * 180) + "0");
this.transformMatrix = this.transformMatrix.multiply(Matrix2x3f.createSkew(new Vector2f(0.0f, angle)));
}
}
/**
* parse all the element needed in the basic node
* @param element standart XML node
* @return true if no problem arrived
*/
boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) {
// TODO UNDERSTAND why nothing is done here ...
// Parse basic elements (ID...):
this.id = element.getAttribute("id", "");
sizeMax.value = Vector2f.ZERO;
return false;
}
/**
* parse x, y, width, height attribute of the xml node
* @param element XML node
* @param pos parsed position
* @param size parsed dimention
*/
protected Vector2f parseXmlPosition(final XmlElement element) {
Vector2f out = Vector2f.ZERO;
if (element == null) {
return out;
}
String content = element.getAttribute("x", "");
if (content.length() != 0) {
out = out.withX(parseLength(content));
}
content = element.getAttribute("y", "");
if (content.length() != 0) {
out = out.withY(parseLength(content));
}
return out;
}
protected Vector2f parseXmlSize(final XmlElement element) {
Vector2f out = Vector2f.ZERO;
if (element == null) {
return out;
}
String content = element.getAttribute("width", "");
if (content.length() != 0) {
out = out.withX(parseLength(content));
}
content = element.getAttribute("height", "");
if (content.length() != 0) {
out = out.withY(parseLength(content));
}
return out;
}
/**
* Set the ID of the Element
* @param _newId New Id of the element
* @param newId New Id of the element
*/
public void setId(String _newId) {
this.id = _newId;
public void setId(final String newId) {
this.id = newId;
}
protected String spacingDist(final int spacing) {
StringBuilder out = new StringBuilder();
for (int iii = 0; iii < spacing; iii++) {
out.append(" ");
}
return out.toString();
}
}

View File

@ -1,166 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/debug.hpp>
#include <esvg/Circle.hpp>
#include <esvg/render/Path.hpp>
#include <esvg/render/Weight.hpp>
esvg::Circle::Circle(PaintState _parentPaintState) : esvg::Base(_parentPaintState) {
}
esvg::Circle::~Circle() {
}
boolean esvg::Circle::parseXML(const exml::Element& _element, mat2x3& _parentTrans, Vector2f& _sizeMax) {
this.radius = 0.0;
this.position.setValue(0,0);
if (_element.exist() == false) {
return false;
}
parseTransform(_element);
parsePaintAttr(_element);
// add the property of the parrent modifications ...
this.transformMatrix *= _parentTrans;
etk::String content = _element.attributes["cx"];
if (content.size()!=0) {
this.position.setX(parseLength(content));
}
content = _element.attributes["cy"];
if (content.size()!=0) {
this.position.setY(parseLength(content));
}
content = _element.attributes["r"];
if (content.size()!=0) {
this.radius = parseLength(content);
} else {
Log.error("(l "<<_element.getPos()<<") Circle \"r\" is not present");
return false;
}
if (0 > this.radius) {
this.radius = 0;
Log.error("(l "<<_element.getPos()<<") Circle \"r\" is negative");
return false;
}
_sizeMax.setValue(this.position.x() + this.radius, this.position.y() + this.radius);
return true;
}
void esvg::Circle::display(int _spacing) {
Log.debug(spacingDist(_spacing) << "Circle " << this.position << " radius=" << this.radius);
}
esvg::render::Path esvg::Circle::createPath() {
esvg::render::Path out;
out.clear();
out.moveTo(false, this.position + Vector2f(this.radius, 0.0f));
out.curveTo(false,
this.position + Vector2f(this.radius, this.radius*esvg::kappa90),
this.position + Vector2f(this.radius*esvg::kappa90, this.radius),
this.position + Vector2f(0.0f, this.radius));
out.curveTo(false,
this.position + Vector2f(-this.radius*esvg::kappa90, this.radius),
this.position + Vector2f(-this.radius, this.radius*esvg::kappa90),
this.position + Vector2f(-this.radius, 0.0f));
out.curveTo(false,
this.position + Vector2f(-this.radius, -this.radius*esvg::kappa90),
this.position + Vector2f(-this.radius*esvg::kappa90, -this.radius),
this.position + Vector2f(0.0f, -this.radius));
out.curveTo(false,
this.position + Vector2f(this.radius*esvg::kappa90, -this.radius),
this.position + Vector2f(this.radius, -this.radius*esvg::kappa90),
this.position + Vector2f(this.radius, 0.0f));
out.close();
return out;
}
void esvg::Circle::draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int _level) {
Log.verbose(spacingDist(_level) << "DRAW esvg::Circle");
if (this.radius <= 0.0f) {
Log.verbose(spacingDist(_level+1) << "Too small radius" << this.radius);
return;
}
esvg::render::Path listElement = createPath();
mat2x3 mtx = this.transformMatrix;
mtx *= _basicTrans;
esvg::render::PointList listPoints;
listPoints = listElement.generateListPoints(_level,
_myRenderer.getInterpolationRecurtionMax(),
_myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx);
esvg::render::SegmentList listSegmentFill;
esvg::render::SegmentList listSegmentStroke;
esvg::render::Weight tmpFill;
esvg::render::Weight tmpStroke;
ememory::SharedPtr<esvg::render::DynamicColor> colorFill = esvg::render::createColor(this.paint.fill, mtx);
ememory::SharedPtr<esvg::render::DynamicColor> colorStroke;
if (this.paint.strokeWidth > 0.0f) {
colorStroke = esvg::render::createColor(this.paint.stroke, mtx);
}
// Check if we need to display background
if (colorFill != null) {
listSegmentFill.createSegmentList(listPoints);
colorFill->setViewPort(listSegmentFill.getViewPort());
listSegmentFill.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpFill.generate(_myRenderer.getSize(),
_myRenderer.getNumberSubScanLine(),
listSegmentFill);
}
// check if we need to display stroke:
if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints,
this.paint.strokeWidth,
this.paint.lineCap,
this.paint.lineJoin,
this.paint.miterLimit);
colorStroke->setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpStroke.generate(_myRenderer.getSize(),
_myRenderer.getNumberSubScanLine(),
listSegmentStroke);
}
// add on images:
_myRenderer.print(tmpFill,
colorFill,
tmpStroke,
colorStroke,
this.paint.opacity);
#ifdef DEBUG
_myRenderer.addDebugSegment(listSegmentFill);
_myRenderer.addDebugSegment(listSegmentStroke);
#endif
}
void esvg::Circle::drawShapePoints(List<etk::Vector<Vector2f>>& _out,
int _recurtionMax,
float _threshold,
mat2x3& _basicTrans,
int _level) {
Log.verbose(spacingDist(_level) << "DRAW Shape esvg::Circle");
esvg::render::Path listElement = createPath();
mat2x3 mtx = this.transformMatrix;
mtx *= _basicTrans;
esvg::render::PointList listPoints;
listPoints = listElement.generateListPoints(_level, _recurtionMax, _threshold);
listPoints.applyMatrix(mtx);
for (auto &it : listPoints.this.data) {
List<Vector2f> listPoint;
for (auto &itDot : it) {
listPoint.pushBack(itDot.this.pos);
}
_out.pushBack(listPoint);
}
}

View File

@ -1,38 +1,147 @@
package org.atriasoft.esvg;
import java.util.ArrayList;
import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.Point;
import org.atriasoft.esvg.render.PointList;
import org.atriasoft.esvg.render.SegmentList;
import org.atriasoft.esvg.render.Weight;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.exml.model.XmlElement;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<esvg/Base.hpp>
namespace esvg{
class Circle extends esvg::Base
{
private:
Vector2f this.position; //!< Position of the Circle
float this.radius; //!< Radius of the Circle
public:
public class Circle extends Base {
private Vector2f position; //!< Position of the Circle
private float radius; //!< Radius of the Circle
Circle(PaintState _parentPaintState);~
public Circle(final PaintState parentPaintState) {
super(parentPaintState);
}
Circle();
private PathModel createPath() {
PathModel out = new PathModel();
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 * Base.kappa90, 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();
return out;
}
boolean parseXML(const exml::Element& _element, mat2x3& _parentTrans, Vector2f& _sizeMax) override;
@Override
public void display(final int spacing) {
Log.debug(spacingDist(spacing) + "Circle " + this.position + " radius=" + this.radius);
}
void display(final int _spacing) override;
@Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW esvg::Circle");
if (this.radius <= 0.0f) {
Log.verbose(spacingDist(level + 1) + "Too small radius" + this.radius);
return;
}
PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix;
mtx = mtx.multiply(basicTrans);
PointList listPoints = new PointList();
listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx);
SegmentList listSegmentFill = new SegmentList();
SegmentList listSegmentStroke = new SegmentList();
Weight tmpFill = new Weight();
Weight tmpStroke = new Weight();
DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx);
DynamicColor colorStroke = null;
if (this.paint.strokeWidth > 0.0f) {
colorStroke = DynamicColor.createColor(this.paint.stroke, mtx);
}
// Check if we need to display background
if (colorFill != null) {
listSegmentFill.createSegmentList(listPoints);
colorFill.setViewPort(listSegmentFill.getViewPort());
listSegmentFill.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpFill.generate(myRenderer.getSize(), myRenderer.getNumberSubScanLine(), listSegmentFill);
}
// check if we need to display stroke:
if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit);
colorStroke.setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpStroke.generate(myRenderer.getSize(), myRenderer.getNumberSubScanLine(), listSegmentStroke);
}
// add on images:
myRenderer.print(tmpFill, colorFill, tmpStroke, colorStroke, this.paint.opacity);
//myRenderer.addDebugSegment(listSegmentFill);
//myRenderer.addDebugSegment(listSegmentStroke);
}
void draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int _level) override;
@Override
public void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW Shape esvg::Circle");
PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix;
mtx = mtx.multiply(basicTrans);
PointList listPoints = new PointList();
listPoints = listElement.generateListPoints(level, recurtionMax, threshold);
listPoints.applyMatrix(mtx);
for (List<Point> it : listPoints.data) {
List<Vector2f> listPoint = new ArrayList<>();
for (Point itDot : it) {
listPoint.add(itDot.pos);
}
out.add(listPoint);
}
}
void drawShapePoints(List<List<Vector2f>>& _out,
int _recurtionMax,
float _threshold,
mat2x3& _basicTrans,
int _level=1) override;
private:
esvg::render::
Path createPath();
};}
@Override
public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) {
this.radius = 0.0f;
this.position = Vector2f.ZERO;
if (element == null) {
return false;
}
parseTransform(element);
parsePaintAttr(element);
// add the property of the parrent modifications ...
this.transformMatrix = this.transformMatrix.multiply(parentTrans);
String content = element.getAttribute("cx", "");
if (content.length() != 0) {
this.position = this.position.withX(parseLength(content));
}
content = element.getAttribute("cy", "");
if (content.length() != 0) {
this.position = this.position.withY(parseLength(content));
}
content = element.getAttribute("r", "");
if (content.length() == 0) {
Log.error("Circle \"r\" is not present");
return false;
}
this.radius = parseLength(content);
if (0 > this.radius) {
this.radius = 0;
Log.error("Circle \"r\" is negative");
return false;
}
sizeMax.value = new Vector2f(this.position.x() + this.radius, this.position.y() + this.radius);
return true;
}
}

View File

@ -1,445 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/Dimension.hpp>
#include <esvg/debug.hpp>
static const float inchToMillimeter = 1.0f/25.4f;
static const float footToMillimeter = 1.0f/304.8f;
static const float meterToMillimeter = 1.0f/1000.0f;
static const float centimeterToMillimeter = 1.0f/10.0f;
static const float kilometerToMillimeter = 1.0f/1000000.0f;
static const float millimeterToInch = 25.4f;
static const float millimeterToFoot = 304.8f;
static const float millimeterToMeter =1000.0f;
static const float millimeterToCentimeter = 10.0f;
static const float millimeterToKilometer = 1000000.0f;
// 72 px /inch(2.54cm)
static const float basicRatio = 72.0f / 25.4f;
esvg::Dimension::Dimension() :
this.data(0,0),
this.type(esvg::distance_pixel) {
// notinh to do ...
}
esvg::Dimension::Dimension(const Vector2f& _size, enum esvg::distance _type) :
this.data(0,0),
this.type(esvg::distance_pixel) {
set(_size, _type);
}
void esvg::Dimension::set(etk::String _config) {
this.data.setValue(0,0);
this.type = esvg::distance_pixel;
enum distance type = esvg::distance_pixel;
if (etk::end_with(_config, "%", false) == true) {
type = esvg::distance_pourcent;
_config.erase(_config.size()-1, 1);
} else if (etk::end_with(_config, "px",false) == true) {
type = esvg::distance_pixel;
_config.erase(_config.size()-2, 2);
} else if (etk::end_with(_config, "ft",false) == true) {
type = esvg::distance_foot;
_config.erase(_config.size()-2, 2);
} else if (etk::end_with(_config, "in",false) == true) {
type = esvg::distance_inch;
_config.erase(_config.size()-2, 2);
} else if (etk::end_with(_config, "km",false) == true) {
type = esvg::distance_kilometer;
_config.erase(_config.size()-2, 2);
} else if (etk::end_with(_config, "mm",false) == true) {
type = esvg::distance_millimeter;
_config.erase(_config.size()-2, 2);
} else if (etk::end_with(_config, "cm",false) == true) {
type = esvg::distance_centimeter;
_config.erase(_config.size()-2, 2);
} else if (etk::end_with(_config, "m",false) == true) {
type = esvg::distance_meter;
_config.erase(_config.size()-1, 1);
} else {
type = esvg::distance_pixel;
Log.verbose("default dimention type for: '" << _config << "' ==> pixel");
return;
}
Vector2f tmp = _config;
set(tmp, type);
Log.verbose(" config dimention : \"" << _config << "\" == > " << *this );
}
static enum esvg::distance parseType(etk::String& _config) {
enum esvg::distance type = esvg::distance_pixel;
if (etk::end_with(_config, "%", false) == true) {
type = esvg::distance_pourcent;
_config.erase(_config.size()-1, 1);
} else if (etk::end_with(_config, "px",false) == true) {
type = esvg::distance_pixel;
_config.erase(_config.size()-2, 2);
} else if (etk::end_with(_config, "ft",false) == true) {
type = esvg::distance_foot;
_config.erase(_config.size()-2, 2);
} else if (etk::end_with(_config, "in",false) == true) {
type = esvg::distance_inch;
_config.erase(_config.size()-2, 2);
} else if (etk::end_with(_config, "km",false) == true) {
type = esvg::distance_kilometer;
_config.erase(_config.size()-2, 2);
} else if (etk::end_with(_config, "mm",false) == true) {
type = esvg::distance_millimeter;
_config.erase(_config.size()-2, 2);
} else if (etk::end_with(_config, "cm",false) == true) {
type = esvg::distance_centimeter;
_config.erase(_config.size()-2, 2);
} else if (etk::end_with(_config, "m",false) == true) {
type = esvg::distance_meter;
_config.erase(_config.size()-1, 1);
} else {
type = esvg::distance_pixel;
Log.verbose("default dimention type for: '" << _config << "' ==> pixel");
}
return type;
}
void esvg::Dimension::set(etk::String _configX, etk::String _configY) {
this.data.setValue(0,0);
this.type = esvg::distance_pixel;
enum distance type = esvg::distance_pixel;
// First Parse X
enum distance typeX = parseType(_configX);
float valueX = etk::string_to_float(_configX);
// Second Parse Y
enum distance typeY = parseType(_configY);
float valueY = etk::string_to_float(_configY);
// TODO : Check difference ...
set(Vector2f(valueX, valueY), typeX);
Log.verbose(" config dimention : '" << _configX << "' '" << _configY << "' == > " << *this );
}
esvg::Dimension::~Dimension() {
// nothing to do ...
}
esvg::Dimension::operator etk::String() const {
etk::String str;
str = getValue();
switch(getType()) {
case esvg::distance_pourcent:
str += "%";
break;
case esvg::distance_pixel:
str += "px";
break;
case esvg::distance_meter:
str += "m";
break;
case esvg::distance_centimeter:
str += "cm";
break;
case esvg::distance_millimeter:
str += "mm";
break;
case esvg::distance_kilometer:
str += "km";
break;
case esvg::distance_inch:
str += "in";
break;
case esvg::distance_foot:
str += "ft";
break;
case esvg::distance_element:
str += "em";
break;
case esvg::distance_ex:
str += "ex";
break;
case esvg::distance_point:
str += "pt";
break;
case esvg::distance_pc:
str += "pc";
break;
}
return str;
}
void esvg::Dimension::set(const Vector2f& _size, enum esvg::distance _type) {
this.data = _size;
this.type = _type;
switch(_type) {
case esvg::distance_pourcent:
case esvg::distance_pixel:
// nothing to do: Supported ...
break;
case esvg::distance_meter:
case esvg::distance_centimeter:
case esvg::distance_millimeter:
case esvg::distance_kilometer:
case esvg::distance_inch:
case esvg::distance_foot:
case esvg::distance_element:
case esvg::distance_ex:
case esvg::distance_point:
case esvg::distance_pc:
Log.error("Does not support other than Px and % type of dimention : " << _type << " automaticly convert with {72,72} pixel/inch");
break;
}
}
Vector2f esvg::Dimension::getPixel(const Vector2f& _upperSize) const {
switch(this.type) {
case esvg::distance_pourcent:
return Vector2f(_upperSize.x()*this.data.x()*0.01f, _upperSize.y()*this.data.y()*0.01f);
case esvg::distance_pixel:
return this.data;
case esvg::distance_meter:
return Vector2f(this.data.x()*meterToMillimeter*basicRatio, this.data.y()*meterToMillimeter*basicRatio);
case esvg::distance_centimeter:
return Vector2f(this.data.x()*centimeterToMillimeter*basicRatio, this.data.y()*centimeterToMillimeter*basicRatio);
case esvg::distance_millimeter:
return Vector2f(this.data.x()*basicRatio, this.data.y()*basicRatio);
case esvg::distance_kilometer:
return Vector2f(this.data.x()*kilometerToMillimeter*basicRatio, this.data.y()*kilometerToMillimeter*basicRatio);
case esvg::distance_inch:
return Vector2f(this.data.x()*inchToMillimeter*basicRatio, this.data.y()*inchToMillimeter*basicRatio);
case esvg::distance_foot:
return Vector2f(this.data.x()*footToMillimeter*basicRatio, this.data.y()*footToMillimeter*basicRatio);
}
return Vector2f(128.0f, 128.0f);
}
etk::Stream& esvg::operator <<(etk::Stream& _os, enum esvg::distance _obj) {
switch(_obj) {
case esvg::distance_pourcent:
_os << "%";
break;
case esvg::distance_pixel:
_os << "px";
break;
case esvg::distance_meter:
_os << "m";
break;
case esvg::distance_centimeter:
_os << "cm";
break;
case esvg::distance_millimeter:
_os << "mm";
break;
case esvg::distance_kilometer:
_os << "km";
break;
case esvg::distance_inch:
_os << "in";
break;
case esvg::distance_foot:
_os << "ft";
break;
case esvg::distance_element:
_os << "em";
break;
case esvg::distance_ex:
_os << "ex";
break;
case esvg::distance_point:
_os << "pt";
break;
case esvg::distance_pc:
_os << "pc";
break;
}
return _os;
}
etk::Stream& esvg::operator <<(etk::Stream& _os, const esvg::Dimension& _obj) {
_os << _obj.getValue() << _obj.getType();
return _os;
}
namespace etk {
template<> etk::String toString<esvg::Dimension>(const esvg::Dimension& _obj) {
return _obj;
}
template<> etk::UString toUString<esvg::Dimension>(const esvg::Dimension& _obj) {
return etk::toUString(etk::toString(_obj));
}
template<> boolean frothis.string<esvg::Dimension>(esvg::Dimension& _variableRet, const etk::String& _value) {
_variableRet = esvg::Dimension(_value);
return true;
}
template<> boolean frothis.string<esvg::Dimension>(esvg::Dimension& _variableRet, const etk::UString& _value) {
return frothis.string(_variableRet, etk::toString(_value));
}
};
esvg::Dimension1D::Dimension1D() :
this.data(0.0f),
this.type(esvg::distance_pixel) {
// notinh to do ...
}
esvg::Dimension1D::Dimension1D(float _size, enum esvg::distance _type) :
this.data(0.0f),
this.type(esvg::distance_pixel) {
set(_size, _type);
}
void esvg::Dimension1D::set(etk::String _config) {
this.data = 0;
this.type = esvg::distance_pixel;
enum distance type = esvg::distance_pixel;
if (etk::end_with(_config, "%", false) == true) {
type = esvg::distance_pourcent;
_config.erase(_config.size()-1, 1);
} else if (etk::end_with(_config, "px",false) == true) {
type = esvg::distance_pixel;
_config.erase(_config.size()-2, 2);
} else if (etk::end_with(_config, "ft",false) == true) {
type = esvg::distance_foot;
_config.erase(_config.size()-2, 2);
} else if (etk::end_with(_config, "in",false) == true) {
type = esvg::distance_inch;
_config.erase(_config.size()-2, 2);
} else if (etk::end_with(_config, "km",false) == true) {
type = esvg::distance_kilometer;
_config.erase(_config.size()-2, 2);
} else if (etk::end_with(_config, "mm",false) == true) {
type = esvg::distance_millimeter;
_config.erase(_config.size()-2, 2);
} else if (etk::end_with(_config, "cm",false) == true) {
type = esvg::distance_centimeter;
_config.erase(_config.size()-2, 2);
} else if (etk::end_with(_config, "m",false) == true) {
type = esvg::distance_meter;
_config.erase(_config.size()-1, 1);
} else {
type = esvg::distance_pixel;
Log.verbose("default dimention type for: '" << _config << "' ==> pixel");
}
float tmp = etk::string_to_float(_config);
set(tmp, type);
Log.verbose(" config dimention : \"" << _config << "\" == > " << *this );
}
esvg::Dimension1D::~Dimension1D() {
// nothing to do ...
}
esvg::Dimension1D::operator etk::String() const {
etk::String str;
str = getValue();
switch(getType()) {
case esvg::distance_pourcent:
str += "%";
break;
case esvg::distance_pixel:
str += "px";
break;
case esvg::distance_meter:
str += "m";
break;
case esvg::distance_centimeter:
str += "cm";
break;
case esvg::distance_millimeter:
str += "mm";
break;
case esvg::distance_kilometer:
str += "km";
break;
case esvg::distance_inch:
str += "in";
break;
case esvg::distance_foot:
str += "ft";
break;
case esvg::distance_element:
str += "em";
break;
case esvg::distance_ex:
str += "ex";
break;
case esvg::distance_point:
str += "pt";
break;
case esvg::distance_pc:
str += "pc";
break;
}
return str;
}
void esvg::Dimension1D::set(float _size, enum esvg::distance _type) {
this.data = _size;
this.type = _type;
switch(_type) {
case esvg::distance_pourcent:
case esvg::distance_pixel:
// nothing to do: Supported ...
break;
case esvg::distance_meter:
case esvg::distance_centimeter:
case esvg::distance_millimeter:
case esvg::distance_kilometer:
case esvg::distance_inch:
case esvg::distance_foot:
case esvg::distance_element:
case esvg::distance_ex:
case esvg::distance_point:
case esvg::distance_pc:
Log.error("Does not support other than Px and % type of dimention1D : " << _type << " automaticly convert with {72,72} pixel/inch");
break;
}
}
float esvg::Dimension1D::getPixel(float _upperSize) const {
switch(this.type) {
case esvg::distance_pourcent:
return _upperSize*this.data*0.01f;
case esvg::distance_pixel:
return this.data;
case esvg::distance_meter:
return this.data*meterToMillimeter*basicRatio;
case esvg::distance_centimeter:
return this.data*centimeterToMillimeter*basicRatio;
case esvg::distance_millimeter:
return this.data*basicRatio;
case esvg::distance_kilometer:
return this.data*kilometerToMillimeter*basicRatio;
case esvg::distance_inch:
return this.data*inchToMillimeter*basicRatio;
case esvg::distance_foot:
return this.data*footToMillimeter*basicRatio;
}
return 128.0f;
}
etk::Stream& esvg::operator <<(etk::Stream& _os, const esvg::Dimension1D& _obj) {
_os << _obj.getValue() << _obj.getType();
return _os;
}
namespace etk {
template<> etk::String toString<esvg::Dimension1D>(const esvg::Dimension1D& _obj) {
return _obj;
}
template<> etk::UString toUString<esvg::Dimension1D>(const esvg::Dimension1D& _obj) {
return etk::toUString(etk::toString(_obj));
}
template<> boolean frothis.string<esvg::Dimension1D>(esvg::Dimension1D& _variableRet, const etk::String& _value) {
_variableRet = esvg::Dimension1D(_value);
return true;
}
template<> boolean frothis.string<esvg::Dimension1D>(esvg::Dimension1D& _variableRet, const etk::UString& _value) {
return frothis.string(_variableRet, etk::toString(_value));
}
};

View File

@ -1,253 +0,0 @@
package org.atriasoft.esvg;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<etk/types.hpp>#include<etk/math/Vector2D.hpp>
namespace esvg{
/**
* in the dimention class we store the data as the more usefull unit (pixel)
* but one case need to be dynamic the %, then when requested in % the register the % value
*/
class Dimension {
private:Vector2f this.data;
enum distance this.type;
public:
/**
* Constructor (default :0,0 mode pixel)
*/
Dimension();
/**
* Constructor
* @param _size Requested dimention
* @param _type Unit of the Dimention
*/
Dimension(const Vector2f& _size, enum esvg::distance _type=esvg::distance_pixel);
/**
* Constructor
* @param _config dimension configuration.
*/
Dimension(const etk::String& _config) :
this.data(0,0),
this.type(esvg::distance_pixel) {
set(_config);
};
/**
* Constructor
* @param _configX dimension X configuration.
* @param _configY dimension Y configuration.
*/
Dimension(const etk::String& _configX, const etk::String& _configY) :
this.data(0,0),
this.type(esvg::distance_pixel) {
set(_configX, _configY);
};
/**
* Destructor
*/
~Dimension();
/**
* string cast :
*/
operator etk::String() const;
/**
* get the current dimention.
* @return dimention requested.
*/
const Vector2f& getValue() const {
return this.data;
}
/**
* @breif get the dimension type
* @return the type
*/
enum distance getType() const {
return this.type;
};
/**
* set the current dimention in requested type
* @param _size Dimention to set
* @param _type Type of unit requested.
*/
void set(const Vector2f& _size, enum distance _type);
public:
/**
* set the current dimention in requested type
* @param _config dimension configuration.
*/
void set(etk::String _config);
/**
* set the current dimention in requested type
* @param _configX dimension X configuration.
* @param _configY dimension Y configuration.
*/
void set(etk::String _configX, etk::String _configY);
public:
/**
* get the current dimention in pixel
* @param _upperSize Size in pixel of the upper value
* @return dimention in Pixel
*/
Vector2f getPixel(const Vector2f& _upperSize) const;
/*****************************************************
* = assigment
*****************************************************/
const Dimension& operator= (const Dimension& _obj ) {
if (this!=&_obj) {
this.data = _obj.this.data;
this.type = _obj.this.type;
}
return *this;
}
/*****************************************************
* == operator
*****************************************************/
boolean operator == (const Dimension& _obj) const {
if( this.data == _obj.this.data
&& this.type == _obj.this.type) {
return true;
}
return false;
}
/*****************************************************
* != operator
*****************************************************/
boolean operator!= (const Dimension& _obj) const {
if( this.data != _obj.this.data
|| this.type != _obj.this.type) {
return true;
}
return false;
}
};
etk::Stream& operator <<(etk::Stream& _os, enum esvg::distance _obj);
etk::Stream& operator <<(etk::Stream& _os, const esvg::Dimension& _obj);
/**
* in the dimention class we store the data as the more usefull unit (pixel)
* but one case need to be dynamic the %, then when requested in % the register the % value
*/
class Dimension1D {
private:
float this.data;
enum distance this.type;
public:
/**
* Constructor (default :0,0 mode pixel)
*/
Dimension1D();
/**
* Constructor
* @param _size Requested dimention
* @param _type Unit of the Dimention
*/
Dimension1D(float _size, enum esvg::distance _type=esvg::distance_pixel);
/**
* Constructor
* @param _config dimension configuration.
*/
Dimension1D(const etk::String& _config) :
this.data(0.0f),
this.type(esvg::distance_pixel) {
set(_config);
};
/**
* Destructor
*/
~Dimension1D();
/**
* string cast :
*/
operator etk::String() const;
/**
* get the current dimention.
* @return dimention requested.
*/
const float& getValue() const {
return this.data;
}
/**
* @breif get the dimension type
* @return the type
*/
enum distance getType() const {
return this.type;
};
/**
* set the current dimention in requested type
* @param _size Dimention to set
* @param _type Type of unit requested.
*/
void set(float _size, enum distance _type);
public:
/**
* set the current dimention in requested type
* @param _config dimension configuration.
*/
void set(etk::String _config);
public:
/**
* get the current dimention in pixel
* @param _upperSize Size in pixel of the upper value
* @return dimention in Pixel
*/
float getPixel(float _upperSize) const;
/*****************************************************
* = assigment
*****************************************************/
const Dimension1D& operator= (const Dimension1D& _obj ) {
if (this!=&_obj) {
this.data = _obj.this.data;
this.type = _obj.this.type;
}
return *this;
}
/*****************************************************
* == operator
*****************************************************/
boolean operator == (const Dimension1D& _obj) const {
if( this.data == _obj.this.data
&& this.type == _obj.this.type) {
return true;
}
return false;
}
/*****************************************************
* != operator
*****************************************************/
boolean operator!= (const Dimension1D& _obj) const {
if( this.data != _obj.this.data
|| this.type != _obj.this.type) {
return true;
}
return false;
}
};
etk::Stream& operator <<(etk::Stream& _os, const esvg::Dimension1D& _obj);
}
;
enum distance {
distance_pourcent=0, //!< "%"
distance_pixel, //!< "px"
distance_meter, //!< "m"
distance_centimeter, //!< "cm"
distance_millimeter, //!< "mm"
distance_kilometer, //!< "km"
distance_inch, //!< "in"
distance_foot, //!< "ft"
distance_element, //!< "em"
distance_ex, //!< "ex"
distance_point, //!< "pt"
distance_pc //!< "pc"
}

View File

@ -1,172 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/debug.hpp>
#include <esvg/Ellipse.hpp>
#include <esvg/render/Path.hpp>
#include <esvg/render/Weight.hpp>
esvg::Ellipse::Ellipse(PaintState _parentPaintState) : esvg::Base(_parentPaintState) {
}
esvg::Ellipse::~Ellipse() {
}
boolean esvg::Ellipse::parseXML(const exml::Element& _element, mat2x3& _parentTrans, Vector2f& _sizeMax) {
if (_element.exist() == false) {
return false;
}
parseTransform(_element);
parsePaintAttr(_element);
// add the property of the parrent modifications ...
this.transformMatrix *= _parentTrans;
this.c.setValue(0,0);
this.r.setValue(0,0);
etk::String content = _element.attributes["cx"];
if (content.size()!=0) {
this.c.setX(parseLength(content));
}
content = _element.attributes["cy"];
if (content.size()!=0) {
this.c.setY(parseLength(content));
}
content = _element.attributes["rx"];
if (content.size()!=0) {
this.r.setX(parseLength(content));
} else {
Log.error("(l "<<_element.getPos()<<") Ellipse \"rx\" is not present");
return false;
}
content = _element.attributes["ry"];
if (content.size()!=0) {
this.r.setY(parseLength(content));
} else {
Log.error("(l "<<_element.getPos()<<") Ellipse \"ry\" is not present");
return false;
}
_sizeMax.setValue(this.c.x() + this.r.x(), this.c.y() + this.r.y());
return true;
}
void esvg::Ellipse::display(int _spacing) {
Log.debug(spacingDist(_spacing) << "Ellipse c=" << this.c << " r=" << this.r);
}
esvg::render::Path esvg::Ellipse::createPath() {
esvg::render::Path out;
out.clear();
out.moveTo(false, this.c + Vector2f(this.r.x(), 0.0f));
out.curveTo(false,
this.c + Vector2f(this.r.x(), this.r.y()*esvg::kappa90),
this.c + Vector2f(this.r.x()*esvg::kappa90, this.r.y()),
this.c + Vector2f(0.0f, this.r.y()));
out.curveTo(false,
this.c + Vector2f(-this.r.x()*esvg::kappa90, this.r.y()),
this.c + Vector2f(-this.r.x(), this.r.y()*esvg::kappa90),
this.c + Vector2f(-this.r.x(), 0.0f));
out.curveTo(false,
this.c + Vector2f(-this.r.x(), -this.r.y()*esvg::kappa90),
this.c + Vector2f(-this.r.x()*esvg::kappa90, -this.r.y()),
this.c + Vector2f(0.0f, -this.r.y()));
out.curveTo(false,
this.c + Vector2f(this.r.x()*esvg::kappa90, -this.r.y()),
this.c + Vector2f(this.r.x(), -this.r.y()*esvg::kappa90),
this.c + Vector2f(this.r.x(), 0.0f));
out.close();
return out;
}
void esvg::Ellipse::draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int _level) {
Log.verbose(spacingDist(_level) << "DRAW esvg::Ellipse");
if ( this.r.x()<=0.0f
|| this.r.y()<=0.0f) {
Log.verbose(spacingDist(_level+1) << "Too small radius" << this.r);
return;
}
esvg::render::Path listElement = createPath();
mat2x3 mtx = this.transformMatrix;
mtx *= _basicTrans;
esvg::render::PointList listPoints;
listPoints = listElement.generateListPoints(_level,
_myRenderer.getInterpolationRecurtionMax(),
_myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx);
esvg::render::SegmentList listSegmentFill;
esvg::render::SegmentList listSegmentStroke;
esvg::render::Weight tmpFill;
esvg::render::Weight tmpStroke;
ememory::SharedPtr<esvg::render::DynamicColor> colorFill = esvg::render::createColor(this.paint.fill, mtx);
ememory::SharedPtr<esvg::render::DynamicColor> colorStroke;
if (this.paint.strokeWidth > 0.0f) {
colorStroke = esvg::render::createColor(this.paint.stroke, mtx);
}
// Check if we need to display background
if (colorFill != null) {
listSegmentFill.createSegmentList(listPoints);
colorFill->setViewPort(listSegmentFill.getViewPort());
listSegmentFill.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpFill.generate(_myRenderer.getSize(),
_myRenderer.getNumberSubScanLine(),
listSegmentFill);
}
// check if we need to display stroke:
if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints,
this.paint.strokeWidth,
this.paint.lineCap,
this.paint.lineJoin,
this.paint.miterLimit);
colorStroke->setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpStroke.generate(_myRenderer.getSize(),
_myRenderer.getNumberSubScanLine(),
listSegmentStroke);
}
// add on images:
_myRenderer.print(tmpFill,
colorFill,
tmpStroke,
colorStroke,
this.paint.opacity);
#ifdef DEBUG
_myRenderer.addDebugSegment(listSegmentFill);
_myRenderer.addDebugSegment(listSegmentStroke);
#endif
}
void esvg::Ellipse::drawShapePoints(List<etk::Vector<Vector2f>>& _out,
int _recurtionMax,
float _threshold,
mat2x3& _basicTrans,
int _level) {
Log.verbose(spacingDist(_level) << "DRAW Shape esvg::Ellipse");
esvg::render::Path listElement = createPath();
mat2x3 mtx = this.transformMatrix;
mtx *= _basicTrans;
esvg::render::PointList listPoints;
listPoints = listElement.generateListPoints(_level, _recurtionMax, _threshold);
listPoints.applyMatrix(mtx);
for (auto &it : listPoints.this.data) {
List<Vector2f> listPoint;
for (auto &itDot : it) {
listPoint.pushBack(itDot.this.pos);
}
_out.pushBack(listPoint);
}
}

View File

@ -1,35 +1,149 @@
package org.atriasoft.esvg;
import java.util.ArrayList;
import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.Point;
import org.atriasoft.esvg.render.PointList;
import org.atriasoft.esvg.render.SegmentList;
import org.atriasoft.esvg.render.Weight;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.exml.model.XmlElement;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<esvg/Base.hpp>
namespace esvg{
class Ellipse extends esvg::Base
{
public class Ellipse extends Base {
private Vector2f c; //!< Center property of the ellipse
private Vector2f r; //!< Radius property of the ellipse
public Ellipse(final PaintState _parentPaintState) {
super(_parentPaintState);
public Ellipse(final PaintState parentPaintState) {
super(parentPaintState);
}
public boolean parseXML(const exml::Element& _element, mat2x3& _parentTrans, Vector2f& _sizeMax) override;
PathModel createPath() {
PathModel out = new PathModel();
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() * 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.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();
return out;
}
public void display(final int _spacing) override;
@Override
public void display(final int spacing) {
Log.debug(spacingDist(spacing) + "Ellipse c=" + this.c + " r=" + this.r);
}
public void draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int _level) override;
@Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW esvg::Ellipse");
if (this.r.x() <= 0.0f || this.r.y() <= 0.0f) {
Log.verbose(spacingDist(level + 1) + "Too small radius" + this.r);
return;
}
PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix;
mtx = mtx.multiply(basicTrans);
PointList listPoints = new PointList();
listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx);
SegmentList listSegmentFill = new SegmentList();
SegmentList listSegmentStroke = new SegmentList();
Weight tmpFill = new Weight();
Weight tmpStroke = new Weight();
DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx);
DynamicColor colorStroke = null;
if (this.paint.strokeWidth > 0.0f) {
colorStroke = DynamicColor.createColor(this.paint.stroke, mtx);
}
// Check if we need to display background
if (colorFill != null) {
listSegmentFill.createSegmentList(listPoints);
colorFill.setViewPort(listSegmentFill.getViewPort());
listSegmentFill.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpFill.generate(myRenderer.getSize(), myRenderer.getNumberSubScanLine(), listSegmentFill);
}
// check if we need to display stroke:
if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit);
colorStroke.setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpStroke.generate(myRenderer.getSize(), myRenderer.getNumberSubScanLine(), listSegmentStroke);
}
// add on images:
myRenderer.print(tmpFill, colorFill, tmpStroke, colorStroke, this.paint.opacity);
//myRenderer.addDebugSegment(listSegmentFill);
//myRenderer.addDebugSegment(listSegmentStroke)
}
public void drawShapePoints(final List<List<Vector2f>> _out,
final int _recurtionMax,
final float _threshold,
mat2x3& _basicTrans,
int _level=1) override;
private esvg::render::
@Override
public void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW Shape esvg::Ellipse");
PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix;
mtx = mtx.multiply(basicTrans);
PointList listPoints;
listPoints = listElement.generateListPoints(level, recurtionMax, threshold);
listPoints.applyMatrix(mtx);
for (List<Point> it : listPoints.data) {
List<Vector2f> listPoint = new ArrayList<>();
for (Point itDot : it) {
listPoint.add(itDot.pos);
}
out.add(listPoint);
}
}
Path createPath();
};}
@Override
public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) {
if (element == null) {
return false;
}
parseTransform(element);
parsePaintAttr(element);
// add the property of the parrent modifications ...
this.transformMatrix = this.transformMatrix.multiply(parentTrans);
this.c = Vector2f.ZERO;
this.r = Vector2f.ZERO;
String content = element.getAttribute("cx", "");
if (content.length() != 0) {
this.c = this.c.withX(parseLength(content));
}
content = element.getAttribute("cy", "");
if (content.length() != 0) {
this.c = this.c.withY(parseLength(content));
}
content = element.getAttribute("rx", "");
if (content.length() == 0) {
Log.error("Ellipse \"rx\" is not present");
return false;
}
this.r = this.r.withX(parseLength(content));
content = element.getAttribute("ry", "");
if (content.length() == 0) {
Log.error("Ellipse \"ry\" is not present");
return false;
}
this.r = this.r.withY(parseLength(content));
sizeMax.value = new Vector2f(this.c.x() + this.r.x(), this.c.y() + this.r.y());
return true;
}
}

View File

@ -0,0 +1,449 @@
package org.atriasoft.esvg;
import java.util.ArrayList;
import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.Color;
import org.atriasoft.etk.Uri;
import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.math.Vector2i;
import org.atriasoft.exml.Exml;
import org.atriasoft.exml.exception.ExmlBuilderException;
import org.atriasoft.exml.exception.ExmlNodeDoesNotExist;
import org.atriasoft.exml.model.XmlElement;
import org.atriasoft.exml.model.XmlNode;
public class EsvgDocument extends Base {
private boolean loadOK = false;
private List<Base> refList;
private Vector2f size = Vector2f.ZERO;
private List<Base> subElementList;
private String title = ""; //!< sub-element list
private Uri uri = null; //!< reference elements ...
private String version = "0.0";
public EsvgDocument() {
}
/**
* change all style in a xml atribute
*/
public boolean cleanStyleProperty(final XmlElement root) {
// for each nodes:
for (XmlNode it : root.getNodes()) {
if (!(it instanceof XmlElement child)) {
continue;
}
// get attribute style:
if (child.existAttribute("style")) {
String content = child.getAttribute("style", "");
if (content.length() != 0) {
String[] listStyle = content.split(";");
for (String it1 : listStyle) {
String[] value = it1.split(":");
if (value.length != 2) {
Log.error("parsing style with a wrong patern : " + it1 + " missing ':'");
continue;
}
// TODO Check if the attibute already exist ...
child.setAttribute(value[0], value[1]);
}
}
// remove attribute style:
child.removeAttribute("style");
}
// sub-parsing ...
cleanStyleProperty(child);
}
return true;
}
public void clear() {
this.uri = null;
this.version = "0.0";
this.loadOK = true;
this.paint.clear();
this.size = Vector2f.ZERO;
}
/**
* Display all the node in the svg file.
*/
public void displayDebug() {
Log.debug("Main SVG: size=" + this.size);
Log.debug(" refs:");
for (int iii = 0; iii < this.refList.size(); iii++) {
if (this.refList.get(iii) != null) {
this.refList.get(iii).display(2);
}
}
Log.debug(" Nodes:");
for (int iii = 0; iii < this.subElementList.size(); iii++) {
if (this.subElementList.get(iii) != null) {
this.subElementList.get(iii).display(2);
}
}
}
@Override
protected void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
for (int iii = 0; iii < this.subElementList.size(); iii++) {
if (this.subElementList.get(iii) != null) {
this.subElementList.get(iii).draw(myRenderer, basicTrans);
}
}
}
@Override
protected void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW shape EsvgDocument");
for (Base it : this.subElementList) {
if (it != null) {
it.drawShapePoints(out, recurtionMax, threshold, basicTrans, level + 1);
}
}
}
/**
* generate a string that contain the created SVG
* @param data Data where the svg is stored
* @return false : An error occured
* @return true : Parsing is OK
*/
public boolean generate(final String data) {
return false;
}
public void generateAnImage(final Uri uri) {
generateAnImage(uri, false);
}
public void generateAnImage(final Uri uri, final boolean visualDebug) {
generateAnImage(new Vector2i((int) this.size.x(), (int) this.size.y()), uri, visualDebug);
}
public void generateAnImage(final Vector2i size, final Uri uri) {
generateAnImage(size, uri, false);
}
public void generateAnImage(final Vector2i size, final Uri uri, final boolean visualDebug) {
Vector2i sizeRender = size;
if (sizeRender.x() <= 0) {
sizeRender = sizeRender.withX((int) this.size.x());
}
if (sizeRender.y() <= 0) {
sizeRender = sizeRender.withY((int) this.size.y());
}
Log.debug("Generate size " + sizeRender);
Renderer renderedElement = new Renderer(sizeRender, this, visualDebug);
// create the first element matrix modification ...
Matrix2x3f basicTrans = Matrix2x3f.IDENTITY.multiply(Matrix2x3f.createScale(new Vector2f(sizeRender.x() / this.size.x(), sizeRender.y() / this.size.y())));
draw(renderedElement, basicTrans);
if (uri.getExtention().equals("ppm")) {
renderedElement.writePPM(uri);
} else {
Log.error("Can not store with this extention : " + uri + " not in .bmp/.ppm");
}
}
// TODO remove this fucntion : use generic function ...
public Vector2f getDefinedSize() {
return this.size;
}
public List<List<Vector2f>> getLines() {
return getLines(new Vector2f(256, 256));
}
public List<List<Vector2f>> getLines(Vector2f size) {
List<List<Vector2f>> out = new ArrayList<>();
if (size.x() <= 0) {
size = size.withX(this.size.x());
}
if (size.y() <= 0) {
size = size.withY(this.size.y());
}
Log.debug("lineification size " + size);
// 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())));
drawShapePoints(out, 10, 0.25f, basicTrans);
return out;
}
public Base getReference(final String name) {
if (name == "") {
Log.error("request a reference with no name ... ");
return null;
}
for (Base it : this.refList) {
if (it == null) {
continue;
}
if (it.getId() == name) {
return it;
}
}
Log.error("Can not find reference name : '" + name + "'");
return null;
}
public boolean isLoadOk() {
return this.loadOK;
}
/*
//! @previous
public List<Color> renderImageFloatRGB(final Vector2i size) {
List<Color> data = renderImageFloatRGBA(size);
// Reduce scope:
List<Color<float,3>> out;
out.resize(data.size());
for (sizet iii=0; iii<data.size(); ++iii) {
out[iii] = data[iii];
}
return out;
}
//! @previous
public List<Color<uint8t,4>> renderImageU8RGBA(final Vector2i size) {
List<Color> data = renderImageFloatRGBA(size);
// Reduce scope:
List<Color<uint8t,4>> out;
out.resize(data.size());
for (sizet iii=0; iii<data.size(); ++iii) {
out[iii] = data[iii];
}
return out;
}
//! @previous
public List<Color<uint8t,3>> renderImageU8RGB(final Vector2i size) {
List<Color> data = renderImageFloatRGBA(size);
// Reduce scope:
List<Color<uint8t,3>> out;
out.resize(data.size());
for (sizet iii=0; iii<data.size(); ++iii) {
out[iii] = data[iii];
}
return out;
}
*/
/**
* Load the file that might contain the svg
* @param uri File of the svg
* @return false : An error occured
* @return true : Parsing is OK
*/
public boolean load(final Uri uri) {
clear();
this.uri = uri;
XmlNode doc = null;
try {
doc = Exml.parse(uri);
} catch (ExmlBuilderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
if (doc instanceof XmlElement elem && elem.existNode("svg")) {
try {
if (elem.getNode("svg") instanceof XmlElement rootElement) {
cleanStyleProperty(rootElement);
this.loadOK = parseXMLData(rootElement);
}
} catch (ExmlNodeDoesNotExist e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}
return this.loadOK;
}
/**
* parse a string that contain an svg stream
* @param data Data to parse
* @return false : An error occured
* @return true : Parsing is OK
*/
public boolean parse(final String data) {
clear();
this.uri = null;
XmlNode doc = null;
try {
doc = Exml.parse(data);
} catch (ExmlBuilderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
if (doc instanceof XmlElement elem && elem.existNode("svg")) {
try {
if (elem.getNode("svg") instanceof XmlElement rootElement) {
cleanStyleProperty(rootElement);
this.loadOK = parseXMLData(rootElement);
}
} catch (ExmlNodeDoesNotExist e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}
return this.loadOK;
}
public boolean parseXMLData(final XmlElement root) {
return parseXMLData(root, false);
}
public boolean parseXMLData(final XmlElement root, final boolean isReference) {
// get the svg version :
this.version = root.getAttribute("version", "");
// parse ...
Vector2f pos = Vector2f.ZERO;
if (!isReference) {
parseTransform(root);
pos = parseXmlPosition(root);
this.size = parseXmlSize(root);
parsePaintAttr(root);
Log.verbose("parsed .ROOT trans: " + this.transformMatrix);
} else {
Log.verbose("Parse Reference section ... (no attibute)");
}
Vector2f maxSize = Vector2f.ZERO;
Dynamic<Vector2f> size = new Dynamic<>(Vector2f.ZERO);
// parse all sub node:
for (XmlNode it : root.getNodes()) {
if (!(it instanceof XmlElement child)) {
// comment can be here...
continue;
}
Base elementParser = null;
if (child.getValue().equals("g")) {
elementParser = new Group(this.paint);
} else if (child.getValue().equals("a")) {
Log.info("Note : 'a' balise is parsed like a g balise ...");
elementParser = new Group(this.paint);
} else if (child.getValue().equals("title")) {
this.title = "TODO : set the title here ...";
continue;
} else if (child.getValue().equals("path")) {
elementParser = new Path(this.paint);
} else if (child.getValue().equals("rect")) {
elementParser = new Rectangle(this.paint);
} else if (child.getValue().equals("circle")) {
elementParser = new Circle(this.paint);
} else if (child.getValue().equals("ellipse")) {
elementParser = new Ellipse(this.paint);
} else if (child.getValue().equals("line")) {
elementParser = new Line(this.paint);
} else if (child.getValue().equals("polyline")) {
elementParser = new Polyline(this.paint);
} else if (child.getValue().equals("polygon")) {
elementParser = new Polygon(this.paint);
} else if (child.getValue().equals("text")) {
elementParser = new Text(this.paint);
} else if (child.getValue().equals("radialGradient")) {
if (!isReference) {
Log.error("'" + child.getValue() + "' node must not be defined outside a defs Section");
continue;
}
elementParser = new RadialGradient(this.paint);
} else if (child.getValue().equals("linearGradient")) {
if (!isReference) {
Log.error("'" + child.getValue() + "' node must not be defined outside a defs Section");
continue;
}
elementParser = new LinearGradient(this.paint);
} else if (child.getValue().equals("defs")) {
if (isReference) {
Log.error("'" + child.getValue() + "' node must not be defined in a defs Section");
continue;
}
boolean retRefs = parseXMLData(child, true);
// TODO Use retRefs ...
continue;
} else if (child.getValue().equals("sodipodi:namedview")) {
// Node ignore : generaly inkscape data
continue;
} else if (child.getValue().equals("metadata")) {
// Node ignore : generaly inkscape data
continue;
} else {
Log.error("node not suported : '" + child.getValue() + "' must be [title,g,a,path,rect,circle,ellipse,line,polyline,polygon,text,metadata]");
}
if (elementParser == null) {
Log.error("error on node: '" + child.getValue() + "' allocation error or not supported ...");
continue;
}
if (!elementParser.parseXML(child, this.transformMatrix, size)) {
Log.error("error on node: '" + child.getValue() + "' Sub Parsing ERROR");
elementParser = null;
continue;
}
if (maxSize.x() < size.value.x()) {
maxSize = maxSize.withX(size.value.x());
}
if (maxSize.y() < size.value.y()) {
maxSize = maxSize.withY(size.value.y());
}
// add element in the system
if (!isReference) {
this.subElementList.add(elementParser);
} else {
this.refList.add(elementParser);
}
}
if (this.size.x() == 0 || this.size.y() == 0) {
this.size = Vector2f.clipInt(maxSize);
} else {
this.size = Vector2f.clipInt(this.size);
}
if (!isReference) {
displayDebug();
}
return true;
}
/**
* Generate Image in a specific format.
* @param size Size expected of the rendered image (value <=0 if it need to be automatic.) return the size generate
* @return Vector of the data used to display (simple vector: generic to transmit)
*/
public Color[][] renderImageFloatRGBA(Vector2i size) {
if (size.x() <= 0) {
size = size.withX((int) this.size.x());
}
if (size.y() <= 0) {
size = size.withY((int) this.size.y());
}
Log.debug("Generate size " + size);
Renderer renderedElement = new Renderer(size, this);
// 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())));
draw(renderedElement, basicTrans);
// direct return the generated data ...
return renderedElement.getData();
}
/**
* Store the SVG in the file
* @param uri File of the svg
* @return false : An error occured
* @return true : Parsing is OK
*/
public boolean store(final Uri uri) {
Log.todo("not implemented store in SVG...");
return false;
}
}

View File

@ -1,13 +1,10 @@
package org.atriasoft.esvg;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/debug.hpp>
int esvg::getLogId() {
static int g_val = elog::registerInstance("esvg");
return g_val;
public enum GradientUnits {
gradientUnitsobjectBoundingBox, gradientUnitsuserSpaceOnUse
}

View File

@ -1,129 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/debug.hpp>
#include <esvg/Group.hpp>
#include <etk/types.hpp>
#include <esvg/Base.hpp>
#include <esvg/Circle.hpp>
#include <esvg/Ellipse.hpp>
#include <esvg/Line.hpp>
#include <esvg/Path.hpp>
#include <esvg/Polygon.hpp>
#include <esvg/Polyline.hpp>
#include <esvg/Rectangle.hpp>
#include <esvg/Text.hpp>
#include <esvg/Group.hpp>
esvg::Group::Group(PaintState _parentPaintState) : esvg::Base(_parentPaintState) {
}
esvg::Group::~Group() {
}
boolean esvg::Group::parseXML(const exml::Element& _element, mat2x3& _parentTrans, Vector2f& _sizeMax) {
if (_element.exist() == false) {
return false;
}
// parse ...
Vector2f pos(0,0);
Vector2f size(0,0);
parseTransform(_element);
parsePosition(_element, pos, size);
parsePaintAttr(_element);
Log.verbose("parsed G1. trans : " << this.transformMatrix);
// add the property of the parrent modifications ...
this.transformMatrix *= _parentTrans;
Log.verbose("parsed G2. trans : " << this.transformMatrix);
_sizeMax.setValue(0,0);
Vector2f tmpPos(0,0);
// parse all sub node :
for(const auto it : _element.nodes) {
exml::Element child = it.toElement();
if (child.exist() == false) {
// can be a comment ...
continue;
}
ememory::SharedPtr<esvg::Base> elementParser;
if (child.getValue() == "g") {
elementParser = ememory::makeShared<esvg::Group>(this.paint);
} else if (child.getValue() == "a") {
// TODO ...
} else if (child.getValue() == "path") {
elementParser = ememory::makeShared<esvg::Path>(this.paint);
} else if (child.getValue() == "rect") {
elementParser = ememory::makeShared<esvg::Rectangle>(this.paint);
} else if (child.getValue() == "circle") {
elementParser = ememory::makeShared<esvg::Circle>(this.paint);
} else if (child.getValue() == "ellipse") {
elementParser = ememory::makeShared<esvg::Ellipse>(this.paint);
} else if (child.getValue() == "line") {
elementParser = ememory::makeShared<esvg::Line>(this.paint);
} else if (child.getValue() == "polyline") {
elementParser = ememory::makeShared<esvg::Polyline>(this.paint);
} else if (child.getValue() == "polygon") {
elementParser = ememory::makeShared<esvg::Polygon>(this.paint);
} else if (child.getValue() == "text") {
elementParser = ememory::makeShared<esvg::Text>(this.paint);
} else {
Log.error("(l " << child.getPos() << ") node not suported : '" << child.getValue() << "' must be [g,a,path,rect,circle,ellipse,line,polyline,polygon,text]");
}
if (elementParser == null) {
Log.error("(l " << child.getPos() << ") error on node: '" << child.getValue() << "' allocation error or not supported ...");
continue;
}
if (elementParser->parseXML(child, this.transformMatrix, tmpPos) == false) {
Log.error("(l " << child.getPos() << ") error on node: '" << child.getValue() << "' Sub Parsing ERROR");
elementParser.reset();
continue;
}
_sizeMax.setValue(etk::max(_sizeMax.x(), tmpPos.x()),
etk::max(_sizeMax.y(), tmpPos.y()));
// add element in the system
this.subElementList.pushBack(elementParser);
}
return true;
}
void esvg::Group::display(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
<< " stroke-width=" << this.paint.strokeWidth );
for (auto &it : this.subElementList) {
if (it != null) {
it->display(_spacing+1);
}
}
Log.debug(spacingDist(_spacing) << "Group (STOP)");
}
void esvg::Group::draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int _level) {
Log.verbose(spacingDist(_level) << "DRAW esvg::group");
for (auto &it : this.subElementList) {
if (it != null) {
it->draw(_myRenderer, _basicTrans, _level+1);
}
}
}
void esvg::Group::drawShapePoints(List<etk::Vector<Vector2f>>& _out,
int _recurtionMax,
float _threshold,
mat2x3& _basicTrans,
int _level) {
Log.verbose(spacingDist(_level) << "DRAW shape esvg::group");
for (auto &it : this.subElementList) {
if (it != null) {
it->drawShapePoints(_out, _recurtionMax, _threshold, _basicTrans, _level+1);
}
}
}

View File

@ -1,34 +1,122 @@
package org.atriasoft.esvg;
import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.exml.model.XmlElement;
import org.atriasoft.exml.model.XmlNode;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<esvg/Base.hpp>#include<etk/Vector.hpp>
namespace esvg{
class Group extends esvg::Base
{
private:
List<ememory::SharedPtr<esvg::Base>> this.subElementList; //!< sub elements ...
public:
public class Group extends Base {
private List<Base> subElementList; //!< sub elements ...
Group(PaintState _parentPaintState);~
public Group(final PaintState parentPaintState) {
super(parentPaintState);
}
Group();
@Override
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
+ " stroke-width=" + this.paint.strokeWidth);
for (Base it : this.subElementList) {
if (it != null) {
it.display(spacing + 1);
}
}
Log.debug(spacingDist(spacing) + "Group (STOP)");
}
boolean parseXML(const exml::Element& _element, mat2x3& _parentTrans, Vector2f& _sizeMax) override;
@Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW esvg::group");
for (Base it : this.subElementList) {
if (it != null) {
it.draw(myRenderer, basicTrans, level + 1);
}
}
}
void display(final int spacing) override;
@Override
public void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW shape esvg::group");
for (Base it : this.subElementList) {
if (it != null) {
it.drawShapePoints(out, recurtionMax, threshold, basicTrans, level + 1);
}
}
}
void draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int _level) override;
void drawShapePoints(final List<List<Vector2f>>& _out,
int _recurtionMax,
float _threshold,
mat2x3& _basicTrans,
int _level=1) override;
};
@Override
public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) {
if (element == null) {
return false;
}
// parse ...
Vector2f pos = Vector2f.ZERO;
Vector2f size = Vector2f.ZERO;
parseTransform(element);
pos = parseXmlPosition(element);
size = parseXmlSize(element);
parsePaintAttr(element);
Log.verbose("parsed G1. trans : " + this.transformMatrix);
// add the property of the parrent modifications ...
this.transformMatrix = this.transformMatrix.multiply(parentTrans);
Log.verbose("parsed G2. trans : " + this.transformMatrix);
sizeMax.value = Vector2f.ZERO;
Dynamic<Vector2f> tmpPos = new Dynamic<Vector2f>(Vector2f.ZERO);
// parse all sub node :
for (XmlNode it : element.getNodes()) {
if (!(it instanceof XmlElement child)) {
// can be a comment ...
continue;
}
Base elementParser = null;
if (child.getValue().equals("g")) {
elementParser = new Group(this.paint);
} else if (child.getValue().equals("a")) {
// TODO ...
} else if (child.getValue().equals("path")) {
elementParser = new Path(this.paint);
} else if (child.getValue().equals("rect")) {
elementParser = new Rectangle(this.paint);
} else if (child.getValue().equals("circle")) {
elementParser = new Circle(this.paint);
} else if (child.getValue().equals("ellipse")) {
elementParser = new Ellipse(this.paint);
} else if (child.getValue().equals("line")) {
elementParser = new Line(this.paint);
} else if (child.getValue().equals("polyline")) {
elementParser = new Polyline(this.paint);
} else if (child.getValue().equals("polygon")) {
elementParser = new Polygon(this.paint);
} else if (child.getValue().equals("text")) {
elementParser = new Text(this.paint);
} else {
Log.error("node not suported : '" + child.getValue() + "' must be [g,a,path,rect,circle,ellipse,line,polyline,polygon,text]");
}
if (elementParser == null) {
Log.error("error on node: '" + child.getValue() + "' allocation error or not supported ...");
continue;
}
if (!elementParser.parseXML(child, this.transformMatrix, tmpPos)) {
Log.error(" error on node: '" + child.getValue() + "' Sub Parsing ERROR");
elementParser = null;
continue;
}
sizeMax.value = Vector2f.max(sizeMax.value, tmpPos.value);
// add element in the system
this.subElementList.add(elementParser);
}
return true;
}
}

View File

@ -1,139 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/debug.hpp>
#include <esvg/Line.hpp>
#include <esvg/render/Path.hpp>
#include <esvg/render/Weight.hpp>
esvg::Line::Line(PaintState _parentPaintState) : esvg::Base(_parentPaintState) {
this.startPos.setValue(0,0);
this.stopPos.setValue(0,0);
}
esvg::Line::~Line() {
}
boolean esvg::Line::parseXML(const exml::Element& _element, mat2x3& _parentTrans, Vector2f& _sizeMax) {
// line must have a minimum size...
this.paint.strokeWidth = 1;
if (_element.exist() == false) {
return false;
}
parseTransform(_element);
parsePaintAttr(_element);
// add the property of the parrent modifications ...
this.transformMatrix *= _parentTrans;
etk::String content = _element.attributes["x1"];
if (content.size() != 0) {
this.startPos.setX(parseLength(content));
}
content = _element.attributes["y1"];
if (content.size() != 0) {
this.startPos.setY(parseLength(content));
}
content = _element.attributes["x2"];
if (content.size() != 0) {
this.stopPos.setX(parseLength(content));
}
content = _element.attributes["y2"];
if (content.size() != 0) {
this.stopPos.setY(parseLength(content));
}
_sizeMax.setValue(etk::max(this.startPos.x(), this.stopPos.x()),
etk::max(this.startPos.y(), this.stopPos.y()));
return true;
}
void esvg::Line::display(int _spacing) {
Log.debug(spacingDist(_spacing) << "Line " << this.startPos << " to " << this.stopPos);
}
esvg::render::Path esvg::Line::createPath() {
esvg::render::Path out;
out.clear();
out.moveTo(false, this.startPos);
out.lineTo(false, this.stopPos);
out.stop();
return out;
}
void esvg::Line::draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int _level) {
Log.verbose(spacingDist(_level) << "DRAW esvg::Line");
esvg::render::Path listElement = createPath();
mat2x3 mtx = this.transformMatrix;
mtx *= _basicTrans;
esvg::render::PointList listPoints;
listPoints = listElement.generateListPoints(_level,
_myRenderer.getInterpolationRecurtionMax(),
_myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx);
esvg::render::SegmentList listSegmentFill;
esvg::render::SegmentList listSegmentStroke;
esvg::render::Weight tmpFill;
esvg::render::Weight tmpStroke;
ememory::SharedPtr<esvg::render::DynamicColor> colorFill = esvg::render::createColor(this.paint.fill, mtx);
ememory::SharedPtr<esvg::render::DynamicColor> colorStroke;
if (this.paint.strokeWidth > 0.0f) {
colorStroke = esvg::render::createColor(this.paint.stroke, mtx);
}
// Check if we need to display background
// No background ...
// check if we need to display stroke:
if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints,
this.paint.strokeWidth,
this.paint.lineCap,
this.paint.lineJoin,
this.paint.miterLimit);
colorStroke->setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpStroke.generate(_myRenderer.getSize(),
_myRenderer.getNumberSubScanLine(),
listSegmentStroke);
}
// add on images:
_myRenderer.print(tmpFill,
colorFill,
tmpStroke,
colorStroke,
this.paint.opacity);
#ifdef DEBUG
_myRenderer.addDebugSegment(listSegmentFill);
_myRenderer.addDebugSegment(listSegmentStroke);
_myRenderer.addDebugSegment(listElement.this.debugInformation);
#endif
}
void esvg::Line::drawShapePoints(List<etk::Vector<Vector2f>>& _out,
int _recurtionMax,
float _threshold,
mat2x3& _basicTrans,
int _level) {
Log.verbose(spacingDist(_level) << "DRAW Shape esvg::Line");
esvg::render::Path listElement = createPath();
mat2x3 mtx = this.transformMatrix;
mtx *= _basicTrans;
esvg::render::PointList listPoints;
listPoints = listElement.generateListPoints(_level, _recurtionMax, _threshold);
listPoints.applyMatrix(mtx);
for (auto &it : listPoints.this.data) {
List<Vector2f> listPoint;
for (auto &itDot : it) {
listPoint.pushBack(itDot.this.pos);
}
_out.pushBack(listPoint);
}
}

View File

@ -1,37 +1,131 @@
package org.atriasoft.esvg;
import java.util.ArrayList;
import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.Point;
import org.atriasoft.esvg.render.PointList;
import org.atriasoft.esvg.render.SegmentList;
import org.atriasoft.esvg.render.Weight;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.exml.model.XmlElement;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<esvg/Base.hpp>
namespace esvg{
class Line extends Base {
private:
Vector2f this.startPos; //!< Start line position
Vector2f this.stopPos; //!< Stop line position
public:
public class Line extends Base {
private Vector2f startPos = Vector2f.ZERO; //!< Start line position
private Vector2f stopPos = Vector2f.ZERO; //!< Stop line position
Line(PaintState _parentPaintState);~
public Line(final PaintState parentPaintState) {
super(parentPaintState);
}
Line();
private PathModel createPath() {
PathModel out = new PathModel();
out.clear();
out.moveTo(false, this.startPos);
out.lineTo(false, this.stopPos);
out.stop();
return out;
}
boolean parseXML(const exml::Element& _element, mat2x3& _parentTrans, Vector2f& _sizeMax) override;
@Override
public void display(final int spacing) {
Log.debug(spacingDist(spacing) + "Line " + this.startPos + " to " + this.stopPos);
}
void display(final int _spacing) override;
@Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW esvg::Line");
PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
PointList listPoints = new PointList();
listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx);
SegmentList listSegmentFill = new SegmentList();
SegmentList listSegmentStroke = new SegmentList();
Weight tmpFill = new Weight();
Weight tmpStroke = new Weight();
DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx);
DynamicColor colorStroke = null;
if (this.paint.strokeWidth > 0.0f) {
colorStroke = DynamicColor.createColor(this.paint.stroke, mtx);
}
// Check if we need to display background
// No background ...
// check if we need to display stroke:
if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit);
colorStroke.setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpStroke.generate(myRenderer.getSize(), myRenderer.getNumberSubScanLine(), listSegmentStroke);
}
// add on images:
myRenderer.print(tmpFill, colorFill, tmpStroke, colorStroke, this.paint.opacity);
//myRenderer.addDebugSegment(listSegmentFill);
//myRenderer.addDebugSegment(listSegmentStroke);
//myRenderer.addDebugSegment(listElement.debugInformation);
}
void draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int _level) override;
@Override
public void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW Shape esvg::Line");
PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
PointList listPoints;
listPoints = listElement.generateListPoints(level, recurtionMax, threshold);
listPoints.applyMatrix(mtx);
for (List<Point> it : listPoints.data) {
List<Vector2f> listPoint = new ArrayList<>();
for (Point itDot : it) {
listPoint.add(itDot.pos);
}
out.add(listPoint);
}
}
void drawShapePoints(List<List<Vector2f>>& _out,
int _recurtionMax,
float _threshold,
mat2x3& _basicTrans,
int _level=1) override;
private:
esvg::render::
Path createPath();
};}
@Override
public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) {
// line must have a minimum size...
this.paint.strokeWidth = 1;
if (element == null) {
return false;
}
parseTransform(element);
parsePaintAttr(element);
// add the property of the parrent modifications ...
this.transformMatrix = this.transformMatrix.multiply(parentTrans);
String content = element.getAttribute("x1", "");
if (content.length() != 0) {
this.startPos = this.startPos.withX(parseLength(content));
}
content = element.getAttribute("y1", "");
if (content.length() != 0) {
this.startPos = this.startPos.withY(parseLength(content));
}
content = element.getAttribute("x2", "");
if (content.length() != 0) {
this.stopPos = this.stopPos.withX(parseLength(content));
}
content = element.getAttribute("y2", "");
if (content.length() != 0) {
this.stopPos = this.stopPos.withY(parseLength(content));
}
sizeMax.value = Vector2f.max(this.startPos, this.stopPos);
return true;
}
}

View File

@ -1,176 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/debug.hpp>
#include <esvg/LinearGradient.hpp>
#include <esvg/RadialGradient.hpp>
#include <esvg/render/Path.hpp>
#include <esvg/render/Weight.hpp>
#include <esvg/esvg.hpp>
esvg::LinearGradient::LinearGradient(PaintState _parentPaintState) :
esvg::Base(_parentPaintState),
this.pos1(Vector2f(50,50), esvg::distance_pourcent),
this.pos2(Vector2f(50,50), esvg::distance_pourcent),
this.unit(gradientUnits_objectBoundingBox),
this.spread(spreadMethod_pad) {
}
esvg::LinearGradient::~LinearGradient() {
}
boolean esvg::LinearGradient::parseXML(const exml::Element& _element, mat2x3& _parentTrans, Vector2f& _sizeMax) {
// line must have a minimum size...
//this.paint.strokeWidth = 1;
if (_element.exist() == false) {
return false;
}
// ---------------- get unique ID ----------------
this.id = _element.attributes["id"];
//parseTransform(_element);
//parsePaintAttr(_element);
// add the property of the parrent modifications ...
this.transformMatrix *= _parentTrans;
etk::String contentX = _element.attributes["x1"];
etk::String contentY = _element.attributes["y1"];
if ( contentX != ""
&& contentY != "") {
this.pos1.set(contentX, contentY);
}
contentX = _element.attributes["x2"];
contentY = _element.attributes["y2"];
if ( contentX != ""
&& contentY != "") {
this.pos2.set(contentX, contentY);
}
contentX = _element.attributes["gradientUnits"];
if (contentX == "userSpaceOnUse") {
this.unit = gradientUnits_userSpaceOnUse;
} else {
this.unit = gradientUnits_objectBoundingBox;
if ( contentX.size() != 0
&& contentX != "objectBoundingBox") {
Log.error("Parsing error of 'gradientUnits' ==> not suported value: '" << contentX << "' not in : {userSpaceOnUse/objectBoundingBox} use objectBoundingBox");
}
}
contentX = _element.attributes["spreadMethod"];
if (contentX == "reflect") {
this.spread = spreadMethod_reflect;
} else if (contentX == "repeat") {
this.spread = spreadMethod_repeat;
} else {
this.spread = spreadMethod_pad;
if ( contentX.size() != 0
&& contentX != "pad") {
Log.error("Parsing error of 'spreadMethod' ==> not suported value: '" << contentX << "' not in : {reflect/repeate/pad} use pad");
}
}
// note: xlink:href is incompatible with subNode "stop"
this.href = _element.attributes["xlink:href"];
if (this.href.size() != 0) {
this.href = etk::String(this.href.begin()+1, this.href.end());
}
// parse all sub node :
for(const auto it : _element.nodes) {
exml::Element child = it.toElement();
if (child.exist() == false) {
// can be a comment ...
continue;
}
if (child.getValue() == "stop") {
float offset = 100;
etk::Color<float,4> stopColor = etk::color::none;
etk::String content = child.attributes["offset"];
if (content.size()!=0) {
Pair<float, enum esvg::distance> tmp = parseLength2(content);
if (tmp.second == esvg::distance_pixel) {
// special case ==> all time % then no type define ==> % in [0.0 .. 1.0]
offset = tmp.first*100.0f;
} else if (tmp.second != esvg::distance_pourcent) {
Log.error("offset : " << content << " res=" << tmp.first << "," << tmp.second << " Not support other than pourcent %");
} else {
offset = tmp.first;
}
}
content = child.attributes["stop-color"];
if (content.size()!=0) {
stopColor = parseColor(content).first;
Log.verbose(" color : '" << content << "' == > " << stopColor);
}
content = child.attributes["stop-opacity"];
if (content.size()!=0) {
float opacity = parseLength(content);
opacity = etk::avg(0.0f, opacity, 1.0f);
stopColor.setA(opacity);
Log.verbose(" opacity : '" << content << "' == > " << stopColor);
}
this.data.pushBack(Pair<float, etk::Color<float,4>>(offset, stopColor));
} else {
Log.error("(l " << child.getPos() << ") node not suported : '" << child.getValue() << "' must be [stop]");
}
}
if (this.data.size() != 0) {
if (this.href != "") {
Log.error("(l " << _element.getPos() << ") node can not have an xlink:href element with sub node named: stop ==> removing href");
this.href = "";
}
}
return true;
}
void esvg::LinearGradient::display(int _spacing) {
Log.debug(spacingDist(_spacing) << "LinearGradient " << this.pos1 << " to " << this.pos2);
for (auto &it : this.data) {
Log.debug(spacingDist(_spacing+1) << "STOP: offset=" << it.first << " color=" << it.second);
}
}
void esvg::LinearGradient::draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int _level) {
Log.verbose(spacingDist(_level) << "DRAW esvg::LinearGradient");
}
const esvg::Dimension& esvg::LinearGradient::getPosition1() {
return this.pos1;
}
const esvg::Dimension& esvg::LinearGradient::getPosition2() {
return this.pos2;
}
const List<Pair<float, etk::Color<float,4>>>& esvg::LinearGradient::getColors(esvg::Document* _document) {
if (this.href == "") {
return this.data;
}
if (_document == null) {
Log.error("Get null input for document");
return this.data;
}
ememory::SharedPtr<esvg::Base> base = _document->getReference(this.href);
if (base == null) {
Log.error("Can not get base : '" << this.href << "'");
return this.data;
}
ememory::SharedPtr<esvg::RadialGradient> gradientR = ememory::dynamicPointerCast<esvg::RadialGradient>(base);
if (gradientR == null) {
ememory::SharedPtr<esvg::LinearGradient> gradientL = ememory::dynamicPointerCast<esvg::LinearGradient>(base);
if (gradientL == null) {
Log.error("Can not cast in a linear/radial gradient: '" << this.href << "' ==> wrong type");
return this.data;
}
return gradientL->getColors(_document);
}
return gradientR->getColors(_document);
}

View File

@ -1,35 +1,181 @@
package org.atriasoft.esvg;
import java.util.ArrayList;
import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.Color;
import org.atriasoft.etk.Dimension;
import org.atriasoft.etk.Distance;
import org.atriasoft.etk.math.FMath;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.etk.util.Pair;
import org.atriasoft.exml.model.XmlElement;
import org.atriasoft.exml.model.XmlNode;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<esvg/Base.hpp>#include<esvg/gradientUnits.hpp>#include<esvg/spreadMethod.hpp>
namespace esvg{
class Document;
class LinearGradient extends esvg::Base
{
private:
esvg::Dimension this.pos1; //!< gradient position x1 y1
esvg::Dimension this.pos2; //!< gradient position x2 y2
public:
enum gradientUnits this.unit;
enum spreadMethod this.spread;
private:
etk::String this.href; //!< in case of using a single gradient in multiple gradient, the gradient is store in an other element...
List<Pair<float, etk::Color<float,4>>> this.data; //!< incompatible with href
public:
LinearGradient(PaintState _parentPaintState);
~LinearGradient();
virtual boolean parseXML(const exml::Element& _element, mat2x3& _parentTrans, Vector2f& _sizeMax);
virtual void display(int _spacing);
virtual void draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int _level);
public:
const esvg::Dimension& getPosition1();
const esvg::Dimension& getPosition2();
const List<Pair<float, etk::Color<float,4>>>& getColors(esvg::Document* _document);
};
public class LinearGradient extends Base {
private final List<Pair<Float, Color>> data = new ArrayList<>(); //!< gradient position x1 y1
private String href = ""; //!< gradient position x2 y2
private Dimension pos1 = new Dimension(new Vector2f(50, 50), Distance.POURCENT);
private Dimension pos2 = new Dimension(new Vector2f(50, 50), Distance.POURCENT);
public SpreadMethod spread = SpreadMethod.PAD; //!< in case of using a single gradient in multiple gradient, the gradient is store in an other element...
public GradientUnits unit = GradientUnits.gradientUnitsobjectBoundingBox; //!< incompatible with href
public LinearGradient(final PaintState parentPaintState) {
super(parentPaintState);
}
@Override
public void display(final int spacing) {
Log.debug(spacingDist(spacing) + "LinearGradient " + this.pos1 + " to " + this.pos2);
for (Pair<Float, Color> it : this.data) {
Log.debug(spacingDist(spacing + 1) + "STOP: offset=" + it.first + " color=" + it.second);
}
}
@Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW esvg::LinearGradient");
}
public List<Pair<Float, Color>> getColors(final EsvgDocument document) {
if (this.href == "") {
return this.data;
}
if (document == null) {
Log.error("Get null input for document");
return this.data;
}
Base base = document.getReference(this.href);
if (base == null) {
Log.error("Can not get base : '" + this.href + "'");
return this.data;
}
if (base instanceof RadialGradient gradientR) {
return gradientR.getColors(document);
}
if (base instanceof LinearGradient gradientL) {
return gradientL.getColors(document);
}
return this.data;
}
public Dimension getPosition1() {
return this.pos1;
}
public Dimension getPosition2() {
return this.pos2;
}
@Override
public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) {
{
// line must have a minimum size...
//this.paint.strokeWidth = 1;
if (element == null) {
return false;
}
// ---------------- get unique ID ----------------
this.id = element.getAttribute("id", "");
//parseTransform(element);
//parsePaintAttr(element);
// add the property of the parrent modifications ...
this.transformMatrix = this.transformMatrix.multiply(parentTrans);
String contentX = element.getAttribute("x1", "");
String contentY = element.getAttribute("y1", "");
if (contentX != "" && contentY != "") {
this.pos1 = new Dimension(new Vector2f(Float.parseFloat(contentX), Float.parseFloat(contentY)));
}
contentX = element.getAttribute("x2", "");
contentY = element.getAttribute("y2", "");
if (contentX != "" && contentY != "") {
this.pos2 = new Dimension(new Vector2f(Float.parseFloat(contentX), Float.parseFloat(contentY)));
}
contentX = element.getAttribute("gradientUnits", "");
if (contentX == "userSpaceOnUse") {
this.unit = GradientUnits.gradientUnitsuserSpaceOnUse;
} else {
this.unit = GradientUnits.gradientUnitsobjectBoundingBox;
if (contentX.length() != 0 && contentX != "objectBoundingBox") {
Log.error("Parsing error of 'gradientUnits' ==> not suported value: '" + contentX + "' not in : {userSpaceOnUse/objectBoundingBox} use objectBoundingBox");
}
}
contentX = element.getAttribute("spreadMethod", "");
if (contentX == "reflect") {
this.spread = SpreadMethod.REFLECT;
} else if (contentX == "repeat") {
this.spread = SpreadMethod.REPEAT;
} else {
this.spread = SpreadMethod.PAD;
if (contentX.length() != 0 && contentX != "pad") {
Log.error("Parsing error of 'spreadMethod' ==> not suported value: '" + contentX + "' not in : {reflect/repeate/pad} use pad");
}
}
// note: xlink:href is incompatible with subNode "stop"
this.href = element.getAttribute("xlink:href", "");
if (this.href.length() != 0) {
this.href = this.href.substring(1);
}
// parse all sub node :
for (XmlNode it : element.getNodes()) {
if (it instanceof XmlElement child) {
if (child.getValue() == "stop") {
float offset = 100;
Color stopColor = Color.NONE;
String content = child.getAttribute("offset", "");
if (content.length() != 0) {
Pair<Float, Distance> tmp = parseLength2(content);
if (tmp.second == Distance.PIXEL) {
// special case ==> all time % then no type define ==> % in [0.0 .. 1.0]
offset = tmp.first * 100.0f;
} else if (tmp.second != Distance.POURCENT) {
Log.error("offset : " + content + " res=" + tmp.first + "," + tmp.second + " Not support other than pourcent %");
} else {
offset = tmp.first;
}
}
content = child.getAttribute("stop-color", "");
if (content.length() != 0) {
stopColor = parseColor(content).first;
Log.verbose(" color : '" + content + "' == > " + stopColor);
}
content = child.getAttribute("stop-opacity", "");
if (content.length() != 0) {
float opacity = parseLength(content);
opacity = FMath.avg(0.0f, opacity, 1.0f);
stopColor = stopColor.withA(opacity);
Log.verbose(" opacity : '" + content + "' == > " + stopColor);
}
this.data.add(new Pair<Float, Color>(offset, stopColor));
} else {
Log.error(" node not suported : '" + child.getValue() + "' must be [stop]");
}
}
}
if (this.data.size() != 0) {
if (this.href != "") {
Log.error(" node can not have an xlink:href element with sub node named: stop ==> removing href");
this.href = "";
}
}
return true;
}
}
}

View File

@ -6,7 +6,7 @@ package org.atriasoft.esvg;
public enum PaintMode {
NONE, //!< No painting.
COLOR, //!< Painting a color.
GRADIENT_LINEAR, //!< Painting a linear gradient.
GRADIENT_RADIAL; //!< Painting a radial gradient.
GRADIENTLINEAR, //!< Painting a linear gradient.
GRADIENTRADIAL; //!< Painting a radial gradient.
}

View File

@ -6,35 +6,23 @@ import org.atriasoft.etk.util.Pair;
public class PaintState {
public Pair<Color, String> fill;
public Pair<Color, String> stroke;
public float strokeWidth;
public boolean flagEvenOdd;
public CapMode lineCap;
public JoinMode lineJoin; //!< Fill rules
public float miterLimit;
public Pair<Vector2f, Vector2f> viewPort;
public float opacity;
public Pair<Color, String> fill = new Pair<Color, String>(Color.BLACK, "");
public boolean flagEvenOdd = false;
public CapMode lineCap = CapMode.BUTT;
public JoinMode lineJoin = JoinMode.MITER;
public float miterLimit = 4.0f;
public float opacity = 1.0f;
public Pair<Color, String> stroke = new Pair<Color, String>(Color.NONE, "");
public float strokeWidth = 1.0f;
public Pair<Vector2f, Vector2f> viewPort = new Pair<>(Vector2f.ZERO, Vector2f.ZERO);
public PaintState() {
this.fill = new Pair<Color, String>(new Color(0, 0, 0, 1), "");
this.stroke = new Pair<Color, String>(new Color(0, 0, 0, 0), "");
this.strokeWidth = 1.0f;
this.viewPort.first.setValue(0.0f, 0.0f);
this.viewPort.first.setValue(0.0f, 0.0f);
this.flagEvenOdd = false;
this.lineJoin = JoinMode.MITER;
this.lineCap = CapMode.BUTT;
this.miterLimit = 4.0f;
this.opacity = 1.0f;
}
public PaintState() {}
public void clear() {
this.fill = new Pair<Color, String>(new Color(0, 0, 0, 1), "");
this.stroke = new Pair<Color, String>(new Color(0, 0, 0, 0), "");
this.fill = new Pair<Color, String>(Color.BLACK, "");
this.stroke = new Pair<Color, String>(Color.NONE, "");
this.strokeWidth = 1.0f;
this.viewPort.first.setValue(0.0f, 0.0f);
this.viewPort.first.setValue(0.0f, 0.0f);
this.viewPort = new Pair<>(Vector2f.ZERO, Vector2f.ZERO);
this.flagEvenOdd = false;
this.lineJoin = JoinMode.MITER;
this.lineCap = CapMode.BUTT;

View File

@ -1,349 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/debug.hpp>
#include <esvg/Path.hpp>
#include <esvg/render/PointList.hpp>
#include <esvg/render/Weight.hpp>
esvg::Path::Path(PaintState _parentPaintState) : esvg::Base(_parentPaintState) {
}
esvg::Path::~Path() {
}
// return the next char position ... (after 'X' or NULL)
const char * extractCmd(const char* _input, char& _cmd, List<float>& _outputList) {
if (*_input == '\0') {
return null;
}
_outputList.clear();
_cmd = '\0';
const char * outputPointer = null;
if (!( ( _input[0] <= 'Z'
&& _input[0] >= 'A')
|| ( _input[0] <= 'z'
&& _input[0] >= 'a') ) ) {
Log.error("Error in the SVG Path : \"" << _input << "\"");
return null;
}
_cmd = _input[0];
Log.verbose("Find command : " << _cmd);
if (_input[1] == '\0') {
return &_input[1];
}
int iii=1;
// extract every float separated by a ' ' or a ','
float element;
char spacer[10];
int nbElementRead;
while( sscanf(&_input[iii], "%1[, ]%f%n", spacer, &element, &nbElementRead) == 2
|| sscanf(&_input[iii], "%f%n", &element, &nbElementRead) == 1) {
Log.verbose("Find element : " << element);
_outputList.pushBack(element);
iii += nbElementRead;
}
outputPointer = &_input[iii];
while(*outputPointer!= '\0' && *outputPointer == ' ') {
outputPointer++;
}
//outputPointer++;
return outputPointer;
}
etk::String cleanBadSpaces(const etk::String& _input) {
etk::String out;
boolean haveSpace = false;
for (auto &it : _input) {
if ( it == ' '
|| it == '\t'
|| it == '\t'
|| it == '\r') {
haveSpace = true;
} else {
if (haveSpace == true) {
haveSpace = false;
out += ' ';
}
out += it;
}
}
return out;
}
boolean esvg::Path::parseXML(const exml::Element& _element, mat2x3& _parentTrans, Vector2f& _sizeMax) {
if (_element.exist() == false) {
return false;
}
parseTransform(_element);
parsePaintAttr(_element);
// add the property of the parrent modifications ...
this.transformMatrix *= _parentTrans;
etk::String elementXML1 = _element.attributes["d"];
if (elementXML1.size() == 0) {
Log.warning("(l "<<_element.getPos()<<") path: missing 'd' attribute or empty");
return false;
}
Log.verbose("Parse Path : \"" << elementXML1 << "\"");
char command;
List<float> listDot;
elementXML1 = cleanBadSpaces(elementXML1);
const char* elementXML = elementXML1.c_str();
for( const char *sss=extractCmd(elementXML, command, listDot);
sss != null;
sss=extractCmd(sss, command, listDot) ) {
boolean relative = false;
switch(command) {
case 'm': // Move to (relative)
relative = true;
case 'M': // Move to (absolute)
// 2 Elements ...
if(listDot.size()%2 != 0) {
Log.warning("the PATH command "<< command << " has not the good number of element = " << listDot.size() );
break;
}
if (listDot.size() >= 2) {
this.listElement.moveTo(relative,
Vector2f(listDot[0], listDot[1]));
}
for (size_t iii=2; iii<listDot.size(); iii+=2) {
this.listElement.lineTo(relative,
Vector2f(listDot[iii], listDot[iii+1]));
}
break;
case 'l': // Line to (relative)
relative = true;
case 'L': // Line to (absolute)
// 2 Elements ...
if(listDot.size()%2 != 0) {
Log.warning("the PATH command "<< command << " has not the good number of element = " << listDot.size() );
break;
}
for (size_t iii=0; iii<listDot.size(); iii+=2) {
this.listElement.lineTo(relative,
Vector2f(listDot[iii], listDot[iii+1]));
}
break;
case 'v': // Vertical Line to (relative)
relative = true;
case 'V': // Vertical Line to (absolute)
// 1 Element ...
if(listDot.size() == 0) {
Log.warning("the PATH command "<< command << " has not the good number of element = " << listDot.size() );
break;
}
for (size_t iii=0; iii<listDot.size(); iii+=1) {
this.listElement.lineToV(relative,
listDot[iii]);
}
break;
case 'h': // Horizantal Line to (relative)
relative = true;
case 'H': // Horizantal Line to (absolute)
// 1 Element ...
if (listDot.size() == 0) {
Log.warning("the PATH command "<< command << " has not the good number of element = " << listDot.size() );
break;
}
for (size_t iii=0; iii<listDot.size(); iii+=1) {
this.listElement.lineToH(relative,
listDot[iii]);
}
break;
case 'q': // Quadratic Bezier curve (relative)
relative = true;
case 'Q': // Quadratic Bezier curve (absolute)
// 4 Elements ...
if (listDot.size()%4 != 0) {
Log.warning("the PATH command "<< command << " has not the good number of element = " << listDot.size() );
break;
}
for (size_t iii=0; iii<listDot.size(); iii+=4) {
this.listElement.bezierCurveTo(relative,
Vector2f(listDot[iii],listDot[iii+1]),
Vector2f(listDot[iii+2],listDot[iii+3]));
}
break;
case 't': // smooth quadratic Bezier curve to (relative)
relative = true;
case 'T': // smooth quadratic Bezier curve to (absolute)
// 2 Elements ...
if (listDot.size()%2 != 0) {
Log.warning("the PATH command "<< command << " has not the good number of element = " << listDot.size() );
break;
}
for (size_t iii=0; iii<listDot.size(); iii+=2) {
this.listElement.bezierSmoothCurveTo(relative,
Vector2f(listDot[iii],listDot[iii+1]));
}
break;
case 'c': // curve to (relative)
relative = true;
case 'C': // curve to (absolute)
// 6 Elements ...
if (listDot.size()%6 != 0) {
Log.warning("the PATH command "<< command << " has not the good number of element = " << listDot.size() );
break;
}
for (size_t iii=0; iii<listDot.size(); iii+=6) {
this.listElement.curveTo(relative,
Vector2f(listDot[iii],listDot[iii+1]),
Vector2f(listDot[iii+2],listDot[iii+3]),
Vector2f(listDot[iii+4],listDot[iii+5]));
}
break;
case 's': // smooth curve to (relative)
relative = true;
case 'S': // smooth curve to (absolute)
// 4 Elements ...
if (listDot.size()%4 != 0) {
Log.warning("the PATH command "<< command << " has not the good number of element = " << listDot.size() );
break;
}
for (size_t iii=0; iii<listDot.size(); iii+=4) {
this.listElement.smoothCurveTo(relative,
Vector2f(listDot[iii],listDot[iii+1]),
Vector2f(listDot[iii+2],listDot[iii+3]));
}
break;
case 'a': // elliptical Arc (relative)
relative = true;
case 'A': // elliptical Arc (absolute)
// 7 Elements ...
if (listDot.size()%7 != 0) {
Log.warning("the PATH command "<< command << " has not the good number of element = " << listDot.size() );
break;
}
for (size_t iii=0; iii<listDot.size(); iii+=7) {
boolean largeArcFlag = true;
boolean sweepFlag = true;
if (listDot[iii+3] == 0.0f) {
largeArcFlag = false;
}
if (listDot[iii+4] == 0.0f) {
sweepFlag = false;
}
this.listElement.ellipticTo(relative,
Vector2f(listDot[iii], listDot[iii+1]),
listDot[iii+2],
largeArcFlag,
sweepFlag,
Vector2f(listDot[iii+5], listDot[iii+6]) );
}
break;
case 'z': // closepath (relative)
relative = true;
case 'Z': // closepath (absolute)
// 0 Element ...
if (listDot.size() != 0) {
Log.warning("the PATH command "<< command << " has not the good number of element = " << listDot.size() );
break;
}
this.listElement.close(relative);
break;
default:
ESVG_ERROR ("Unknow error : \"" << command << "\"");
}
}
return true;
}
void esvg::Path::display(int _spacing) {
this.listElement.display(_spacing);
}
void esvg::Path::draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int _level) {
Log.verbose(spacingDist(_level) << "DRAW esvg::Path");
mat2x3 mtx = this.transformMatrix;
mtx *= _basicTrans;
esvg::render::PointList listPoints;
listPoints = this.listElement.generateListPoints(_level,
_myRenderer.getInterpolationRecurtionMax(),
_myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx);
esvg::render::SegmentList listSegmentFill;
esvg::render::SegmentList listSegmentStroke;
esvg::render::Weight tmpFill;
esvg::render::Weight tmpStroke;
ememory::SharedPtr<esvg::render::DynamicColor> colorFill = esvg::render::createColor(this.paint.fill, mtx);
ememory::SharedPtr<esvg::render::DynamicColor> colorStroke;
if (this.paint.strokeWidth > 0.0f) {
colorStroke = esvg::render::createColor(this.paint.stroke, mtx);
}
// Check if we need to display background
if (colorFill != null) {
listSegmentFill.createSegmentList(listPoints);
colorFill->setViewPort(listSegmentFill.getViewPort());
listSegmentFill.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpFill.generate(_myRenderer.getSize(), _myRenderer.getNumberSubScanLine(), listSegmentFill);
}
// check if we need to display stroke:
if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints,
this.paint.strokeWidth,
this.paint.lineCap,
this.paint.lineJoin,
this.paint.miterLimit);
colorStroke->setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpStroke.generate(_myRenderer.getSize(), _myRenderer.getNumberSubScanLine(), listSegmentStroke);
}
// add on images:
_myRenderer.print(tmpFill,
colorFill,
tmpStroke,
colorStroke,
this.paint.opacity);
#ifdef DEBUG
_myRenderer.addDebugSegment(listSegmentFill);
_myRenderer.addDebugSegment(listSegmentStroke);
this.listElement.this.debugInformation.applyMatrix(mtx);
_myRenderer.addDebugSegment(this.listElement.this.debugInformation);
#endif
}
void esvg::Path::drawShapePoints(List<etk::Vector<Vector2f>>& _out,
int _recurtionMax,
float _threshold,
mat2x3& _basicTrans,
int _level) {
Log.verbose(spacingDist(_level) << "DRAW Shape esvg::Path");
mat2x3 mtx = this.transformMatrix;
mtx *= _basicTrans;
esvg::render::PointList listPoints;
listPoints = this.listElement.generateListPoints(_level, _recurtionMax, _threshold);
listPoints.applyMatrix(mtx);
for (auto &it : listPoints.this.data) {
List<Vector2f> listPoint;
for (auto &itDot : it) {
listPoint.pushBack(itDot.this.pos);
}
_out.pushBack(listPoint);
}
}

View File

@ -1,34 +1,349 @@
package org.atriasoft.esvg;
import java.util.ArrayList;
import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.Point;
import org.atriasoft.esvg.render.PointList;
import org.atriasoft.esvg.render.Weight;
import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.SegmentList;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.exml.model.XmlElement;
import org.atriasoft.exml.parser.Tools;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<esvg/Base.hpp>#include<esvg/render/Path.hpp>
namespace esvg{
class Path extends esvg::Base
{
public:
esvg::render::Path this.listElement;
public:
public class Path extends Base {
private record Command(
char cmd,
float[] listDot,
int offset) {
Command(final char cmd, final float[] listDot, final int offset) {
this.cmd = cmd;
this.listDot = listDot;
this.offset = offset;
}
Command(final char cmd, final int offset) {
this(cmd, null, offset);
}
}
Path(PaintState _parentPaintState);~
private static String cleanBadSpaces(final String input) {
StringBuilder out = new StringBuilder(input.length());
boolean haveSpace = false;
for (char it : input.toCharArray()) {
if (it == ' ' || it == '\t' || it == '\t' || it == '\r') {
haveSpace = true;
} else {
if (haveSpace) {
haveSpace = false;
out.append(' ');
}
out.append(it);
}
}
return out.toString();
}
Path();
//return the next char position ... (after 'X' or NULL)
private static Command extractCmd(final char[] input, final int offset) {
if (input[offset] == '\0') {
return null;
}
char cmd = '\0';
if (!((input[offset] <= 'Z' && input[offset] >= 'A') || (input[offset] <= 'z' && input[offset] >= 'a'))) {
Log.error("Error in the SVG Path : '" + input + "' [" + offset);
return null;
}
cmd = input[0];
Log.verbose("Find command : " + cmd);
if (input[offset + 1] == '\0') {
return new Command(cmd, offset + 1);
}
StringBuilder tmpData = new StringBuilder();
List<String> elements = new ArrayList<>();
int iii;
for (iii = offset; iii < input.length; iii++) {
if (Tools.checkNumber(input[iii], iii == offset)) {
tmpData.append(input[iii]);
continue;
}
elements.add(tmpData.toString());
tmpData.setLength(0);
if (input[iii] == ' ' || input[iii] == '\t' || input[iii] == '\n' || input[iii] == '\r' || input[iii] == ',' || input[iii] == ';') {
continue;
}
break;
}
float[] outputList = new float[elements.size()];
int jjj = 0;
for (String ekems : elements) {
outputList[jjj++] = Float.parseFloat(ekems);
}
// remove after white space...
for (; iii < input.length; iii++) {
if (input[iii] == ' ' || input[iii] == '\t' || input[iii] == '\n' || input[iii] == '\r') {
continue;
}
break;
}
return new Command(cmd, outputList, offset + 1);
}
boolean parseXML(const exml::Element& _element, mat2x3& _parentTrans, Vector2f& _sizeMax) override;
public PathModel listElement;
void display(final int _spacing) override;
public Path(final PaintState parentPaintState) {
super(parentPaintState);
}
void draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int _level) override;
@Override
void display(final int spacing) {
this.listElement.display(spacing);
}
@Override
void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW esvg::Path");
Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
PointList listPoints = new PointList();
listPoints = this.listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx);
SegmentList listSegmentFill = new SegmentList();
SegmentList listSegmentStroke = new SegmentList();
Weight tmpFill = new Weight();
Weight tmpStroke = new Weight();
DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx);
DynamicColor colorStroke = null;
if (this.paint.strokeWidth > 0.0f) {
colorStroke = DynamicColor.createColor(this.paint.stroke, mtx);
}
// Check if we need to display background
if (colorFill != null) {
listSegmentFill.createSegmentList(listPoints);
colorFill.setViewPort(listSegmentFill.getViewPort());
listSegmentFill.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpFill.generate(myRenderer.getSize(), myRenderer.getNumberSubScanLine(), listSegmentFill);
}
// check if we need to display stroke:
if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit);
colorStroke.setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpStroke.generate(myRenderer.getSize(), myRenderer.getNumberSubScanLine(), listSegmentStroke);
}
// add on images:
myRenderer.print(tmpFill, colorFill, tmpStroke, colorStroke, this.paint.opacity);
//myRenderer.addDebugSegment(listSegmentFill);
//myRenderer.addDebugSegment(listSegmentStroke);
//this.listElement.debugInformation.applyMatrix(mtx);
//myRenderer.addDebugSegment(this.listElement.debugInformation);
}
@Override
void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW Shape esvg::Path");
Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
PointList listPoints = new PointList();
listPoints = this.listElement.generateListPoints(level, recurtionMax, threshold);
listPoints.applyMatrix(mtx);
for (List<Point> it : listPoints.data) {
List<Vector2f> listPoint = new ArrayList<Vector2f>();
for (Point itDot : it) {
listPoint.add(itDot.pos);
}
out.add(listPoint);
}
}
@Override
boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) {
if (element == null) {
return false;
}
parseTransform(element);
parsePaintAttr(element);
// add the property of the parrent modifications ...
this.transformMatrix = this.transformMatrix.multiply(parentTrans);
String elementXML1 = element.getAttribute("d", "");
if (elementXML1.length() == 0) {
Log.warning("path: missing 'd' attribute or empty");
return false;
}
Log.verbose("Parse Path : \"" + elementXML1 + "\"");
float[] listDot = null;
elementXML1 = Path.cleanBadSpaces(elementXML1);
char[] elementXML = elementXML1.toCharArray();
// TODO REWORK this, can be done with a simple split and search in a list...
for (Command sss = Path.extractCmd(elementXML, 0); sss != null; sss = Path.extractCmd(elementXML, sss.offset())) {
boolean relative = false;
listDot = sss.listDot();
switch (sss.cmd) {
case 'm': // Move to (relative)
relative = true;
case 'M': // Move to (absolute)
// 2 Elements ...
if (listDot.length % 2 != 0) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length);
break;
}
if (listDot.length >= 2) {
this.listElement.moveTo(relative, new Vector2f(listDot[0], listDot[1]));
}
for (int iii = 2; iii < listDot.length; iii += 2) {
this.listElement.lineTo(relative, new Vector2f(listDot[iii], listDot[iii + 1]));
}
break;
case 'l': // Line to (relative)
relative = true;
case 'L': // Line to (absolute)
// 2 Elements ...
if (listDot.length % 2 != 0) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length);
break;
}
for (int iii = 0; iii < listDot.length; iii += 2) {
this.listElement.lineTo(relative, new Vector2f(listDot[iii], listDot[iii + 1]));
}
break;
case 'v': // Vertical Line to (relative)
relative = true;
case 'V': // Vertical Line to (absolute)
// 1 Element ...
if (listDot.length == 0) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length);
break;
}
for (int iii = 0; iii < listDot.length; iii += 1) {
this.listElement.lineToV(relative, listDot[iii]);
}
break;
case 'h': // Horizantal Line to (relative)
relative = true;
case 'H': // Horizantal Line to (absolute)
// 1 Element ...
if (listDot.length == 0) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length);
break;
}
for (int iii = 0; iii < listDot.length; iii += 1) {
this.listElement.lineToH(relative, listDot[iii]);
}
break;
case 'q': // Quadratic Bezier curve (relative)
relative = true;
case 'Q': // Quadratic Bezier curve (absolute)
// 4 Elements ...
if (listDot.length % 4 != 0) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length);
break;
}
for (int iii = 0; iii < listDot.length; iii += 4) {
this.listElement.bezierCurveTo(relative, new Vector2f(listDot[iii], listDot[iii + 1]), new Vector2f(listDot[iii + 2], listDot[iii + 3]));
}
break;
case 't': // smooth quadratic Bezier curve to (relative)
relative = true;
case 'T': // smooth quadratic Bezier curve to (absolute)
// 2 Elements ...
if (listDot.length % 2 != 0) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length);
break;
}
for (int iii = 0; iii < listDot.length; iii += 2) {
this.listElement.bezierSmoothCurveTo(relative, new Vector2f(listDot[iii], listDot[iii + 1]));
}
break;
case 'c': // curve to (relative)
relative = true;
case 'C': // curve to (absolute)
// 6 Elements ...
if (listDot.length % 6 != 0) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length);
break;
}
for (int iii = 0; iii < listDot.length; iii += 6) {
this.listElement.curveTo(relative, new Vector2f(listDot[iii], listDot[iii + 1]), new Vector2f(listDot[iii + 2], listDot[iii + 3]),
new Vector2f(listDot[iii + 4], listDot[iii + 5]));
}
break;
case 's': // smooth curve to (relative)
relative = true;
case 'S': // smooth curve to (absolute)
// 4 Elements ...
if (listDot.length % 4 != 0) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length);
break;
}
for (int iii = 0; iii < listDot.length; iii += 4) {
this.listElement.smoothCurveTo(relative, new Vector2f(listDot[iii], listDot[iii + 1]), new Vector2f(listDot[iii + 2], listDot[iii + 3]));
}
break;
case 'a': // elliptical Arc (relative)
relative = true;
case 'A': // elliptical Arc (absolute)
// 7 Elements ...
if (listDot.length % 7 != 0) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length);
break;
}
for (int iii = 0; iii < listDot.length; iii += 7) {
boolean largeArcFlag = true;
boolean sweepFlag = true;
if (listDot[iii + 3] == 0.0f) {
largeArcFlag = false;
}
if (listDot[iii + 4] == 0.0f) {
sweepFlag = false;
}
this.listElement.ellipticTo(relative, new Vector2f(listDot[iii], listDot[iii + 1]), listDot[iii + 2], largeArcFlag, sweepFlag,
new Vector2f(listDot[iii + 5], listDot[iii + 6]));
}
break;
case 'z': // closepath (relative)
relative = true;
case 'Z': // closepath (absolute)
// 0 Element ...
if (listDot.length != 0) {
Log.warning("the PATH command " + sss.cmd + " has not the good number of element = " + listDot.length);
break;
}
this.listElement.close(relative);
break;
default:
Log.error("Unknow error : '" + sss.cmd + "'");
}
}
return true;
}
void drawShapePoints(final List<List<Vector2f>>& _out,
int _recurtionMax,
float _threshold,
mat2x3& _basicTrans,
int _level=1) override;
};
}

View File

@ -1,153 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/debug.hpp>
#include <esvg/Polygon.hpp>
#include <esvg/render/Path.hpp>
#include <esvg/render/Weight.hpp>
esvg::Polygon::Polygon(PaintState parentPaintState) : esvg::Base(parentPaintState) {
}
esvg::Polygon::~Polygon() {
}
boolean esvg::Polygon::parseXML(const exml::Element& _element, mat2x3& _parentTrans, Vector2f& _sizeMax) {
if (_element.exist() == false) {
return false;
}
parseTransform(_element);
parsePaintAttr(_element);
Log.verbose("parsed P1. trans: " << this.transformMatrix);
// add the property of the parrent modifications ...
this.transformMatrix *= _parentTrans;
Log.verbose("parsed P2. trans: " << this.transformMatrix);
const etk::String sss1 = _element.attributes["points"];
if (sss1.size() == 0) {
Log.error("(l "/*<<_element->Pos()*/<<") polygon: missing points attribute");
return false;
}
const char * sss = sss1.c_str();
_sizeMax.setValue(0,0);
Log.verbose("Parse polygon : \"" << sss << "\"");
while ('\0' != sss[0]) {
Vector2f pos(0,0);
int n;
if (sscanf(sss, "%f,%f%n", &pos.this.floats[0], &pos.this.floats[1], &n) == 2) {
this.listPoint.pushBack(pos);
sss += n;
_sizeMax.setValue(etk::max(_sizeMax.x(), pos.x()),
etk::max(_sizeMax.y(), pos.y()));
if(sss[0] == ' ' || sss[0] == ',') {
sss++;
}
} else {
break;
}
}
return true;
}
void esvg::Polygon::display(int _spacing) {
Log.debug(spacingDist(_spacing) << "Polygon nbPoint=" << this.listPoint.size());
}
esvg::render::Path esvg::Polygon::createPath() {
esvg::render::Path out;
out.moveTo(false, this.listPoint[0]);
for(size_t iii=1; iii< this.listPoint.size(); iii++) {
out.lineTo(false, this.listPoint[iii]);
}
out.close();
return out;
}
void esvg::Polygon::draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int _level) {
Log.verbose(spacingDist(_level) << "DRAW esvg::Polygon");
esvg::render::Path listElement = createPath();
mat2x3 mtx = this.transformMatrix;
mtx *= _basicTrans;
esvg::render::PointList listPoints;
listPoints = listElement.generateListPoints(_level,
_myRenderer.getInterpolationRecurtionMax(),
_myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx);
esvg::render::SegmentList listSegmentFill;
esvg::render::SegmentList listSegmentStroke;
esvg::render::Weight tmpFill;
esvg::render::Weight tmpStroke;
ememory::SharedPtr<esvg::render::DynamicColor> colorFill = esvg::render::createColor(this.paint.fill, mtx);
ememory::SharedPtr<esvg::render::DynamicColor> colorStroke;
if (this.paint.strokeWidth > 0.0f) {
colorStroke = esvg::render::createColor(this.paint.stroke, mtx);
}
// Check if we need to display background
if (colorFill != null) {
listSegmentFill.createSegmentList(listPoints);
colorFill->setViewPort(listSegmentFill.getViewPort());
listSegmentFill.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpFill.generate(_myRenderer.getSize(),
_myRenderer.getNumberSubScanLine(),
listSegmentFill);
}
// check if we need to display stroke:
if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints,
this.paint.strokeWidth,
this.paint.lineCap,
this.paint.lineJoin,
this.paint.miterLimit);
colorStroke->setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpStroke.generate(_myRenderer.getSize(),
_myRenderer.getNumberSubScanLine(),
listSegmentStroke);
}
// add on images:
_myRenderer.print(tmpFill,
colorFill,
tmpStroke,
colorStroke,
this.paint.opacity);
#ifdef DEBUG
_myRenderer.addDebugSegment(listSegmentFill);
_myRenderer.addDebugSegment(listSegmentStroke);
#endif
}
void esvg::Polygon::drawShapePoints(List<etk::Vector<Vector2f>>& _out,
int _recurtionMax,
float _threshold,
mat2x3& _basicTrans,
int _level) {
Log.verbose(spacingDist(_level) << "DRAW Shape esvg::Polygon");
esvg::render::Path listElement = createPath();
mat2x3 mtx = this.transformMatrix;
mtx *= _basicTrans;
esvg::render::PointList listPoints;
listPoints = listElement.generateListPoints(_level, _recurtionMax, _threshold);
listPoints.applyMatrix(mtx);
for (auto &it : listPoints.this.data) {
List<Vector2f> listPoint;
for (auto &itDot : it) {
listPoint.pushBack(itDot.this.pos);
}
_out.pushBack(listPoint);
}
}

View File

@ -1,44 +1,137 @@
package org.atriasoft.esvg;
import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.Point;
import org.atriasoft.esvg.render.PointList;
import org.atriasoft.esvg.render.SegmentList;
import org.atriasoft.esvg.render.Weight;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.exml.model.XmlElement;
import java.util.ArrayList;
import java.util.List;
import org.atriasoft.esvg.internal.Log;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<esvg/Base.hpp>#include<etk/Vector.hpp>
namespace esvg{
/*
enum polygonMode {
polygoneModeNonZero,
polygoneModeEvenOdd
};
*/
class Polygon extends esvg::Base
{
private:
List<Vector2f > this.listPoint; //!< list of all point of the polygone
//enum esvg::polygonMode this.diplayMode; //!< polygone specific display mode
public:
public class Polygon extends Base {
private List<Vector2f> listPoint; //!< list of all point of the polygone
Polygon(PaintState parentPaintState);~
public Polygon(final PaintState parentPaintState) {
super(parentPaintState);
}
Polygon();
private PathModel createPath() {
PathModel out = new PathModel();
out.moveTo(false, this.listPoint.get(0));
for (int iii = 1; iii < this.listPoint.size(); iii++) {
out.lineTo(false, this.listPoint.get(iii));
}
out.close();
return out;
}
boolean parseXML(const exml::Element& _element, mat2x3& _parentTrans, Vector2f& _sizeMax) override;
@Override
public void display(final int spacing) {
Log.debug(spacingDist(spacing) + "Polygon nbPoint=" + this.listPoint.size());
}
void display(final int _spacing) override;
@Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW esvg::Polygon");
PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
PointList listPoints = new PointList();
listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx);
SegmentList listSegmentFill = new SegmentList();
SegmentList listSegmentStroke = new SegmentList();
Weight tmpFill = new Weight();
Weight tmpStroke = new Weight();
DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx);
DynamicColor colorStroke = null;
if (this.paint.strokeWidth > 0.0f) {
colorStroke = DynamicColor.createColor(this.paint.stroke, mtx);
}
// Check if we need to display background
if (colorFill != null) {
listSegmentFill.createSegmentList(listPoints);
colorFill.setViewPort(listSegmentFill.getViewPort());
listSegmentFill.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpFill.generate(myRenderer.getSize(), myRenderer.getNumberSubScanLine(), listSegmentFill);
}
// check if we need to display stroke:
if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit);
colorStroke.setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpStroke.generate(myRenderer.getSize(), myRenderer.getNumberSubScanLine(), listSegmentStroke);
}
// add on images:
myRenderer.print(tmpFill, colorFill, tmpStroke, colorStroke, this.paint.opacity);
//myRenderer.addDebugSegment(listSegmentFill);
//myRenderer.addDebugSegment(listSegmentStroke);
}
void draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int _level) override;
@Override
public void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW Shape esvg::Polygon");
PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
PointList listPoints;
listPoints = listElement.generateListPoints(level, recurtionMax, threshold);
listPoints.applyMatrix(mtx);
for (List<Point> it : listPoints.data) {
List<Vector2f> listPoint = new ArrayList<>();
for (Point itDot : it) {
listPoint.add(itDot.pos);
}
out.add(listPoint);
}
}
void drawShapePoints(List<List<Vector2f>>& _out,
int _recurtionMax,
float _threshold,
mat2x3& _basicTrans,
int _level=1) override;
private:
esvg::render::
Path createPath();
};}
@Override
public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) {
if (element == null) {
return false;
}
parseTransform(element);
parsePaintAttr(element);
Log.verbose("parsed P1. trans: " + this.transformMatrix);
// add the property of the parrent modifications ...
this.transformMatrix = this.transformMatrix.multiply(parentTrans);
Log.verbose("parsed P2. trans: " + this.transformMatrix);
String sss1 = element.getAttribute("points", "");
if (sss1.length() == 0) {
Log.error("(l "/*+element.Pos()*/ + ") polygon: missing points attribute");
return false;
}
sizeMax.value = Vector2f.ZERO;
Log.verbose("Parse polyline : '" + sss1 + "'");
String[] elems = sss1.split(" ");
for (String elem : elems) {
Vector2f pos = Vector2f.valueOf(elem);
this.listPoint.add(pos);
sizeMax.value = Vector2f.max(sizeMax.value, pos);
}
return true;
}
}

View File

@ -1,149 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/debug.hpp>
#include <esvg/Polyline.hpp>
#include <esvg/render/Path.hpp>
#include <esvg/render/Weight.hpp>
esvg::Polyline::Polyline(PaintState _parentPaintState) : esvg::Base(_parentPaintState) {
}
esvg::Polyline::~Polyline() {
}
boolean esvg::Polyline::parseXML(const exml::Element& _element, mat2x3& _parentTrans, Vector2f& _sizeMax) {
// line must have a minimum size...
this.paint.strokeWidth = 1;
if (_element.exist() == false) {
return false;
}
parseTransform(_element);
parsePaintAttr(_element);
// add the property of the parrent modifications ...
this.transformMatrix *= _parentTrans;
etk::String sss1 = _element.attributes["points"];
if (sss1.size() == 0) {
Log.error("(l "<<_element.getPos()<<") polyline: missing points attribute");
return false;
}
_sizeMax.setValue(0,0);
Log.verbose("Parse polyline : \"" << sss1 << "\"");
const char* sss = sss1.c_str();
while ('\0' != sss[0]) {
Vector2f pos;
int n;
if (sscanf(sss, "%f,%f %n", &pos.this.floats[0], &pos.this.floats[1], &n) == 2) {
this.listPoint.pushBack(pos);
_sizeMax.setValue(etk::max(_sizeMax.x(), pos.x()),
etk::max(_sizeMax.y(), pos.y()));
sss += n;
} else {
break;
}
}
return true;
}
void esvg::Polyline::display(int _spacing) {
Log.debug(spacingDist(_spacing) << "Polyline nbPoint=" << this.listPoint.size());
}
esvg::render::Path esvg::Polyline::createPath() {
esvg::render::Path out;
out.clear();
out.moveTo(false, this.listPoint[0]);
for(size_t iii=1; iii< this.listPoint.size(); iii++) {
out.lineTo(false, this.listPoint[iii]);
}
out.stop();
return out;
}
void esvg::Polyline::draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int _level) {
Log.verbose(spacingDist(_level) << "DRAW esvg::Polyline");
esvg::render::Path listElement = createPath();
mat2x3 mtx = this.transformMatrix;
mtx *= _basicTrans;
esvg::render::PointList listPoints;
listPoints = listElement.generateListPoints(_level,
_myRenderer.getInterpolationRecurtionMax(),
_myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx);
esvg::render::SegmentList listSegmentFill;
esvg::render::SegmentList listSegmentStroke;
esvg::render::Weight tmpFill;
esvg::render::Weight tmpStroke;
ememory::SharedPtr<esvg::render::DynamicColor> colorFill = esvg::render::createColor(this.paint.fill, mtx);
ememory::SharedPtr<esvg::render::DynamicColor> colorStroke;
if (this.paint.strokeWidth > 0.0f) {
colorStroke = esvg::render::createColor(this.paint.stroke, mtx);
}
// Check if we need to display background
if (colorFill != null) {
listSegmentFill.createSegmentList(listPoints);
colorFill->setViewPort(listSegmentFill.getViewPort());
listSegmentFill.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpFill.generate(_myRenderer.getSize(),
_myRenderer.getNumberSubScanLine(),
listSegmentFill);
}
// check if we need to display stroke:
if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints,
this.paint.strokeWidth,
this.paint.lineCap,
this.paint.lineJoin,
this.paint.miterLimit);
colorStroke->setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpStroke.generate(_myRenderer.getSize(),
_myRenderer.getNumberSubScanLine(),
listSegmentStroke);
}
// add on images:
_myRenderer.print(tmpFill,
colorFill,
tmpStroke,
colorStroke,
this.paint.opacity);
#ifdef DEBUG
_myRenderer.addDebugSegment(listSegmentFill);
_myRenderer.addDebugSegment(listSegmentStroke);
#endif
}
void esvg::Polyline::drawShapePoints(List<etk::Vector<Vector2f>>& _out,
int _recurtionMax,
float _threshold,
mat2x3& _basicTrans,
int _level) {
Log.verbose(spacingDist(_level) << "DRAW Shape esvg::Polyline");
esvg::render::Path listElement = createPath();
mat2x3 mtx = this.transformMatrix;
mtx *= _basicTrans;
esvg::render::PointList listPoints;
listPoints = listElement.generateListPoints(_level, _recurtionMax, _threshold);
listPoints.applyMatrix(mtx);
for (auto &it : listPoints.this.data) {
List<Vector2f> listPoint;
for (auto &itDot : it) {
listPoint.pushBack(itDot.this.pos);
}
_out.pushBack(listPoint);
}
}

View File

@ -1,37 +1,134 @@
package org.atriasoft.esvg;
import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.Point;
import org.atriasoft.esvg.render.PointList;
import org.atriasoft.esvg.render.SegmentList;
import org.atriasoft.esvg.render.Weight;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.exml.model.XmlElement;
import java.util.ArrayList;
import java.util.List;
import org.atriasoft.esvg.internal.Log;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<esvg/Base.hpp>#include<etk/Vector.hpp>
namespace esvg{
class Polyline extends esvg::Base
{
private:
List<Vector2f > this.listPoint; //!< list of all point of the polyline
public:
public class Polyline extends Base {
private final List<Vector2f> listPoint = new ArrayList<>(); //!< list of all point of the polyline
Polyline(PaintState _parentPaintState);~
public Polyline(final PaintState parentPaintState) {
super(parentPaintState);
}
Polyline();
private PathModel createPath() {
PathModel out = new PathModel();
out.clear();
out.moveTo(false, this.listPoint.get(0));
for (int iii = 1; iii < this.listPoint.size(); iii++) {
out.lineTo(false, this.listPoint.get(iii));
}
out.stop();
return out;
}
boolean parseXML(const exml::Element& _element, mat2x3& _parentTrans, Vector2f& _sizeMax) override;
@Override
public void display(final int spacing) {
Log.debug(spacingDist(spacing) + "Polyline nbPoint=" + this.listPoint.size());
}
void display(final int _spacing) override;
@Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW esvg::Polyline");
PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
PointList listPoints;
listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx);
SegmentList listSegmentFill = new SegmentList();
SegmentList listSegmentStroke = new SegmentList();
Weight tmpFill = new Weight();
Weight tmpStroke = new Weight();
DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx);
DynamicColor colorStroke = null;
if (this.paint.strokeWidth > 0.0f) {
colorStroke = DynamicColor.createColor(this.paint.stroke, mtx);
}
// Check if we need to display background
if (colorFill != null) {
listSegmentFill.createSegmentList(listPoints);
colorFill.setViewPort(listSegmentFill.getViewPort());
listSegmentFill.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpFill.generate(myRenderer.getSize(), myRenderer.getNumberSubScanLine(), listSegmentFill);
}
// check if we need to display stroke:
if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit);
colorStroke.setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpStroke.generate(myRenderer.getSize(), myRenderer.getNumberSubScanLine(), listSegmentStroke);
}
// add on images:
myRenderer.print(tmpFill, colorFill, tmpStroke, colorStroke, this.paint.opacity);
//myRenderer.addDebugSegment(listSegmentFill);
//myRenderer.addDebugSegment(listSegmentStroke);
}
void draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int _level) override;
@Override
public void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW Shape esvg::Polyline");
PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix.multiply(basicTrans);
PointList listPoints;
listPoints = listElement.generateListPoints(level, recurtionMax, threshold);
listPoints.applyMatrix(mtx);
for (List<Point> it : listPoints.data) {
List<Vector2f> listPoint = new ArrayList<>();
for (Point itDot : it) {
listPoint.add(itDot.pos);
}
out.add(listPoint);
}
}
void drawShapePoints(List<List<Vector2f>>& _out,
int _recurtionMax,
float _threshold,
mat2x3& _basicTrans,
int _level=1) override;
private:
esvg::render::
Path createPath();
};}
@Override
public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) {
// line must have a minimum size...
this.paint.strokeWidth = 1;
if (element == null) {
return false;
}
parseTransform(element);
parsePaintAttr(element);
// add the property of the parrent modifications ...
this.transformMatrix = this.transformMatrix.multiply(parentTrans);
String sss1 = element.getAttribute("points", "");
if (sss1.length() == 0) {
Log.error("polyline: missing points attribute");
return false;
}
sizeMax.value = Vector2f.ZERO;
Log.verbose("Parse polyline : '" + sss1 + "'");
String[] elems = sss1.split(" ");
for (String elem : elems) {
Vector2f pos = Vector2f.valueOf(elem);
this.listPoint.add(pos);
sizeMax.value = Vector2f.max(sizeMax.value, pos);
}
return true;
}
}

View File

@ -1,185 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/debug.hpp>
#include <esvg/LinearGradient.hpp>
#include <esvg/RadialGradient.hpp>
#include <esvg/render/Path.hpp>
#include <esvg/render/Weight.hpp>
#include <esvg/esvg.hpp>
esvg::RadialGradient::RadialGradient(PaintState _parentPaintState) :
esvg::Base(_parentPaintState),
this.center(Vector2f(50,50), esvg::distance_pourcent),
this.radius(50, esvg::distance_pourcent),
this.focal(Vector2f(50,50), esvg::distance_pourcent),
this.unit(gradientUnits_objectBoundingBox),
this.spread(spreadMethod_pad) {
}
esvg::RadialGradient::~RadialGradient() {
}
boolean esvg::RadialGradient::parseXML(const exml::Element& _element, mat2x3& _parentTrans, Vector2f& _sizeMax) {
// line must have a minimum size...
//this.paint.strokeWidth = 1;
if (_element.exist() == false) {
return false;
}
// ---------------- get unique ID ----------------
this.id = _element.attributes["id"];
//parseTransform(_element);
//parsePaintAttr(_element);
// add the property of the parrent modifications ...
this.transformMatrix *= _parentTrans;
etk::String contentX = _element.attributes["cx"];
etk::String contentY = _element.attributes["cy"];
if ( contentX != ""
&& contentY != "") {
this.center.set(contentX, contentY);
}
contentX = _element.attributes["r"];
if (contentX != "") {
this.radius.set(contentX);
}
contentX = _element.attributes["fx"];
contentY = _element.attributes["fy"];
if ( contentX != ""
&& contentY != "") {
this.focal.set(contentX, contentY);
}
contentX = _element.attributes["gradientUnits"];
if (contentX == "userSpaceOnUse") {
this.unit = gradientUnits_userSpaceOnUse;
} else {
this.unit = gradientUnits_objectBoundingBox;
if ( contentX.size() != 0
&& contentX != "objectBoundingBox") {
Log.error("Parsing error of 'gradientUnits' ==> not suported value: '" << contentX << "' not in : {userSpaceOnUse/objectBoundingBox} use objectBoundingBox");
}
}
contentX = _element.attributes["spreadMethod"];
if (contentX == "reflect") {
this.spread = spreadMethod_reflect;
} else if (contentX == "repeat") {
this.spread = spreadMethod_repeat;
} else {
this.spread = spreadMethod_pad;
if ( contentX.size() != 0
&& contentX != "pad") {
Log.error("Parsing error of 'spreadMethod' ==> not suported value: '" << contentX << "' not in : {reflect/repeate/pad} use pad");
}
}
// note: xlink:href is incompatible with subNode "stop"
this.href = _element.attributes["xlink:href"];
if (this.href.size() != 0) {
this.href = etk::String(this.href.begin()+1, this.href.end());
}
// parse all sub node :
for(auto it : _element.nodes) {
exml::Element child = it.toElement();
if (child.exist() == false) {
// can be a comment ...
continue;
}
if (child.getValue() == "stop") {
float offset = 100;
etk::Color<float,4> stopColor = etk::color::none;
etk::String content = child.attributes["offset"];
if (content.size()!=0) {
Pair<float, enum esvg::distance> tmp = parseLength2(content);
if (tmp.second == esvg::distance_pixel) {
// special case ==> all time % then no type define ==> % in [0.0 .. 1.0]
offset = tmp.first*100.0f;
} else if (tmp.second != esvg::distance_pourcent) {
Log.error("offset : " << content << " res=" << tmp.first << "," << tmp.second << " Not support other than pourcent %");
} else {
offset = tmp.first;
}
}
content = child.attributes["stop-color"];
if (content.size()!=0) {
stopColor = parseColor(content).first;
Log.verbose(" color : \"" << content << "\" == > " << stopColor);
}
content = child.attributes["stop-opacity"];
if (content.size()!=0) {
float opacity = parseLength(content);
opacity = etk::avg(0.0f, opacity, 1.0f);
stopColor.setA(opacity);
Log.verbose(" opacity : '" << content << "' == > " << stopColor);
}
this.data.pushBack(Pair<float, etk::Color<float,4>>(offset, stopColor));
} else {
Log.error("(l " << child.getPos() << ") node not suported : '" << child.getValue() << "' must be [stop]");
}
}
if (this.data.size() != 0) {
if (this.href != "") {
Log.error("(l " << _element.getPos() << ") node can not have an xlink:href element with sub node named: stop ==> removing href");
this.href = "";
}
}
return true;
}
void esvg::RadialGradient::display(int _spacing) {
Log.debug(spacingDist(_spacing) << "RadialGradient center=" << this.center << " focal=" << this.focal << " radius=" << this.radius);
for (auto &it : this.data) {
Log.debug(spacingDist(_spacing+1) << "STOP: offset=" << it.first << " color=" << it.second);
}
}
void esvg::RadialGradient::draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int _level) {
Log.verbose(spacingDist(_level) << "DRAW esvg::RadialGradient");
}
const esvg::Dimension& esvg::RadialGradient::getCenter() {
return this.center;
}
const esvg::Dimension& esvg::RadialGradient::getFocal() {
return this.focal;
}
const esvg::Dimension1D& esvg::RadialGradient::getRadius() {
return this.radius;
}
const List<Pair<float, etk::Color<float,4>>>& esvg::RadialGradient::getColors(esvg::Document* _document) {
if (this.href == "") {
return this.data;
}
if (_document == null) {
Log.error("Get null input for document");
return this.data;
}
ememory::SharedPtr<esvg::Base> base = _document->getReference(this.href);
if (base == null) {
Log.error("Can not get base : '" << this.href << "'");
return this.data;
}
ememory::SharedPtr<esvg::RadialGradient> gradientR = ememory::dynamicPointerCast<esvg::RadialGradient>(base);
if (gradientR == null) {
ememory::SharedPtr<esvg::LinearGradient> gradientL = ememory::dynamicPointerCast<esvg::LinearGradient>(base);
if (gradientL == null) {
Log.error("Can not cast in a linear/radial gradient: '" << this.href << "' ==> wrong type");
return this.data;
}
return gradientL->getColors(_document);
}
return gradientR->getColors(_document);
}

View File

@ -1,37 +1,185 @@
package org.atriasoft.esvg;
import java.util.ArrayList;
import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.Color;
import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.etk.util.Pair;
import org.atriasoft.exml.model.XmlElement;
import org.atriasoft.exml.model.XmlNode;
import org.atriasoft.etk.Dimension;
import org.atriasoft.etk.Dimension1D;
import org.atriasoft.etk.Distance;
import org.atriasoft.etk.math.FMath;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<esvg/Base.hpp>#include<esvg/gradientUnits.hpp>#include<esvg/spreadMethod.hpp>
namespace esvg{
class Document;
class RadialGradient extends esvg::Base
{
private:
esvg::Dimension this.center; //!< gradient position cx cy
esvg::Dimension1D this.radius; //!< Radius of the gradient
esvg::Dimension this.focal; //!< gradient Focal fx fy
public:
enum gradientUnits this.unit;
enum spreadMethod this.spread;
private:
etk::String this.href; //!< in case of using a single gradient in multiple gradient, the gradient is store in an other element...
List<Pair<float, etk::Color<float,4>>> this.data; //!< incompatible with href
public:
RadialGradient(PaintState _parentPaintState);
~RadialGradient();
virtual boolean parseXML(const exml::Element& _element, mat2x3& _parentTrans, Vector2f& _sizeMax);
virtual void display(int _spacing);
virtual void draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int _level);
public:
const esvg::Dimension& getCenter();
const esvg::Dimension& getFocal();
const esvg::Dimension1D& getRadius();
const List<Pair<float, etk::Color<float,4>>>& getColors(esvg::Document* _document);
};
public class RadialGradient extends Base {
private Dimension center = new Dimension(new Vector2f(50, 50), Distance.POURCENT); //!< gradient position cx cy
private final List<Pair<Float, Color>> data = new ArrayList<>(); //!< incompatible with href
private Dimension focal = new Dimension(new Vector2f(50, 50), Distance.POURCENT); //!< gradient Focal fx fy
private String href = ""; //!< in case of using a single gradient in multiple gradient, the gradient is store in an other element...
private Dimension1D radius = new Dimension1D(50, Distance.POURCENT); //!< Radius of the gradient
public SpreadMethod spread = SpreadMethod.PAD;
public GradientUnits unit = GradientUnits.gradientUnitsobjectBoundingBox;
public RadialGradient(final PaintState parentPaintState) {
super(parentPaintState);
}
@Override
public void display(final int spacing) {
Log.debug(spacingDist(spacing) + "RadialGradient center=" + this.center + " focal=" + this.focal + " radius=" + this.radius);
for (Pair<Float, Color> it : this.data) {
Log.debug(spacingDist(spacing + 1) + "STOP: offset=" + it.first + " color=" + it.second);
}
}
@Override
public void draw(final Renderer myRenderer, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW esvg::RadialGradient");
}
public Dimension getCenter() {
return this.center;
}
public List<Pair<Float, Color>> getColors(final EsvgDocument document) {
if (this.href == "") {
return this.data;
}
if (document == null) {
Log.error("Get null input for document");
return this.data;
}
Base base = document.getReference(this.href);
if (base == null) {
Log.error("Can not get base : '" + this.href + "'");
return this.data;
}
if (base instanceof RadialGradient gradientR) {
return gradientR.getColors(document);
}
if (base instanceof LinearGradient gradientL) {
return gradientL.getColors(document);
}
return this.data;
}
public Dimension getFocal() {
return this.focal;
}
public Dimension1D getRadius() {
return this.radius;
}
@Override
public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) {
// line must have a minimum size...
//this.paint.strokeWidth = 1;
if (element == null) {
return false;
}
// ---------------- get unique ID ----------------
this.id = element.getAttribute("id", "");
//parseTransform(element);
//parsePaintAttr(element);
// add the property of the parrent modifications ...
this.transformMatrix = this.transformMatrix.multiply(parentTrans);
String contentX = element.getAttribute("cx", "");
String contentY = element.getAttribute("cy", "");
if (contentX != "" && contentY != "") {
this.center = new Dimension(new Vector2f(Float.parseFloat(contentX), Float.parseFloat(contentY)));
}
contentX = element.getAttribute("r", "");
if (contentX != "") {
this.radius = new Dimension1D(Float.parseFloat(contentX));
}
contentX = element.getAttribute("fx", "");
contentY = element.getAttribute("fy", "");
if (contentX != "" && contentY != "") {
this.focal = new Dimension(new Vector2f(Float.parseFloat(contentX), Float.parseFloat(contentY)));
}
contentX = element.getAttribute("gradientUnits", "");
if (contentX == "userSpaceOnUse") {
this.unit = GradientUnits.gradientUnitsuserSpaceOnUse;
} else {
this.unit = GradientUnits.gradientUnitsobjectBoundingBox;
if (contentX.length() != 0 && contentX != "objectBoundingBox") {
Log.error("Parsing error of 'gradientUnits' ==> not suported value: '" + contentX + "' not in : {userSpaceOnUse/objectBoundingBox} use objectBoundingBox");
}
}
contentX = element.getAttribute("spreadMethod", "");
if (contentX == "reflect") {
this.spread = SpreadMethod.REFLECT;
} else if (contentX == "repeat") {
this.spread = SpreadMethod.REPEAT;
} else {
this.spread = SpreadMethod.PAD;
if (contentX.length() != 0 && contentX != "pad") {
Log.error("Parsing error of 'spreadMethod' ==> not suported value: '" + contentX + "' not in : {reflect/repeate/pad} use pad");
}
}
// note: xlink:href is incompatible with subNode "stop"
this.href = element.getAttribute("xlink:href", "");
if (this.href.length() != 0) {
this.href = this.href.substring(1);
}
// parse all sub node :
for (XmlNode it : element.getNodes()) {
if (it instanceof XmlElement child) {
if (child.getValue() == "stop") {
float offset = 100;
Color stopColor = Color.NONE;
String content = child.getAttribute("offset", "");
if (content.length() != 0) {
Pair<Float, Distance> tmp = parseLength2(content);
if (tmp.second == Distance.PIXEL) {
// special case ==> all time % then no type define ==> % in [0.0 .. 1.0]
offset = tmp.first * 100.0f;
} else if (tmp.second != Distance.POURCENT) {
Log.error("offset : " + content + " res=" + tmp.first + "," + tmp.second + " Not support other than pourcent %");
} else {
offset = tmp.first;
}
}
content = child.getAttribute("stop-color", "");
if (content.length() != 0) {
stopColor = parseColor(content).first;
Log.verbose(" color : \"" + content + "\" == > " + stopColor);
}
content = child.getAttribute("stop-opacity", "");
if (content.length() != 0) {
float opacity = parseLength(content);
opacity = FMath.avg(0.0f, opacity, 1.0f);
stopColor = stopColor.withA(opacity);
Log.verbose(" opacity : '" + content + "' == > " + stopColor);
}
this.data.add(new Pair<Float, Color>(offset, stopColor));
} else {
Log.error("node not suported : '" + child.getValue() + "' must be [stop]");
}
}
}
if (this.data.size() != 0) {
if (this.href != "") {
Log.error("node can not have an xlink:href element with sub node named: stop ==> removing href");
this.href = "";
}
}
return true;
}
}

View File

@ -1,166 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/debug.hpp>
#include <esvg/Rectangle.hpp>
#include <esvg/render/Path.hpp>
#include <esvg/render/Weight.hpp>
esvg::Rectangle::Rectangle(PaintState _parentPaintState) : esvg::Base(_parentPaintState) {
this.position.setValue(0,0);
this.size.setValue(0,0);
this.roundedCorner.setValue(0,0);
}
esvg::Rectangle::~Rectangle() {
}
boolean esvg::Rectangle::parseXML(const exml::Element& _element, mat2x3& _parentTrans, Vector2f& _sizeMax) {
if (_element.exist() == false) {
return false;
}
this.position.setValue(0.0f, 0.0f);
this.size.setValue(0.0f, 0.0f);
this.roundedCorner.setValue(0.0f, 0.0f);
parseTransform(_element);
parsePaintAttr(_element);
// add the property of the parrent modifications ...
this.transformMatrix *= _parentTrans;
parsePosition(_element, this.position, this.size);
etk::String content = _element.attributes["rx"];
if (content.size()!=0) {
this.roundedCorner.setX(parseLength(content));
}
content = _element.attributes["ry"];
if (content.size()!=0) {
this.roundedCorner.setY(parseLength(content));
}
_sizeMax.setValue(this.position.x() + this.size.x() + this.paint.strokeWidth,
this.position.y() + this.size.y() + this.paint.strokeWidth);
return true;
}
void esvg::Rectangle::display(int _spacing) {
Log.debug(spacingDist(_spacing) << "Rectangle : pos=" << this.position << " size=" << this.size << " corner=" << this.roundedCorner);
}
esvg::render::Path esvg::Rectangle::createPath() {
esvg::render::Path out;
out.clear();
if ( this.roundedCorner.x() == 0.0f
|| this.roundedCorner.y() == 0.0f) {
out.moveTo(false, this.position);
out.lineToH(true, this.size.x());
out.lineToV(true, this.size.y());
out.lineToH(true, -this.size.x());
} else {
// Rounded rectangle
out.moveTo(false, this.position + Vector2f(this.roundedCorner.x(), 0.0f));
out.lineToH(true, this.size.x()-this.roundedCorner.x()*2.0f);
out.curveTo(true, Vector2f(this.roundedCorner.x()*esvg::kappa90, 0.0f),
Vector2f(this.roundedCorner.x(), this.roundedCorner.y() * (1.0f - esvg::kappa90)),
Vector2f(this.roundedCorner.x(), this.roundedCorner.y()) );
out.lineToV(true, this.size.y()-this.roundedCorner.y()*2.0f);
out.curveTo(true, Vector2f(0.0f, this.roundedCorner.y() * esvg::kappa90),
Vector2f(-this.roundedCorner.x()* (1.0f - esvg::kappa90), this.roundedCorner.y()),
Vector2f(-this.roundedCorner.x(), this.roundedCorner.y()) );
out.lineToH(true, -(this.size.x()-this.roundedCorner.x()*2.0f));
out.curveTo(true, Vector2f(-this.roundedCorner.x()*esvg::kappa90, 0.0f),
Vector2f(-this.roundedCorner.x(), -this.roundedCorner.y() * (1.0f - esvg::kappa90)),
Vector2f(-this.roundedCorner.x(), -this.roundedCorner.y()) );
out.lineToV(true, -(this.size.y()-this.roundedCorner.y()*2.0f));
out.curveTo(true, Vector2f(0.0f, -this.roundedCorner.y() * esvg::kappa90),
Vector2f(this.roundedCorner.x()* (1.0f - esvg::kappa90), -this.roundedCorner.y()),
Vector2f(this.roundedCorner.x(), -this.roundedCorner.y()) );
}
out.close();
return out;
}
void esvg::Rectangle::draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, 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);
esvg::render::Path listElement = createPath();
mat2x3 mtx = this.transformMatrix;
mtx *= _basicTrans;
esvg::render::PointList listPoints;
listPoints = listElement.generateListPoints(_level,
_myRenderer.getInterpolationRecurtionMax(),
_myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx);
esvg::render::SegmentList listSegmentFill;
esvg::render::SegmentList listSegmentStroke;
esvg::render::Weight tmpFill;
esvg::render::Weight tmpStroke;
ememory::SharedPtr<esvg::render::DynamicColor> colorFill = esvg::render::createColor(this.paint.fill, mtx);
ememory::SharedPtr<esvg::render::DynamicColor> colorStroke;
if (this.paint.strokeWidth > 0.0f) {
colorStroke = esvg::render::createColor(this.paint.stroke, mtx);
}
// Check if we need to display background
if (colorFill != null) {
listSegmentFill.createSegmentList(listPoints);
colorFill->setViewPort(listSegmentFill.getViewPort());
listSegmentFill.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpFill.generate(_myRenderer.getSize(),
_myRenderer.getNumberSubScanLine(),
listSegmentFill);
}
// check if we need to display stroke:
if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints,
this.paint.strokeWidth,
this.paint.lineCap,
this.paint.lineJoin,
this.paint.miterLimit);
colorStroke->setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpStroke.generate(_myRenderer.getSize(),
_myRenderer.getNumberSubScanLine(),
listSegmentStroke);
}
// add on images:
_myRenderer.print(tmpFill,
colorFill,
tmpStroke,
colorStroke,
this.paint.opacity);
#ifdef DEBUG
_myRenderer.addDebugSegment(listSegmentFill);
_myRenderer.addDebugSegment(listSegmentStroke);
#endif
}
void esvg::Rectangle::drawShapePoints(List<etk::Vector<Vector2f>>& _out,
int _recurtionMax,
float _threshold,
mat2x3& _basicTrans,
int _level) {
Log.verbose(spacingDist(_level) << "DRAW Shape esvg::Rectangle");
esvg::render::Path listElement = createPath();
mat2x3 mtx = this.transformMatrix;
mtx *= _basicTrans;
esvg::render::PointList listPoints;
listPoints = listElement.generateListPoints(_level, _recurtionMax, _threshold);
listPoints.applyMatrix(mtx);
for (auto &it : listPoints.this.data) {
List<Vector2f> listPoint;
for (auto &itDot : it) {
listPoint.pushBack(itDot.this.pos);
}
_out.pushBack(listPoint);
}
}

View File

@ -1,39 +1,156 @@
package org.atriasoft.esvg;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.exml.model.XmlElement;
import java.util.ArrayList;
import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.PathModel;
import org.atriasoft.esvg.render.Point;
import org.atriasoft.esvg.render.PointList;
import org.atriasoft.esvg.render.SegmentList;
import org.atriasoft.esvg.render.Weight;
import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<esvg/Base.hpp>
namespace esvg{
class Rectangle extends esvg::Base
{
private:
Vector2f this.position; //!< position of the rectangle
Vector2f this.size; //!< size of the rectangle
Vector2f this.roundedCorner; //!< property of the rounded corner
public:
public class Rectangle extends Base {
private Vector2f position = Vector2f.ZERO; //!< position of the rectangle
private Vector2f roundedCorner = Vector2f.ZERO; //!< property of the rounded corner
private Vector2f size = Vector2f.ZERO; //!< size of the rectangle
Rectangle(PaintState _parentPaintState);~
public Rectangle(final PaintState parentPaintState) {
super(parentPaintState);
}
Rectangle();
private PathModel createPath() {
PathModel out = new PathModel();
out.clear();
if (this.roundedCorner.x() == 0.0f || this.roundedCorner.y() == 0.0f) {
out.moveTo(false, this.position);
out.lineToH(true, this.size.x());
out.lineToV(true, this.size.y());
out.lineToH(true, -this.size.x());
} else {
// Rounded rectangle
out.moveTo(false, this.position.add(this.roundedCorner.x(), 0.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)),
new Vector2f(this.roundedCorner.x(), this.roundedCorner.y()));
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()),
new Vector2f(-this.roundedCorner.x(), this.roundedCorner.y()));
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)),
new Vector2f(-this.roundedCorner.x(), -this.roundedCorner.y()));
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()),
new Vector2f(this.roundedCorner.x(), -this.roundedCorner.y()));
}
out.close();
return out;
}
boolean parseXML(const exml::Element& _element, mat2x3& _parentTrans, Vector2f& _sizeMax) override;
@Override
public void display(final int spacing) {
Log.debug(spacingDist(spacing) + "Rectangle : pos=" + this.position + " size=" + this.size + " corner=" + this.roundedCorner);
}
void display(final int _spacing) override;
@Override
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);
PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix;
mtx = mtx.multiply(basicTrans);
PointList listPoints = new PointList();
listPoints = listElement.generateListPoints(level, myRenderer.getInterpolationRecurtionMax(), myRenderer.getInterpolationThreshold());
//listPoints.applyMatrix(mtx);
SegmentList listSegmentFill = new SegmentList();
SegmentList listSegmentStroke = new SegmentList();
Weight tmpFill = new Weight();
Weight tmpStroke = new Weight();
DynamicColor colorFill = DynamicColor.createColor(this.paint.fill, mtx);
DynamicColor colorStroke = null;
if (this.paint.strokeWidth > 0.0f) {
colorStroke = DynamicColor.createColor(this.paint.stroke, mtx);
}
// Check if we need to display background
if (colorFill != null) {
listSegmentFill.createSegmentList(listPoints);
colorFill.setViewPort(listSegmentFill.getViewPort());
listSegmentFill.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpFill.generate(myRenderer.getSize(), myRenderer.getNumberSubScanLine(), listSegmentFill);
}
// check if we need to display stroke:
if (colorStroke != null) {
listSegmentStroke.createSegmentListStroke(listPoints, this.paint.strokeWidth, this.paint.lineCap, this.paint.lineJoin, this.paint.miterLimit);
colorStroke.setViewPort(listSegmentStroke.getViewPort());
listSegmentStroke.applyMatrix(mtx);
// now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
tmpStroke.generate(myRenderer.getSize(), myRenderer.getNumberSubScanLine(), listSegmentStroke);
}
// add on images:
myRenderer.print(tmpFill, colorFill, tmpStroke, colorStroke, this.paint.opacity);
//myRenderer.addDebugSegment(listSegmentFill);
//myRenderer.addDebugSegment(listSegmentStroke)
}
void draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int _level) override;
@Override
public void drawShapePoints(final List<List<Vector2f>> out, final int recurtionMax, final float threshold, final Matrix2x3f basicTrans, final int level) {
Log.verbose(spacingDist(level) + "DRAW Shape esvg::Rectangle");
PathModel listElement = createPath();
Matrix2x3f mtx = this.transformMatrix;
mtx = mtx.multiply(basicTrans);
PointList listPoints;
listPoints = listElement.generateListPoints(level, recurtionMax, threshold);
listPoints.applyMatrix(mtx);
for (List<Point> it : listPoints.data) {
List<Vector2f> listPoint = new ArrayList<>();
for (Point itDot : it) {
listPoint.add(itDot.pos);
}
out.add(listPoint);
}
}
void drawShapePoints(List<List<Vector2f>>& _out,
int _recurtionMax,
float _threshold,
mat2x3& _basicTrans,
int _level=1) override;
private:
esvg::render::
Path createPath();
};}
@Override
public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) {
if (element == null) {
return false;
}
this.position = Vector2f.ZERO;
this.size = Vector2f.ZERO;
this.roundedCorner = Vector2f.ZERO;
parseTransform(element);
parsePaintAttr(element);
// add the property of the parrent modifications ...
this.transformMatrix = this.transformMatrix.multiply(parentTrans);
this.position = parseXmlPosition(element);
this.size = parseXmlSize(element);
String content = element.getAttribute("rx", "");
if (content.length() != 0) {
this.roundedCorner = this.roundedCorner.withX(parseLength(content));
}
content = element.getAttribute("ry", "");
if (content.length() != 0) {
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);
return true;
}
}

View File

@ -1,427 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/debug.hpp>
#include <esvg/Renderer.hpp>
#include <etk/uri/Uri.hpp>
#include <etk/uri/provider/provider.hpp>
esvg::Renderer::Renderer(const Vector2i& _size, esvg::Document* _document, boolean _visualDebug) :
#ifdef DEBUG
this.visualDebug(_visualDebug),
this.factor(1),
#endif
this.interpolationRecurtionMax(10),
this.interpolationThreshold(0.25f),
this.nbSubScanLine(8),
this.document(_document) {
#ifdef DEBUG
if (this.visualDebug == true) {
this.factor = 20;
}
#endif
setSize(_size);
}
esvg::Renderer::~Renderer() {
this.buffer.clear();
this.size = Vector2i(0,0);
}
etk::Color<float,4> esvg::Renderer::mergeColor(etk::Color<float,4> _base, etk::Color<float,4> _integration) {
etk::Color<float,4> result;
/*
if (_integration.a() < _base.a()) {
result = _integration;
_integration = _base;
_base = result;
}
*/
result.setR(_integration.a() * _integration.r() + _base.a() * (1.0f - _integration.a()) * _base.r());
result.setG(_integration.a() * _integration.g() + _base.a() * (1.0f - _integration.a()) * _base.g());
result.setB(_integration.a() * _integration.b() + _base.a() * (1.0f - _integration.a()) * _base.b());
result.setA(_integration.a() + _base.a() * (1.0f - _integration.a()));
if (result.a() != 0.0f) {
float reverse = 1.0f/result.a();
result.setR(result.r()*reverse);
result.setG(result.g()*reverse);
result.setB(result.b()*reverse);
}
return result;
}
void esvg::Renderer::print(const esvg::render::Weight& _weightFill,
ememory::SharedPtr<esvg::render::DynamicColor>& _colorFill,
const esvg::render::Weight& _weightStroke,
ememory::SharedPtr<esvg::render::DynamicColor>& _colorStroke,
float _opacity) {
if (_colorFill != null) {
//_colorFill->setViewPort(Pair<Vector2f, Vector2f>(Vector2f(0,0), Vector2f(sizeX, sizeY)));
_colorFill->generate(this.document);
}
if (_colorStroke != null) {
//_colorStroke->setViewPort(Pair<Vector2f, Vector2f>(Vector2f(0,0), Vector2f(sizeX, sizeY)));
_colorStroke->generate(this.document);
}
// all together
for (int yyy=0; yyy<this.size.y(); ++yyy) {
for (int xxx=0; xxx<this.size.x(); ++xxx) {
Vector2i pos(xxx, yyy);
float valueFill = _weightFill.get(pos);
float valueStroke = _weightStroke.get(pos);
// calculate merge of stroke and fill value:
etk::Color<float,4> intermediateColorFill(etk::color::none);
etk::Color<float,4> intermediateColorStroke(etk::color::none);
if ( _colorFill != null
&& valueFill != 0.0f) {
intermediateColorFill = _colorFill->getColor(pos);
intermediateColorFill.setA(intermediateColorFill.a()*valueFill);
}
if ( _colorStroke != null
&& valueStroke != 0.0f) {
intermediateColorStroke = _colorStroke->getColor(pos);
intermediateColorStroke.setA(intermediateColorStroke.a()*valueStroke);
}
etk::Color<float,4> intermediateColor = mergeColor(intermediateColorFill, intermediateColorStroke);
intermediateColor.setA(intermediateColor.a() * _opacity);
#if DEBUG
for (int deltaY=0; deltaY<this.factor; ++deltaY) {
for (int deltaX=0; deltaX<this.factor; ++deltaX) {
int id = this.size.x()*this.factor*(yyy*this.factor+deltaY) + (xxx*this.factor+deltaX);
this.buffer[id] = mergeColor(this.buffer[id], intermediateColor);
}
}
#else
this.buffer[this.size.x()*yyy + xxx] = mergeColor(this.buffer[this.size.x()*yyy + xxx], intermediateColor);
#endif
}
}
#ifdef DEBUG
// display the gradient position:
ememory::SharedPtr<esvg::render::DynamicColorSpecial> tmpColor = ememory::dynamicPointerCast<esvg::render::DynamicColorSpecial>(_colorFill);
if (tmpColor != null) {
esvg::render::SegmentList listSegment;
// Display bounding box
listSegment.addSegment(esvg::render::Point(tmpColor->this.viewPort.first),
esvg::render::Point(Vector2f(tmpColor->this.viewPort.first.x(), tmpColor->this.viewPort.second.y()) ),
false);
listSegment.addSegment(esvg::render::Point(Vector2f(tmpColor->this.viewPort.first.x(), tmpColor->this.viewPort.second.y()) ),
esvg::render::Point(tmpColor->this.viewPort.second),
false);
listSegment.addSegment(esvg::render::Point(tmpColor->this.viewPort.second),
esvg::render::Point(Vector2f(tmpColor->this.viewPort.second.x(), tmpColor->this.viewPort.first.y()) ),
false);
listSegment.addSegment(esvg::render::Point(Vector2f(tmpColor->this.viewPort.second.x(), tmpColor->this.viewPort.first.y()) ),
esvg::render::Point(tmpColor->this.viewPort.first),
false);
listSegment.applyMatrix(tmpColor->this.matrix);
// display the gradient axis
listSegment.addSegment(esvg::render::Point(tmpColor->this.pos1),
esvg::render::Point(tmpColor->this.pos2),
false);
/*
mat2x3 this.matrix;
Pair<Vector2f, Vector2f> this.viewPort;
Vector2f this.pos1;
Vector2f this.pos2;
*/
addDebugSegment(listSegment);
}
#endif
}
#ifdef DEBUG
void esvg::Renderer::addDebugSegment(const esvg::render::SegmentList& _listSegment) {
if (this.visualDebug == false) {
return;
}
Vector2i dynamicSize = this.size * this.factor;
// for each lines:
for (int yyy=0; yyy<dynamicSize.y(); ++yyy) {
// Reduce the number of lines in the subsampling parsing:
List<esvg::render::Segment> availlableSegmentPixel;
for (auto &it : _listSegment.this.data) {
if ( it.p0.y() * this.factor <= float(yyy+1)
&& it.p1.y() * this.factor >= float(yyy)) {
availlableSegmentPixel.pushBack(it);
}
}
//find all the segment that cross the middle of the line of the center of the pixel line:
float subSamplingCenterPos = yyy + 0.5f;
List<esvg::render::Segment> availlableSegment;
// find in the subList ...
for (auto &it : availlableSegmentPixel) {
if ( it.p0.y() * this.factor <= subSamplingCenterPos
&& it.p1.y() * this.factor >= subSamplingCenterPos ) {
availlableSegment.pushBack(it);
}
}
// x position, angle
List<Pair<float, float>> listPosition;
for (auto &it : availlableSegment) {
Vector2f delta = it.p0 * this.factor - it.p1 * this.factor;
// x = coefficent*y+bbb;
float coefficient = delta.x()/delta.y();
float bbb = it.p0.x() * this.factor - coefficient*it.p0.y() * this.factor;
float xpos = coefficient * subSamplingCenterPos + bbb;
if ( xpos >= 0
&& xpos < dynamicSize.x()
&& yyy >= 0
&& yyy < dynamicSize.y() ) {
if (it.direction == 1.0f) {
this.buffer[(dynamicSize.x()*yyy + int(xpos))] = etk::color::blue;
} else {
this.buffer[(dynamicSize.x()*yyy + int(xpos))] = etk::color::darkRed;
}
}
}
}
// for each colomn:
for (int xxx=0; xxx<dynamicSize.x(); ++xxx) {
// Reduce the number of lines in the subsampling parsing:
List<esvg::render::Segment> availlableSegmentPixel;
for (auto &it : _listSegment.this.data) {
if ( ( it.p0.x() * this.factor <= float(xxx+1)
&& it.p1.x() * this.factor >= float(xxx) )
|| ( it.p0.x() * this.factor >= float(xxx+1)
&& it.p1.x() * this.factor <= float(xxx) ) ) {
availlableSegmentPixel.pushBack(it);
}
}
//find all the segment that cross the middle of the line of the center of the pixel line:
float subSamplingCenterPos = xxx + 0.5f;
List<esvg::render::Segment> availlableSegment;
// find in the subList ...
for (auto &it : availlableSegmentPixel) {
if ( ( it.p0.x() * this.factor <= subSamplingCenterPos
&& it.p1.x() * this.factor >= subSamplingCenterPos)
|| ( it.p0.x() * this.factor >= subSamplingCenterPos
&& it.p1.x() * this.factor <= subSamplingCenterPos) ) {
availlableSegment.pushBack(it);
}
}
// x position, angle
List<Pair<float, float>> listPosition;
for (auto &it : availlableSegment) {
Vector2f delta = it.p0 * this.factor - it.p1 * this.factor;
// x = coefficent*y+bbb;
if (delta.x() == 0) {
continue;
}
float coefficient = delta.y()/delta.x();
float bbb = it.p0.y() * this.factor - coefficient*it.p0.x() * this.factor;
float ypos = coefficient * subSamplingCenterPos + bbb;
if ( ypos >= 0
&& ypos < dynamicSize.y()
&& xxx >= 0
&& xxx < dynamicSize.y() ) {
if (it.direction == 1.0f) {
this.buffer[(dynamicSize.x()*int(ypos) + xxx)] = etk::color::blue;
} else {
this.buffer[(dynamicSize.x()*int(ypos) + xxx)] = etk::color::darkRed;
}
}
}
}
}
#endif
void esvg::Renderer::writePPM(const etk::Uri& _uri) {
if (this.buffer.size() == 0) {
return;
}
auto fileIo = etk::uri::get(_uri);
if (fileIo == null) {
Log.error("Can not create the uri: " << _uri);
return;
}
if (fileIo->open(etk::io::OpenMode::Write) == false) {
Log.error("Can not open (r) the file : " << _uri);
return;
}
int sizeX = this.size.x();
int sizeY = this.size.y();
#if DEBUG
sizeX *= this.factor;
sizeY *= this.factor;
#endif
Log.debug("Generate ppm : " << this.size << " debug size=" << Vector2i(sizeX,sizeY));
char tmpValue[1024];
sprintf(tmpValue, "P6 %d %d 255 ", sizeX, sizeY);
fileIo->write(tmpValue,1,sizeof(tmpValue));
for (int iii=0 ; iii<sizeX*sizeY; iii++) {
etk::Color<uint8_t,3> tmp = this.buffer[iii];
fileIo->write(&tmp, 1, 3);
}
fileIo->close();
}
#define PLOPPP
extern "C" {
#pragma pack(push,1)
struct bitmapFileHeader {
int16_t bfType;
int bfSize;
int bfReserved;
int bfOffBits;
};
struct bitmapInfoHeader {
int biSize;
int biWidth;
int biHeight;
int16_t biPlanes;
int16_t biBitCount;
int biCompression;
int biSizeImage;
int biXPelsPerMeter;
int biYPelsPerMeter;
#ifndef PLOPPP
int biClrUsed;
int biClrImportant;
#else
// https://en.wikipedia.org/wiki/BMP_file_format / example 2
int biPaletteNumber;
int biImportantColor;
int biBitMaskRed;
int biBitMaskGreen;
int biBitMaskBlue;
int biBitMaskAlpha;
int biLCSColorSpace;
int biUnused[16];
#endif
};
#pragma pack(pop)
}
void esvg::Renderer::writeBMP(const etk::Uri& _uri) {
if (this.buffer.size() == 0) {
return;
}
auto fileIo = etk::uri::get(_uri);
if (fileIo == null) {
Log.error("Can not create the uri: " << _uri);
return;
}
if (fileIo->open(etk::io::OpenMode::Write) == false) {
Log.error("Can not open (r) the file : " << _uri);
return;
}
struct bitmapFileHeader fileHeader;
struct bitmapInfoHeader infoHeader;
int sizeX = this.size.x();
int sizeY = this.size.y();
#if DEBUG
sizeX *= this.factor;
sizeY *= this.factor;
#endif
fileHeader.bfType = 0x4D42;
fileHeader.bfSize = sizeof(struct bitmapFileHeader) + sizeof(struct bitmapInfoHeader) + sizeX*sizeY*4;
fileHeader.bfReserved = 0;
fileHeader.bfOffBits = sizeof(struct bitmapFileHeader) + sizeof(struct bitmapInfoHeader);
infoHeader.biSize = sizeof(struct bitmapInfoHeader);
infoHeader.biWidth = sizeX;
infoHeader.biHeight = sizeY;
infoHeader.biPlanes = 1;
infoHeader.biBitCount = 32;
#ifndef PLOPPP
infoHeader.biCompression = 0;
#else
infoHeader.biCompression = 3;
#endif
infoHeader.biSizeImage = sizeX*sizeY*4;
infoHeader.biXPelsPerMeter = 75;
infoHeader.biYPelsPerMeter = 75;
#ifndef PLOPPP
infoHeader.biClrUsed = 0;
infoHeader.biClrImportant = 0;
#else
infoHeader.biPaletteNumber = 0;
infoHeader.biImportantColor = 0;
infoHeader.biBitMaskRed = 0xFF000000;
infoHeader.biBitMaskGreen = 0x00FF0000;
infoHeader.biBitMaskBlue =0x0000FF00;
infoHeader.biBitMaskAlpha = 0x000000FF;
infoHeader.biLCSColorSpace = 0x73524742; // "Win "
for (int jjj=0; jjj<16; ++jjj) {
infoHeader.biUnused[jjj] = 0;
}
infoHeader.biUnused[12] = 0x00000002;
#endif
// get the data :
fileIo->write(&fileHeader, sizeof(struct bitmapFileHeader), 1);
fileIo->write(&infoHeader, sizeof(struct bitmapInfoHeader), 1);
uint8_t data[16];
for(int yyy=sizeY-1; yyy>=0; --yyy) {
for(int xxx=0; xxx<sizeX; ++xxx) {
const etk::Color<uint8_t,4>& tmpColor = this.buffer[sizeX*yyy + xxx];
uint8_t* pointer = data;
#ifndef PLOPPP
*pointer++ = tmpColor.a();
*pointer++ = tmpColor.r();
*pointer++ = tmpColor.g();
*pointer++ = tmpColor.b();
#else
*pointer++ = tmpColor.a();
*pointer++ = tmpColor.b();
*pointer++ = tmpColor.g();
*pointer++ = tmpColor.r();
#endif
fileIo->write(data,1,4);
}
}
fileIo->close();
}
void esvg::Renderer::setSize(const Vector2i& _size) {
this.size = _size;
this.buffer.resize(this.size.x() * this.size.y()
#if DEBUG
* this.factor * this.factor
#endif
, etk::color::none);
}
const Vector2i& esvg::Renderer::getSize() const {
return this.size;
}
List<etk::Color<float,4>> esvg::Renderer::getData() {
return this.buffer;
}
void esvg::Renderer::setInterpolationRecurtionMax(int _value) {
this.interpolationRecurtionMax = etk::avg(1, _value, 200);
}
int esvg::Renderer::getInterpolationRecurtionMax() const {
return this.interpolationRecurtionMax;
}
void esvg::Renderer::setInterpolationThreshold(float _value) {
this.interpolationThreshold = etk::avg(0.0f, _value, 20000.0f);
}
float esvg::Renderer::getInterpolationThreshold() const {
return this.interpolationThreshold;
}
void esvg::Renderer::setNumberSubScanLine(int _value) {
this.nbSubScanLine = etk::avg(1, _value, 200);
}
int esvg::Renderer::getNumberSubScanLine() const {
return this.nbSubScanLine;
}

View File

@ -1,83 +1,301 @@
package org.atriasoft.esvg;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.atriasoft.esvg.render.DynamicColor;
import org.atriasoft.esvg.render.DynamicColorSpecial;
import org.atriasoft.esvg.render.Point;
import org.atriasoft.esvg.render.Segment;
import org.atriasoft.esvg.render.SegmentList;
import org.atriasoft.esvg.render.Weight;
import org.atriasoft.etk.Color;
import org.atriasoft.etk.Uri;
import org.atriasoft.etk.math.FMath;
import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.math.Vector2i;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<etk/types.hpp>#include<etk/math/Vector2D.hpp>#include<etk/Color.hpp>#include<esvg/render/Weight.hpp>#include<esvg/render/DynamicColor.hpp>#include<etk/uri/uri.hpp>
namespace esvg{
class Document;
class Renderer {
#ifdef DEBUG
private:
boolean this.visualDebug;
int this.factor;
#endif
public:
Renderer(const Vector2i& _size, esvg::Document* _document, boolean _visualDebug=false);
~Renderer();
protected:
Vector2i this.size;
public:
void setSize(const Vector2i& _size);
const Vector2i& getSize() const;
protected:
List<etk::Color<float,4>> this.buffer;
public:
List<etk::Color<float,4>> getData();
protected:
int this.interpolationRecurtionMax;
public:
void setInterpolationRecurtionMax(int _value);
int getInterpolationRecurtionMax() const;
protected:
float this.interpolationThreshold;
public:
void setInterpolationThreshold(float _value);
float getInterpolationThreshold() const;
protected:
int this.nbSubScanLine;
public:
void setNumberSubScanLine(int _value);
int getNumberSubScanLine() const;
public:
void writePPM(const etk::Uri& _uri);
void writeBMP(const etk::Uri& _uri);
protected:
etk::Color<float,4> mergeColor(etk::Color<float,4> _base, etk::Color<float,4> _integration);
public:
void print(const esvg::render::Weight& _weightFill,
ememory::SharedPtr<esvg::render::DynamicColor>& _colorFill,
const esvg::render::Weight& _weightStroke,
ememory::SharedPtr<esvg::render::DynamicColor>& _colorStroke,
float _opacity);
#ifdef DEBUG
void addDebugSegment(const esvg::render::SegmentList& _listSegment);
void addDebug(const List<Pair<Vector2f,Vector2f>>& _info);
#endif
protected:
esvg::Document* this.document;
public:
esvg::Document*
getMainDocument() {
return this.document;
public class Renderer {
private static final boolean DEBUG_MODE = false;
protected Color[][] buffer; // for debug
protected EsvgDocument document; // for debug
private int factor = 1;
protected int interpolationRecurtionMax = 10;
protected float interpolationThreshold = 0.25f;
protected int nbSubScanLine = 8;
protected Vector2i size;
private final boolean visualDebug = false;
public Renderer(final Vector2i size, final EsvgDocument document) {
this(size, document, false);
}
public Renderer(final Vector2i size, final EsvgDocument document, final boolean visualDebug) {
this.size = size;
this.document = document;
if (Renderer.DEBUG_MODE) {
if (this.visualDebug) {
this.factor = 20;
}
};
}
setSize(size);
}
void addDebugSegment(final SegmentList listSegment) {
if (!this.visualDebug) {
return;
}
Vector2i dynamicSize = this.size.multiply(this.factor);
// for each lines:
for (int yyy = 0; yyy < dynamicSize.y(); ++yyy) {
// Reduce the number of lines in the subsampling parsing:
List<Segment> availlableSegmentPixel = new ArrayList<>();
for (Segment it : listSegment.data) {
if (it.p0.y() * this.factor <= yyy + 1 && it.p1.y() * this.factor >= (yyy)) {
availlableSegmentPixel.add(it);
}
}
//find all the segment that cross the middle of the line of the center of the pixel line:
float subSamplingCenterPos = yyy + 0.5f;
List<Segment> availlableSegment = new ArrayList<>();
// find in the subList ...
for (Segment it : availlableSegmentPixel) {
if (it.p0.y() * this.factor <= subSamplingCenterPos && it.p1.y() * this.factor >= subSamplingCenterPos) {
availlableSegment.add(it);
}
}
// x position, angle
for (Segment it : availlableSegment) {
Vector2f delta = it.p0.multiply(this.factor).less(it.p1.multiply(this.factor));
// x = coefficent*y+bbb;
float coefficient = delta.x() / delta.y();
float bbb = it.p0.x() * this.factor - coefficient * it.p0.y() * this.factor;
float xpos = coefficient * subSamplingCenterPos + bbb;
if (xpos >= 0 && xpos < dynamicSize.x() && yyy >= 0 && yyy < dynamicSize.y()) {
if (it.direction == 1.0f) {
this.buffer[yyy][(int) (xpos)] = Color.BLUE;
} else {
this.buffer[yyy][(int) (xpos)] = Color.DARK_RED;
}
}
}
}
// for each colomn:
for (int xxx = 0; xxx < dynamicSize.x(); ++xxx) {
// Reduce the number of lines in the subsampling parsing:
List<Segment> availlableSegmentPixel = new ArrayList<>();
for (Segment it : listSegment.data) {
if ((it.p0.x() * this.factor <= xxx + 1 && it.p1.x() * this.factor >= (xxx)) || (it.p0.x() * this.factor >= xxx + 1 && it.p1.x() * this.factor <= (xxx))) {
availlableSegmentPixel.add(it);
}
}
//find all the segment that cross the middle of the line of the center of the pixel line:
float subSamplingCenterPos = xxx + 0.5f;
List<Segment> availlableSegment = new ArrayList<>();
// find in the subList ...
for (Segment it : availlableSegmentPixel) {
if ((it.p0.x() * this.factor <= subSamplingCenterPos && it.p1.x() * this.factor >= subSamplingCenterPos)
|| (it.p0.x() * this.factor >= subSamplingCenterPos && it.p1.x() * this.factor <= subSamplingCenterPos)) {
availlableSegment.add(it);
}
}
// x position, angle
for (Segment it : availlableSegment) {
Vector2f delta = it.p0.multiply(this.factor).less(it.p1.multiply(this.factor));
// x = coefficent*y+bbb;
if (delta.x() == 0) {
continue;
}
float coefficient = delta.y() / delta.x();
float bbb = it.p0.y() * this.factor - coefficient * it.p0.x() * this.factor;
float ypos = coefficient * subSamplingCenterPos + bbb;
if (ypos >= 0 && ypos < dynamicSize.y() && xxx >= 0 && xxx < dynamicSize.y()) {
if (it.direction == 1.0f) {
this.buffer[(int) (ypos)][xxx] = Color.BLUE;
} else {
this.buffer[(int) (ypos)][xxx] = Color.DARK_RED;
}
}
}
}
}
Color[][] getData() {
return this.buffer;
}
int getInterpolationRecurtionMax() {
return this.interpolationRecurtionMax;
}
float getInterpolationThreshold() {
return this.interpolationThreshold;
}
public EsvgDocument getMainDocument() {
return this.document;
}
int getNumberSubScanLine() {
return this.nbSubScanLine;
}
Vector2i getSize() {
return this.size;
}
protected Color mergeColor(final Color base, final Color integration) {
/*
if (integration.a() < base.a()) {
result = integration;
integration = base;
base = result;
}
*/
float r = (integration.a() * integration.r() + base.a() * (1.0f - integration.a()) * base.r());
float g = (integration.a() * integration.g() + base.a() * (1.0f - integration.a()) * base.g());
float b = (integration.a() * integration.b() + base.a() * (1.0f - integration.a()) * base.b());
float a = (integration.a() + base.a() * (1.0f - integration.a()));
if (a != 0.0f) {
float reverse = 1.0f / a;
r *= reverse;
g *= reverse;
b *= reverse;
}
return new Color(r, g, b, a);
}
public void print(final Weight weightFill, final DynamicColor colorFill, final Weight weightStroke, final DynamicColor colorStroke, final float opacity) {
if (colorFill != null) {
//colorFill.setViewPort(Pair<Vector2f, Vector2f>(new Vector2f(0,0), Vector2f(sizeX, sizeY)));
colorFill.generate(this.document);
}
if (colorStroke != null) {
//colorStroke.setViewPort(Pair<Vector2f, Vector2f>(new Vector2f(0,0), Vector2f(sizeX, sizeY)));
colorStroke.generate(this.document);
}
// all together
for (int yyy = 0; yyy < this.size.y(); ++yyy) {
for (int xxx = 0; xxx < this.size.x(); ++xxx) {
Vector2i pos = new Vector2i(xxx, yyy);
float valueFill = weightFill.get(pos);
float valueStroke = weightStroke.get(pos);
// calculate merge of stroke and fill value:
Color intermediateColorFill = Color.NONE;
Color intermediateColorStroke = Color.NONE;
if (colorFill != null && valueFill != 0.0f) {
intermediateColorFill = colorFill.getColor(pos);
intermediateColorFill = intermediateColorFill.withA(intermediateColorFill.a() * valueFill);
}
if (colorStroke != null && valueStroke != 0.0f) {
intermediateColorStroke = colorStroke.getColor(pos);
intermediateColorStroke = intermediateColorStroke.withA(intermediateColorStroke.a() * valueStroke);
}
Color intermediateColor = mergeColor(intermediateColorFill, intermediateColorStroke);
intermediateColor = intermediateColor.withA(intermediateColor.a() * opacity);
if (Renderer.DEBUG_MODE) {
for (int deltaY = 0; deltaY < this.factor; ++deltaY) {
for (int deltaX = 0; deltaX < this.factor; ++deltaX) {
int idx = xxx * this.factor + deltaX;
int idy = yyy * this.factor + deltaY;
this.buffer[idy][idx] = mergeColor(this.buffer[idy][idx], intermediateColor);
}
}
} else {
this.buffer[yyy][xxx] = mergeColor(this.buffer[yyy][xxx], intermediateColor);
}
}
}
if (Renderer.DEBUG_MODE) {
// display the gradient position:
DynamicColorSpecial tmpColor = (DynamicColorSpecial) (colorFill);
if (tmpColor != null) {
SegmentList listSegment = new SegmentList();
// Display bounding box
listSegment.addSegment(new Point(tmpColor.viewPort.first), new Point(new Vector2f(tmpColor.viewPort.first.x(), tmpColor.viewPort.second.y())), false);
listSegment.addSegment(new Point(new Vector2f(tmpColor.viewPort.first.x(), tmpColor.viewPort.second.y())), new Point(tmpColor.viewPort.second), false);
listSegment.addSegment(new Point(tmpColor.viewPort.second), new Point(new Vector2f(tmpColor.viewPort.second.x(), tmpColor.viewPort.first.y())), false);
listSegment.addSegment(new Point(new Vector2f(tmpColor.viewPort.second.x(), tmpColor.viewPort.first.y())), new Point(tmpColor.viewPort.first), false);
listSegment.applyMatrix(tmpColor.matrix);
// display the gradient axis
listSegment.addSegment(new Point(tmpColor.pos1), new Point(tmpColor.pos2), false);
/*
Matrix2x3f this.matrix;
Pair<Vector2f, Vector2f> this.viewPort;
Vector2f this.pos1;
Vector2f this.pos2;
*/
addDebugSegment(listSegment);
}
}
}
public void setInterpolationRecurtionMax(final int value) {
this.interpolationRecurtionMax = FMath.avg(1, value, 200);
}
void setInterpolationThreshold(final float value) {
this.interpolationThreshold = FMath.avg(0.0f, value, 20000.0f);
}
void setNumberSubScanLine(final int value) {
this.nbSubScanLine = FMath.avg(1, value, 200);
}
public void setSize(final Vector2i size) {
this.size = size;
if (Renderer.DEBUG_MODE) {
this.buffer = new Color[this.size.x()][this.size.y()];
} else {
this.buffer = new Color[this.size.x() * this.factor][this.size.y() * this.factor];
}
Arrays.fill(this.buffer, Color.NONE);
}
void writePPM(final Uri uri) {
/*
if (this.buffer.length == 0) {
return;
}
auto fileIo = uri::get(uri);
if (fileIo == null) {
Log.error("Can not create the uri: " + uri);
return;
}
if (fileIo.open(io::OpenMode::Write) == false) {
Log.error("Can not open (r) the file : " + uri);
return;
}
int sizeX = this.size.x();
int sizeY = this.size.y();
if (Renderer.DEBUG_MODE) {
sizeX *= this.factor;
sizeY *= this.factor;
}
Log.debug("Generate ppm : " + this.size + " debug size=" + (new Vector2i(sizeX,sizeY)));
char tmpValue[1024];
sprintf(tmpValue, "P6 %d %d 255 ", sizeX, sizeY);
fileIo.write(tmpValue,1,sizeof(tmpValue));
for (int iii=0 ; iii<sizeX*sizeY; iii++) {
Color tmp = this.buffer[iii];
fileIo.write(&tmp, 1, 3);
}
fileIo.close();
*/
}
}

View File

@ -6,8 +6,6 @@ package org.atriasoft.esvg;
* @license MPL v2.0 (see license file)
*/
enum SpreadMethod {
PAD,
REFLECT,
REPEAT
};
public enum SpreadMethod {
PAD, REFLECT, REPEAT
}

View File

@ -1,28 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/debug.hpp>
#include <esvg/Text.hpp>
esvg::Text::Text(PaintState _parentPaintState) : esvg::Base(_parentPaintState) {
}
esvg::Text::~Text() {
}
boolean esvg::Text::parse(const exml::Element& _element, mat2x3& _parentTrans, Vector2f& _sizeMax) {
_sizeMax.setValue(0,0);
Log.error("NOT IMPLEMENTED");
return false;
}
void esvg::Text::display(int _spacing) {
Log.debug(spacingDist(_spacing) << "Text");
}

View File

@ -1,25 +1,31 @@
package org.atriasoft.esvg;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Dynamic;
import org.atriasoft.exml.model.XmlElement;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
class Text extends Base {
public Text(final PaintState _parentPaintState) {
super(_parentPaintState);
public class Text extends Base {
public Text(final PaintState parentPaintState) {
super(parentPaintState);
}
@Override
public boolean parse(const exml::Element& _element, mat2x3& _parentTrans, Vector2f& _sizeMax)
_sizeMax.setValue(0,0);
public void display(final int spacing) {
Log.debug(spacingDist(spacing) + "Text");
}
@Override
public boolean parseXML(final XmlElement element, final Matrix2x3f parentTrans, final Dynamic<Vector2f> sizeMax) {
sizeMax.value = Vector2f.ZERO;
Log.error("NOT IMPLEMENTED");
return false;
}
@Override
public void display(final int _spacing) {
Log.debug(spacingDist(_spacing) << "Text");
}
}

View File

@ -1,20 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/cap.hpp>
#include <esvg/debug.hpp>
static const char* values[] = {
"butt",
"round",
"square"
};
etk::Stream& esvg::operator <<(etk::Stream& _os, enum esvg::cap _obj) {
_os << values[_obj];
return _os;
}

View File

@ -19,382 +19,55 @@
#include <esvg/LinearGradient.hpp>
#include <esvg/RadialGradient.hpp>
esvg::Document::Document() {
EsvgDocument::Document() {
this.uri = "";
this.version = "0.0";
this.loadOK = false;
this.size.setValue(0,0);
}
esvg::Document::~Document() {
EsvgDocument::~Document() {
}
void esvg::Document::displayDebug() {
Log.debug("Main SVG: size=" << this.size);
Log.debug(" refs:");
for (size_t iii=0; iii<this.refList.size(); iii++) {
if (this.refList[iii] != null) {
this.refList[iii]->display(2);
}
}
Log.debug(" Nodes:");
for (size_t iii=0; iii<this.subElementList.size(); iii++) {
if (this.subElementList[iii] != null) {
this.subElementList[iii]->display(2);
}
}
}
void esvg::Document::draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int _level) {
for (size_t iii=0; iii<this.subElementList.size(); iii++) {
if (this.subElementList[iii] != null) {
this.subElementList[iii]->draw(_myRenderer, _basicTrans);
}
}
}
void EsvgDocument::displayDebug()
void EsvgDocument::draw(Renderer myRenderer, Matrix2x3f basicTrans, int level)
// FOR TEST only ...
void esvg::Document::generateAnImage(const etk::Uri& _uri, boolean _visualDebug) {
generateAnImage(this.size, _uri, _visualDebug);
}
void esvg::Document::generateAnImage(const Vector2i& _size, const etk::Uri& _uri, boolean _visualDebug) {
Vector2i sizeRender = _size;
if (sizeRender.x() <= 0) {
sizeRender.setX(this.size.x());
}
if (sizeRender.y() <= 0) {
sizeRender.setY(this.size.y());
}
Log.debug("Generate size " << sizeRender);
ememory::SharedPtr<esvg::Renderer> renderedElement = ememory::makeShared<esvg::Renderer>(sizeRender, this, _visualDebug);
// create the first element matrix modification ...
mat2x3 basicTrans;
basicTrans *= etk::mat2x3Scale(Vector2f(sizeRender.x()/this.size.x(), sizeRender.y()/this.size.y()));
draw(*renderedElement, basicTrans);
if (_uri.getPath().getExtention() == "ppm") {
renderedElement->writePPM(_uri);
} else if (_uri.getPath().getExtention() == "bmp") {
renderedElement->writeBMP(_uri);
} else {
Log.error("Can not store with this extention : " << _uri << " not in .bmp/.ppm");
}
}
void EsvgDocument::generateAnImage(Uri& uri, boolean visualDebug)
void EsvgDocument::generateAnImage(Vector2i size, Uri& uri, boolean visualDebug)
List<etk::Color<float,4>> esvg::Document::renderImageFloatRGBA(Vector2i& _size) {
if (_size.x() <= 0) {
_size.setX(this.size.x());
}
if (_size.y() <= 0) {
_size.setY(this.size.y());
}
Log.debug("Generate size " << _size);
ememory::SharedPtr<esvg::Renderer> renderedElement = ememory::makeShared<esvg::Renderer>(_size, this);
// create the first element matrix modification ...
mat2x3 basicTrans;
basicTrans *= etk::mat2x3Scale(Vector2f(_size.x()/this.size.x(), _size.y()/this.size.y()));
draw(*renderedElement, basicTrans);
// direct return the generated data ...
return renderedElement->getData();
}
List<Color> EsvgDocument::renderImageFloatRGBA(Vector2i size)
List<etk::Color<float,3>> esvg::Document::renderImageFloatRGB(Vector2i& _size) {
List<etk::Color<float,4>> data = renderImageFloatRGBA(_size);
// Reduce scope:
List<etk::Color<float,3>> out;
out.resize(data.size());
for (size_t iii=0; iii<data.size(); ++iii) {
out[iii] = data[iii];
}
return out;
}
List<Color<float,3>> EsvgDocument::renderImageFloatRGB(Vector2i size)
List<Color<uint8t,4>> EsvgDocument::renderImageU8RGBA(Vector2i size)
List<etk::Color<uint8_t,4>> esvg::Document::renderImageU8RGBA(Vector2i& _size) {
List<etk::Color<float,4>> data = renderImageFloatRGBA(_size);
// Reduce scope:
List<etk::Color<uint8_t,4>> out;
out.resize(data.size());
for (size_t iii=0; iii<data.size(); ++iii) {
out[iii] = data[iii];
}
return out;
}
List<Color<uint8t,3>> EsvgDocument::renderImageU8RGB(Vector2i size)
List<etk::Color<uint8_t,3>> esvg::Document::renderImageU8RGB(Vector2i& _size) {
List<etk::Color<float,4>> data = renderImageFloatRGBA(_size);
// Reduce scope:
List<etk::Color<uint8_t,3>> out;
out.resize(data.size());
for (size_t iii=0; iii<data.size(); ++iii) {
out[iii] = data[iii];
}
return out;
}
void EsvgDocument::clear()
void esvg::Document::clear() {
this.uri = "";
this.version = "0.0";
this.loadOK = true;
this.paint.clear();
this.size.setValue(0,0);
}
boolean EsvgDocument::parse(String& data)
boolean EsvgDocument::generate(String& data)
boolean esvg::Document::parse(const etk::String& _data) {
clear();
exml::Document doc;
if (doc.parse(_data) == false) {
Log.error("Error occured when loading SVG: " << this.uri);
this.loadOK = false;
return this.loadOK;
}
if (doc.nodes.size() == 0) {
Log.error("(l ?) No nodes in the SVG file ... '" << this.uri << "'");
this.loadOK = false;
return this.loadOK;
}
exml::Element root = doc.nodes["svg"];
if (root.exist() == false) {
Log.error("(l ?) main node not find: 'svg' in '" << this.uri << "'");
this.loadOK = false;
return this.loadOK;
}
cleanStyleProperty(root);
this.loadOK = parseXMLData(root);
return this.loadOK;
}
boolean EsvgDocument::load(Uri& uri)
boolean esvg::Document::generate(etk::String& _data) {
return false;
}
boolean EsvgDocument::store(Uri& uri)
boolean EsvgDocument::cleanStyleProperty(XmlElement root)
boolean esvg::Document::load(const etk::Uri& _uri) {
clear();
this.uri = _uri;
exml::Document doc;
if (doc.load(this.uri) == false) {
Log.error("Error occured when loading SVG : " << this.uri);
this.loadOK = false;
return this.loadOK;
}
if (doc.nodes.size() == 0) {
Log.error("(l ?) No nodes in the SVG file ... '" << this.uri << "'");
this.loadOK = false;
return this.loadOK;
}
exml::Element root = doc.nodes["svg"];
if (root.exist() == false) {
Log.error("(l ?) main node not find: 'svg' in '" << this.uri << "'");
this.loadOK = false;
return this.loadOK;
}
cleanStyleProperty(root);
this.loadOK = parseXMLData(root);
return this.loadOK;
}
boolean esvg::Document::store(const etk::Uri& _uri) {
Log.todo("not implemented store in SVG...");
return false;
}
boolean esvg::Document::cleanStyleProperty(const exml::Element& _root) {
// for each nodes:
for(auto it: _root.nodes) {
exml::Element child = it.toElement();
if (child.exist() == false) {
continue;
}
// get attribute style:
if (child.attributes.exist("style") == true) {
etk::String content = child.attributes["style"];
if (content.size() != 0) {
List<etk::String> listStyle = etk::split(content, ';');
for (auto &it : listStyle) {
List<etk::String> value = etk::split(it, ':');
if (value.size() != 2) {
Log.error("parsing style with a wrong patern : " << it << " missing ':'");
continue;
}
// TODO : Check if the attibute already exist ...
child.attributes.set(value[0], value[1]);
}
}
// remove attribute style:
child.attributes.remove("style");
}
// sub-parsing ...
cleanStyleProperty(child);
}
return true;
}
boolean esvg::Document::parseXMLData(const exml::Element& _root, boolean _isReference) {
// get the svg version :
this.version = _root.attributes["version"];
// parse ...
Vector2f pos(0,0);
if (_isReference == false) {
parseTransform(_root);
parsePosition(_root, pos, this.size);
parsePaintAttr(_root);
Log.verbose("parsed .ROOT trans: " << this.transformMatrix);
} else {
Log.verbose("Parse Reference section ... (no attibute)");
}
Vector2f maxSize(0,0);
Vector2f size(0,0);
// parse all sub node:
for(auto it : _root.nodes) {
exml::Element child = it.toElement();
if (child.exist() == false) {
// comment can be here...
continue;
}
ememory::SharedPtr<esvg::Base> elementParser;
if (child.getValue() == "g") {
elementParser = ememory::makeShared<esvg::Group>(this.paint);
} else if (child.getValue() == "a") {
Log.info("Note : 'a' balise is parsed like a g balise ...");
elementParser = ememory::makeShared<esvg::Group>(this.paint);
} else if (child.getValue() == "title") {
this.title = "TODO : set the title here ...";
continue;
} else if (child.getValue() == "path") {
elementParser = ememory::makeShared<esvg::Path>(this.paint);
} else if (child.getValue() == "rect") {
elementParser = ememory::makeShared<esvg::Rectangle>(this.paint);
} else if (child.getValue() == "circle") {
elementParser = ememory::makeShared<esvg::Circle>(this.paint);
} else if (child.getValue() == "ellipse") {
elementParser = ememory::makeShared<esvg::Ellipse>(this.paint);
} else if (child.getValue() == "line") {
elementParser = ememory::makeShared<esvg::Line>(this.paint);
} else if (child.getValue() == "polyline") {
elementParser = ememory::makeShared<esvg::Polyline>(this.paint);
} else if (child.getValue() == "polygon") {
elementParser = ememory::makeShared<esvg::Polygon>(this.paint);
} else if (child.getValue() == "text") {
elementParser = ememory::makeShared<esvg::Text>(this.paint);
} else if (child.getValue() == "radialGradient") {
if (_isReference == false) {
Log.error("'" << child.getValue() << "' node must not be defined outside a defs Section");
continue;
} else {
elementParser = ememory::makeShared<esvg::RadialGradient>(this.paint);
}
} else if (child.getValue() == "linearGradient") {
if (_isReference == false) {
Log.error("'" << child.getValue() << "' node must not be defined outside a defs Section");
continue;
} else {
elementParser = ememory::makeShared<esvg::LinearGradient>(this.paint);
}
} else if (child.getValue() == "defs") {
if (_isReference == true) {
Log.error("'" << child.getValue() << "' node must not be defined in a defs Section");
continue;
} else {
boolean retRefs = parseXMLData(child, true);
// TODO : Use retRefs ...
continue;
}
} else if (child.getValue() == "sodipodi:namedview") {
// Node ignore : generaly inkscape data
continue;
} else if (child.getValue() == "metadata") {
// Node ignore : generaly inkscape data
continue;
} else {
Log.error("(l " << child.getPos() << ") node not suported : '" << child.getValue() << "' must be [title,g,a,path,rect,circle,ellipse,line,polyline,polygon,text,metadata]");
}
if (elementParser == null) {
Log.error("(l " << child.getPos() << ") error on node: '" << child.getValue() << "' allocation error or not supported ...");
continue;
}
if (elementParser->parseXML(child, this.transformMatrix, size) == false) {
Log.error("(l " << child.getPos() << ") error on node: '" << child.getValue() << "' Sub Parsing ERROR");
elementParser.reset();
continue;
}
if (maxSize.x()<size.x()) {
maxSize.setX(size.x());
}
if (maxSize.y()<size.y()) {
maxSize.setY(size.y());
}
// add element in the system
if (_isReference == false) {
this.subElementList.pushBack(elementParser);
} else {
this.refList.pushBack(elementParser);
}
}
if ( this.size.x() == 0
|| this.size.y()==0) {
this.size.setValue((int)maxSize.x(), (int)maxSize.y());
} else {
this.size.setValue((int)this.size.x(), (int)this.size.y());
}
if (_isReference == false) {
displayDebug();
}
return true;
}
boolean EsvgDocument::parseXMLData(XmlElement root, boolean isReference)
ememory::SharedPtr<esvg::Base> esvg::Document::getReference(const etk::String& _name) {
if (_name == "") {
Log.error("request a reference with no name ... ");
return null;
}
for (auto &it : this.refList) {
if (it == null) {
continue;
}
if (it->getId() == _name) {
return it;
}
}
Log.error("Can not find reference name : '" << _name << "'");
return null;
}
List<etk::Vector<Vector2f>> esvg::Document::getLines(Vector2f _size) {
List<etk::Vector<Vector2f>> out;
if (_size.x() <= 0) {
_size.setX(this.size.x());
}
if (_size.y() <= 0) {
_size.setY(this.size.y());
}
Log.debug("lineification size " << _size);
// create the first element matrix modification ...
mat2x3 basicTrans;
basicTrans *= etk::mat2x3Scale(Vector2f(_size.x()/this.size.x(), _size.y()/this.size.y()));
drawShapePoints(out, 10, 0.25f, basicTrans);
return out;
}
Base EsvgDocument::getReference(String& name)
List<Vector<Vector2f>> EsvgDocument::getLines(Vector2f size)
void esvg::Document::drawShapePoints(List<etk::Vector<Vector2f>>& _out,
int _recurtionMax,
float _threshold,
mat2x3& _basicTrans,
int _level) {
Log.verbose(spacingDist(_level) << "DRAW shape esvg::Document");
for (auto &it : this.subElementList) {
if (it != null) {
it->drawShapePoints(_out, _recurtionMax, _threshold, _basicTrans, _level+1);
}
}
}
void EsvgDocument::drawShapePoints(List<Vector<Vector2f>>& out,
int recurtionMax,
float threshold,
Matrix2x3f basicTrans,
int level)

View File

@ -1,121 +0,0 @@
package org.atriasoft.esvg;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<etk/types.hpp>#include<etk/Vector.hpp>#include<etk/math/Vector2D.hpp>#include<etk/uri/uri.hpp>
#include<esvg/Base.hpp>
/**
* Main esvg namespace
*/
namespace esvg{
class Document extends esvg::Base
{
private:
etk::Uri this.uri;
boolean this.loadOK;
etk::String this.version;
etk::String this.title;
List<ememory::SharedPtr<esvg::Base>> this.subElementList; //!< sub-element list
List<ememory::SharedPtr<esvg::Base>> this.refList; //!< reference elements ...
Vector2f this.size;
public:
Document();
~Document();
void clear();
/**
* parse a string that contain an svg stream
* @param _data Data to parse
* @return false : An error occured
* @return true : Parsing is OK
*/
boolean parse(const etk::String& _data);
/**
* generate a string that contain the created SVG
* @param _data Data where the svg is stored
* @return false : An error occured
* @return true : Parsing is OK
*/
boolean generate(etk::String& _data);
/**
* Load the file that might contain the svg
* @param _uri File of the svg
* @return false : An error occured
* @return true : Parsing is OK
*/
boolean load(const etk::Uri& _uri);
/**
* Store the SVG in the file
* @param _uri File of the svg
* @return false : An error occured
* @return true : Parsing is OK
*/
boolean store(const etk::Uri& _uri);
protected:
/**
* change all style in a xml atribute
*/
virtual
boolean cleanStyleProperty(const exml::Element& _root);
virtual
boolean parseXMLData(const exml::Element& _root, boolean _isReference = false);
public:
boolean isLoadOk() {
return this.loadOK;
};
/**
* Display all the node in the svg file.
*/
void displayDebug();
// TODO: remove this fucntion : use generic function ...
void generateAnImage(const etk::Uri& _uri, boolean _visualDebug=false);
void generateAnImage(const Vector2i& _size, const etk::Uri& _uri, boolean _visualDebug=false);
/**
* Generate Image in a specific format.
* @param[in,out] _size Size expected of the rendered image (value <=0 if it need to be automatic.) return the size generate
* @return Vector of the data used to display (simple vector: generic to transmit)
*/
List<etk::Color<float,4>> renderImageFloatRGBA(Vector2i& _size);
//! @previous
List<etk::Color<float,3>> renderImageFloatRGB(Vector2i& _size);
//! @previous
List<etk::Color<uint8_t,4>> renderImageU8RGBA(Vector2i& _size);
//! @previous
List<etk::Color<uint8_t,3>> renderImageU8RGB(Vector2i& _size);
List<List<Vector2f>> getLines(final Vector2f _size=Vector2f(256,256));
protected:
void draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int _level=0) override;
public:
Vector2f getDefinedSize() {
return this.size;
};ememory::SharedPtr<esvg::Base>
getReference(const etk::String& _name);
protected:
void drawShapePoints(final List<List<Vector2f>>& _out,
int _recurtionMax,
float _threshold,
mat2x3& _basicTrans,
int _level=1) override;
};
}

View File

@ -1,19 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/gradientUnits.hpp>
#include <esvg/debug.hpp>
static const char* values[] = {
"userSpaceOnUse",
"objectBoundingBox"
};
etk::Stream& esvg::operator <<(etk::Stream& _os, enum esvg::gradientUnits _obj) {
_os << values[_obj];
return _os;
}

View File

@ -1,20 +0,0 @@
package org.atriasoft.esvg;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<etk/types.hpp>#include<etk/Stream.hpp>
namespace esvg{enum esvg::gradientUnits _obj);
};/**
* Debug operator To display the curent element in a Human redeable information
*/
etk::Stream&operator<<(etk::Stream&_os,
enum gradientUnits {
gradientUnits_userSpaceOnUse,
gradientUnits_objectBoundingBox
}

View File

@ -3,63 +3,63 @@ package org.atriasoft.esvg.internal;
import io.scenarium.logger.LogLevel;
import io.scenarium.logger.Logger;
class Log {
private static final String LIB_NAME = "esvg";
private static final String LIB_NAME_DRAW = Logger.getDrawableName(LIB_NAME);
private static final boolean PRINT_CRITICAL = Logger.getNeedPrint(LIB_NAME, LogLevel.CRITICAL);
private static final boolean PRINT_ERROR = Logger.getNeedPrint(LIB_NAME, LogLevel.ERROR);
private static final boolean PRINT_WARNING = Logger.getNeedPrint(LIB_NAME, LogLevel.WARNING);
private static final boolean PRINT_INFO = Logger.getNeedPrint(LIB_NAME, LogLevel.INFO);
private static final boolean PRINT_DEBUG = Logger.getNeedPrint(LIB_NAME, LogLevel.DEBUG);
private static final boolean PRINT_VERBOSE = Logger.getNeedPrint(LIB_NAME, LogLevel.VERBOSE);
private static final boolean PRINT_TODO = Logger.getNeedPrint(LIB_NAME, LogLevel.TODO);
private static final boolean PRINT_PRINT = Logger.getNeedPrint(LIB_NAME, LogLevel.PRINT);
public class Log {
private static final String LIBNAME = "esvg";
private static final String LIBNAMEDRAW = Logger.getDrawableName(Log.LIBNAME);
private static final boolean PRINTCRITICAL = Logger.getNeedPrint(Log.LIBNAME, LogLevel.CRITICAL);
private static final boolean PRINTDEBUG = Logger.getNeedPrint(Log.LIBNAME, LogLevel.DEBUG);
private static final boolean PRINTERROR = Logger.getNeedPrint(Log.LIBNAME, LogLevel.ERROR);
private static final boolean PRINTINFO = Logger.getNeedPrint(Log.LIBNAME, LogLevel.INFO);
private static final boolean PRINTPRINT = Logger.getNeedPrint(Log.LIBNAME, LogLevel.PRINT);
private static final boolean PRINTTODO = Logger.getNeedPrint(Log.LIBNAME, LogLevel.TODO);
private static final boolean PRINTVERBOSE = Logger.getNeedPrint(Log.LIBNAME, LogLevel.VERBOSE);
private static final boolean PRINTWARNING = Logger.getNeedPrint(Log.LIBNAME, LogLevel.WARNING);
public static void critical(final String data) {
if (PRINT_CRITICAL) {
Logger.critical(LIB_NAME_DRAW, data);
if (Log.PRINTCRITICAL) {
Logger.critical(Log.LIBNAMEDRAW, data);
}
}
public static void debug(final String data) {
if (PRINT_DEBUG) {
Logger.debug(LIB_NAME_DRAW, data);
if (Log.PRINTDEBUG) {
Logger.debug(Log.LIBNAMEDRAW, data);
}
}
public static void error(final String data) {
if (PRINT_ERROR) {
Logger.error(LIB_NAME_DRAW, data);
if (Log.PRINTERROR) {
Logger.error(Log.LIBNAMEDRAW, data);
}
}
public static void info(final String data) {
if (PRINT_INFO) {
Logger.info(LIB_NAME_DRAW, data);
if (Log.PRINTINFO) {
Logger.info(Log.LIBNAMEDRAW, data);
}
}
public static void print(final String data) {
if (PRINT_PRINT) {
Logger.print(LIB_NAME_DRAW, data);
if (Log.PRINTPRINT) {
Logger.print(Log.LIBNAMEDRAW, data);
}
}
public static void todo(final String data) {
if (PRINT_TODO) {
Logger.todo(LIB_NAME_DRAW, data);
if (Log.PRINTTODO) {
Logger.todo(Log.LIBNAMEDRAW, data);
}
}
public static void verbose(final String data) {
if (PRINT_VERBOSE) {
Logger.verbose(LIB_NAME_DRAW, data);
if (Log.PRINTVERBOSE) {
Logger.verbose(Log.LIBNAMEDRAW, data);
}
}
public static void warning(final String data) {
if (PRINT_WARNING) {
Logger.warning(LIB_NAME_DRAW, data);
if (Log.PRINTWARNING) {
Logger.warning(Log.LIBNAMEDRAW, data);
}
}

View File

@ -1,20 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/join.hpp>
#include <esvg/debug.hpp>
static const char* values[] = {
"miter",
"round",
"bevel"
};
etk::Stream& esvg::operator <<(etk::Stream& _os, enum esvg::join _obj) {
_os << values[_obj];
return _os;
}

View File

@ -1,452 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/debug.hpp>
#include <esvg/render/DynamicColor.hpp>
#include <esvg/LinearGradient.hpp>
#include <esvg/RadialGradient.hpp>
#include <esvg/esvg.hpp>
esvg::render::DynamicColorSpecial::DynamicColorSpecial(const etk::String& _link, const mat2x3& _mtx) :
this.linear(true),
this.colorName(_link),
this.matrix(_mtx),
this.viewPort(Vector2f(9999999999.0,9999999999.0),Vector2f(-9999999999.0,-9999999999.0)) {
}
void esvg::render::DynamicColorSpecial::setViewPort(const Pair<Vector2f, Vector2f>& _viewPort) {
this.viewPort = _viewPort;
}
static Vector2f getIntersect(const Vector2f& _point1,
const Vector2f& _vect1,
const Vector2f& _point2,
const Vector2f& _vect2) {
float diviseur = _vect1.x() * _vect2.y() - _vect1.y() * _vect2.x();
if(diviseur != 0.0f) {
float mmm = ( _vect1.x() * _point1.y()
- _vect1.x() * _point2.y()
- _vect1.y() * _point1.x()
+ _vect1.y() * _point2.x()
) / diviseur;
return Vector2f(_point2 + _vect2 * mmm);
}
Log.error("Get divider / 0.0f");
return _point2;
}
etk::Color<float,4> esvg::render::DynamicColorSpecial::getColor(const Vector2i& _pos) const {
if (this.data.size() < 2) {
return etk::color::purple;
}
if (this.linear == true) {
return getColorLinear(_pos);
} else {
return getColorRadial(_pos);
}
return etk::color::purple;
}
etk::Color<float,4> esvg::render::DynamicColorSpecial::getColorLinear(const Vector2i& _pos) const {
float ratio = 0.0f;
if (this.unit == gradientUnits_userSpaceOnUse) {
Vector2f vectorBase = this.pos2 - this.pos1;
Vector2f vectorOrtho(vectorBase.y(), -vectorBase.x());
Vector2f intersec = getIntersect(this.pos1, vectorBase,
Vector2f(_pos.x(), _pos.y()), vectorOrtho);
float baseSize = vectorBase.length();
Vector2f vectorBaseDraw = intersec - this.pos1;
float baseDraw = vectorBaseDraw.length();
ratio = baseDraw / baseSize;
switch(this.spread) {
case spreadMethod_pad:
if (vectorBase.dot(vectorBaseDraw) < 0) {
ratio *= -1.0;
}
break;
case spreadMethod_reflect:
ratio -= float((int(ratio)>>1)<<1);
if (ratio > 1.0f) {
ratio = 2.0f-ratio;
}
break;
case spreadMethod_repeat:
if (vectorBase.dot(vectorBaseDraw) < 0) {
ratio *= -1.0;
}
ratio -= float(int(ratio));
if (ratio <0.0f) {
#ifndef __STDCPP_LLVM__
ratio = 1.0f-etk::abs(ratio);
#else
ratio = 1.0f-abs(ratio);
#endif
}
break;
}
} 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..
Vector2f intersecX = getIntersect(this.pos1, this.axeX,
Vector2f(_pos.x(), _pos.y()), this.axeY);
Vector2f intersecY = getIntersect(this.pos1, this.axeY,
Vector2f(_pos.x(), _pos.y()), this.axeX);
Vector2f vectorBaseDrawX = intersecX - this.pos1;
Vector2f vectorBaseDrawY = intersecY - this.pos1;
float baseDrawX = vectorBaseDrawX.length();
float baseDrawY = vectorBaseDrawY.length();
if (this.axeX.dot(vectorBaseDrawX) < 0) {
baseDrawX *= -1.0f;
}
if (this.axeY.dot(vectorBaseDrawY) < 0) {
baseDrawY *= -1.0f;
}
if (this.baseSize.x()+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);
} else if (this.baseSize.x() != 0.0f) {
ratio = baseDrawX/this.baseSize.x();
} else {
ratio = baseDrawY/this.baseSize.y();
}
} else {
ratio = 1.0f;
}
switch(this.spread) {
case spreadMethod_pad:
// nothing to do ...
break;
case spreadMethod_reflect:
#ifndef __STDCPP_LLVM__
ratio = etk::abs(ratio);
#else
ratio = abs(ratio);
#endif
ratio -= float((int(ratio)>>1)<<1);
if (ratio > 1.0f) {
ratio = 2.0f-ratio;
}
break;
case spreadMethod_repeat:
ratio -= float(int(ratio));
if (ratio <0.0f) {
#ifndef __STDCPP_LLVM__
ratio = 1.0f-etk::abs(ratio);
#else
ratio = 1.0f-abs(ratio);
#endif
}
break;
}
}
if (ratio <= this.data[0].first*0.01f) {
return this.data[0].second;
}
if (ratio >= this.data.back().first*0.01f) {
return this.data.back().second;
}
for (size_t iii=1; iii<this.data.size(); ++iii) {
if (ratio <= this.data[iii].first*0.01f) {
float localRatio = ratio - this.data[iii-1].first*0.01f;
localRatio = localRatio / ((this.data[iii].first - this.data[iii-1].first) * 0.01f);
return etk::Color<float,4>(this.data[iii-1].second.r() * (1.0-localRatio) + this.data[iii].second.r() * localRatio,
this.data[iii-1].second.g() * (1.0-localRatio) + this.data[iii].second.g() * localRatio,
this.data[iii-1].second.b() * (1.0-localRatio) + this.data[iii].second.b() * localRatio,
this.data[iii-1].second.a() * (1.0-localRatio) + this.data[iii].second.a() * localRatio);
}
}
return etk::color::green;
}
static Pair<Vector2f,Vector2f> intersectLineToCircle(const Vector2f& _pos1,
const Vector2f& _pos2,
const Vector2f& _center = Vector2f(0.0f, 0.0f),
float _radius = 1.0f) {
Vector2f v1;
Vector2f v2;
//vector2D from point 1 to point 2
v1 = _pos2 - _pos1;
//vector2D from point 1 to the circle's center
v2 = _center - _pos1;
float dot = v1.dot(v2);
Vector2f proj1 = Vector2f(((dot / (v1.length2())) * v1.x()),
((dot / (v1.length2())) * v1.y()));
Vector2f midpt = _pos1 + proj1;
float distToCenter = (midpt - _center).length2();
if (distToCenter > _radius * _radius) {
return Pair<Vector2f,Vector2f>(Vector2f(0.0,0.0), Vector2f(0.0,0.0));
}
if (distToCenter == _radius * _radius) {
return Pair<Vector2f,Vector2f>(midpt, midpt);
}
float distToIntersection;
if (distToCenter == 0.0f) {
distToIntersection = _radius;
} else {
#ifndef __STDCPP_LLVM__
distToCenter = etk::sqrt(distToCenter);
distToIntersection = etk::sqrt(_radius * _radius - distToCenter * distToCenter);
#else
distToCenter = sqrtf(distToCenter);
distToIntersection = sqrtf(_radius * _radius - distToCenter * distToCenter);
#endif
}
// normalize...
v1.safeNormalize();
v1 *= distToIntersection;
return Pair<Vector2f,Vector2f>(midpt + v1, midpt - v1);
}
etk::Color<float,4> esvg::render::DynamicColorSpecial::getColorRadial(const Vector2i& _pos) const {
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)..
Vector2f intersecX = getIntersect(this.pos1, this.axeX,
Vector2f(_pos.x(), _pos.y()), this.axeY);
Vector2f intersecY = getIntersect(this.pos1, this.axeY,
Vector2f(_pos.x(), _pos.y()), this.axeX);
Vector2f vectorBaseDrawX = intersecX - this.pos1;
Vector2f vectorBaseDrawY = intersecY - this.pos1;
float baseDrawX = vectorBaseDrawX.length();
float baseDrawY = vectorBaseDrawY.length();
// specal case when focal == center (this is faster ...)
if (this.centerIsFocal == true) {
ratio = Vector2f(baseDrawX, baseDrawY).length();
if (this.baseSize.x()+this.baseSize.y() != 0.0f) {
if ( this.baseSize.x() != 0.0f
&& this.baseSize.y() != 0.0f) {
ratio = Vector2f(baseDrawX/this.baseSize.x(), baseDrawY/this.baseSize.y()).length();
} else if (this.baseSize.x() != 0.0f) {
ratio = baseDrawX/this.baseSize.x();
} else {
ratio = baseDrawY/this.baseSize.y();
}
} else {
ratio = 1.0f;
}
} else {
// set the sense of the elements:
if (this.axeX.dot(vectorBaseDrawX) < 0) {
baseDrawX *= -1.0f;
}
if (this.axeY.dot(vectorBaseDrawY) < 0) {
baseDrawY *= -1.0f;
}
if (this.baseSize.y() != 0.0f) {
baseDrawY /= this.baseSize.y();
}
// normalize to 1.0f
baseDrawX /= this.baseSize.x();
if ( this.clipOut == true
&& baseDrawX <= -1.0f) {
ratio = 1.0f;
} else {
float tmpLength = -this.focalLength/this.baseSize.x();
Vector2f focalCenter = Vector2f(tmpLength, 0.0f);
Vector2f currentPoint = Vector2f(baseDrawX, baseDrawY);
if (focalCenter == currentPoint) {
ratio = 0.0f;
} else {
Pair<Vector2f,Vector2f> positions = intersectLineToCircle(focalCenter, currentPoint);
float lenghtBase = (currentPoint - focalCenter).length();
float lenghtBorder1 = (positions.first - focalCenter).length();
float lenghtBorder2 = (positions.second - focalCenter).length();
ratio = lenghtBase/lenghtBorder1;
}
}
}
switch(this.spread) {
case spreadMethod_pad:
// nothing to do ...
break;
case spreadMethod_reflect:
ratio -= float((int(ratio)>>1)<<1);
if (ratio > 1.0f) {
ratio = 2.0f-ratio;
}
break;
case spreadMethod_repeat:
ratio -= float(int(ratio));
if (ratio <0.0f) {
#ifndef __STDCPP_LLVM__
ratio = 1.0f-etk::abs(ratio);
#else
ratio = 1.0f-abs(ratio);
#endif
}
break;
}
if (ratio <= this.data[0].first*0.01f) {
return this.data[0].second;
}
if (ratio >= this.data.back().first*0.01f) {
return this.data.back().second;
}
for (size_t iii=1; iii<this.data.size(); ++iii) {
if (ratio <= this.data[iii].first*0.01f) {
float localRatio = ratio - this.data[iii-1].first*0.01f;
localRatio = localRatio / ((this.data[iii].first - this.data[iii-1].first) * 0.01f);
return etk::Color<float,4>(this.data[iii-1].second.r() * (1.0-localRatio) + this.data[iii].second.r() * localRatio,
this.data[iii-1].second.g() * (1.0-localRatio) + this.data[iii].second.g() * localRatio,
this.data[iii-1].second.b() * (1.0-localRatio) + this.data[iii].second.b() * localRatio,
this.data[iii-1].second.a() * (1.0-localRatio) + this.data[iii].second.a() * localRatio);
}
}
return etk::color::green;
}
void esvg::render::DynamicColorSpecial::generate(esvg::Document* _document) {
if (_document == null) {
Log.error("Get null input for document");
return;
}
ememory::SharedPtr<esvg::Base> base = _document->getReference(this.colorName);
if (base == null) {
Log.error("Can not get base : '" << this.colorName << "'");
return;
}
// Now we can know if we use linear or radial gradient ...
ememory::SharedPtr<esvg::LinearGradient> gradient = ememory::dynamicPointerCast<esvg::LinearGradient>(base);
if (gradient != null) {
this.linear = true;
Log.verbose("get for color linear:");
gradient->display(2);
this.unit = gradient->this.unit;
this.spread = gradient->this.spread;
Log.verbose(" viewport = {" << this.viewPort.first << "," << this.viewPort.second << "}");
Vector2f size = this.viewPort.second - this.viewPort.first;
esvg::Dimension dimPos1 = gradient->getPosition1();
this.pos1 = dimPos1.getPixel(size);
if (dimPos1.getType() == esvg::distance_pourcent) {
this.pos1 += this.viewPort.first;
}
esvg::Dimension dimPos2 = gradient->getPosition2();
this.pos2 = dimPos2.getPixel(size);
if (dimPos2.getType() == esvg::distance_pourcent) {
this.pos2 += 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..
Vector2f delta = this.pos2 - this.pos1;
if (delta.x() < 0.0f) {
this.axeX = Vector2f(-1.0f, 0.0f);
} else {
this.axeX = Vector2f(1.0f, 0.0f);
}
if (delta.y() < 0.0f) {
this.axeY = Vector2f(0.0f, -1.0f);
} else {
this.axeY = Vector2f(0.0f, 1.0f);
}
// Move the positions ...
this.pos1 = this.matrix * this.pos1;
this.pos2 = this.matrix * this.pos2;
this.axeX = this.matrix.applyScaleRotation(this.axeX);
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..
Vector2f intersecX = getIntersect(this.pos1, this.axeX,
this.pos2, this.axeY);
Vector2f intersecY = getIntersect(this.pos1, this.axeY,
this.pos2, this.axeX);
this.baseSize = Vector2f((this.pos1 - intersecX).length(),
(this.pos1 - intersecY).length());
// get all the colors
this.data = gradient->getColors(_document);
} else {
this.linear = false;
ememory::SharedPtr<esvg::RadialGradient> gradient = ememory::dynamicPointerCast<esvg::RadialGradient>(base);
if (gradient == null) {
Log.error("Can not cast in a linear gradient: '" << this.colorName << "' ==> wrong type");
return;
}
Log.verbose("get for color Radial:");
gradient->display(2);
this.unit = gradient->this.unit;
this.spread = gradient->this.spread;
Log.verbose(" viewport = {" << this.viewPort.first << "," << this.viewPort.second << "}");
Vector2f size = this.viewPort.second - this.viewPort.first;
esvg::Dimension dimCenter = gradient->getCenter();
Vector2f center = dimCenter.getPixel(size);
if (dimCenter.getType() == esvg::distance_pourcent) {
center += this.viewPort.first;
}
esvg::Dimension dimFocal = gradient->getFocal();
Vector2f focal = dimFocal.getPixel(size);
if (dimFocal.getType() == esvg::distance_pourcent) {
focal += this.viewPort.first;
}
esvg::Dimension1D 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)..
if (center == focal) {
this.centerIsFocal = true;
this.pos2.setX(dimRadius.getPixel(size.x()));
this.pos2.setY(dimRadius.getPixel(size.y()));
this.pos2 += center;
Vector2f delta = center - this.pos2;
if (delta.x() < 0.0f) {
this.axeX = Vector2f(-1.0f, 0.0f);
} else {
this.axeX = Vector2f(1.0f, 0.0f);
}
if (delta.y() < 0.0f) {
this.axeY = Vector2f(0.0f, -1.0f);
} else {
this.axeY = Vector2f(0.0f, 1.0f);
}
this.pos1 = center;
} else {
this.centerIsFocal = false;
this.axeX = (center - focal).safeNormalize();
this.axeY = Vector2f(this.axeX.y(), -this.axeX.x());
this.pos2 = this.axeX * dimRadius.getPixel(size.x()) + this.axeY * dimRadius.getPixel(size.y());
this.pos2 += center;
this.pos1 = center;
}
// Move the positions ...
this.pos1 = this.matrix * this.pos1;
center = this.matrix * center;
this.pos2 = this.matrix * this.pos2;
this.axeX = this.matrix.applyScaleRotation(this.axeX);
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..
Vector2f intersecX = getIntersect(this.pos1, this.axeX,
this.pos2, this.axeY);
Vector2f intersecY = getIntersect(this.pos1, this.axeY,
this.pos2, this.axeX);
this.baseSize = Vector2f((intersecX - this.pos1).length(),
(intersecY - this.pos1).length());
if (this.centerIsFocal == false) {
this.focalLength = (center - this.matrix * focal).length();
if (this.focalLength >= this.baseSize.x()) {
Log.debug("Change position of the Focal ... ==> set it inside the circle");
this.focalLength = this.baseSize.x()*0.999998f;
this.clipOut = true;
} else {
this.clipOut = false;
}
}
Log.verbose("baseSize=" << this.baseSize << " this.pos1=" << this.pos1 << " dim=" << dimCenter << " this.focal=" << this.focal << " this.pos2=" << this.pos2 << " dim=" << dimRadius);
// get all the colors
this.data = gradient->getColors(_document);
}
}
ememory::SharedPtr<esvg::render::DynamicColor> esvg::render::createColor(Pair<etk::Color<float,4>, etk::String> _color, const mat2x3& _mtx) {
// Check if need to create a color:
if ( _color.first.a() == 0x00
&& _color.second == "") {
return null;
}
if (_color.second != "") {
return ememory::makeShared<esvg::render::DynamicColorSpecial>(_color.second, _mtx);
}
return ememory::makeShared<esvg::render::DynamicColorUni>(_color.first);
}

View File

@ -1,74 +1,34 @@
package org.atriasoft.esvg.render;
import org.atriasoft.etk.math.Vector2i;
import org.atriasoft.etk.util.Pair;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Color;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<ememory/memory.hpp>#include<etk/types.hpp>#include<etk/Pair.hpp>#include<etk/Color.hpp>#include<etk/math/Vector2D.hpp>#include<etk/math/Matrix2x3.hpp>#include<esvg/gradientUnits.hpp>#include<esvg/spreadMethod.hpp>
namespace esvg{
class Document;
namespace render
{
class DynamicColor {
public:
DynamicColor() {
// nothing to do ...
}
virtual ~DynamicColor() {};
virtual etk::Color<float,4> getColor(const Vector2i& _pos) const = 0;
virtual void generate(esvg::Document* _document) = 0;
virtual void setViewPort(const Pair<Vector2f, Vector2f>& _viewPort) = 0;
};
class DynamicColorUni extends esvg::render::DynamicColor {
public:
etk::Color<float,4> this.color;
public:
DynamicColorUni(const etk::Color<float,4>& _color) :
this.color(_color) {
}
virtual etk::Color<float,4> getColor(const Vector2i& _pos) const {
return this.color;
}
virtual void generate(esvg::Document* _document) {
// nothing to do ...
}
virtual void setViewPort(const Pair<Vector2f, Vector2f>& _viewPort) {
// nothing to do ...
};
};
class DynamicColorSpecial extends esvg::render::DynamicColor {
public:
boolean this.linear;
esvg::spreadMethod this.spread;
esvg::gradientUnits this.unit;
etk::String this.colorName;
mat2x3 this.matrix;
Pair<Vector2f, Vector2f> this.viewPort;
Vector2f this.pos1; // in radius ==> center
Vector2f this.pos2; // in radius ==> radius end position
Vector2f this.focal; // Specific radius
Vector2f this.axeX;
Vector2f this.axeY;
Vector2f this.baseSize;
float this.focalLength;
boolean this.clipOut;
boolean this.centerIsFocal;
List<Pair<float, etk::Color<float,4>>> this.data;
public:
DynamicColorSpecial(const etk::String& _link, const mat2x3& _mtx);
virtual etk::Color<float,4> getColor(const Vector2i& _pos) const;
private:
etk::Color<float,4> getColorLinear(const Vector2i& _pos) const;
etk::Color<float,4> getColorRadial(const Vector2i& _pos) const;
public:
virtual void generate(esvg::Document* _document);
virtual void setViewPort(const Pair<Vector2f, Vector2f>& _viewPort);
};
ememory::SharedPtr<DynamicColor> createColor(Pair<etk::Color<float,4>, etk::String> _color, const mat2x3& _mtx);
public interface DynamicColor {
public static DynamicColor createColor(final Pair<Color, String> color, final Matrix2x3f mtx) {
// Check if need to create a color:
if (color.first.a() == 0 && color.second.isEmpty()) {
return null;
}
if (color.second.isEmpty()) {
return new DynamicColorUni(color.first);
}
return new DynamicColorSpecial(color.second, mtx);
}
void generate(EsvgDocument document);
public Color getColor(Vector2i pos);
public void setViewPort(Pair<Vector2f, Vector2f> viewPort);
}

View File

@ -0,0 +1,434 @@
package org.atriasoft.esvg.render;
import java.util.List;
import org.atriasoft.esvg.SpreadMethod;
import org.atriasoft.esvg.Base;
import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.esvg.GradientUnits;
import org.atriasoft.esvg.LinearGradient;
import org.atriasoft.esvg.RadialGradient;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.Color;
import org.atriasoft.etk.Dimension;
import org.atriasoft.etk.Dimension1D;
import org.atriasoft.etk.Distance;
import org.atriasoft.etk.math.FMath;
import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.math.Vector2i;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.util.Pair;
public class DynamicColorSpecial implements DynamicColor {
protected static Vector2f getIntersect(final Vector2f point1, final Vector2f vect1, final Vector2f point2, final Vector2f vect2) {
float diviseur = vect1.x() * vect2.y() - vect1.y() * vect2.x();
if (diviseur != 0.0f) {
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));
}
Log.error("Get divider / 0.0f");
return point2;
}
protected static Pair<Vector2f, Vector2f> intersectLineToCircle(final Vector2f pos1, final Vector2f pos2) {
return DynamicColorSpecial.intersectLineToCircle(pos1, pos2, Vector2f.ZERO);
}
protected static Pair<Vector2f, Vector2f> intersectLineToCircle(final Vector2f pos1, final Vector2f pos2, final Vector2f center) {
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) {
Vector2f v1;
Vector2f v2;
//vector2D from point 1 to point 2
v1 = pos2.less(pos1);
//vector2D from point 1 to the circle's center
v2 = center.less(pos1);
float dot = v1.dot(v2);
Vector2f proj1 = new Vector2f(((dot / (v1.length2())) * v1.x()), ((dot / (v1.length2())) * v1.y()));
Vector2f midpt = pos1.add(proj1);
float distToCenter = midpt.less(center).length2();
if (distToCenter > radius * radius) {
return new Pair<>(Vector2f.ZERO, Vector2f.ZERO);
}
if (distToCenter == radius * radius) {
return new Pair<>(midpt, midpt);
}
float distToIntersection;
if (distToCenter == 0.0f) {
distToIntersection = radius;
} else {
distToCenter = FMath.sqrt(distToCenter);
distToIntersection = FMath.sqrt(radius * radius - distToCenter * distToCenter);
}
// normalize...
v1.safeNormalize();
v1 = v1.multiply(distToIntersection);
return new Pair<>(midpt.add(v1), midpt.less(v1));
}
public Vector2f axeX;
public Vector2f axeY;
public Vector2f baseSize;
public boolean centerIsFocal;
public boolean clipOut;
public String colorName;
public List<Pair<Float, Color>> data;
public Vector2f focal; // Specific radius
public float focalLength;
public boolean linear;
public Matrix2x3f matrix;
public Vector2f pos1; // in radius ==> center
public Vector2f pos2; // in radius ==> radius end position
public SpreadMethod spread;
public GradientUnits unit;
public Pair<Vector2f, Vector2f> viewPort;
public DynamicColorSpecial(final String link, final Matrix2x3f mtx) {
this.linear = true;
this.colorName = link;
this.matrix = mtx;
this.viewPort = new Pair<>(Vector2f.MAX_VALUE, Vector2f.MAX_VALUE);
}
@Override
public void generate(final EsvgDocument document) {
if (document == null) {
Log.error("Get null input for document");
}
Base base = document.getReference(this.colorName);
if (base == null) {
Log.error("Can not get base : '" + this.colorName + "'");
return;
}
// Now we can know if we use linear or radial gradient ...
if (base instanceof LinearGradient gradient) {
this.linear = true;
Log.verbose("get for color linear:");
gradient.display(2);
this.unit = gradient.unit;
this.spread = gradient.spread;
Log.verbose(" viewport = {" + this.viewPort.first + "," + this.viewPort.second + "}");
Vector2f size = this.viewPort.second.less(this.viewPort.first);
Dimension dimPos1 = gradient.getPosition1();
this.pos1 = dimPos1.getPixel(size);
if (dimPos1.getType() == Distance.POURCENT) {
this.pos1 = this.pos1.add(this.viewPort.first);
}
Dimension dimPos2 = gradient.getPosition2();
this.pos2 = dimPos2.getPixel(size);
if (dimPos2.getType() == Distance.POURCENT) {
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..
Vector2f delta = this.pos2.less(this.pos1);
if (delta.x() < 0.0f) {
this.axeX = new Vector2f(-1.0f, 0.0f);
} else {
this.axeX = new Vector2f(1.0f, 0.0f);
}
if (delta.y() < 0.0f) {
this.axeY = new Vector2f(0.0f, -1.0f);
} else {
this.axeY = new Vector2f(0.0f, 1.0f);
}
// Move the positions ...
this.pos1 = this.matrix.multiply(this.pos1);
this.pos2 = this.matrix.multiply(this.pos2);
this.axeX = this.matrix.applyScaleRotation(this.axeX);
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..
Vector2f intersecX = DynamicColorSpecial.getIntersect(this.pos1, this.axeX, this.pos2, this.axeY);
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());
// get all the colors
this.data = gradient.getColors(document);
} else {
this.linear = false;
if (!(base instanceof RadialGradient gradient)) {
Log.error("Can not cast in a linear gradient: '" + this.colorName + "' ==> wrong type");
return;
}
Log.verbose("get for color Radial:");
gradient.display(2);
this.unit = gradient.unit;
this.spread = gradient.spread;
Log.verbose(" viewport = {" + this.viewPort.first + "," + this.viewPort.second + "}");
Vector2f size = this.viewPort.second.less(this.viewPort.first);
Dimension dimCenter = gradient.getCenter();
Vector2f center = dimCenter.getPixel(size);
if (dimCenter.getType() == Distance.POURCENT) {
center = center.add(this.viewPort.first);
}
Dimension dimFocal = gradient.getFocal();
Vector2f focal = dimFocal.getPixel(size);
if (dimFocal.getType() == Distance.POURCENT) {
focal = focal.add(this.viewPort.first);
}
Dimension1D 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)..
if (center == focal) {
this.centerIsFocal = true;
this.pos2 = new Vector2f(dimRadius.getPixel(size.x()), dimRadius.getPixel(size.y()));
this.pos2 = this.pos2.add(center);
Vector2f delta = center.less(this.pos2);
if (delta.x() < 0.0f) {
this.axeX = new Vector2f(-1.0f, 0.0f);
} else {
this.axeX = new Vector2f(1.0f, 0.0f);
}
if (delta.y() < 0.0f) {
this.axeY = new Vector2f(0.0f, -1.0f);
} else {
this.axeY = new Vector2f(0.0f, 1.0f);
}
this.pos1 = center;
} else {
this.centerIsFocal = false;
this.axeX = center.less(focal).safeNormalize();
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.pos2.add(center);
this.pos1 = center;
}
// Move the positions ...
this.pos1 = this.matrix.multiply(this.pos1);
center = this.matrix.multiply(center);
this.pos2 = this.matrix.multiply(this.pos2);
this.axeX = this.matrix.applyScaleRotation(this.axeX);
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..
Vector2f intersecX = DynamicColorSpecial.getIntersect(this.pos1, this.axeX, this.pos2, this.axeY);
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());
if (!this.centerIsFocal) {
this.focalLength = (center.less(this.matrix.multiply(focal))).length();
if (this.focalLength >= this.baseSize.x()) {
Log.debug("Change position of the Focal ... ==> set it inside the circle");
this.focalLength = this.baseSize.x() * 0.999998f;
this.clipOut = true;
} else {
this.clipOut = false;
}
}
Log.verbose("baseSize=" + this.baseSize + " this.pos1=" + this.pos1 + " dim=" + dimCenter + " this.focal=" + this.focal + " this.pos2=" + this.pos2 + " dim=" + dimRadius);
// get all the colors
this.data = gradient.getColors(document);
}
}
@Override
public Color getColor(final Vector2i pos) {
if (this.data.size() < 2) {
return Color.PURPLE;
}
if (this.linear) {
return getColorLinear(pos);
}
return getColorRadial(pos);
}
private Color getColorLinear(final Vector2i pos) {
float ratio = 0.0f;
if (this.unit == GradientUnits.gradientUnitsuserSpaceOnUse) {
Vector2f vectorBase = this.pos2.less(this.pos1);
Vector2f vectorOrtho = new Vector2f(vectorBase.y(), -vectorBase.x());
Vector2f intersec = DynamicColorSpecial.getIntersect(this.pos1, vectorBase, new Vector2f(pos.x(), pos.y()), vectorOrtho);
float baseSize = vectorBase.length();
Vector2f vectorBaseDraw = intersec.less(this.pos1);
float baseDraw = vectorBaseDraw.length();
ratio = baseDraw / baseSize;
switch (this.spread) {
default:
case PAD:
if (vectorBase.dot(vectorBaseDraw) < 0) {
ratio *= -1.0;
}
break;
case REFLECT:
ratio -= ((int) (ratio) >> 1) + 1;
if (ratio > 1.0f) {
ratio = 2.0f - ratio;
}
break;
case REPEAT:
if (vectorBase.dot(vectorBaseDraw) < 0) {
ratio *= -1.0;
}
ratio -= ((int) (ratio));
if (ratio < 0.0f) {
ratio = 1.0f - FMath.abs(ratio);
}
break;
}
} 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..
Vector2f intersecX = DynamicColorSpecial.getIntersect(this.pos1, this.axeX, new Vector2f(pos.x(), pos.y()), this.axeY);
Vector2f intersecY = DynamicColorSpecial.getIntersect(this.pos1, this.axeY, new Vector2f(pos.x(), pos.y()), this.axeX);
Vector2f vectorBaseDrawX = intersecX.less(this.pos1);
Vector2f vectorBaseDrawY = intersecY.less(this.pos1);
float baseDrawX = vectorBaseDrawX.length();
float baseDrawY = vectorBaseDrawY.length();
if (this.axeX.dot(vectorBaseDrawX) < 0) {
baseDrawX *= -1.0f;
}
if (this.axeY.dot(vectorBaseDrawY) < 0) {
baseDrawY *= -1.0f;
}
if (this.baseSize.x() + 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);
} else if (this.baseSize.x() != 0.0f) {
ratio = baseDrawX / this.baseSize.x();
} else {
ratio = baseDrawY / this.baseSize.y();
}
} else {
ratio = 1.0f;
}
switch (this.spread) {
default:
case PAD:
// nothing to do ...
break;
case REFLECT:
ratio = FMath.abs(ratio);
ratio -= ((int) (ratio) >> 1) + 1;
if (ratio > 1.0f) {
ratio = 2.0f - ratio;
}
break;
case REPEAT:
ratio -= ((int) (ratio));
if (ratio < 0.0f) {
ratio = 1.0f - FMath.abs(ratio);
}
break;
}
}
if (ratio <= this.data.get(0).first * 0.01f) {
return this.data.get(0).second;
}
if (ratio >= this.data.get(this.data.size() - 1).first * 0.01f) {
return this.data.get(this.data.size() - 1).second;
}
for (int iii = 1; iii < this.data.size(); ++iii) {
if (ratio <= this.data.get(iii).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);
return new Color(this.data.get(iii - 1).second.r() * (1.0 - localRatio) + this.data.get(iii).second.r() * 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;
}
private Color getColorRadial(final Vector2i pos) {
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)..
Vector2f intersecX = DynamicColorSpecial.getIntersect(this.pos1, this.axeX, new Vector2f(pos.x(), pos.y()), this.axeY);
Vector2f intersecY = DynamicColorSpecial.getIntersect(this.pos1, this.axeY, new Vector2f(pos.x(), pos.y()), this.axeX);
Vector2f vectorBaseDrawX = intersecX.less(this.pos1);
Vector2f vectorBaseDrawY = intersecY.less(this.pos1);
float baseDrawX = vectorBaseDrawX.length();
float baseDrawY = vectorBaseDrawY.length();
// specal case when focal == center (this is faster ...)
if (this.centerIsFocal) {
ratio = (new Vector2f(baseDrawX, baseDrawY)).length();
if (this.baseSize.x() + this.baseSize.y() != 0.0f) {
if (this.baseSize.x() != 0.0f && this.baseSize.y() != 0.0f) {
ratio = new Vector2f(baseDrawX / this.baseSize.x(), baseDrawY / this.baseSize.y()).length();
} else if (this.baseSize.x() != 0.0f) {
ratio = baseDrawX / this.baseSize.x();
} else {
ratio = baseDrawY / this.baseSize.y();
}
} else {
ratio = 1.0f;
}
} else {
// set the sense of the elements:
if (this.axeX.dot(vectorBaseDrawX) < 0) {
baseDrawX *= -1.0f;
}
if (this.axeY.dot(vectorBaseDrawY) < 0) {
baseDrawY *= -1.0f;
}
if (this.baseSize.y() != 0.0f) {
baseDrawY /= this.baseSize.y();
}
// normalize to 1.0f
baseDrawX /= this.baseSize.x();
if (this.clipOut && baseDrawX <= -1.0f) {
ratio = 1.0f;
} else {
float tmpLength = -this.focalLength / this.baseSize.x();
Vector2f focalCenter = new Vector2f(tmpLength, 0.0f);
Vector2f currentPoint = new Vector2f(baseDrawX, baseDrawY);
if (focalCenter == currentPoint) {
ratio = 0.0f;
} else {
Pair<Vector2f, Vector2f> positions = DynamicColorSpecial.intersectLineToCircle(focalCenter, currentPoint);
float lenghtBase = currentPoint.less(focalCenter).length();
float lenghtBorder1 = positions.first.less(focalCenter).length();
//float lenghtBorder2 = positions.second.less(focalCenter).length();
ratio = lenghtBase / lenghtBorder1;
}
}
}
switch (this.spread) {
default:
case PAD:
// nothing to do ...
break;
case REFLECT:
ratio -= ((int) (ratio) >> 1) + 1;
if (ratio > 1.0f) {
ratio = 2.0f - ratio;
}
break;
case REPEAT:
ratio -= ((int) (ratio));
if (ratio < 0.0f) {
ratio = 1.0f - FMath.abs(ratio);
}
break;
}
if (ratio <= this.data.get(0).first * 0.01f) {
return this.data.get(0).second;
}
if (ratio >= this.data.get(this.data.size() - 1).first * 0.01f) {
return this.data.get(this.data.size() - 1).second;
}
for (int iii = 1; iii < this.data.size(); ++iii) {
if (ratio <= this.data.get(iii).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);
return new Color(this.data.get(iii - 1).second.r() * (1.0 - localRatio) + this.data.get(iii).second.r() * 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;
}
@Override
public void setViewPort(final Pair<Vector2f, Vector2f> viewPort) {
this.viewPort = viewPort;
}
}

View File

@ -0,0 +1,30 @@
package org.atriasoft.esvg.render;
import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.math.Vector2i;
import org.atriasoft.etk.util.Pair;
import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Color;
public class DynamicColorUni implements DynamicColor {
public Color color;
public DynamicColorUni(final Color color) {
this.color = color;
}
@Override
public void generate(final EsvgDocument document) {
// nothing to do ...
}
@Override
public Color getColor(final Vector2i pos) {
return this.color;
}
@Override
public void setViewPort(final Pair<Vector2f, Vector2f> viewPort) {
// nothing to do ...
}
}

View File

@ -1,57 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/render/Element.hpp>
#include <esvg/debug.hpp>
etk::Stream& esvg::operator <<(etk::Stream& _os, enum esvg::render::path _obj) {
switch (_obj) {
case esvg::render::path_stop:
_os << "path_stop";
break;
case esvg::render::path_close:
_os << "path_close";
break;
case esvg::render::path_moveTo:
_os << "path_moveTo";
break;
case esvg::render::path_lineTo:
_os << "path_lineTo";
break;
case esvg::render::path_lineToH:
_os << "path_lineToH";
break;
case esvg::render::path_lineToV:
_os << "path_lineToV";
break;
case esvg::render::path_curveTo:
_os << "path_curveTo";
break;
case esvg::render::path_smoothCurveTo:
_os << "path_smoothCurveTo";
break;
case esvg::render::path_bezierCurveTo:
_os << "path_bezierCurveTo";
break;
case esvg::render::path_bezierSmoothCurveTo:
_os << "path_bezierSmoothCurveTo";
break;
case esvg::render::path_elliptic:
_os << "path_elliptic";
break;
default:
_os << "????";
break;
};
return _os;
}
etk::Stream& esvg::operator <<(etk::Stream& _os, const esvg::render::Element& _obj) {
_os << _obj.getType();
_os << ": rel=" << etk::toString(_obj.getRelative()) << " ";
_os << _obj.display();
return _os;
}

View File

@ -1,101 +1,76 @@
package org.atriasoft.esvg.render;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<etk/types.hpp>#include<etk/math/Vector2D.hpp>
import org.atriasoft.etk.math.Vector2f;
namespace esvg{namespace render{
class Element {
public:
Element(enum path _type, boolean _relative=false) :
this.cmd(_type),
this.relative(_relative) {
}
virtual ~Element() { }
private:
enum path this.cmd;
public:
enum path getType() const {
return this.cmd;
}
protected:
boolean this.relative;
public:
boolean getRelative() const {
return this.relative;
}
void setRelative(boolean _relative) {
this.relative = _relative;
}
protected:
Vector2f this.pos;
public:
const Vector2f& getPos() const {
return this.pos;
}
void setPos(const Vector2f& _val) {
this.pos = _val;
}
protected:
Vector2f this.pos1;
public:
const Vector2f& getPos1() const {
return this.pos1;
}
void setPos1(const Vector2f& _val) {
this.pos1 = _val;
}
protected:
Vector2f this.pos2;
public:
const Vector2f& getPos2() const {
return this.pos2;
}
void setPos2(const Vector2f& _val) {
this.pos2 = _val;
}
public:
virtual etk::String display() const = 0;
};
public abstract class Element {
protected PathType cmd;
protected Vector2f pos;
protected Vector2f pos1;
protected Vector2f pos2;
protected boolean relative;
public Element(final PathType type) {
this.cmd = type;
this.relative = false;
}
public Element(final PathType type, final boolean relative) {
this.cmd = type;
this.relative = relative;
}
public abstract String display();
public Vector2f getPos() {
return this.pos;
}
public Vector2f getPos1() {
return this.pos1;
}
public Vector2f getPos2() {
return this.pos2;
}
public boolean getRelative() {
return this.relative;
}
public PathType getType() {
return this.cmd;
}
public void setPos(final Vector2f val) {
this.pos = val;
}
public void setPos1(final Vector2f val) {
this.pos1 = val;
}
public void setPos2(final Vector2f val) {
this.pos2 = val;
}
void setRelative(final boolean relative) {
this.relative = relative;
}
@Override
public String toString() {
return "" + this.cmd + ": rel=" + getRelative() + " " + display();
}
/**
* Debug operator To display the curent element in a Human redeable information
*/
etk::Stream& operator <<(etk::Stream& _os, const esvg::render::Element& _obj);
/**
* Debug operator To display the curent element in a Human redeable information
*/
etk::Stream& operator <<(etk::Stream& _os, enum esvg::render::path _obj);
}
#include <esvg/render/ElementStop.hpp>
#include <esvg/render/ElementClose.hpp>
#include <esvg/render/ElementMoveTo.hpp>
#include <esvg/render/ElementLineTo.hpp>
#include <esvg/render/ElementLineToH.hpp>
#include <esvg/render/ElementLineToV.hpp>
#include <esvg/render/ElementCurveTo.hpp>
#include <esvg/render/ElementSmoothCurveTo.hpp>
#include <esvg/render/ElementBezierCurveTo.hpp>
#include <esvg/render/ElementBezierSmoothCurveTo.hpp>
#include <esvg/render/ElementElliptic.hpp>
;
enum path {
path_stop,
path_close,
path_moveTo,
path_lineTo,
path_lineToH,
path_lineToV,
path_curveTo,
path_smoothCurveTo,
path_bezierCurveTo,
path_bezierSmoothCurveTo,
path_elliptic
}

View File

@ -1,18 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/render/Element.hpp>
#include <esvg/debug.hpp>
esvg::render::ElementBezierCurveTo::ElementBezierCurveTo(boolean _relative, const Vector2f& _pos1, const Vector2f& _pos):
Element(esvg::render::path_bezierCurveTo, _relative) {
this.pos = _pos;
this.pos1 = _pos1;
}
etk::String esvg::render::ElementBezierCurveTo::display() const {
return etk::String("pos=") + etk::toString(this.pos) + " pos1=" + etk::toString(this.pos1);
}

View File

@ -1,23 +1,22 @@
package org.atriasoft.esvg.render;
import org.atriasoft.etk.math.Vector2f;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include <etk/types.hpp>
#include <etk/math/Vector2D.hpp>
#include <esvg/render/Element.hpp>
namespace esvg {
namespace render {
class ElementBezierCurveTo extends esvg::render::Element {
public:
ElementBezierCurveTo(boolean _relative, const Vector2f& _pos1, const Vector2f& _pos);
public:
virtual etk::String display() const;
};
public class ElementBezierCurveTo extends Element {
public ElementBezierCurveTo(final boolean relative, final Vector2f pos1, final Vector2f pos) {
super(PathType.bezierCurveTo, relative);
this.pos = pos;
this.pos1 = pos1;
}
@Override
public String display() {
return "pos=" + this.pos + " pos1=" + this.pos1;
}
}

View File

@ -1,18 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/render/Element.hpp>
#include <esvg/debug.hpp>
esvg::render::ElementBezierSmoothCurveTo::ElementBezierSmoothCurveTo(boolean _relative, const Vector2f& _pos):
Element(esvg::render::path_bezierSmoothCurveTo, _relative) {
this.pos = _pos;
}
etk::String esvg::render::ElementBezierSmoothCurveTo::display() const {
return etk::String("pos=") + etk::toString(this.pos);
}

View File

@ -1,24 +1,21 @@
package org.atriasoft.esvg.render;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
import org.atriasoft.etk.math.Vector2f;
#include <etk/types.hpp>
#include <etk/math/Vector2D.hpp>
#include <esvg/render/Element.hpp>
namespace esvg {
namespace render {
class ElementBezierSmoothCurveTo extends esvg::render::Element {
public:
ElementBezierSmoothCurveTo(boolean _relative, const Vector2f& _pos);
public:
virtual etk::String display() const;
};
public class ElementBezierSmoothCurveTo extends Element {
ElementBezierSmoothCurveTo(final boolean relative, final Vector2f pos) {
super(PathType.bezierSmoothCurveTo, relative);
this.pos = pos;
}
@Override
public String display() {
return "pos=" + this.pos;
}
}

View File

@ -1,19 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/render/Element.hpp>
#include <esvg/debug.hpp>
esvg::render::ElementClose::ElementClose(boolean _relative):
Element(esvg::render::path_close, _relative) {
}
etk::String esvg::render::ElementClose::display() const {
return "";
}

View File

@ -1,19 +1,22 @@
package org.atriasoft.esvg.render;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<etk/types.hpp>#include<etk/math/Vector2D.hpp>#include<esvg/render/Element.hpp>
namespace esvg{namespace render{
class ElementClose extends esvg::render::Element
{
public:
ElementClose(boolean _relative=false);
public:
virtual etk::String display() const;
};
}}
public class ElementClose extends Element {
ElementClose() {
super(PathType.close, false);
}
ElementClose(final boolean relative) {
super(PathType.close, relative);
}
@Override
public String display() {
return "";
}
}

View File

@ -1,21 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/render/Element.hpp>
#include <esvg/debug.hpp>
esvg::render::ElementCurveTo::ElementCurveTo(boolean _relative, const Vector2f& _pos1, const Vector2f& _pos2, const Vector2f& _pos):
Element(esvg::render::path_curveTo, _relative) {
this.pos = _pos;
this.pos1 = _pos1;
this.pos2 = _pos2;
}
etk::String esvg::render::ElementCurveTo::display() const {
return etk::String("pos=") + etk::toString(this.pos) + " pos1=" + etk::toString(this.pos1) + " pos2=" + etk::toString(this.pos2);
}

View File

@ -1,22 +1,23 @@
package org.atriasoft.esvg.render;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <etk/types.hpp>
#include <etk/math/Vector2D.hpp>
#include <esvg/render/Element.hpp>
import org.atriasoft.etk.math.Vector2f;
namespace esvg {
namespace render {
class ElementCurveTo extends esvg::render::Element {
public:
ElementCurveTo(boolean _relative, const Vector2f& _pos1, const Vector2f& _pos2, const Vector2f& _pos);
public:
virtual etk::String display() const;
};
public class ElementCurveTo extends Element {
public ElementCurveTo(final boolean relative, final Vector2f pos1, final Vector2f pos2, final Vector2f pos) {
super(PathType.curveTo, relative);
this.pos = pos;
this.pos1 = pos1;
this.pos2 = pos2;
}
@Override
public String display() {
return "pos=" + this.pos + " pos1=" + this.pos1 + " pos2=" + this.pos2;
}
}

View File

@ -1,31 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/render/Element.hpp>
#include <esvg/debug.hpp>
esvg::render::ElementElliptic::ElementElliptic(boolean _relative,
const Vector2f& _radius, // in this.vec1
float _angle,
boolean _largeArcFlag,
boolean _sweepFlag,
const Vector2f& _pos):
Element(esvg::render::path_elliptic, _relative) {
this.pos1 = _radius;
this.pos = _pos;
this.angle = _angle;
this.largeArcFlag = _largeArcFlag;
this.sweepFlag = _sweepFlag;
}
etk::String esvg::render::ElementElliptic::display() const {
return etk::String("pos=") + etk::toString(this.pos)
+ " radius=" + etk::toString(this.pos1)
+ " angle=" + etk::toString(this.angle)
+ " largeArcFlag=" + etk::toString(this.largeArcFlag)
+ " sweepFlag=" + etk::toString(this.sweepFlag);
}

View File

@ -1,32 +1,29 @@
package org.atriasoft.esvg.render;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
import org.atriasoft.etk.math.Vector2f;
#include <etk/types.hpp>
#include <etk/math/Vector2D.hpp>
#include <esvg/render/Element.hpp>
namespace esvg {
namespace render {
class ElementElliptic extends esvg::render::Element {
public:
float this.angle;
boolean this.largeArcFlag;
boolean this.sweepFlag;
public:
ElementElliptic(boolean _relative,
const Vector2f& _radius, // in this.pos1
float _angle,
boolean _largeArcFlag,
boolean _sweepFlag,
const Vector2f& _pos);
public:
virtual etk::String display() const;
};
public class ElementElliptic extends Element {
public float angle;
public boolean largeArcFlag;
public boolean sweepFlag;
public ElementElliptic(final boolean relative, final Vector2f radius, // in this.pos1
final float angle, final boolean largeArcFlag, final boolean sweepFlag, final Vector2f pos) {
super(PathType.elliptic, relative);
this.pos1 = radius;
this.pos = pos;
this.angle = angle;
this.largeArcFlag = largeArcFlag;
this.sweepFlag = sweepFlag;
}
@Override
public String display() {
return "pos=" + this.pos + " radius=" + this.pos1 + " angle=" + this.angle + " largeArcFlag=" + this.largeArcFlag + " sweepFlag=" + this.sweepFlag;
}
}

View File

@ -1,18 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/render/Element.hpp>
#include <esvg/debug.hpp>
esvg::render::ElementLineTo::ElementLineTo(boolean _relative, const Vector2f& _pos):
Element(esvg::render::path_lineTo, _relative) {
this.pos = _pos;
}
etk::String esvg::render::ElementLineTo::display() const {
return etk::String("pos=") + etk::toString(this.pos);
}

View File

@ -1,23 +1,21 @@
package org.atriasoft.esvg.render;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
import org.atriasoft.etk.math.Vector2f;
#include <etk/types.hpp>
#include <etk/math/Vector2D.hpp>
#include <esvg/render/Element.hpp>
namespace esvg {
namespace render {
class ElementLineTo extends esvg::render::Element {
public:
ElementLineTo(boolean _relative, const Vector2f& _pos);
public:
virtual etk::String display() const;
};
public class ElementLineTo extends Element {
public ElementLineTo(final boolean relative, final Vector2f pos) {
super(PathType.lineTo, relative);
this.pos = pos;
}
}
@Override
public String display() {
return "pos=" + this.pos;
}
}

View File

@ -1,18 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/render/Element.hpp>
#include <esvg/debug.hpp>
esvg::render::ElementLineToH::ElementLineToH(boolean _relative, float _posX):
Element(esvg::render::path_lineToH, _relative) {
this.pos = Vector2f(_posX, 0.0f);
}
etk::String esvg::render::ElementLineToH::display() const {
return etk::String("posX=") + etk::toString(this.pos.x());
}

View File

@ -1,20 +1,13 @@
package org.atriasoft.esvg.render;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<etk/types.hpp>#include<etk/math/Vector2D.hpp>#include<esvg/render/Element.hpp>
namespace esvg{namespace render{
class ElementLineToH extends esvg::render::Element
{
public:
public class ElementLineToH extends Element {
public ElementLineToH(final boolean relative, final float poX) {
super(PathType.lineToH, relative);
this.pos = this.pos.withX(poX);
}
ElementLineToH(boolean _relative, float _posX);public:
virtual etk::String display() const;
};
}}
@Override
public String display() {
return "posX=" + this.pos;
}
}

View File

@ -1,18 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/render/Element.hpp>
#include <esvg/debug.hpp>
esvg::render::ElementLineToV::ElementLineToV(boolean _relative, float _posY):
Element(esvg::render::path_lineToV, _relative) {
this.pos = Vector2f(0.0f, _posY);
}
etk::String esvg::render::ElementLineToV::display() const {
return etk::String("posY=") + etk::toString(this.pos.y());
}

View File

@ -1,20 +1,13 @@
package org.atriasoft.esvg.render;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<etk/types.hpp>#include<etk/math/Vector2D.hpp>#include<esvg/render/Element.hpp>
namespace esvg{namespace render{
class ElementLineToV extends esvg::render::Element
{
public:
public class ElementLineToV extends Element {
public ElementLineToV(final boolean relative, final float posY) {
super(PathType.lineToV, relative);
this.pos = this.pos.withX(posY);
}
ElementLineToV(boolean _relative, float _posY);public:
virtual etk::String display() const;
};
}}
@Override
public String display() {
return "posY=" + this.pos;
}
}

View File

@ -1,18 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/render/Element.hpp>
#include <esvg/debug.hpp>
esvg::render::ElementMoveTo::ElementMoveTo(boolean _relative, const Vector2f& _pos):
Element(esvg::render::path_moveTo, _relative) {
this.pos = _pos;
}
etk::String esvg::render::ElementMoveTo::display() const {
return etk::String("pos=") + etk::toString(this.pos);
}

View File

@ -1,23 +1,21 @@
package org.atriasoft.esvg.render;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
import org.atriasoft.etk.math.Vector2f;
#include <etk/types.hpp>
#include <etk/math/Vector2D.hpp>
#include <esvg/render/Element.hpp>
namespace esvg {
namespace render {
class ElementMoveTo extends esvg::render::Element {
public:
ElementMoveTo(boolean _relative, const Vector2f& _pos);
public:
virtual etk::String display() const;
};
public class ElementMoveTo extends Element {
public ElementMoveTo(final boolean relative, final Vector2f pos) {
super(PathType.moveTo, relative);
this.pos = pos;
}
@Override
public String display() {
return "pos=" + this.pos;
}
}

View File

@ -1,19 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/render/Element.hpp>
#include <esvg/debug.hpp>
esvg::render::ElementSmoothCurveTo::ElementSmoothCurveTo(boolean _relative, const Vector2f& _pos2, const Vector2f& _pos):
Element(esvg::render::path_smoothCurveTo, _relative) {
this.pos = _pos;
this.pos2 = _pos2;
}
etk::String esvg::render::ElementSmoothCurveTo::display() const {
return etk::String("pos=") + etk::toString(this.pos) + " pos2=" + etk::toString(this.pos2);
}

View File

@ -1,23 +1,22 @@
package org.atriasoft.esvg.render;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
import org.atriasoft.etk.math.Vector2f;
#include <etk/types.hpp>
#include <etk/math/Vector2D.hpp>
#include <esvg/render/Element.hpp>
namespace esvg {
namespace render {
class ElementSmoothCurveTo extends esvg::render::Element {
public:
ElementSmoothCurveTo(boolean _relative, const Vector2f& _pos2, const Vector2f& _pos);
public:
virtual etk::String display() const;
};
public class ElementSmoothCurveTo extends Element {
public ElementSmoothCurveTo(final boolean relative, final Vector2f pos2, final Vector2f pos) {
super(PathType.moveTo, relative);
this.pos = pos;
this.pos2 = pos2;
}
}
@Override
public String display() {
return "pos=" + this.pos + " pos2=" + this.pos2;
}
}

View File

@ -1,19 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/render/Element.hpp>
#include <esvg/debug.hpp>
esvg::render::ElementStop::ElementStop():
Element(esvg::render::path_stop) {
}
etk::String esvg::render::ElementStop::display() const {
return "";
}

View File

@ -1,19 +1,12 @@
package org.atriasoft.esvg.render;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<etk/types.hpp>#include<etk/math/Vector2D.hpp>#include<esvg/render/Element.hpp>
namespace esvg{namespace render{
class ElementStop extends esvg::render::Element
{
public:
ElementStop();
public:
virtual etk::String display() const;
};
}}
public class ElementStop extends Element {
ElementStop() {
super(PathType.stop, false);
}
@Override
public String display() {
return "";
}
}

View File

@ -1,513 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/debug.hpp>
#include <esvg/render/Path.hpp>
#include <esvg/render/Element.hpp>
void esvg::render::Path::clear() {
this.listElement.clear();
}
void esvg::render::Path::stop() {
this.listElement.pushBack(ememory::makeShared<esvg::render::ElementStop>());
}
void esvg::render::Path::close(boolean _relative) {
this.listElement.pushBack(ememory::makeShared<esvg::render::ElementClose>(_relative));
}
void esvg::render::Path::moveTo(boolean _relative, const Vector2f& _pos) {
this.listElement.pushBack(ememory::makeShared<esvg::render::ElementMoveTo>(_relative, _pos));
}
void esvg::render::Path::lineTo(boolean _relative, const Vector2f& _pos) {
this.listElement.pushBack(ememory::makeShared<esvg::render::ElementLineTo>(_relative, _pos));
}
void esvg::render::Path::lineToH(boolean _relative, float _posX) {
this.listElement.pushBack(ememory::makeShared<esvg::render::ElementLineToH>(_relative, _posX));
}
void esvg::render::Path::lineToV(boolean _relative, float _posY) {
this.listElement.pushBack(ememory::makeShared<esvg::render::ElementLineToV>(_relative, _posY));
}
void esvg::render::Path::curveTo(boolean _relative, const Vector2f& _pos1, const Vector2f& _pos2, const Vector2f& _pos) {
this.listElement.pushBack(ememory::makeShared<esvg::render::ElementCurveTo>(_relative, _pos1, _pos2, _pos));
}
void esvg::render::Path::smoothCurveTo(boolean _relative, const Vector2f& _pos2, const Vector2f& _pos) {
this.listElement.pushBack(ememory::makeShared<esvg::render::ElementSmoothCurveTo>(_relative, _pos2, _pos));
}
void esvg::render::Path::bezierCurveTo(boolean _relative, const Vector2f& _pos1, const Vector2f& _pos) {
this.listElement.pushBack(ememory::makeShared<esvg::render::ElementBezierCurveTo>(_relative, _pos1, _pos));
}
void esvg::render::Path::bezierSmoothCurveTo(boolean _relative, const Vector2f& _pos) {
this.listElement.pushBack(ememory::makeShared<esvg::render::ElementBezierSmoothCurveTo>(_relative, _pos));
}
void esvg::render::Path::ellipticTo(boolean _relative,
const Vector2f& _radius,
float _angle,
boolean _largeArcFlag,
boolean _sweepFlag,
const Vector2f& _pos) {
this.listElement.pushBack(ememory::makeShared<esvg::render::ElementElliptic>(_relative, _radius, _angle, _largeArcFlag, _sweepFlag, _pos));
}
static const char* spacingDist(int _spacing) {
static const char *tmpValue = " ";
if (_spacing>20) {
_spacing = 20;
}
return tmpValue + 20*4 - _spacing*4;
}
void esvg::render::Path::display(int _spacing) {
Log.debug(spacingDist(_spacing) << "Path");
for(auto &it : this.listElement) {
if (it == null) {
continue;
}
Log.debug(spacingDist(_spacing+1) << *it);
}
}
void interpolateCubicBezier(List<esvg::render::Point>& _listPoint,
int _recurtionMax,
float _threshold,
Vector2f _pos1,
Vector2f _pos2,
Vector2f _pos3,
Vector2f _pos4,
int _level,
enum esvg::render::Point::type _type) {
if (_level > _recurtionMax) {
return;
}
Vector2f pos12 = (_pos1+_pos2)*0.5f;
Vector2f pos23 = (_pos2+_pos3)*0.5f;
Vector2f pos34 = (_pos3+_pos4)*0.5f;
Vector2f delta = _pos4 - _pos1;
#ifndef __STDCPP_LLVM__
float distance2 = etk::abs(((_pos2.x() - _pos4.x()) * delta.y() - (_pos2.y() - _pos4.y()) * delta.x() ));
float distance3 = etk::abs(((_pos3.x() - _pos4.x()) * delta.y() - (_pos3.y() - _pos4.y()) * delta.x() ));
#else
float distance2 = fabs(((_pos2.x() - _pos4.x()) * delta.y() - (_pos2.y() - _pos4.y()) * delta.x() ));
float distance3 = fabs(((_pos3.x() - _pos4.x()) * delta.y() - (_pos3.y() - _pos4.y()) * delta.x() ));
#endif
if ((distance2 + distance3)*(distance2 + distance3) < _threshold * delta.length2()) {
_listPoint.pushBack(esvg::render::Point(_pos4, _type) );
return;
}
Vector2f pos123 = (pos12+pos23)*0.5f;
Vector2f pos234 = (pos23+pos34)*0.5f;
Vector2f pos1234 = (pos123+pos234)*0.5f;
interpolateCubicBezier(_listPoint, _recurtionMax, _threshold, _pos1, pos12, pos123, pos1234, _level+1, esvg::render::Point::type::interpolation);
interpolateCubicBezier(_listPoint, _recurtionMax, _threshold, pos1234, pos234, pos34, _pos4, _level+1, _type);
}
static float vectorAngle(Vector2f _uuu, Vector2f _vvv) {
_uuu.safeNormalize();
_vvv.safeNormalize();
return atan2(_uuu.cross(_vvv), _uuu.dot(_vvv));
}
esvg::render::PointList esvg::render::Path::generateListPoints(int _level, int _recurtionMax, float _threshold) {
Log.verbose(spacingDist(_level) << "Generate List Points ... from a path");
esvg::render::PointList out;
List<esvg::render::Point> tmpListPoint;
Vector2f lastPosition(0.0f, 0.0f);
Vector2f lastAngle(0.0f, 0.0f);
int lastPointId = -1;
boolean PathStart = false;
// Foreach element, we move in the path:
for(auto &it : this.listElement) {
if (it == null) {
continue;
}
Log.verbose(spacingDist(_level+1) << " Draw : " << *it);
switch (it->getType()) {
case esvg::render::path_stop:
if (tmpListPoint.size() != 0) {
if (tmpListPoint.size() == 0) {
Log.warning(spacingDist(_level+1) << " Request path stop of not starting path ...");
} else {
tmpListPoint.back().setEndPath();
out.addList(tmpListPoint);
tmpListPoint.clear();
}
}
lastAngle = Vector2f(0.0f, 0.0f);
// nothing alse to do ...
break;
case esvg::render::path_close:
if (tmpListPoint.size() != 0) {
if (tmpListPoint.size() == 0) {
Log.warning(spacingDist(_level+1) << " Request path close of not starting path ...");
} else {
// find the previous tart of the path ...
tmpListPoint.front().this.type = esvg::render::Point::type::join;
// Remove the last point if it is the same position...
Vector2f delta = (tmpListPoint.front().this.pos - tmpListPoint.back().this.pos).absolute();
if ( delta.x() <= 0.00001
&& delta.y() <= 0.00001) {
tmpListPoint.popBack();
Log.verbose(" Remove point Z property : " << tmpListPoint.back().this.pos << " with delta=" << delta);
}
out.addList(tmpListPoint);
tmpListPoint.clear();
}
}
lastAngle = Vector2f(0.0f, 0.0f);
// nothing alse to do ...
break;
case esvg::render::path_moveTo:
// stop last path
if (tmpListPoint.size() != 0) {
tmpListPoint.back().setEndPath();
out.addList(tmpListPoint);
tmpListPoint.clear();
}
// create a new one
if (it->getRelative() == false) {
lastPosition = Vector2f(0.0f, 0.0f);
}
lastPosition += it->getPos();
tmpListPoint.pushBack(esvg::render::Point(lastPosition, esvg::render::Point::type::start));
lastAngle = lastPosition;
break;
case esvg::render::path_lineTo:
// If no previous point, we need to create the last point has start ...
if (tmpListPoint.size() == 0) {
tmpListPoint.pushBack(esvg::render::Point(lastPosition, esvg::render::Point::type::start));
}
if (it->getRelative() == false) {
lastPosition = Vector2f(0.0f, 0.0f);
}
lastPosition += it->getPos();
tmpListPoint.pushBack(esvg::render::Point(lastPosition, esvg::render::Point::type::join));
lastAngle = lastPosition;
break;
case esvg::render::path_lineToH:
// If no previous point, we need to create the last point has start ...
if (tmpListPoint.size() == 0) {
tmpListPoint.pushBack(esvg::render::Point(lastPosition, esvg::render::Point::type::start));
}
if (it->getRelative() == false) {
lastPosition = Vector2f(0.0f, 0.0f);
}
lastPosition += it->getPos();
tmpListPoint.pushBack(esvg::render::Point(lastPosition, esvg::render::Point::type::join));
lastAngle = lastPosition;
break;
case esvg::render::path_lineToV:
// If no previous point, we need to create the last point has start ...
if (tmpListPoint.size() == 0) {
tmpListPoint.pushBack(esvg::render::Point(lastPosition, esvg::render::Point::type::start));
}
if (it->getRelative() == false) {
lastPosition = Vector2f(0.0f, 0.0f);
}
lastPosition += it->getPos();
tmpListPoint.pushBack(esvg::render::Point(lastPosition, esvg::render::Point::type::join));
lastAngle = lastPosition;
break;
case esvg::render::path_curveTo:
// If no previous point, we need to create the last point has start ...
if (tmpListPoint.size() == 0) {
tmpListPoint.pushBack(esvg::render::Point(lastPosition, esvg::render::Point::type::join));
}
{
Vector2f lastPosStore(lastPosition);
if (it->getRelative() == false) {
lastPosition = Vector2f(0.0f, 0.0f);
}
Vector2f pos1 = lastPosition + it->getPos1();
Vector2f pos2 = lastPosition + it->getPos2();
Vector2f pos = lastPosition + it->getPos();
interpolateCubicBezier(tmpListPoint,
_recurtionMax,
_threshold,
lastPosStore,
pos1,
pos2,
pos,
0,
esvg::render::Point::type::join);
lastPosition = pos;
lastAngle = pos2;
}
break;
case esvg::render::path_smoothCurveTo:
// If no previous point, we need to create the last point has start ...
if (tmpListPoint.size() == 0) {
tmpListPoint.pushBack(esvg::render::Point(lastPosition, esvg::render::Point::type::join));
}
{
Vector2f lastPosStore(lastPosition);
if (it->getRelative() == false) {
lastPosition = Vector2f(0.0f, 0.0f);
}
Vector2f pos2 = lastPosition + it->getPos2();
Vector2f pos = lastPosition + it->getPos();
// generate Pos 1
Vector2f pos1 = lastPosStore*2.0f - lastAngle;
interpolateCubicBezier(tmpListPoint,
_recurtionMax,
_threshold,
lastPosStore,
pos1,
pos2,
pos,
0,
esvg::render::Point::type::join);
lastPosition = pos;
lastAngle = pos2;
}
break;
case esvg::render::path_bezierCurveTo:
// If no previous point, we need to create the last point has start ...
if (tmpListPoint.size() == 0) {
tmpListPoint.pushBack(esvg::render::Point(lastPosition, esvg::render::Point::type::join));
}
{
Vector2f lastPosStore(lastPosition);
if (it->getRelative() == false) {
lastPosition = Vector2f(0.0f, 0.0f);
}
Vector2f pos = lastPosition + it->getPos();
Vector2f tmp1 = lastPosition + it->getPos1();
// generate pos1 and pos2
Vector2f pos1 = lastPosStore + (tmp1 - lastPosStore)*0.666666666f;
Vector2f pos2 = pos + (tmp1 - pos)*0.666666666f;
interpolateCubicBezier(tmpListPoint,
_recurtionMax,
_threshold,
lastPosStore,
pos1,
pos2,
pos,
0,
esvg::render::Point::type::join);
lastPosition = pos;
lastAngle = tmp1;
}
break;
case esvg::render::path_bezierSmoothCurveTo:
// If no previous point, we need to create the last point has start ...
if (tmpListPoint.size() == 0) {
tmpListPoint.pushBack(esvg::render::Point(lastPosition, esvg::render::Point::type::join));
}
{
Vector2f lastPosStore(lastPosition);
if (it->getRelative() == false) {
lastPosition = Vector2f(0.0f, 0.0f);
}
Vector2f pos = lastPosition + it->getPos();
Vector2f tmp1 = lastPosStore*2.0f - lastAngle;
// generate pos1 and pos2
Vector2f pos1 = lastPosStore + (tmp1 - lastPosStore)*0.666666666f;
Vector2f pos2 = pos + (tmp1 - pos)*0.66666666f;
interpolateCubicBezier(tmpListPoint,
_recurtionMax,
_threshold,
lastPosStore,
pos1,
pos2,
pos,
0,
esvg::render::Point::type::join);
lastPosition = pos;
lastAngle = tmp1;
}
break;
case esvg::render::path_elliptic:
// If no previous point, we need to create the last point has start ...
if (tmpListPoint.size() == 0) {
tmpListPoint.pushBack(esvg::render::Point(lastPosition, esvg::render::Point::type::join));
}
{
ememory::SharedPtr<esvg::render::ElementElliptic> tmpIt(ememory::dynamicPointerCast<esvg::render::ElementElliptic>(it));
float angle = tmpIt->this.angle * (M_PI / 180.0);
Log.todo(spacingDist(_level+1) << " Elliptic arc: radius=" << tmpIt->getPos1());
Log.todo(spacingDist(_level+1) << " angle=" << tmpIt->this.angle);
Log.todo(spacingDist(_level+1) << " this.largeArcFlag=" << tmpIt->this.largeArcFlag);
Log.todo(spacingDist(_level+1) << " this.sweepFlag=" << tmpIt->this.sweepFlag);
Vector2f lastPosStore(lastPosition);
if (it->getRelative() == false) {
lastPosition = Vector2f(0.0f, 0.0f);
}
Vector2f pos = lastPosition + it->getPos();
float rotationX = tmpIt->this.angle * (M_PI / 180.0);
Vector2f radius = tmpIt->getPos1();
#ifdef DEBUG
this.debugInformation.addSegment(lastPosStore, pos);
#endif
Vector2f delta = lastPosStore - pos;
float ddd = delta.length();
if ( ddd < 1e-6f
|| radius.x() < 1e-6f
|| radius.y() < 1e-6f) {
Log.warning("Degenerate arc in Line");
if (tmpListPoint.size() == 0) {
tmpListPoint.pushBack(esvg::render::Point(lastPosition, esvg::render::Point::type::join));
}
tmpListPoint.pushBack(esvg::render::Point(pos, esvg::render::Point::type::join));
} else {
// Convert to center point parameterization.
// http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
// procedure describe here : http://www.w3.org/TR/SVG11/implnote.html#ArcConversionCenterToEndpoint
// Compute delta'
mat2x3 matrixRotationCenter = etk::mat2x3Rotate(-rotationX);
Vector2f deltaPrim = matrixRotationCenter * (delta*0.5f);
ddd = (deltaPrim.x()*deltaPrim.x())/(radius.x()*radius.x())
+ (deltaPrim.y()*deltaPrim.y())/(radius.y()*radius.y());
if (ddd > 1.0f) {
#ifndef __STDCPP_LLVM__
ddd = etk::sqrt(ddd);
#else
ddd = sqrtf(ddd);
#endif
radius *= ddd;
}
// Compute center'
float sss = 0.0f;
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();
float ssb = radius.x()*radius.x()*deltaPrim.y()*deltaPrim.y()
+ radius.y()*radius.y()*deltaPrim.x()*deltaPrim.x();
if (ssa < 0.0f) {
ssa = 0.0f;
}
if (ssb > 0.0f) {
#ifndef __STDCPP_LLVM__
sss = etk::sqrt(ssa / ssb);
#else
sss = sqrtf(ssa / ssb);
#endif
}
if (tmpIt->this.largeArcFlag == tmpIt->this.sweepFlag) {
sss *= -1.0f;
}
Vector2f centerPrime(sss * radius.x() * deltaPrim.y() / radius.y(),
sss * -radius.y() * deltaPrim.x() / radius.x());
// Compute center from center'
mat2x3 matrix = etk::mat2x3Rotate(rotationX);
Vector2f center = (lastPosStore + pos)*0.5f + matrix*centerPrime;
#ifdef DEBUG
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));
#endif
// Calculate theta1, and delta theta.
Vector2f vectorA = (deltaPrim - centerPrime) / radius;
Vector2f vectorB = (deltaPrim + centerPrime) / radius * -1.0f;
#ifdef DEBUG
this.debugInformation.addSegment(center, center+vectorA*radius.x());
this.debugInformation.addSegment(center, center+vectorB*radius.y());
#endif
// Initial angle
float theta1 = vectorAngle(Vector2f(1.0f,0.0f), vectorA);
// Delta angle
float deltaTheta = vectorAngle(vectorA, vectorB);
// special case of invert angle...
if ( ( deltaTheta == float(M_PI)
|| deltaTheta == -float(M_PI))
&& tmpIt->this.sweepFlag == false) {
deltaTheta *= -1.0f;
}
if (tmpIt->this.largeArcFlag == true) {
// Choose large arc
if (deltaTheta > 0.0f) {
deltaTheta -= 2.0f*M_PI;
} else {
deltaTheta += 2.0f*M_PI;
}
}
// Approximate the arc using cubic spline segments.
matrix.translate(center);
// Split arc into max 90 degree segments.
// The loop assumes an iteration per end point (including start and end), this +1.
#ifndef __STDCPP_LLVM__
int ndivs = int(etk::abs(deltaTheta) / (M_PI*0.5f)) + 1;
#else
int ndivs = int(fabs(deltaTheta) / (M_PI*0.5f)) + 1;
#endif
float hda = (deltaTheta / float(ndivs)) * 0.5f;
#ifndef __STDCPP_LLVM__
float kappa = etk::abs(4.0f / 3.0f * (1.0f - etk::cos(hda)) / etk::sin(hda));
#else
float kappa = fabs(4.0f / 3.0f * (1.0f - cosf(hda)) / sinf(hda));
#endif
if (deltaTheta < 0.0f) {
kappa = -kappa;
}
Vector2f pointPosPrevious(0.0,0.0);
Vector2f tangentPrevious(0.0,0.0);
for (int iii=0; iii<=ndivs; ++iii) {
float a = theta1 + deltaTheta * (float(iii)/(float)ndivs);
#ifndef __STDCPP_LLVM__
delta = Vector2f(etk::cos(a), etk::sin(a));
#else
delta = Vector2f(cosf(a), sinf(a));
#endif
// position
Vector2f pointPos = matrix * Vector2f(delta.x()*radius.x(), delta.y()*radius.y());
// tangent
Vector2f tangent = matrix.applyScaleRotation(Vector2f(-delta.y()*radius.x() * kappa, delta.x()*radius.y() * kappa));
if (iii > 0) {
Vector2f zlastPosStore(lastPosition);
if (it->getRelative() == false) {
lastPosition = Vector2f(0.0f, 0.0f);
}
Vector2f zpos1 = pointPosPrevious + tangentPrevious;
Vector2f zpos2 = pointPos - tangent;
Vector2f zpos = pointPos;
interpolateCubicBezier(tmpListPoint,
_recurtionMax,
_threshold,
zlastPosStore,
zpos1,
zpos2,
zpos,
0,
esvg::render::Point::type::join);
lastPosition = zpos;
lastAngle = zpos2;
}
pointPosPrevious = pointPos;
tangentPrevious = tangent;
}
}
lastPosition = pos;
}
break;
default:
Log.error(spacingDist(_level+1) << " Unknow PATH commant (internal error)");
break;
}
}
// special case : No request end of path ==> open path:
if (tmpListPoint.size() != 0) {
Log.verbose("Auto-end PATH");
tmpListPoint.back().setEndPath();
out.addList(tmpListPoint);
tmpListPoint.clear();
}
out.display();
return out;
}

View File

@ -1,51 +0,0 @@
package org.atriasoft.esvg.render;
import java.util.List;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
class Path {
public List<Element> listElement;
SegmentList debugInformation;
public Path() {
}
void clear();
void stop();
void close(final boolean _relative=false);
void moveTo(final boolean _relative, const Vector2f& _pos);
void lineTo(final boolean _relative, const Vector2f& _pos);
void lineToH(boolean _relative, float _posX);
void lineToV(boolean _relative, float _posY);
void curveTo(final boolean _relative, const Vector2f& _pos1, const Vector2f& _pos2, const Vector2f& _pos);
void smoothCurveTo(final boolean _relative, const Vector2f& _pos2, const Vector2f& _pos);
void bezierCurveTo(final boolean _relative, const Vector2f& _pos1, const Vector2f& _pos);
void bezierSmoothCurveTo(final boolean _relative, const Vector2f& _pos);
void ellipticTo(final boolean _relative,
const Vector2f& _radius,
float _angle,
boolean _largeArcFlag,
boolean _sweepFlag,
const Vector2f& _pos);
void display(int _spacing);esvg::render::PointList generateListPoints(final int _level, final int _recurtionMax = 10, float _threshold = 0.25f);
};
}}

View File

@ -0,0 +1,446 @@
package org.atriasoft.esvg.render;
import java.util.ArrayList;
import java.util.List;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.math.FMath;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
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,
final Vector2f pos4, final int level, final PointType type) {
if (level > recurtionMax) {
return;
}
Vector2f pos12 = pos1.add(pos2).multiply(0.5f);
Vector2f pos23 = pos2.add(pos3).multiply(0.5f);
Vector2f pos34 = pos3.add(pos4).multiply(0.5f);
Vector2f delta = pos4.less(pos1);
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()));
if ((distance2 + distance3) * (distance2 + distance3) < threshold * delta.length2()) {
listPoint.add(new Point(pos4, type));
return;
}
Vector2f pos123 = pos12.add(pos23).multiply(0.5f);
Vector2f pos234 = pos23.add(pos34).multiply(0.5f);
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, pos1234, pos234, pos34, pos4, level + 1, type);
}
/**
* add indentation of the string input.
* @param data String where the indentation is done.
* @param indent Number of tab to add at the string.
*/
public static String spacingDist(final int indent) {
final StringBuilder data = new StringBuilder();
for (int iii = 0; iii < indent; iii++) {
data.append("\t");
}
return data.toString();
}
private static float vectorAngle(Vector2f uuu, Vector2f vvv) {
uuu = uuu.safeNormalize();
vvv = vvv.safeNormalize();
return (float) Math.atan2(uuu.cross(vvv), uuu.dot(vvv));
}
SegmentList debugInformation;
public List<Element> listElement = new ArrayList<>();
public PathModel() {
}
public void bezierCurveTo(final boolean relative, final Vector2f pos1, final Vector2f pos) {
this.listElement.add(new ElementBezierCurveTo(relative, pos1, pos));
}
public void bezierSmoothCurveTo(final boolean relative, final Vector2f pos) {
this.listElement.add(new ElementBezierSmoothCurveTo(relative, pos));
}
public void clear() {
this.listElement.clear();
}
public void close() {
close(false);
}
public void close(final boolean relative) {
this.listElement.add(new ElementClose(relative));
}
public void curveTo(final boolean relative, final Vector2f pos1, final Vector2f pos2, final Vector2f pos) {
this.listElement.add(new ElementCurveTo(relative, pos1, pos2, pos));
}
public void display(final int spacing) {
Log.debug(PathModel.spacingDist(spacing) + "Path");
for (Element it : this.listElement) {
if (it == null) {
continue;
}
Log.debug(PathModel.spacingDist(spacing + 1) + it);
}
}
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));
}
public PointList generateListPoints(final int level) {
return generateListPoints(level, 10);
}
public PointList generateListPoints(final int level, final int recurtionMax) {
return generateListPoints(level, recurtionMax, 0.25f);
}
public PointList generateListPoints(final int level, final int recurtionMax, final float threshold) {
Log.verbose(PathModel.spacingDist(level) + "Generate List Points ... from a path");
PointList out = new PointList();
List<Point> tmpListPoint = new ArrayList<>();
Vector2f lastPosition = Vector2f.ZERO;
Vector2f lastAngle = Vector2f.ZERO;
// Foreach element, we move in the path:
for (Element it : this.listElement) {
if (it == null) {
continue;
}
Log.verbose(PathModel.spacingDist(level + 1) + " Draw : " + it.toString());
switch (it.getType()) {
case stop:
if (tmpListPoint.size() != 0) {
if (tmpListPoint.size() == 0) {
Log.warning(PathModel.spacingDist(level + 1) + " Request path stop of not starting path ...");
} else {
tmpListPoint.get(tmpListPoint.size() - 1).setEndPath();
out.addList(tmpListPoint);
tmpListPoint.clear();
}
}
lastAngle = Vector2f.ZERO;
// nothing alse to do ...
break;
case close:
if (tmpListPoint.size() != 0) {
if (tmpListPoint.size() == 0) {
Log.warning(PathModel.spacingDist(level + 1) + " Request path close of not starting path ...");
} else {
// find the previous tart of the path ...
tmpListPoint.get(0).type = PointType.join;
// Remove the last point if it is the same position...
Vector2f delta = (tmpListPoint.get(0).pos.less(tmpListPoint.get(tmpListPoint.size() - 1).pos)).abs();
if (delta.x() <= 0.00001 && delta.y() <= 0.00001) {
tmpListPoint.remove(tmpListPoint.size() - 1);
Log.verbose(" Remove point Z property : " + tmpListPoint.get(tmpListPoint.size() - 1).pos + " with delta=" + delta);
}
out.addList(tmpListPoint);
tmpListPoint.clear();
}
}
lastAngle = Vector2f.ZERO;
// nothing alse to do ...
break;
case moveTo:
// stop last path
if (tmpListPoint.size() != 0) {
tmpListPoint.get(tmpListPoint.size() - 1).setEndPath();
out.addList(tmpListPoint);
tmpListPoint.clear();
}
// create a new one
if (!it.getRelative()) {
lastPosition = Vector2f.ZERO;
}
lastPosition = lastPosition.add(it.getPos());
tmpListPoint.add(new Point(lastPosition, PointType.start));
lastAngle = lastPosition;
break;
case lineTo:
// If no previous point, we need to create the last point has start ...
if (tmpListPoint.size() == 0) {
tmpListPoint.add(new Point(lastPosition, PointType.start));
}
if (!it.getRelative()) {
lastPosition = Vector2f.ZERO;
}
lastPosition = lastPosition.add(it.getPos());
tmpListPoint.add(new Point(lastPosition, PointType.join));
lastAngle = lastPosition;
break;
case lineToH:
// If no previous point, we need to create the last point has start ...
if (tmpListPoint.size() == 0) {
tmpListPoint.add(new Point(lastPosition, PointType.start));
}
if (!it.getRelative()) {
lastPosition = Vector2f.ZERO;
}
lastPosition = lastPosition.add(it.getPos());
tmpListPoint.add(new Point(lastPosition, PointType.join));
lastAngle = lastPosition;
break;
case lineToV:
// If no previous point, we need to create the last point has start ...
if (tmpListPoint.size() == 0) {
tmpListPoint.add(new Point(lastPosition, PointType.start));
}
if (!it.getRelative()) {
lastPosition = Vector2f.ZERO;
}
lastPosition = lastPosition.add(it.getPos());
tmpListPoint.add(new Point(lastPosition, PointType.join));
lastAngle = lastPosition;
break;
case curveTo:
// If no previous point, we need to create the last point has start ...
if (tmpListPoint.size() == 0) {
tmpListPoint.add(new Point(lastPosition, PointType.join));
} {
Vector2f lastPosStore = lastPosition;
if (!it.getRelative()) {
lastPosition = Vector2f.ZERO;
}
Vector2f pos1 = lastPosition.add(it.getPos1());
Vector2f pos2 = lastPosition.add(it.getPos2());
Vector2f pos = lastPosition.add(it.getPos());
PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, lastPosStore, pos1, pos2, pos, 0, PointType.join);
lastPosition = pos;
lastAngle = pos2;
}
break;
case smoothCurveTo:
// If no previous point, we need to create the last point has start ...
if (tmpListPoint.size() == 0) {
tmpListPoint.add(new Point(lastPosition, PointType.join));
} {
Vector2f lastPosStore = lastPosition;
if (!it.getRelative()) {
lastPosition = Vector2f.ZERO;
}
Vector2f pos2 = lastPosition.add(it.getPos2());
Vector2f pos = lastPosition.add(it.getPos());
// generate Pos 1
Vector2f pos1 = lastPosStore.multiply(2.0f).less(lastAngle);
PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, lastPosStore, pos1, pos2, pos, 0, PointType.join);
lastPosition = pos;
lastAngle = pos2;
}
break;
case bezierCurveTo:
// If no previous point, we need to create the last point has start ...
if (tmpListPoint.size() == 0) {
tmpListPoint.add(new Point(lastPosition, PointType.join));
} {
Vector2f lastPosStore = lastPosition;
if (!it.getRelative()) {
lastPosition = Vector2f.ZERO;
}
Vector2f pos = lastPosition.add(it.getPos());
Vector2f tmp1 = lastPosition.add(it.getPos1());
// generate pos1 and pos2
Vector2f pos1 = lastPosStore.add(tmp1.less(lastPosStore).multiply(0.666666666f));
Vector2f pos2 = pos.add(tmp1.less(pos).multiply(0.666666666f));
PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, lastPosStore, pos1, pos2, pos, 0, PointType.join);
lastPosition = pos;
lastAngle = tmp1;
}
break;
case bezierSmoothCurveTo:
// If no previous point, we need to create the last point has start ...
if (tmpListPoint.size() == 0) {
tmpListPoint.add(new Point(lastPosition, PointType.join));
} {
Vector2f lastPosStore = lastPosition;
if (!it.getRelative()) {
lastPosition = Vector2f.ZERO;
}
Vector2f pos = lastPosition.add(it.getPos());
Vector2f tmp1 = lastPosStore.multiply(2.0f).less(lastAngle);
// generate pos1 and pos2
Vector2f pos1 = lastPosStore.add(tmp1.less(lastPosStore).multiply(0.666666666f));
Vector2f pos2 = pos.add(tmp1.less(pos).multiply(0.66666666f));
PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, lastPosStore, pos1, pos2, pos, 0, PointType.join);
lastPosition = pos;
lastAngle = tmp1;
}
break;
case elliptic:
// If no previous point, we need to create the last point has start ...
if (tmpListPoint.size() == 0) {
tmpListPoint.add(new Point(lastPosition, PointType.join));
} {
ElementElliptic tmpIt = (ElementElliptic) it;
Log.todo(PathModel.spacingDist(level + 1) + " Elliptic arc: radius=" + tmpIt.getPos1());
Log.todo(PathModel.spacingDist(level + 1) + " angle=" + tmpIt.angle);
Log.todo(PathModel.spacingDist(level + 1) + " this.largeArcFlag=" + tmpIt.largeArcFlag);
Log.todo(PathModel.spacingDist(level + 1) + " this.sweepFlag=" + tmpIt.sweepFlag);
Vector2f lastPosStore = lastPosition;
if (!it.getRelative()) {
lastPosition = Vector2f.ZERO;
}
Vector2f pos = lastPosition.add(it.getPos());
float rotationX = tmpIt.angle * ((float) Math.PI / 180.0f);
Vector2f radius = tmpIt.getPos1();
//this.debugInformation.addSegment(lastPosStore, pos);
Vector2f delta = lastPosStore.less(pos);
float ddd = delta.length();
if (ddd < 1e-6f || radius.x() < 1e-6f || radius.y() < 1e-6f) {
Log.warning("Degenerate arc in Line");
if (tmpListPoint.size() == 0) {
tmpListPoint.add(new Point(lastPosition, PointType.join));
}
tmpListPoint.add(new Point(pos, PointType.join));
} else {
// Convert to center point parameterization.
// http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
// procedure describe here : http://www.w3.org/TR/SVG11/implnote.html#ArcConversionCenterToEndpoint
// Compute delta'
Matrix2x3f matrixRotationCenter = Matrix2x3f.createRotate(-rotationX);
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());
if (ddd > 1.0f) {
ddd = (float) Math.sqrt(ddd);
radius = radius.multiply(ddd);
}
// Compute center'
float sss = 0.0f;
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();
float ssb = radius.x() * radius.x() * deltaPrim.y() * deltaPrim.y() + radius.y() * radius.y() * deltaPrim.x() * deltaPrim.x();
if (ssa < 0.0f) {
ssa = 0.0f;
}
if (ssb > 0.0f) {
sss = (float) Math.sqrt(ssa / ssb);
}
if (tmpIt.largeArcFlag == tmpIt.sweepFlag) {
sss *= -1.0f;
}
Vector2f centerPrime = new Vector2f(sss * radius.x() * deltaPrim.y() / radius.y(), sss * -radius.y() * deltaPrim.x() / radius.x());
// Compute center from center'
Matrix2x3f matrix = Matrix2x3f.createRotate(rotationX);
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));
// Calculate theta1, and delta theta.
Vector2f vectorA = deltaPrim.less(centerPrime).devide(radius);
Vector2f vectorB = deltaPrim.add(centerPrime).devide(radius.multiply(-1.0f));
//this.debugInformation.addSegment(center, center+vectorA*radius.x());
//this.debugInformation.addSegment(center, center+vectorB*radius.y());
// Initial angle
float theta1 = PathModel.vectorAngle(new Vector2f(1.0f, 0.0f), vectorA);
// Delta angle
float deltaTheta = PathModel.vectorAngle(vectorA, vectorB);
// special case of invert angle...
if ((deltaTheta == (float) Math.PI || deltaTheta == -(float) Math.PI) && !tmpIt.sweepFlag) {
deltaTheta *= -1.0f;
}
if (tmpIt.largeArcFlag) {
// Choose large arc
if (deltaTheta > 0.0f) {
deltaTheta -= 2.0f * (float) Math.PI;
} else {
deltaTheta += 2.0f * (float) Math.PI;
}
}
// Approximate the arc using cubic spline segments.
matrix.translate(center);
// Split arc into max 90 degree segments.
// 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;
float hda = (deltaTheta / ndivs) * 0.5f;
float kappa = (float) Math.abs(4.0f / 3.0f * (1.0f - Math.cos(hda)) / Math.sin(hda));
if (deltaTheta < 0.0f) {
kappa = -kappa;
}
Vector2f pointPosPrevious = Vector2f.ZERO;
Vector2f tangentPrevious = Vector2f.ZERO;
for (int iii = 0; iii <= ndivs; ++iii) {
float a = theta1 + deltaTheta * ((float) iii / (float) ndivs);
delta = new Vector2f(FMath.cos(a), FMath.sin(a));
// position
Vector2f pointPos = matrix.multiply(new Vector2f(delta.x() * radius.x(), delta.y() * radius.y()));
// tangent
Vector2f tangent = matrix.applyScaleRotation(new Vector2f(-delta.y() * radius.x() * kappa, delta.x() * radius.y() * kappa));
if (iii > 0) {
Vector2f zlastPosStore = lastPosition;
if (!it.getRelative()) {
lastPosition = Vector2f.ZERO;
}
Vector2f zpos1 = pointPosPrevious.add(tangentPrevious);
Vector2f zpos2 = pointPos.less(tangent);
Vector2f zpos = pointPos;
PathModel.interpolateCubicBezier(tmpListPoint, recurtionMax, threshold, zlastPosStore, zpos1, zpos2, zpos, 0, PointType.join);
lastPosition = zpos;
lastAngle = zpos2;
}
pointPosPrevious = pointPos;
tangentPrevious = tangent;
}
}
lastPosition = pos;
}
break;
default:
Log.error(PathModel.spacingDist(level + 1) + " Unknow PATH commant (internal error)");
break;
}
}
// special case : No request end of path ==> open path:
if (tmpListPoint.size() != 0) {
Log.verbose("Auto-end PATH");
tmpListPoint.get(tmpListPoint.size() - 1).setEndPath();
out.addList(tmpListPoint);
tmpListPoint.clear();
}
out.display();
return out;
}
public void lineTo(final boolean relative, final Vector2f pos) {
this.listElement.add(new ElementLineTo(relative, pos));
}
public void lineToH(final boolean relative, final float posX) {
this.listElement.add(new ElementLineToH(relative, posX));
}
public void lineToV(final boolean relative, final float posY) {
this.listElement.add(new ElementLineToV(relative, posY));
}
public void moveTo(final boolean relative, final Vector2f pos) {
this.listElement.add(new ElementMoveTo(relative, pos));
}
public void smoothCurveTo(final boolean relative, final Vector2f pos2, final Vector2f pos) {
this.listElement.add(new ElementSmoothCurveTo(relative, pos2, pos));
}
public void stop() {
this.listElement.add(new ElementStop());
}
}

View File

@ -0,0 +1,5 @@
package org.atriasoft.esvg.render;
public enum PathType {
bezierCurveTo, bezierSmoothCurveTo, close, curveTo, elliptic, lineTo, lineToH, lineToV, moveTo, smoothCurveTo, stop,
}

View File

@ -1,31 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/render/Point.hpp>
#include <esvg/debug.hpp>
void esvg::render::Point::setEndPath() {
if (this.type == esvg::render::Point::type::interpolation) {
Log.warning("Request stop path of an interpolate Point");
this.type = esvg::render::Point::type::stop;
return;
}
if (this.type == esvg::render::Point::type::stop) {
Log.warning("Request stop path of an STOP Point");
return;
}
if (this.type == esvg::render::Point::type::start) {
this.type = esvg::render::Point::type::single;
return;
}
this.type = esvg::render::Point::type::stop;
}
void esvg::render::Point::normalize(const Vector2f& _nextPoint) {
this.delta = _nextPoint - this.pos;
this.len = this.delta.length();
}

View File

@ -1,51 +1,60 @@
package org.atriasoft.esvg.render;
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.math.Vector2f;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include <etk/types.hpp>
#include <etk/math/Vector2D.hpp>
#include <esvg/render/Element.hpp>
namespace esvg {
namespace render {
class Point {
public:
enum class type {
single, //!< Point type is single, this mean that it start and stop of a path
start, //!< Point type is starting of a path
stop, //!< Point type is stoping of a path
join, //!< Point type in an user point provided inside a path
interpolation, //!< This point is dynamicly calculated to create an interpolation
};
public:
// TODO : Clean all element here ...
Vector2f this.pos; //!< position of the point
enum esvg::render::Point::type this.type;
Vector2f this.miterAxe;
Vector2f this.orthoAxePrevious;
Vector2f this.orthoAxeNext;
Vector2f this.posPrevious;
Vector2f this.posNext;
Vector2f this.delta;
float this.len;
// TODO: Update List to support not having it ...
Point() :
this.pos(0,0),
this.type(esvg::render::Point::type::join) {
// nothing to do ...
}
Point(const Vector2f& _pos, enum esvg::render::Point::type _type = esvg::render::Point::type::join) :
this.pos(_pos),
this.type(_type) {
// nothing to do ...
}
void setEndPath();
void normalize(const Vector2f& _nextPoint);
};
public class Point {
public Vector2f delta = Vector2f.ZERO;
public float len = 0;
public Vector2f miterAxe = Vector2f.ZERO;
public Vector2f orthoAxeNext = Vector2f.ZERO;
public Vector2f orthoAxePrevious = Vector2f.ZERO;
// TODO : Clean all element here ...
public Vector2f pos; //!< position of the point
public Vector2f posNext = Vector2f.ZERO;
public Vector2f posPrevious = Vector2f.ZERO;
public PointType type;
public Point() {
this.pos = Vector2f.ZERO;
this.type = PointType.join;
}
public Point(final Vector2f pos) {
this.pos = pos;
this.type = PointType.join;
}
public Point(final Vector2f pos, final PointType type) {
this.pos = pos;
this.type = type;
}
void normalize(final Vector2f nextPoint) {
this.delta = nextPoint.less(this.pos);
this.len = this.delta.length();
}
void setEndPath() {
if (this.type == PointType.interpolation) {
Log.warning("Request stop path of an interpolate Point");
this.type = PointType.stop;
return;
}
if (this.type == PointType.stop) {
Log.warning("Request stop path of an STOP Point");
return;
}
if (this.type == PointType.start) {
this.type = PointType.single;
return;
}
this.type = PointType.stop;
}
}

View File

@ -1,64 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/debug.hpp>
#include <esvg/render/PointList.hpp>
esvg::render::PointList::PointList() {
// nothing to do ...
}
void esvg::render::PointList::addList(List<esvg::render::Point>& _list) {
this.data.pushBack(_list);
// TODO : Add a checker of correct list ...
}
void esvg::render::PointList::applyMatrix(const mat2x3& _transformationMatrix) {
for (auto &it : this.data) {
for (auto &val : it) {
val.this.pos = _transformationMatrix * val.this.pos;
}
}
}
Pair<Vector2f, Vector2f> esvg::render::PointList::getViewPort() {
Pair<Vector2f, Vector2f> out(Vector2f(9999999999.0,9999999999.0),Vector2f(-9999999999.0,-9999999999.0));
for (auto &it : this.data) {
for (auto &it2 : it) {
out.first.setMin(it2.this.pos);
out.second.setMax(it2.this.pos);
}
}
return out;
}
void esvg::render::PointList::display() {
Log.verbose(" Display list of points : size=" << this.data.size());
for (auto &it : this.data) {
Log.verbose(" Find List " << it.size() << " members");
for (size_t iii=0;
iii < it.size();
++iii) {
switch (it[iii].this.type) {
case esvg::render::Point::type::single:
Log.verbose(" [" << iii << "] Find Single " << it[iii].this.pos);
break;
case esvg::render::Point::type::start:
Log.verbose(" [" << iii << "] Find Start " << it[iii].this.pos);
break;
case esvg::render::Point::type::stop:
Log.verbose(" [" << iii << "] Find Stop " << it[iii].this.pos);
break;
case esvg::render::Point::type::interpolation:
Log.verbose(" [" << iii << "] Find interpolation " << it[iii].this.pos);
break;
case esvg::render::Point::type::join:
Log.verbose(" [" << iii << "] Find Join " << it[iii].this.pos);
break;
}
}
}
}

View File

@ -1,24 +1,51 @@
package org.atriasoft.esvg.render;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<etk/types.hpp>#include<etk/math/Vector2D.hpp>#include<etk/math/Matrix2x3.hpp>#include<etk/Pair.hpp>#include<esvg/render/Element.hpp>#include<esvg/render/Point.hpp>
import java.util.ArrayList;
import java.util.List;
namespace esvg{namespace render{
class PointList {
public:
List<List<esvg::render::Point>> this.data;
public:
PointList();
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.util.Pair;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f;
public class PointList {
public List<List<Point>> data = new ArrayList<>();
void addList(List<esvg::render::Point>& _list);
public PointList() {
}
void display();
public void addList(final List<Point> list) {
this.data.add(list);
// TODO : Add a checker of correct list ...
}
void applyMatrix(const mat2x3& _transformationMatrix);
Pair<Vector2f, Vector2f> getViewPort();
};}}
public void applyMatrix(final Matrix2x3f transformationMatrix) {
for (List<Point> it : this.data) {
for (Point val : it) {
val.pos = transformationMatrix.multiply(val.pos);
}
}
}
public void display() {
Log.verbose(" Display list of points : size=" + this.data.size());
for (List<Point> it : this.data) {
Log.verbose(" Find List " + it.size() + " members");
for (int iii = 0; iii < it.size(); ++iii) {
Point elem = it.get(iii);
Log.verbose(" [" + iii + "] Find " + elem.type + " " + elem.pos);
}
}
}
public Pair<Vector2f, Vector2f> getViewPort() {
Pair<Vector2f, Vector2f> out = new Pair<>(Vector2f.MAX_VALUE, Vector2f.MIN_VALUE);
for (List<Point> it : this.data) {
for (Point it2 : it) {
out = new Pair<>(Vector2f.min(out.first, it2.pos), Vector2f.max(out.second, it2.pos));
}
}
return out;
}
}

View File

@ -0,0 +1,10 @@
package org.atriasoft.esvg.render;
public enum PointType {
interpolation, //!< Point type is single, this mean that it start and stop of a path
join, //!< Point type is starting of a path
single, //!< Point type is stoping of a path
start, //!< Point type in an user point provided inside a path
stop; //!< This point is dynamicly calculated to create an interpolation
}

View File

@ -1,38 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/render/Scanline.hpp>
#include <esvg/debug.hpp>
esvg::render::Scanline::Scanline(size_t _size) {
this.data.resize(_size, 0.0f);
}
size_t esvg::render::Scanline::size() const {
return this.data.size();
}
void esvg::render::Scanline::clear(float _fill) {
for (auto &it : this.data) {
it = _fill;
}
}
float esvg::render::Scanline::get(int _pos) const {
if( _pos >= 0
&& size_t(_pos) < this.data.size()) {
return this.data[_pos];
}
return 0;
}
void esvg::render::Scanline::set(int _pos, float _newColor) {
if( _pos >= 0
&& size_t(_pos) < this.data.size()) {
this.data[_pos] = _newColor;
}
}

View File

@ -1,31 +1,43 @@
package org.atriasoft.esvg.render;
import java.util.Arrays;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<etk/types.hpp>#include<etk/math/Vector2D.hpp>
namespace esvg{namespace render{
class Scanline {
private:
List<float> this.data;
public:
// constructor :
Scanline(final size_t _size=32);
// destructor
~
public class Scanline {
private final float[] data;
Scanline() {};
public Scanline() {
this(32);
}
public:
size_t size() const;
public Scanline(final int size) {
this.data = new float[size];
Arrays.fill(this.data, 0);
}
void clear(float _fill);
void clear(final float fill) {
Arrays.fill(this.data, 0);
}
float get(final int _pos) const;
float get(final int pos) {
if (pos >= 0 && pos < this.data.length) {
return this.data[pos];
}
return 0;
}
void set(int _pos, float _newColor);
};}}
void set(final int pos, final float newColor) {
if (pos >= 0 && pos < this.data.length) {
this.data[pos] = newColor;
}
}
public int size() {
return this.data.length;
}
}

View File

@ -1,39 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/render/Segment.hpp>
#include <esvg/debug.hpp>
esvg::render::Segment::Segment() {
p0 = Vector2f(0,0);
p1 = Vector2f(0,0);
direction = 0;
}
esvg::render::Segment::Segment(const Vector2f& _p0, const Vector2f& _p1) {
// segment register all time the lower at P0n then we need to register the sens of the path
p0 = _p0;
p1 = _p1;
direction = 0;
}
void esvg::render::Segment::applyMatrix(const mat2x3& _transformationMatrix) {
p0 = _transformationMatrix * p0;
p1 = _transformationMatrix * p1;
createDirection();
}
void esvg::render::Segment::createDirection() {
if (p0.y() < p1.y()) {
direction = 1; // direction like clock
} else {
Vector2f tmp(p0);
p0 = p1;
p1 = tmp;
direction = -1; // direction like anti-clock
}
}

View File

@ -1,25 +1,48 @@
package org.atriasoft.esvg.render;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.etk.math.Vector2f;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<etk/types.hpp>#include<etk/math/Vector2D.hpp>#include<etk/math/Matrix2x3.hpp>
namespace esvg{namespace render{
class Segment {
public:
// TODO: Update List to support not having it ...
Segment();
public class Segment {
Segment(const Vector2f& _p0, const Vector2f& _p1);
Vector2f p0;
Vector2f p1;
int direction;
public int direction;
public Vector2f p0;
public Vector2f p1;
void applyMatrix(const mat2x3& _transformationMatrix);
// TODO Update List to support not having it ...
public Segment() {
this.p0 = Vector2f.ZERO;
this.p1 = Vector2f.ZERO;
this.direction = 0;
}
void createDirection();
};}}
public Segment(final Vector2f p0, final Vector2f p1) {
// segment register all time the lower at P0n then we need to register the sens of the path
this.p0 = p0;
this.p1 = p1;
this.direction = 0;
}
void applyMatrix(final Matrix2x3f transformationMatrix) {
this.p0 = transformationMatrix.multiply(this.p0);
this.p1 = transformationMatrix.multiply(this.p1);
createDirection();
}
void createDirection() {
if (this.p0.y() < this.p1.y()) {
this.direction = 1; // direction like clock
} else {
Vector2f tmp = this.p0;
this.p0 = this.p1;
this.p1 = tmp;
this.direction = -1; // direction like anti-clock
}
}
}

View File

@ -1,508 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/render/SegmentList.hpp>
#include <esvg/debug.hpp>
#include <etk/math/Matrix2x3.hpp>
esvg::render::SegmentList::SegmentList() {
}
#ifdef DEBUG
void esvg::render::SegmentList::addSegment(const Vector2f& _pos0, const Vector2f& _pos1) {
this.data.pushBack(Segment(_pos0, _pos1));
}
#endif
void esvg::render::SegmentList::addSegment(const esvg::render::Point& _pos0, const esvg::render::Point& _pos1) {
// Skip horizontal Segments
if (_pos0.this.pos.y() == _pos1.this.pos.y()) {
// remove /0 operation
return;
}
this.data.pushBack(Segment(_pos0.this.pos, _pos1.this.pos));
}
void esvg::render::SegmentList::addSegment(const esvg::render::Point& _pos0, const esvg::render::Point& _pos1, boolean _disableHorizontal) {
// Skip horizontal Segments
if ( _disableHorizontal == true
&& _pos0.this.pos.y() == _pos1.this.pos.y()) {
// remove /0 operation
return;
}
this.data.pushBack(Segment(_pos0.this.pos, _pos1.this.pos));
}
Pair<Vector2f, Vector2f> esvg::render::SegmentList::getViewPort() {
Pair<Vector2f, Vector2f> out(Vector2f(9999999999.0,9999999999.0),Vector2f(-9999999999.0,-9999999999.0));
for (auto &it : this.data) {
out.first.setMin(it.p0);
out.second.setMax(it.p0);
out.first.setMin(it.p1);
out.second.setMax(it.p1);
}
return out;
}
void esvg::render::SegmentList::createSegmentList(const esvg::render::PointList& _listPoint) {
for (auto &it : _listPoint.this.data) {
// Build Segments
for (size_t iii=0, jjj=it.size()-1;
iii < it.size();
jjj = iii++) {
addSegment(it[jjj], it[iii]);
}
}
}
static Vector2f getIntersect(const Vector2f& _point1,
const Vector2f& _vect1,
const Vector2f& _point2,
const Vector2f& _vect2) {
float diviseur = _vect1.x() * _vect2.y() - _vect1.y() * _vect2.x();
if(diviseur != 0.0f) {
float mmm = ( _vect1.x() * _point1.y()
- _vect1.x() * _point2.y()
- _vect1.y() * _point1.x()
+ _vect1.y() * _point2.x()
) / diviseur;
return Vector2f(_point2 + _vect2 * mmm);
}
Log.error("Get divider / 0.0f");
return _point2;
}
void esvg::render::SegmentList::createSegmentListStroke(const Vector2f& _point1,
const Vector2f& _point2,
const Vector2f& _center,
float _width,
boolean _isStart) {
int nbDot = int(_width);
if (nbDot <= 2) {
nbDot = 2;
}
float angleToDraw = acos((_point1 - _center).safeNormalize().dot((_point2 - _center).safeNormalize()));
float baseAngle = angleToDraw/float(nbDot);
float iii;
Vector2f axe = (_point1 - _center).safeNormalize();
Vector2f ppp1(_point1);
Vector2f ppp2(_point2);
for (iii=baseAngle; iii<angleToDraw; iii+=baseAngle) {
mat2x3 tmpMat;
if (_isStart == true) {
tmpMat = etk::mat2x3Rotate(-iii);
} else {
tmpMat = etk::mat2x3Rotate(iii);
}
Vector2f axeRotate = tmpMat * axe;
ppp2 = _center
+ axeRotate*_width*0.5f;
if (_isStart == true) {
addSegment(ppp2, ppp1);
Log.verbose(" segment :" << ppp2 << " -> " << ppp1);
} else {
addSegment(ppp1, ppp2);
Log.verbose(" segment :" << ppp1 << " -> " << ppp2);
}
ppp1 = ppp2;
}
if (_isStart == true) {
addSegment(_point2, ppp1);
Log.verbose(" segment :" << _point2 << " -> " << ppp1);
} else {
addSegment(ppp1, _point2);
Log.verbose(" segment :" << ppp1 << " -> " << _point2);
}
}
void esvg::render::SegmentList::createSegmentListStroke(esvg::render::PointList& _listPoint,
float _width,
enum esvg::cap _cap,
enum esvg::join _join,
float _miterLimit) {
for (auto &itListPoint : _listPoint.this.data) {
// generate for every point all the orthogonal elements
//
// normal edge * end path
// (mitter) * | * * * * * * * * * * * * * *
// * |<--*----this | *
// * | * this -->| *
// * * * | *
// * . | . * . . . . . . . . * *
// * . | . * | *
// * A . | . B * | *
// . * . | *
// . * * . * * * * * * * * * * * * *
// * *
// * *
for (long idPevious=itListPoint.size()-1, idCurrent=0, idNext=1;
idCurrent < long(itListPoint.size());
idPevious = idCurrent++, idNext++) {
if (idNext == long(itListPoint.size())) {
idNext = 0;
}
if ( itListPoint[idCurrent].this.type == esvg::render::Point::type::join
|| itListPoint[idCurrent].this.type == esvg::render::Point::type::interpolation) {
if (idPevious < 0 ) {
Log.error("an error occure a previous ID is < 0.... ");
continue;
}
if (idNext >= long(itListPoint.size())) {
Log.error("an error occure a next ID is >= nbPoint len .... ");
continue;
}
//Log.debug("JOIN : id : prev/curr/next : " << idPevious << "/" << idCurrent << "/" << idNext);
//Log.debug("JOIN : val : prev/curr/next : " << itListPoint[idPevious].this.pos << "/" << itListPoint[idCurrent].this.pos << "/" << itListPoint[idNext].this.pos);
Vector2f vecA = itListPoint[idCurrent].this.pos - itListPoint[idPevious].this.pos;
//Log.debug("JOIN : vecA : " << vecA);
vecA.safeNormalize();
Vector2f vecB = itListPoint[idNext].this.pos - itListPoint[idCurrent].this.pos;
//Log.debug("JOIN : vecB : " << vecB);
vecB.safeNormalize();
Vector2f vecC = vecA - vecB;
//Log.debug("JOIN : vecC : " << vecC);
if (vecC == Vector2f(0.0f, 0.0f)) {
// special case: 1 line ...
itListPoint[idCurrent].this.miterAxe = Vector2f(vecA.y(), vecA.x());
} else {
vecC.safeNormalize();
itListPoint[idCurrent].this.miterAxe = vecC;
}
itListPoint[idCurrent].this.posPrevious = itListPoint[idPevious].this.pos;
itListPoint[idCurrent].this.posNext = itListPoint[idNext].this.pos;
vecB = itListPoint[idNext].this.pos - itListPoint[idCurrent].this.pos;
vecB.safeNormalize();
itListPoint[idCurrent].this.orthoAxeNext = Vector2f(vecB.y(), -vecB.x());
vecB = itListPoint[idCurrent].this.pos - itListPoint[idPevious].this.pos;
vecB.safeNormalize();
itListPoint[idCurrent].this.orthoAxePrevious = Vector2f(vecB.y(), -vecB.x());
//Log.debug("JOIN : miterAxe " << itListPoint[idCurrent].this.miterAxe);
} else if (itListPoint[idCurrent].this.type == esvg::render::Point::type::start) {
itListPoint[idCurrent].this.posNext = itListPoint[idNext].this.pos;
Vector2f vecB = itListPoint[idNext].this.pos - itListPoint[idCurrent].this.pos;
vecB.safeNormalize();
itListPoint[idCurrent].this.miterAxe = Vector2f(vecB.y(), -vecB.x());
itListPoint[idCurrent].this.orthoAxePrevious = itListPoint[idCurrent].this.miterAxe;
itListPoint[idCurrent].this.orthoAxeNext = itListPoint[idCurrent].this.miterAxe;
} else if (itListPoint[idCurrent].this.type == esvg::render::Point::type::stop) {
if (idPevious < 0 ) {
Log.error("an error occure a previous ID is < 0.... ");
continue;
}
itListPoint[idCurrent].this.posPrevious = itListPoint[idPevious].this.pos;
Vector2f vecA = itListPoint[idCurrent].this.pos - itListPoint[idPevious].this.pos;
vecA.safeNormalize();
itListPoint[idCurrent].this.miterAxe = Vector2f(vecA.y(), -vecA.x());
itListPoint[idCurrent].this.orthoAxePrevious = itListPoint[idCurrent].this.miterAxe;
itListPoint[idCurrent].this.orthoAxeNext = itListPoint[idCurrent].this.miterAxe;
} else {
Log.todo("Unsupported type of point ....");
}
}
// create segment list:
boolean haveStartLine = false;
Vector2f leftPoint(0,0);
Vector2f rightPoint(0,0);
if (itListPoint.size() > 0) {
if (itListPoint.front().this.type == esvg::render::Point::type::join) {
const esvg::render::Point& it = itListPoint.back();
// Calculate the perpendiculary axis ...
leftPoint = itListPoint.back().this.pos
+ itListPoint.back().this.orthoAxePrevious*_width*0.5f;
rightPoint = itListPoint.back().this.pos
- itListPoint.back().this.orthoAxePrevious*_width*0.5f;
// cyclic path...
if (it.this.type == esvg::render::Point::type::interpolation) {
leftPoint = getIntersect(leftPoint, it.this.pos-it.this.posPrevious, it.this.pos, it.this.miterAxe);
rightPoint = getIntersect(rightPoint, it.this.pos-it.this.posPrevious, it.this.pos, it.this.miterAxe);
} else if (it.this.type == esvg::render::Point::type::join) {
// Calculate the perpendiculary axis ...
leftPoint = it.this.pos
+ it.this.orthoAxePrevious*_width*0.5f;
rightPoint = it.this.pos
- it.this.orthoAxePrevious*_width*0.5f;
// project on the miter Axis ...
switch (_join) {
case esvg::join_miter:
{
Vector2f left = getIntersect(leftPoint, it.this.pos-it.this.posPrevious, it.this.pos, it.this.miterAxe);
Vector2f right = getIntersect(rightPoint, it.this.pos-it.this.posPrevious, it.this.pos, it.this.miterAxe);
// Check the miter limit:
float limitRight = (left - it.this.pos).length() / _width * 2.0f;
float limitLeft = (right - it.this.pos).length() / _width * 2.0f;
Log.verbose(" miter Limit: " << limitRight << " " << limitLeft << " <= " << _miterLimit);
if ( limitRight <= _miterLimit
&& limitLeft <= _miterLimit) {
leftPoint = left;
rightPoint = right;
break;
} else {
// BEVEL the miter point ...
}
}
case esvg::join_round:
case esvg::join_bevel:
{
Vector2f axePrevious = (it.this.pos-it.this.posPrevious).safeNormalize();
Vector2f axeNext = (it.this.posNext - it.this.pos).safeNormalize();
float cross = axePrevious.cross(axeNext);
if (cross > 0.0f) {
rightPoint = getIntersect(rightPoint, it.this.pos-it.this.posPrevious, it.this.pos, it.this.miterAxe);
leftPoint = it.this.pos
+ it.this.orthoAxeNext*_width*0.5f;
} else {
leftPoint = getIntersect(leftPoint, it.this.pos-it.this.posPrevious, it.this.pos, it.this.miterAxe);
rightPoint = it.this.pos
- it.this.orthoAxeNext*_width*0.5f;
}
break;
}
}
} else {
Log.error("Start list point with a join, but last lement is not a join");
}
}
}
for (auto &it : itListPoint) {
switch (it.this.type) {
case esvg::render::Point::type::single:
// just do nothing ....
Log.verbose("Find Single " << it.this.pos);
break;
case esvg::render::Point::type::start:
Log.verbose("Find Start " << it.this.pos);
if (haveStartLine == true) {
// close previous :
Log.warning(" find a non close path ...");
addSegment(leftPoint, rightPoint);
}
haveStartLine = true;
startStopPoint(leftPoint, rightPoint, it, _cap, _width, true);
break;
case esvg::render::Point::type::stop:
Log.verbose("Find Stop " << it.this.pos);
if (haveStartLine == false) {
Log.warning("find close path without start part ...");
break;
}
haveStartLine = false;
startStopPoint(leftPoint, rightPoint, it, _cap, _width, false);
break;
case esvg::render::Point::type::interpolation:
{
Log.verbose("Find interpolation " << it.this.pos);
Vector2f left = getIntersect(leftPoint, it.this.pos-it.this.posPrevious, it.this.pos, it.this.miterAxe);
Vector2f right = getIntersect(rightPoint, it.this.pos-it.this.posPrevious, it.this.pos, it.this.miterAxe);
//Draw from previous point:
addSegment(leftPoint, left);
Log.verbose(" segment :" << leftPoint << " -> " << left);
addSegment(right, rightPoint);
Log.verbose(" segment :" << right << " -> " << rightPoint);
leftPoint = left;
rightPoint = right;
}
break;
case esvg::render::Point::type::join:
Log.verbose("Find join " << it.this.pos);
switch (_join) {
case esvg::join_miter:
{
Vector2f left = getIntersect(leftPoint, it.this.pos-it.this.posPrevious, it.this.pos, it.this.miterAxe);
Vector2f right = getIntersect(rightPoint, it.this.pos-it.this.posPrevious, it.this.pos, it.this.miterAxe);
// Check the miter limit:
float limitRight = (left - it.this.pos).length() / _width * 2.0f;
float limitLeft = (right - it.this.pos).length() / _width * 2.0f;
Log.verbose(" miter Limit: " << limitRight << " " << limitLeft << " <= " << _miterLimit);
if ( limitRight <= _miterLimit
&& limitLeft <= _miterLimit) {
//Draw from previous point:
addSegment(leftPoint, left);
Log.verbose(" segment :" << leftPoint << " -> " << left);
addSegment(right, rightPoint);
Log.verbose(" segment :" << right << " -> " << rightPoint);
leftPoint = left;
rightPoint = right;
break;
} else {
// We do a bevel join ...
Log.verbose(" Find miter Limit ... ==> create BEVEL");
}
}
case esvg::join_round:
case esvg::join_bevel:
{
Vector2f axePrevious = (it.this.pos-it.this.posPrevious).safeNormalize();
Vector2f axeNext = (it.this.posNext - it.this.pos).safeNormalize();
float cross = axePrevious.cross(axeNext);
if (cross > 0.0f) {
Vector2f right = getIntersect(rightPoint, it.this.pos-it.this.posPrevious, it.this.pos, it.this.miterAxe);
Vector2f left1 = it.this.pos
+ it.this.orthoAxePrevious*_width*0.5f;
Vector2f left2 = it.this.pos
+ it.this.orthoAxeNext*_width*0.5f;
//Draw from previous point:
addSegment(leftPoint, left1);
Log.verbose(" segment :" << leftPoint << " -> " << left1);
if (_join != esvg::join_round) {
// Miter and bevel:
addSegment(left1, left2);
Log.verbose(" segment :" << left1 << " -> " << left2);
}else {
createSegmentListStroke(left1,
left2,
it.this.pos,
_width,
false);
}
addSegment(right, rightPoint);
Log.verbose(" segment :" << right << " -> " << rightPoint);
leftPoint = left2;
rightPoint = right;
} else {
Vector2f left = getIntersect(leftPoint, it.this.pos-it.this.posPrevious, it.this.pos, it.this.miterAxe);
Vector2f right1 = it.this.pos
- it.this.orthoAxePrevious*_width*0.5f;
Vector2f right2 = it.this.pos
- it.this.orthoAxeNext*_width*0.5f;//Draw from previous point:
addSegment(leftPoint, left);
Log.verbose(" segment :" << leftPoint << " -> " << left);
addSegment(right1, rightPoint);
Log.verbose(" segment :" << right1 << " -> " << rightPoint);
if (_join != esvg::join_round) {
// Miter and bevel:
addSegment(right2, right1);
Log.verbose(" segment :" << right2 << " -> " << right1);
} else {
createSegmentListStroke(right1,
right2,
it.this.pos,
_width,
true);
}
leftPoint = left;
rightPoint = right2;
}
}
break;
}
break;
}
}
}
}
void esvg::render::SegmentList::startStopPoint(Vector2f& _leftPoint,
Vector2f& _rightPoint,
const esvg::render::Point& _point,
enum esvg::cap _cap,
float _width,
boolean _isStart) {
switch (_cap) {
case esvg::cap_butt:
{
Vector2f left = _point.this.pos
+ _point.this.miterAxe*_width*0.5f;
Vector2f right = _point.this.pos
- _point.this.miterAxe*_width*0.5f;
if (_isStart == false) {
//Draw from previous point:
addSegment(_leftPoint, left);
Log.verbose(" segment :" << _leftPoint << " -> " << left);
addSegment(right, _rightPoint);
Log.verbose(" segment :" << right << " -> " << _rightPoint);
}
_leftPoint = left;
_rightPoint = right;
}
if (_isStart == false) {
addSegment(_leftPoint, _rightPoint);
Log.verbose(" segment :" << _leftPoint << " -> " << _rightPoint);
} else {
addSegment(_rightPoint, _leftPoint);
Log.verbose(" segment :" << _rightPoint << " -> " << _leftPoint);
}
break;
case esvg::cap_round:
{
if (_isStart == false) {
Vector2f left = _point.this.pos
+ _point.this.miterAxe*_width*0.5f;
Vector2f right = _point.this.pos
- _point.this.miterAxe*_width*0.5f;
if (_isStart == false) {
//Draw from previous point:
addSegment(_leftPoint, left);
Log.verbose(" segment :" << _leftPoint << " -> " << left);
addSegment(right, _rightPoint);
Log.verbose(" segment :" << right << " -> " << _rightPoint);
}
_leftPoint = left;
_rightPoint = right;
}
int nbDot = int(_width);
if (nbDot <= 2) {
nbDot = 2;
}
float baseAngle = M_PI/float(nbDot);
float iii;
_leftPoint = _point.this.pos
+ _point.this.miterAxe*_width*0.5f;
_rightPoint = _point.this.pos
- _point.this.miterAxe*_width*0.5f;
createSegmentListStroke(_leftPoint,
_rightPoint,
_point.this.pos,
_width,
_isStart);
}
break;
case esvg::cap_square:
{
Vector2f nextAxe;
if (_isStart == true) {
nextAxe = _point.this.posNext - _point.this.pos;
} else {
nextAxe = _point.this.posPrevious - _point.this.pos;
}
Vector2f left = _point.this.pos
+ _point.this.miterAxe*_width*0.5f;
Vector2f right = _point.this.pos
- _point.this.miterAxe*_width*0.5f;
mat2x3 tmpMat = etk::mat2x3Translate(nextAxe.safeNormalize()*_width*-0.5f);
left = tmpMat*left;
right = tmpMat*right;
if (_isStart == false) {
if (_isStart == false) {
//Draw from previous point:
addSegment(_leftPoint, left);
Log.verbose(" segment :" << _leftPoint << " -> " << left);
addSegment(right, _rightPoint);
Log.verbose(" segment :" << right << " -> " << _rightPoint);
}
}
_leftPoint = left;
_rightPoint = right;
if (_isStart == false) {
addSegment(_leftPoint, _rightPoint);
Log.verbose(" segment :" << _leftPoint << " -> " << _rightPoint);
} else {
addSegment(_rightPoint, _leftPoint);
Log.verbose(" segment :" << _rightPoint << " -> " << _leftPoint);
}
Log.verbose(" segment :" << _leftPoint << " -> " << _rightPoint);
}
break;
default:
Log.error(" Undefined CAP TYPE");
break;
}
}
void esvg::render::SegmentList::applyMatrix(const mat2x3& _transformationMatrix) {
for (auto &it : this.data) {
it.applyMatrix(_transformationMatrix);
}
}

View File

@ -1,49 +1,457 @@
package org.atriasoft.esvg.render;
import java.util.ArrayList;
import java.util.List;
import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.util.Pair;
import org.atriasoft.etk.math.FMath;
import org.atriasoft.etk.math.Matrix2x3f;
import org.atriasoft.esvg.CapMode;
import org.atriasoft.esvg.JoinMode;
import org.atriasoft.esvg.internal.Log;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<etk/types.hpp>#include<etk/math/Vector2D.hpp>#include<esvg/cap.hpp>#include<esvg/join.hpp>#include<esvg/render/Segment.hpp>#include<esvg/render/PointList.hpp>
namespace esvg{namespace render{
class SegmentList {
public:
List<esvg::render::Segment> this.data;
public:
SegmentList();#ifdef DEBUG
void addSegment(const Vector2f& _pos0, const Vector2f& _pos1);
#endif
void addSegment(const esvg::render::Point& _pos0, const esvg::render::Point& _pos1);
void addSegment(const esvg::render::Point& _pos0, const esvg::render::Point& _pos1, boolean _disableHorizontal);
void createSegmentList(const esvg::render::PointList& _listPoint);
void createSegmentListStroke(esvg::render::PointList& _listPoint,
float _width,
enum esvg::cap _cap,
enum esvg::join _join,
float _miterLimit);
private:
void startStopPoint(Vector2f& _leftPoint,
Vector2f& _rightPoint,
const esvg::render::Point& _point,
enum esvg::cap _cap,
float _width,
boolean _isStart);
void createSegmentListStroke(const Vector2f& _point1,
const Vector2f& _point2,
const Vector2f& _center,
float _width,
boolean _isStart);
public:
Pair<Vector2f, Vector2f> getViewPort();
void applyMatrix(const mat2x3& _transformationMatrix);
};
public class SegmentList {
static Vector2f getIntersect(final Vector2f point1, final Vector2f vect1, final Vector2f point2, final Vector2f vect2) {
float diviseur = vect1.x() * vect2.y() - vect1.y() * vect2.x();
if (diviseur != 0.0f) {
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));
}
Log.error("Get divider / 0.0f");
return point2;
}
public List<Segment> data = new ArrayList<>();
public SegmentList() {}
public void addSegment(final Point pos0, final Point pos1) {
// Skip horizontal Segments
if (pos0.pos.y() == pos1.pos.y()) {
// remove /0 operation
return;
}
this.data.add(new Segment(pos0.pos, pos1.pos));
}
public void addSegment(final Point pos0, final Point pos1, final boolean disableHorizontal) {
// Skip horizontal Segments
if (disableHorizontal && pos0.pos.y() == pos1.pos.y()) {
// remove /0 operation
return;
}
this.data.add(new Segment(pos0.pos, pos1.pos));
}
// TODO is it really needed...
void addSegment(final Vector2f pos0, final Vector2f pos1) {
this.data.add(new Segment(pos0, pos1));
}
public void applyMatrix(final Matrix2x3f transformationMatrix) {
for (Segment it : this.data) {
it.applyMatrix(transformationMatrix);
}
}
public void createSegmentList(final PointList listPoint) {
for (List<Point> it : listPoint.data) {
// Build Segments
for (int iii = 0, jjj = it.size() - 1; iii < it.size(); jjj = iii++) {
addSegment(it.get(jjj), it.get(iii));
}
}
}
public void createSegmentListStroke(final PointList listPoint, final float width, final CapMode cap, final JoinMode join, final float miterLimit) {
for (List<Point> itListPoint : listPoint.data) {
// generate for every point all the orthogonal elements
//
// normal edge * end path
// (mitter) * | * * * * * * * * * * * * * *
// * |<--*----this | *
// * | * this -.| *
// * * * | *
// * . | . * . . . . . . . . * *
// * . | . * | *
// * A . | . B * | *
// . * . | *
// . * * . * * * * * * * * * * * * *
// * *
// * *
for (int idPevious = itListPoint.size() - 1, idCurrent = 0, idNext = 1; idCurrent < itListPoint.size(); idPevious = idCurrent++, idNext++) {
if (idNext == itListPoint.size()) {
idNext = 0;
}
if (itListPoint.get(idCurrent).type == PointType.join || itListPoint.get(idCurrent).type == PointType.interpolation) {
if (idPevious < 0) {
Log.error("an error occure a previous ID is < 0.... ");
continue;
}
if (idNext >= itListPoint.size()) {
Log.error("an error occure a next ID is >= nbPoint len .... ");
continue;
}
//Log.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);
Vector2f vecA = itListPoint.get(idCurrent).pos.less(itListPoint.get(idPevious).pos);
//Log.debug("JOIN : vecA : " + vecA);
vecA.safeNormalize();
Vector2f vecB = itListPoint.get(idNext).pos.less(itListPoint.get(idCurrent).pos);
//Log.debug("JOIN : vecB : " + vecB);
vecB.safeNormalize();
Vector2f vecC = vecA.less(vecB);
//Log.debug("JOIN : vecC : " + vecC);
if (vecC.isZero()) {
// special case: 1 line ...
itListPoint.get(idCurrent).miterAxe = new Vector2f(vecA.y(), vecA.x());
} else {
vecC.safeNormalize();
itListPoint.get(idCurrent).miterAxe = vecC;
}
itListPoint.get(idCurrent).posPrevious = itListPoint.get(idPevious).pos;
itListPoint.get(idCurrent).posNext = itListPoint.get(idNext).pos;
vecB = itListPoint.get(idNext).pos.less(itListPoint.get(idCurrent).pos);
vecB.safeNormalize();
itListPoint.get(idCurrent).orthoAxeNext = new Vector2f(vecB.y(), -vecB.x());
vecB = itListPoint.get(idCurrent).pos.less(itListPoint.get(idPevious).pos);
vecB.safeNormalize();
itListPoint.get(idCurrent).orthoAxePrevious = new Vector2f(vecB.y(), -vecB.x());
//Log.debug("JOIN : miterAxe " + itListPoint.get(idCurrent).miterAxe);
} else if (itListPoint.get(idCurrent).type == PointType.start) {
itListPoint.get(idCurrent).posNext = itListPoint.get(idNext).pos;
Vector2f vecB = itListPoint.get(idNext).pos.less(itListPoint.get(idCurrent).pos);
vecB.safeNormalize();
itListPoint.get(idCurrent).miterAxe = new Vector2f(vecB.y(), -vecB.x());
itListPoint.get(idCurrent).orthoAxePrevious = itListPoint.get(idCurrent).miterAxe;
itListPoint.get(idCurrent).orthoAxeNext = itListPoint.get(idCurrent).miterAxe;
} else if (itListPoint.get(idCurrent).type == PointType.stop) {
if (idPevious < 0) {
Log.error("an error occure a previous ID is < 0.... ");
continue;
}
itListPoint.get(idCurrent).posPrevious = itListPoint.get(idPevious).pos;
Vector2f vecA = itListPoint.get(idCurrent).pos.less(itListPoint.get(idPevious).pos);
vecA.safeNormalize();
itListPoint.get(idCurrent).miterAxe = new Vector2f(vecA.y(), -vecA.x());
itListPoint.get(idCurrent).orthoAxePrevious = itListPoint.get(idCurrent).miterAxe;
itListPoint.get(idCurrent).orthoAxeNext = itListPoint.get(idCurrent).miterAxe;
} else {
Log.todo("Unsupported type of point ....");
}
}
// create segment list:
boolean haveStartLine = false;
Vector2f leftPoint = Vector2f.ZERO;
Vector2f rightPoint = Vector2f.ZERO;
if (itListPoint.size() > 0) {
if (itListPoint.get(0).type == PointType.join) {
Point it = itListPoint.get(itListPoint.size() - 1);
// Calculate the perpendiculary axis ...
leftPoint = it.pos.add(it.orthoAxePrevious.multiply(width * 0.5f));
rightPoint = it.pos.less(it.orthoAxePrevious.multiply(width * 0.5f));
// cyclic path...
if (it.type == PointType.interpolation) {
leftPoint = SegmentList.getIntersect(leftPoint, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
rightPoint = SegmentList.getIntersect(rightPoint, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
} else if (it.type == PointType.join) {
// Calculate the perpendiculary axis ...
leftPoint = it.pos.add(it.orthoAxePrevious.multiply(width * 0.5f));
rightPoint = it.pos.less(it.orthoAxePrevious.multiply(width * 0.5f));
// project on the miter Axis ...
switch (join) {
case MITER: {
Vector2f left = SegmentList.getIntersect(leftPoint, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
Vector2f right = SegmentList.getIntersect(rightPoint, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
// Check the miter limit:
float limitRight = (left.less(it.pos)).length() / width * 2.0f;
float limitLeft = (right.less(it.pos)).length() / width * 2.0f;
Log.verbose(" miter Limit: " + limitRight + " " + limitLeft + " <= " + miterLimit);
if (limitRight <= miterLimit && limitLeft <= miterLimit) {
leftPoint = left;
rightPoint = right;
break;
}
}
case ROUND:
case BEVEL: {
Vector2f axePrevious = (it.pos.less(it.posPrevious)).safeNormalize();
Vector2f axeNext = (it.posNext.less(it.pos)).safeNormalize();
float cross = axePrevious.cross(axeNext);
if (cross > 0.0f) {
rightPoint = SegmentList.getIntersect(rightPoint, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
leftPoint = it.pos.add(it.orthoAxeNext.multiply(width * 0.5f));
} else {
leftPoint = SegmentList.getIntersect(leftPoint, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
rightPoint = it.pos.less(it.orthoAxeNext.multiply(width * 0.5f));
}
break;
}
default:
break;
}
} else {
Log.error("Start list point with a join, but last lement is not a join");
}
}
}
for (Point it : itListPoint) {
switch (it.type) {
case single:
// just do nothing ....
Log.verbose("Find Single " + it.pos);
break;
case start:
Log.verbose("Find Start " + it.pos);
if (haveStartLine) {
// close previous :
Log.warning(" find a non close path ...");
addSegment(leftPoint, rightPoint);
}
haveStartLine = true;
startStopPoint(leftPoint, rightPoint, it, cap, width, true);
break;
case stop:
Log.verbose("Find Stop " + it.pos);
if (!haveStartLine) {
Log.warning("find close path without start part ...");
break;
}
haveStartLine = false;
startStopPoint(leftPoint, rightPoint, it, cap, width, false);
break;
case interpolation: {
Log.verbose("Find interpolation " + it.pos);
Vector2f left = SegmentList.getIntersect(leftPoint, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
Vector2f right = SegmentList.getIntersect(rightPoint, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
//Draw from previous point:
addSegment(leftPoint, left);
Log.verbose(" segment :" + leftPoint + " . " + left);
addSegment(right, rightPoint);
Log.verbose(" segment :" + right + " . " + rightPoint);
leftPoint = left;
rightPoint = right;
}
break;
case join:
Log.verbose("Find join " + it.pos);
switch (join) {
case MITER: {
Vector2f left = SegmentList.getIntersect(leftPoint, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
Vector2f right = SegmentList.getIntersect(rightPoint, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
// Check the miter limit:
float limitRight = left.less(it.pos).length() / width * 2.0f;
float limitLeft = right.less(it.pos).length() / width * 2.0f;
Log.verbose(" miter Limit: " + limitRight + " " + limitLeft + " <= " + miterLimit);
if (limitRight <= miterLimit && limitLeft <= miterLimit) {
//Draw from previous point:
addSegment(leftPoint, left);
Log.verbose(" segment :" + leftPoint + " . " + left);
addSegment(right, rightPoint);
Log.verbose(" segment :" + right + " . " + rightPoint);
leftPoint = left;
rightPoint = right;
break;
}
Log.verbose(" Find miter Limit ... ==> create BEVEL");
}
case ROUND:
case BEVEL: {
Vector2f axePrevious = (it.pos.less(it.posPrevious)).safeNormalize();
Vector2f axeNext = (it.posNext.less(it.pos)).safeNormalize();
float cross = axePrevious.cross(axeNext);
if (cross > 0.0f) {
Vector2f right = SegmentList.getIntersect(rightPoint, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
Vector2f left1 = it.pos.add(it.orthoAxePrevious.multiply(width * 0.5f));
Vector2f left2 = it.pos.add(it.orthoAxeNext.multiply(width * 0.5f));
//Draw from previous point:
addSegment(leftPoint, left1);
Log.verbose(" segment :" + leftPoint + " . " + left1);
if (join != JoinMode.ROUND) {
// Miter and bevel:
addSegment(left1, left2);
Log.verbose(" segment :" + left1 + " . " + left2);
} else {
createSegmentListStroke(left1, left2, it.pos, width, false);
}
addSegment(right, rightPoint);
Log.verbose(" segment :" + right + " . " + rightPoint);
leftPoint = left2;
rightPoint = right;
} else {
Vector2f left = SegmentList.getIntersect(leftPoint, it.pos.less(it.posPrevious), it.pos, it.miterAxe);
Vector2f right1 = it.pos.less(it.orthoAxePrevious.multiply(width * 0.5f));
Vector2f right2 = it.pos.less(it.orthoAxeNext.multiply(width * 0.5f));
//Draw from previous point:
addSegment(leftPoint, left);
Log.verbose(" segment :" + leftPoint + " . " + left);
addSegment(right1, rightPoint);
Log.verbose(" segment :" + right1 + " . " + rightPoint);
if (join != JoinMode.ROUND) {
// Miter and bevel:
addSegment(right2, right1);
Log.verbose(" segment :" + right2 + " . " + right1);
} else {
createSegmentListStroke(right1, right2, it.pos, width, true);
}
leftPoint = left;
rightPoint = right2;
}
}
break;
default:
break;
}
break;
default:
break;
}
}
}
}
private void createSegmentListStroke(final Vector2f point1, final Vector2f point2, final Vector2f center, final float width, final boolean isStart) {
int nbDot = (int) width;
if (nbDot <= 2) {
nbDot = 2;
}
float angleToDraw = FMath.acos((point1.less(center)).safeNormalize().dot((point2.less(center)).safeNormalize()));
float baseAngle = angleToDraw / nbDot;
float iii;
Vector2f axe = (point1.less(center)).safeNormalize();
Vector2f ppp1 = point1;
Vector2f ppp2 = point2;
for (iii = baseAngle; iii < angleToDraw; iii += baseAngle) {
Matrix2x3f tmpMat = Matrix2x3f.IDENTITY;
if (isStart) {
tmpMat = Matrix2x3f.createRotate(-iii);
} else {
tmpMat = Matrix2x3f.createRotate(iii);
}
Vector2f axeRotate = tmpMat.multiply(axe);
ppp2 = center.add(axeRotate.multiply(width * 0.5f));
if (isStart) {
addSegment(ppp2, ppp1);
Log.verbose(" segment :" + ppp2 + " . " + ppp1);
} else {
addSegment(ppp1, ppp2);
Log.verbose(" segment :" + ppp1 + " . " + ppp2);
}
ppp1 = ppp2;
}
if (isStart) {
addSegment(point2, ppp1);
Log.verbose(" segment :" + point2 + " . " + ppp1);
} else {
addSegment(ppp1, point2);
Log.verbose(" segment :" + ppp1 + " . " + point2);
}
}
public Pair<Vector2f, Vector2f> getViewPort() {
Pair<Vector2f, Vector2f> out = new Pair<>(Vector2f.MAX_VALUE, Vector2f.MIN_VALUE);
for (Segment it : this.data) {
out = new Pair<>(Vector2f.min(out.first, it.p0, it.p1), Vector2f.max(out.second, it.p0, it.p1));
}
return out;
}
private void startStopPoint(Vector2f leftPoint, Vector2f rightPoint, final Point point, final CapMode cap, final float width, final boolean isStart) {
switch (cap) {
case BUTT: {
Vector2f left = point.pos.add(point.miterAxe.multiply(width * 0.5f));
Vector2f right = point.pos.less(point.miterAxe.multiply(width * 0.5f));
if (!isStart) {
//Draw from previous point:
addSegment(leftPoint, left);
Log.verbose(" segment :" + leftPoint + " . " + left);
addSegment(right, rightPoint);
Log.verbose(" segment :" + right + " . " + rightPoint);
}
leftPoint = left;
rightPoint = right;
}
if (!isStart) {
addSegment(leftPoint, rightPoint);
Log.verbose(" segment :" + leftPoint + " . " + rightPoint);
} else {
addSegment(rightPoint, leftPoint);
Log.verbose(" segment :" + rightPoint + " . " + leftPoint);
}
break;
case ROUND: {
if (!isStart) {
Vector2f left = point.pos.add(point.miterAxe.multiply(width * 0.5f));
Vector2f right = point.pos.less(point.miterAxe.multiply(width * 0.5f));
if (!isStart) {
//Draw from previous point:
addSegment(leftPoint, left);
Log.verbose(" segment :" + leftPoint + " . " + left);
addSegment(right, rightPoint);
Log.verbose(" segment :" + right + " . " + rightPoint);
}
leftPoint = left;
rightPoint = right;
}
int nbDot = (int) width;
if (nbDot <= 2) {
nbDot = 2;
}
leftPoint = point.pos.add(point.miterAxe.multiply(width * 0.5f));
rightPoint = point.pos.less(point.miterAxe.multiply(width * 0.5f));
createSegmentListStroke(leftPoint, rightPoint, point.pos, width, isStart);
}
break;
case SQUARE: {
Vector2f nextAxe;
if (isStart) {
nextAxe = point.posNext.less(point.pos);
} else {
nextAxe = point.posPrevious.less(point.pos);
}
Vector2f left = point.pos.add(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));
left = tmpMat.multiply(left);
right = tmpMat.multiply(right);
if (!isStart) {
if (!isStart) {
//Draw from previous point:
addSegment(leftPoint, left);
Log.verbose(" segment :" + leftPoint + " . " + left);
addSegment(right, rightPoint);
Log.verbose(" segment :" + right + " . " + rightPoint);
}
}
leftPoint = left;
rightPoint = right;
if (!isStart) {
addSegment(leftPoint, rightPoint);
Log.verbose(" segment :" + leftPoint + " . " + rightPoint);
} else {
addSegment(rightPoint, leftPoint);
Log.verbose(" segment :" + rightPoint + " . " + leftPoint);
}
Log.verbose(" segment :" + leftPoint + " . " + rightPoint);
}
break;
default:
Log.error(" Undefined CAP TYPE");
break;
}
}
}

View File

@ -1,203 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/render/Weight.hpp>
#include <esvg/debug.hpp>
#include <etk/algorithm.hpp>
esvg::render::Weight::Weight() :
this.size(0,0) {
}
esvg::render::Weight::Weight(const Vector2i& _size) :
this.size(_size) {
resize(_size);
}
esvg::render::Weight::~Weight() {
}
void esvg::render::Weight::resize(const Vector2i& _size) {
this.size = _size;
float tmp(0);
this.data.resize(this.size.x()*this.size.y(), tmp);
if ((uint)this.size.x()*this.size.y() > this.data.size()) {
Log.warning("Wrong weigth buffer size ...");
return;
}
}
const Vector2i& esvg::render::Weight::getSize() const {
return this.size;
}
int esvg::render::Weight::getWidth() const {
return this.size.x();
}
int esvg::render::Weight::getHeight() const {
return this.size.y();
}
void esvg::render::Weight::clear(float _fill) {
for (int iii=0; iii<this.size.x()*this.size.y(); iii++) {
this.data[iii] = _fill;
}
}
float esvg::render::Weight::get(const Vector2i& _pos) const {
if ( _pos.x()>=0 && _pos.x()<this.size.x()
&& _pos.y()>=0 && _pos.y()<this.size.y()) {
return this.data[_pos.x()+_pos.y()*this.size.x()];
}
return 0;
}
void esvg::render::Weight::set(const Vector2i& _pos, float _newColor) {
if ( _pos.x()>=0 && _pos.x()<this.size.x()
&& _pos.y()>=0 && _pos.y()<this.size.y()) {
this.data[_pos.x()+_pos.y()*this.size.x()] = _newColor;
}
}
void esvg::render::Weight::set(int _posY, const esvg::render::Scanline& _data) {
if ( _posY>=0
&& _posY<this.size.y()) {
for (int xxx=0; xxx<this.size.x(); ++xxx) {
this.data[xxx+_posY*this.size.x()] = _data.get(xxx);
}
}
}
void esvg::render::Weight::append(int _posY, const esvg::render::Scanline& _data) {
if ( _posY>=0
&& _posY<this.size.y()) {
for (int xxx=0; xxx<this.size.x(); ++xxx) {
this.data[xxx+_posY*this.size.x()] += _data.get(xxx);
}
}
}
boolean sortXPosFunction(const Pair<float,int>& _e1, const Pair<float,int>& _e2) {
return _e1.first < _e2.first;
}
void esvg::render::Weight::generate(Vector2i _size, int _subSamplingCount, const esvg::render::SegmentList& _listSegment) {
resize(_size);
// for each lines:
for (int yyy=0; yyy<_size.y(); ++yyy) {
Log.verbose("Weighting ... " << yyy << " / " << _size.y());
// Reduce the number of lines in the subsampling parsing:
List<Segment> availlableSegmentPixel;
for (auto &it : _listSegment.this.data) {
if ( it.p0.y() < float(yyy+1)
&& it.p1.y() > float(yyy)) {
availlableSegmentPixel.pushBack(it);
}
}
if (availlableSegmentPixel.size() == 0) {
continue;
}
Log.verbose(" Find Basic segments " << availlableSegmentPixel.size());
// This represent the pondaration on the subSampling
float deltaSize = 1.0f/_subSamplingCount;
for (int kkk=0; kkk<_subSamplingCount ; ++kkk) {
Log.verbose(" Scanline ... " << kkk << " / " << _subSamplingCount);
Scanline scanline(_size.x());
//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;
List<Segment> availlableSegment;
// find in the subList ...
for (auto &it : availlableSegmentPixel) {
if ( it.p0.y() <= subSamplingCenterPos
&& it.p1.y() > subSamplingCenterPos) {
// check if we not get 2 identical lines:
if ( availlableSegment.size() > 0
&& availlableSegment.back().p1 == it.p0
&& availlableSegment.back().direction == it.direction) {
// we not add this point in this case to prevent double count of the same point.
} else {
availlableSegment.pushBack(it);
}
}
}
Log.verbose(" Availlable Segment " << availlableSegment.size());
if (availlableSegment.size() == 0) {
continue;
}
for (auto &it : availlableSegment) {
Log.verbose(" Availlable Segment " << it.p0 << " -> " << it.p1 << " dir=" << it.direction);
}
// x position, angle
List<Pair<float, int>> listPosition;
for (auto &it : availlableSegment) {
Vector2f delta = it.p0 - it.p1;
// x = coefficent*y+bbb;
float coefficient = delta.x()/delta.y();
float bbb = it.p0.x() - coefficient*it.p0.y();
float xpos = coefficient * subSamplingCenterPos + bbb;
listPosition.pushBack(Pair<float,int>(xpos, it.direction));
}
Log.verbose(" List position " << listPosition.size());
// now we order position of the xPosition:
etk::algorithm::quickSort(listPosition, sortXPosFunction);
// move through all element in the point:
int lastState = 0;
float currentValue = 0.0f;
int lastPos = -1;
int currentPos = -1;
float lastX = 0.0f;
// * | \---------------/ |
// * current pos
// * pos ...
// TODO : Code the Odd/even and non-zero ...
for (auto &it : listPosition) {
if (currentPos != int(it.first)) {
// fill to the new pos -1:
#if __CPP_VERSION__ >= 2011 && !defined(__TARGET_OS__MacOs) && !defined(__TARGET_OS__IOs)
float endValue = float(etk::min(1,etk::abs(lastState))) * deltaSize;
#else
float endValue = float(etk::min(1,abs(lastState))) * deltaSize;
#endif
for (int iii=currentPos+1; iii<int(it.first); ++iii) {
scanline.set(iii, endValue);
}
currentPos = int(it.first);
currentValue = endValue;
}
int oldState = lastState;
lastState += it.second;
if (oldState == 0) {
// nothing to draw before ...
float ratio = 1.0f - (it.first - float(int(it.first)));
currentValue += ratio * deltaSize;
} else if (lastState == 0) {
// something new to draw ...
float ratio = 1.0f - (it.first - float(int(it.first)));
currentValue -= ratio * deltaSize;
} else {
// nothing to do ...
}
if (currentPos == int(it.first)) {
scanline.set(currentPos, currentValue);
}
}
// if the counter is not at 0 ==> fill if to the end with full value ... 2.0
if (lastState != 0) {
// just past the last state to the end of the image ...
Log.error("end of Path whith no end ... " << currentPos << " -> " << _size.x());
for (int xxx=currentPos; xxx<_size.x(); ++xxx) {
scanline.set(xxx, 100.0);
}
}
append(yyy, scanline);
}
}
}

View File

@ -1,47 +1,183 @@
package org.atriasoft.esvg.render;
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include<etk/types.hpp>#include<etk/math/Vector2D.hpp>#include<esvg/render/Scanline.hpp>#include<esvg/render/SegmentList.hpp>
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
namespace esvg{namespace render{
class Weight {
private:
Vector2i this.size;
List<float> this.data;
public:
// constructor :
Weight();
import org.atriasoft.esvg.internal.Log;
import org.atriasoft.etk.math.FMath;
import org.atriasoft.etk.math.Vector2f;
import org.atriasoft.etk.math.Vector2i;
import org.atriasoft.etk.util.Pair;
public class Weight {
private float[][] data = null;
private Vector2i size;
Weight(const Vector2i& _size);
// destructor
~Weight();
// -----------------------------------------------
// -- basic tools :
// -----------------------------------------------
public:
// constructor :
public Weight() {
this.size = Vector2i.ZERO;
}
void resize(const Vector2i& _size);
const Vector2i& getSize() const;
public Weight(final Vector2i size) {
this.size = size;
resize(size);
}
int getWidth() const;
public void append(final int posY, final Scanline data) {
if (posY >= 0 && posY < this.size.y()) {
for (int xxx = 0; xxx < this.size.x(); ++xxx) {
this.data[posY][xxx] += data.get(xxx);
}
}
}
int getHeight() const;
public void clear(final float fill) {
Arrays.fill(this.data, fill);
}
void clear(float _fill);
public void generate(final Vector2i size, final int subSamplingCount, final SegmentList listSegment) {
resize(size);
// for each lines:
for (int yyy = 0; yyy < size.y(); ++yyy) {
Log.verbose("Weighting ... " + yyy + " / " + size.y());
// Reduce the number of lines in the subsampling parsing:
List<Segment> availlableSegmentPixel = new ArrayList<Segment>();
for (Segment it : listSegment.data) {
if (it.p0.y() < yyy + 1 && it.p1.y() > (yyy)) {
availlableSegmentPixel.add(it);
}
}
if (availlableSegmentPixel.size() == 0) {
continue;
}
Log.verbose(" Find Basic segments " + availlableSegmentPixel.size());
// This represent the pondaration on the subSampling
float deltaSize = 1.0f / subSamplingCount;
for (int kkk = 0; kkk < subSamplingCount; ++kkk) {
Log.verbose(" Scanline ... " + kkk + " / " + subSamplingCount);
Scanline scanline = new Scanline(size.x());
//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;
List<Segment> availlableSegment = new ArrayList<>();
// find in the subList ...
for (Segment it : availlableSegmentPixel) {
if (it.p0.y() <= subSamplingCenterPos && it.p1.y() > subSamplingCenterPos) {
// check if we not get 2 identical lines:
if (availlableSegment.size() > 0 && availlableSegment.get(availlableSegment.size() - 1).p1 == it.p0
&& availlableSegment.get(availlableSegment.size() - 1).direction == it.direction) {
// we not add this point in this case to prevent double count of the same point.
} else {
availlableSegment.add(it);
}
}
}
Log.verbose(" Availlable Segment " + availlableSegment.size());
if (availlableSegment.size() == 0) {
continue;
}
for (Segment it : availlableSegment) {
Log.verbose(" Availlable Segment " + it.p0 + " . " + it.p1 + " dir=" + it.direction);
}
// x position, angle
List<Pair<Float, Integer>> listPosition = new ArrayList<>();
for (Segment it : availlableSegment) {
Vector2f delta = it.p0.less(it.p1);
// x = coefficent*y+bbb;
float coefficient = delta.x() / delta.y();
float bbb = it.p0.x() - coefficient * it.p0.y();
float xpos = coefficient * subSamplingCenterPos + bbb;
listPosition.add(new Pair<Float, Integer>(xpos, it.direction));
}
Log.verbose(" List position " + listPosition.size());
// now we order position of the xPosition:
Collections.sort(listPosition, (e1, e2) -> ((int) (e2.first - e1.first)));
// move through all element in the point:
int lastState = 0;
float currentValue = 0.0f;
int currentPos = -1;
// * | \---------------/ |
// * current pos
// * pos ...
// TODO Code the Odd/even and non-zero ...
for (Pair<Float, Integer> it : listPosition) {
if (currentPos != it.first.intValue()) {
// fill to the new pos -1:
float endValue = FMath.min(1.0f, FMath.abs(lastState)) * deltaSize;
for (int iii = currentPos + 1; iii < it.first.intValue(); ++iii) {
scanline.set(iii, endValue);
}
currentPos = it.first.intValue();
currentValue = endValue;
}
int oldState = lastState;
lastState += it.second;
if (oldState == 0) {
// nothing to draw before ...
float ratio = 1.0f - (it.first - it.first.intValue());
currentValue += ratio * deltaSize;
} else if (lastState == 0) {
// something new to draw ...
float ratio = 1.0f - (it.first - it.first.intValue());
currentValue -= ratio * deltaSize;
} else {
// nothing to do ...
}
if (currentPos == it.first.intValue()) {
scanline.set(currentPos, currentValue);
}
}
// if the counter is not at 0 ==> fill if to the end with full value ... 2.0
if (lastState != 0) {
// just past the last state to the end of the image ...
Log.error("end of Path whith no end ... " + currentPos + " . " + size.x());
for (int xxx = currentPos; xxx < size.x(); ++xxx) {
scanline.set(xxx, 100.0f);
}
}
append(yyy, scanline);
}
}
}
float get(const Vector2i& _pos) const;
public float get(final Vector2i pos) {
return this.data[pos.y()][pos.x()];
}
void set(const Vector2i& _pos, float _newColor);
public int getHeight() {
return this.size.y();
}
void set(final int _posY, const esvg::render::Scanline& _data);
public Vector2i getSize() {
return this.size;
}
void append(final int _posY, const esvg::render::Scanline& _data);
public int getWidth() {
return this.size.x();
}
void generate(final Vector2i _size, final int _subSamplingCount, const esvg::render::SegmentList& _listSegment);
};
}}
// -----------------------------------------------
// -- basic tools :
// -----------------------------------------------
public void resize(final Vector2i size) {
this.size = size;
this.data = new float[this.size.y()][this.size.x()];
clear(0);
}
public void set(final int posY, final Scanline data) {
if (posY >= 0 && posY < this.size.y()) {
for (int xxx = 0; xxx < this.size.x(); ++xxx) {
this.data[posY][xxx] = data.get(xxx);
}
}
}
public void set(final Vector2i pos, final float newColor) {
this.data[pos.y()][pos.x()] = newColor;
}
}

View File

@ -1,20 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <esvg/spreadMethod.hpp>
#include <esvg/debug.hpp>
static const char* values[] = {
"pad",
"reflect",
"repeat"
};
etk::Stream& esvg::operator <<(etk::Stream& _os, enum esvg::spreadMethod _obj) {
_os << values[_obj];
return _os;
}

View File

@ -0,0 +1,7 @@
package test.atriasoft.esvg;
public class ConfigTest {
public static final boolean VISUAL_DEBUG = false;
private ConfigTest() {}
}

View File

@ -0,0 +1,139 @@
package test.atriasoft.esvg;
import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Test;
class TestCap {
@Test
public void testTestCapButt() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <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>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri("TestCapbutt.svg"), data);
doc.generateAnImage(new Uri("TestCapbutt.bmp"), ConfigTest.VISUAL_DEBUG);
}
@Test
public void testTestCapButtDiag1() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <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>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri("TestCapbuttDiag1.svg"), data);
doc.generateAnImage(new Uri("TestCapbuttDiag1.bmp"), ConfigTest.VISUAL_DEBUG);
}
@Test
public void testTestCapButtDiag2() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <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>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri("TestCapbuttDiag2.svg"), data);
doc.generateAnImage(new Uri("TestCapbuttDiag2.bmp"), ConfigTest.VISUAL_DEBUG);
}
@Test
public void testTestCapButtVert() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <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>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri("TestCapbuttVert.svg"), data);
doc.generateAnImage(new Uri("TestCapbuttVert.bmp"), ConfigTest.VISUAL_DEBUG);
}
@Test
public void testTestCapRound() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <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>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri("TestCapround.svg"), data);
doc.generateAnImage(new Uri("TestCapround.bmp"), ConfigTest.VISUAL_DEBUG);
}
@Test
public void testTestCapRoundDiag1() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <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>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri("TestCaproundDiag1.svg"), data);
doc.generateAnImage(new Uri("TestCaproundDiag1.bmp"), ConfigTest.VISUAL_DEBUG);
}
@Test
public void testTestCapRoundDiag2() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <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>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri("TestCaproundDiag2.svg"), data);
doc.generateAnImage(new Uri("TestCaproundDiag2.bmp"), ConfigTest.VISUAL_DEBUG);
}
@Test
public void testTestCapRoundVert() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <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>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri("TestCaproundVert.svg"), data);
doc.generateAnImage(new Uri("TestCaproundVert.bmp"), ConfigTest.VISUAL_DEBUG);
}
@Test
public void testTestCapSquare() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <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>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri("TestCapsquare.svg"), data);
doc.generateAnImage(new Uri("TestCapsquare.bmp"), ConfigTest.VISUAL_DEBUG);
}
@Test
public void testTestCapSquareDiag1() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <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>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri("TestCapsquareDiag1.svg"), data);
doc.generateAnImage(new Uri("TestCapsquareDiag1.bmp"), ConfigTest.VISUAL_DEBUG);
}
@Test
public void testTestCapSquareDiag2() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <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>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri("TestCapsquareDiag2.svg"), data);
doc.generateAnImage(new Uri("TestCapsquareDiag2.bmp"), ConfigTest.VISUAL_DEBUG);
}
@Test
public void testTestCapSquareVert() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <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>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri("TestCapsquareVert.svg"), data);
doc.generateAnImage(new Uri("TestCapsquareVert.bmp"), ConfigTest.VISUAL_DEBUG);
}
}

View File

@ -0,0 +1,36 @@
package test.atriasoft.esvg;
import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Test;
class TestCircle {
@Test
public void testTestCircleFill() {
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>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri("TestCirclefill.svg"), data);
doc.generateAnImage(new Uri("TestCirclefill.bmp"), ConfigTest.VISUAL_DEBUG);
}
@Test
public void testTestCircleFillandstroke() {
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' />"
+ "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri("TestCirclefillandstroke.svg"), data);
doc.generateAnImage(new Uri("TestCirclefillandstroke.bmp"), ConfigTest.VISUAL_DEBUG);
}
@Test
public void testTestCircleStroke() {
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>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri("TestCirclestroke.svg"), data);
doc.generateAnImage(new Uri("TestCirclestroke.bmp"), ConfigTest.VISUAL_DEBUG);
}
}

View File

@ -0,0 +1,49 @@
package test.atriasoft.esvg;
import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Test;
class TestColor {
@Test
public void testTestColorBlending() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <rect x='12.5' y='12.5' width='75' height='50' stroke='#0F0' stroke-opacity='0.5' stroke-width='3' fill='#F00' fill-opacity='0.5' />" + "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri("TestColorblending.svg"), data);
doc.generateAnImage(new Uri("TestColorblending.bmp"), ConfigTest.VISUAL_DEBUG);
}
@Test
public void testTestColorBlendingandopacity() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <rect x='12.5' y='12.5' width='75' height='50' stroke='#0F0' stroke-opacity='0.5' stroke-width='3' fill='#F00' fill-opacity='0.5' opacity='0.7' />" + "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri("TestColorblendingandopacity.svg"), data);
doc.generateAnImage(new Uri("TestColorblendingandopacity.bmp"), ConfigTest.VISUAL_DEBUG);
}
@Test
public void testTestColorMultiplelayer() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <rect x='50' y='5' width='15' height='75' stroke='blue' stroke-width='9' fill='green'/>"
+ " <rect x='12.5' y='12.5' width='75' height='30' stroke='#0F0' stroke-opacity='0.5' stroke-width='3' fill='#F00' fill-opacity='0.5' opacity='0.7' />"
+ " <rect x='30' y='30' width='20' height='20' stroke='orange' stroke-width='1' fill='violet'/>" + "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri("TestColormultiplelayer.svg"), data);
doc.generateAnImage(new Uri("TestColormultiplelayer.bmp"), ConfigTest.VISUAL_DEBUG);
}
@Test
public void testTestColorOpacity() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <rect x='12.5' y='12.5' width='75' height='50' stroke='#0F0' stroke-width='3' fill='#F00' opacity='0.5' />" + "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri("TestColoropacity.svg"), data);
doc.generateAnImage(new Uri("TestColoropacity.bmp"), ConfigTest.VISUAL_DEBUG);
}
}

View File

@ -0,0 +1,37 @@
package test.atriasoft.esvg;
import org.atriasoft.esvg.EsvgDocument;
import org.atriasoft.etk.Uri;
import org.junit.jupiter.api.Test;
class TestEllipse {
@Test
public void testTestEllipseFill() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" + " <ellipse cx='50' cy='50' rx='80' ry='30' fill='red' />" + "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri("TestEllipsefill.svg"), data);
doc.generateAnImage(new Uri("TestEllipsefill.bmp"), ConfigTest.VISUAL_DEBUG);
}
@Test
public void testTestEllipseFillAndStroke() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>"
+ " <ellipse cx='50' cy='50' rx='80' ry='30' stroke='green' stroke-width='3' fill='red' />" + "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri("TestEllipsefillandstroke.svg"), data);
doc.generateAnImage(new Uri("TestEllipsefillandstroke.bmp"), ConfigTest.VISUAL_DEBUG);
}
@Test
public void testTestEllipseStroke() {
String data = "<?xml version='1.0' encoding='UTF-8' standalone='no'?>" + "<svg height='100' width='100'>" + " <ellipse cx='50' cy='50' rx='80' ry='30' stroke='green' stroke-width='3' />"
+ "</svg>";
EsvgDocument doc = new EsvgDocument();
doc.parse(data);
Uri.writeAll(new Uri("TestEllipsestroke.svg"), data);
doc.generateAnImage(new Uri("TestEllipsestroke.bmp"), ConfigTest.VISUAL_DEBUG);
}
}

View File

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

View File

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

Some files were not shown because too many files have changed in this diff Show More