diff --git a/features/org.eclipse.elk.algorithms.feature/feature.xml b/features/org.eclipse.elk.algorithms.feature/feature.xml index 6a35894ebc..f02bc58ddc 100644 --- a/features/org.eclipse.elk.algorithms.feature/feature.xml +++ b/features/org.eclipse.elk.algorithms.feature/feature.xml @@ -101,5 +101,12 @@ SPDX-License-Identifier: EPL-2.0 install-size="0" version="0.0.0" unpack="false"/> + + diff --git a/plugins/org.eclipse.elk.alg.vertiflex/.classpath b/plugins/org.eclipse.elk.alg.vertiflex/.classpath new file mode 100644 index 0000000000..f0c5549859 --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/plugins/org.eclipse.elk.alg.vertiflex/.project b/plugins/org.eclipse.elk.alg.vertiflex/.project new file mode 100644 index 0000000000..bb53ae1b34 --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/.project @@ -0,0 +1,46 @@ + + + org.eclipse.elk.alg.vertiflex + + + + + + org.eclipse.xtext.ui.shared.xtextBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + net.sf.eclipsecs.core.CheckstyleBuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.m2e.core.maven2Nature + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + net.sf.eclipsecs.core.CheckstyleNature + org.eclipse.xtext.ui.shared.xtextNature + + diff --git a/plugins/org.eclipse.elk.alg.vertiflex/.settings/org.eclipse.jdt.core.prefs b/plugins/org.eclipse.elk.alg.vertiflex/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..5ed2aebf75 --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,297 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 +org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_assignment=16 +org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 +org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 +org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_field=0 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.format_block_comments=true +org.eclipse.jdt.core.formatter.comment.format_header=false +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true +org.eclipse.jdt.core.formatter.comment.format_line_comments=true +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true +org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert +org.eclipse.jdt.core.formatter.comment.line_length=120 +org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true +org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true +org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false +org.eclipse.jdt.core.formatter.compact_else_if=true +org.eclipse.jdt.core.formatter.continuation_indentation=2 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 +org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off +org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on +org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_empty_lines=false +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false +org.eclipse.jdt.core.formatter.indentation.size=4 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.join_lines_in_comments=true +org.eclipse.jdt.core.formatter.join_wrapped_lines=true +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false +org.eclipse.jdt.core.formatter.lineSplit=120 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.jdt.core.formatter.tabulation.char=space +org.eclipse.jdt.core.formatter.tabulation.size=4 +org.eclipse.jdt.core.formatter.use_on_off_tags=true +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true +org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true +org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter diff --git a/plugins/org.eclipse.elk.alg.vertiflex/.settings/org.eclipse.jdt.ui.prefs b/plugins/org.eclipse.elk.alg.vertiflex/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 0000000000..d529be02be --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +formatter_profile=_Elk +formatter_settings_version=12 +org.eclipse.jdt.ui.javadoc=true +org.eclipse.jdt.ui.text.custom_code_templates= diff --git a/plugins/org.eclipse.elk.alg.vertiflex/META-INF/MANIFEST.MF b/plugins/org.eclipse.elk.alg.vertiflex/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..492ffb38db --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/META-INF/MANIFEST.MF @@ -0,0 +1,14 @@ +Manifest-Version: 1.0 +Automatic-Module-Name: org.eclipse.elk.alg.vertiflex +Bundle-ManifestVersion: 2 +Bundle-Name: VertiFlex Tree Layout Algorithm +Bundle-SymbolicName: org.eclipse.elk.alg.vertiflex;singleton:=true +Bundle-Version: 0.10.0.qualifier +Bundle-Vendor: Eclipse Modeling Project +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Require-Bundle: com.google.guava, + org.eclipse.elk.alg.common, + org.eclipse.elk.core, + org.eclipse.elk.graph +Export-Package: org.eclipse.elk.alg.vertiflex, + org.eclipse.elk.alg.vertiflex.options diff --git a/plugins/org.eclipse.elk.alg.vertiflex/about.html b/plugins/org.eclipse.elk.alg.vertiflex/about.html new file mode 100644 index 0000000000..7a303200e8 --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/about.html @@ -0,0 +1,36 @@ + + + + +About + + +

About This Content

+ +

October 11, 2023

+

License

+ +

+ The Eclipse Foundation makes available all content in this plug-in + ("Content"). Unless otherwise indicated below, the Content + is provided to you under the terms and conditions of the Eclipse + Public License Version 2.0 ("EPL"). A copy of the EPL is + available at http://www.eclipse.org/legal/epl-2.0. + For purposes of the EPL, "Program" will mean the Content. +

+ +

+ If you did not receive this Content directly from the Eclipse + Foundation, the Content is being redistributed by another party + ("Redistributor") and different terms and conditions may + apply to your use of any object code in the Content. Check the + Redistributor's license that was provided with the Content. If no such + license exists, contact the Redistributor. Unless otherwise indicated + below, the terms and conditions of the EPL still apply to any source + code in the Content and such source code may be obtained at http://www.eclipse.org. +

+ + + diff --git a/plugins/org.eclipse.elk.alg.vertiflex/build.properties b/plugins/org.eclipse.elk.alg.vertiflex/build.properties new file mode 100644 index 0000000000..96e1399046 --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/build.properties @@ -0,0 +1,16 @@ +############################################################################### +# Copyright (c) 2023 Kiel University and others. +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0. +# +# SPDX-License-Identifier: EPL-2.0 +############################################################################### +source.. = src/,\ + src-gen/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + about.html +src.includes = about.html diff --git a/plugins/org.eclipse.elk.alg.vertiflex/pom.xml b/plugins/org.eclipse.elk.alg.vertiflex/pom.xml new file mode 100644 index 0000000000..7f65238f92 --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/pom.xml @@ -0,0 +1,49 @@ + + + + 4.0.0 + + org.eclipse.elk + parent + 0.10.0-SNAPSHOT + ../../build/pom.xml + + + org.eclipse.elk + org.eclipse.elk.alg.vertiflex + ELK Y Constraint Tree Layout Algorithm + 0.10.0-SNAPSHOT + Tree drawing algorithm with y-level constraints. + eclipse-plugin + + + + org.eclipse.elk + org.eclipse.elk.core + 0.10.0-SNAPSHOT + + + org.eclipse.elk + org.eclipse.elk.alg.common + 0.10.0-SNAPSHOT + + + + + + + + org.eclipse.xtext + xtext-maven-plugin + + + + diff --git a/plugins/org.eclipse.elk.alg.vertiflex/src/META-INF/services/org.eclipse.elk.core.data.ILayoutMetaDataProvider b/plugins/org.eclipse.elk.alg.vertiflex/src/META-INF/services/org.eclipse.elk.core.data.ILayoutMetaDataProvider new file mode 100644 index 0000000000..20f68e7073 --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/src/META-INF/services/org.eclipse.elk.core.data.ILayoutMetaDataProvider @@ -0,0 +1 @@ +org.eclipse.elk.alg.vertiflex.options.VertiFlexMetaDataProvider \ No newline at end of file diff --git a/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/EdgeRoutingStrategy.java b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/EdgeRoutingStrategy.java new file mode 100644 index 0000000000..c5b02ccc6e --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/EdgeRoutingStrategy.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2023 Kiel University and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.elk.alg.vertiflex; + +/** + * Strategies for routing edges in the tree layout. + * + */ +public enum EdgeRoutingStrategy { + + /** + * Straight lines between nodes. + */ + STRAIGHT, + + /** + * Allow one bend point in edges to enable more compact layouts while also maintaining the node model order. + */ + BEND + +} diff --git a/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/InternalProperties.java b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/InternalProperties.java new file mode 100644 index 0000000000..349ef309cc --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/InternalProperties.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2023 Kiel University and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.elk.alg.vertiflex; + +import org.eclipse.elk.alg.vertiflex.p2relative.OutlineNode; +import org.eclipse.elk.graph.ElkNode; +import org.eclipse.elk.graph.properties.IProperty; +import org.eclipse.elk.graph.properties.Property; + +/** + * The internal properties of the tree layouter. Properties that are used internally + * but do not need to be public are stored here. + * + */ +public final class InternalProperties { + + /** + * Private constructor to prevent initialization. + */ + private InternalProperties() { } + + /** + * Defines the left outline of this subtree. + */ + public static final IProperty LEFT_OUTLINE = new Property("LEFT_OUTLINE"); + + /** + * Defines the right outline of this subtree. + */ + public static final IProperty RIGHT_OUTLINE = new Property("RIGHT_OUTLINE"); + + /** + * Defines the maximum depth of outlines. This is the lowest point of the outline in the tree layout. + */ + public static final IProperty OUTLINE_MAX_DEPTH = new Property("OUTLINE_MAX_DEPTH"); + + /** Defines the canvas of the tree. */ + public static final IProperty MIN_X = new Property("MIN_X"); + + /** Defines the canvas of the tree. */ + public static final IProperty MAX_X = new Property("MAX_X"); + + /** Defines the canvas of the tree. */ + public static final IProperty MIN_Y = new Property("MIN_Y"); + + /** Defines the canvas of the tree. */ + public static final IProperty MAX_Y = new Property("MAX_Y"); + + /** The root node of the graph. */ + public static final IProperty ROOT_NODE = new Property("root"); + + /** + * Defines the bendpoint of an edge. + */ + public static final IProperty EDGE_BEND_HEIGHT = new Property("EDGE_BEND_HEIGHT"); + + /** + * Stores the model order of nodes. Smaller values come before larger values. + */ + public static final IProperty NODE_MODEL_ORDER = new Property("Node Model Order"); + +} diff --git a/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/VertiFlex.melk b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/VertiFlex.melk new file mode 100644 index 0000000000..89336435ff --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/VertiFlex.melk @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright (c) 2023 Kiel University and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.elk.alg.vertiflex + +import org.eclipse.elk.alg.vertiflex.EdgeRoutingStrategy +import org.eclipse.elk.alg.vertiflex.VertiFlexLayoutProvider +import org.eclipse.elk.core.math.ElkPadding + +/** + * Declarations for the ELK VertiFlex tree layout algorithm. + */ +bundle { + metadataClass options.VertiFlexMetaDataProvider + idPrefix org.eclipse.elk.vertiflex +} + +algorithm vertiflex(VertiFlexLayoutProvider) { + label "ELK VertiFlex" + description + "Tree layout algorithm that allows defining set vertical positions for nodes + rather than automatically placing nodes on levels according to their topology." + metadataClass options.VertiFlexOptions + category org.eclipse.elk.tree + features multi_edges, edge_labels + supports org.eclipse.elk.spacing.nodeNode = 20 + supports org.eclipse.elk.padding = new ElkPadding(5) + supports org.eclipse.elk.interactive + supports org.eclipse.elk.portConstraints + supports org.eclipse.elk.edgeLabels.inline = false + // Common node micro layout + supports org.eclipse.elk.omitNodeMicroLayout + supports org.eclipse.elk.margins + // Algorithm specific properties + supports verticalConstraint + supports layoutStrategy + supports layerDistance + supports considerNodeModelOrder + +} + +option verticalConstraint: double { + label "Fixed vertical position" + description + "The Y position that the node should be fixed at." + targets nodes +} + +option layoutStrategy: EdgeRoutingStrategy { + label "Edge layout strategy" + description + "Strategy for the layout of the children. 'straight' for straight line drawings, 'bend' for a possible bend. + When straight edges are prioritized the nodes will be reordered in order to guarantee that straight edges are + possible. If bend points are enabled on the other hand, the given model order of the nodes is maintained and + bend points are introduced to prevent edge node overlaps." + targets nodes + default = EdgeRoutingStrategy.STRAIGHT +} + +option layerDistance: double { + label "Layer distance" + description + "The distance to use between nodes of different layers if no vertical constraints are set." + targets parents + default = 50.0 +} + +option considerNodeModelOrder: boolean { + label "Consider node model order" + description + "Consider node model as a secondary criterion when using straight line routing." + targets parents + default = true +} diff --git a/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/VertiFlexLayoutPhases.java b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/VertiFlexLayoutPhases.java new file mode 100644 index 0000000000..0060d75501 --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/VertiFlexLayoutPhases.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2023 Kiel University and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.elk.alg.vertiflex; + +/** + * This algorithm's layout phases. Each phase has its own strategy factory. + */ +public enum VertiFlexLayoutPhases { + + /** Phase 1. Vertical placement of nodes.*/ + P1_NODE_Y_PLACEMENT, + + /** Phase 2. Horizontal placement of nodes.*/ + P2_NODE_RELATIVE_PLACEMENT, + + /** Phase 3. Computation of absolute coordinates.*/ + P3_NODE_ABSOLUTE_PLACEMENT, + + /** Phase 4. Edge routing.*/ + P4_EDGE_ROUTING; + +} \ No newline at end of file diff --git a/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/VertiFlexLayoutProvider.java b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/VertiFlexLayoutProvider.java new file mode 100644 index 0000000000..643a528f1b --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/VertiFlexLayoutProvider.java @@ -0,0 +1,178 @@ +/******************************************************************************* + * Copyright (c) 2023, 2024 Kiel University and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.elk.alg.vertiflex; + +import java.util.List; + +import org.eclipse.elk.alg.common.NodeMicroLayout; +import org.eclipse.elk.alg.vertiflex.options.VertiFlexOptions; +import org.eclipse.elk.alg.vertiflex.p1yplacement.NodeYPlacerStrategy; +import org.eclipse.elk.alg.vertiflex.p2relative.RelativeXPlacerStrategy; +import org.eclipse.elk.alg.vertiflex.p3absolute.AbsoluteXPlacerStrategy; +import org.eclipse.elk.alg.vertiflex.p4edgerouting.EdgerouterStrategy; +import org.eclipse.elk.core.AbstractLayoutProvider; +import org.eclipse.elk.core.UnsupportedConfigurationException; +import org.eclipse.elk.core.alg.AlgorithmAssembler; +import org.eclipse.elk.core.alg.ILayoutProcessor; +import org.eclipse.elk.core.math.ElkMargin; +import org.eclipse.elk.core.math.ElkPadding; +import org.eclipse.elk.core.options.CoreOptions; +import org.eclipse.elk.core.util.IElkProgressMonitor; +import org.eclipse.elk.graph.ElkEdge; +import org.eclipse.elk.graph.ElkNode; + +/** + * Layout provider for the y constraint tree layout algorithms. + */ +public final class VertiFlexLayoutProvider extends AbstractLayoutProvider { + + + private final AlgorithmAssembler algorithmAssembler = + AlgorithmAssembler.create(VertiFlexLayoutPhases.class); + + private double nodeNodeSpacing; + + @Override + public void layout(final ElkNode graph, final IElkProgressMonitor progressMonitor) { + List> algorithm = assembleAlgorithm(graph); + + progressMonitor.begin("Tree layout", algorithm.size()); + + nodeNodeSpacing = graph.getProperty(CoreOptions.SPACING_NODE_NODE); + + // if requested, compute nodes's dimensions, place node labels, ports, port labels, etc. + if (!graph.getProperty(VertiFlexOptions.OMIT_NODE_MICRO_LAYOUT)) { + NodeMicroLayout.forGraph(graph) + .execute(); + } + + // pre calculate the root node and save it + ElkNode root = VertiFlexUtil.findRoot(graph); + graph.setProperty(InternalProperties.ROOT_NODE, root); + if (root == null) { + throw new UnsupportedConfigurationException("The given graph is not a tree!"); + } + + for (ElkNode child : graph.getChildren()) { + int numberOfParents; + numberOfParents = child.getIncomingEdges().size(); + if (numberOfParents > 1) { + throw new UnsupportedConfigurationException("The given graph is not an acyclic tree!"); + } + + // reset position + child.setLocation(0, 0); + } + + // check that vertical constraints are ordered in valid manner i.e. children always have higher vertical + // constraints than their parents + checkVerticalConstraintValidity(root, 0); + + // store model order + int count = 0; + for (ElkNode node : graph.getChildren()) { + node.setProperty(InternalProperties.NODE_MODEL_ORDER, count); + count += 1; + } + + for (ILayoutProcessor processor : algorithm) { + processor.process(graph, progressMonitor.subTask(1)); + } + + setGraphSize(graph); + + progressMonitor.done(); + } + + /** + * Configure the layout provider by assembling different layout processors. + * + * @param graph The graph which shall be laid out. + * @return The list of assembled layout processors. + */ + public List> assembleAlgorithm(final ElkNode graph) { + algorithmAssembler.reset(); + + // Configure phases + algorithmAssembler.setPhase(VertiFlexLayoutPhases.P1_NODE_Y_PLACEMENT, + NodeYPlacerStrategy.SIMPLE_Y_PLACING); + algorithmAssembler.setPhase(VertiFlexLayoutPhases.P2_NODE_RELATIVE_PLACEMENT, + RelativeXPlacerStrategy.SIMPLE_X_PLACING); + algorithmAssembler.setPhase(VertiFlexLayoutPhases.P3_NODE_ABSOLUTE_PLACEMENT, + AbsoluteXPlacerStrategy.ABSOLUTE_XPLACING); + + EdgerouterStrategy routerStrategy; + switch (graph.getProperty(VertiFlexOptions.LAYOUT_STRATEGY)) { + case BEND: + routerStrategy = EdgerouterStrategy.BEND_ROUTING; + break; + case STRAIGHT: + default: + routerStrategy = EdgerouterStrategy.DIRECT_ROUTING; + break; + + } + algorithmAssembler.setPhase(VertiFlexLayoutPhases.P4_EDGE_ROUTING, routerStrategy); + + // Assemble the algorithm + return algorithmAssembler.build(graph); + } + + /** Checks whether a vertical constraint is larger than the constraints set by any ancestor nodes.*/ + private void checkVerticalConstraintValidity(final ElkNode root, final double currentMinConstraint) { + + double rootHeight; + if (root.hasProperty(VertiFlexOptions.VERTICAL_CONSTRAINT)) { + rootHeight = root.getProperty(VertiFlexOptions.VERTICAL_CONSTRAINT); + } else { + rootHeight = currentMinConstraint; + } + + double newMinConstraint = rootHeight + root.getHeight() + + Math.max(root.getProperty(CoreOptions.MARGINS).bottom, nodeNodeSpacing); + + for (ElkEdge outgoingEdge : root.getOutgoingEdges()) { + ElkNode child = (ElkNode) outgoingEdge.getTargets().get(0); + if (child.hasProperty(VertiFlexOptions.VERTICAL_CONSTRAINT)) { + if (newMinConstraint > child.getProperty(VertiFlexOptions.VERTICAL_CONSTRAINT) + + child.getProperty(CoreOptions.MARGINS).top) { + throw new UnsupportedConfigurationException("Invalid vertical constraints. Node " + + child.getIdentifier() + " has a vertical constraint that is too low for its ancestors."); + } + } + } + for (ElkEdge outgoingEdge : root.getOutgoingEdges()) { + ElkNode child = (ElkNode) outgoingEdge.getTargets().get(0); + checkVerticalConstraintValidity(child, newMinConstraint); + } + } + + /** Computes the space occupied by the layout and sets the graph size accordingly. */ + private void setGraphSize(final ElkNode graph) { + ElkPadding padding = graph.getProperty(CoreOptions.PADDING); + + double maxX = 0.0; + double maxY = 0.0; + for (ElkNode node : graph.getChildren()) { + ElkMargin margin = node.getProperty(CoreOptions.MARGINS); + + if (maxX < node.getX() + node.getWidth() + margin.right) { + maxX = node.getX() + node.getWidth() + margin.right; + } + if (maxY < node.getY() + node.getHeight() + margin.bottom) { + maxY = node.getY() + node.getHeight() + margin.bottom; + } + } + + graph.setWidth(maxX + padding.right); + graph.setHeight(maxY + padding.bottom); + } + +} diff --git a/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/VertiFlexUtil.java b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/VertiFlexUtil.java new file mode 100644 index 0000000000..4b48909be7 --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/VertiFlexUtil.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2023 Kiel University and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.elk.alg.vertiflex; + +import org.eclipse.elk.graph.ElkEdge; +import org.eclipse.elk.graph.ElkNode; +import org.eclipse.elk.graph.util.ElkGraphUtil; + +/** A class for smaller, independent calculation units. */ +public final class VertiFlexUtil { + + /** + * Private constructor to prevent initialization. + */ + private VertiFlexUtil() { } + + /** + * Computes the root node of a graph. + * @param graph + * @return Root node of graph. + */ + public static ElkNode findRoot(final ElkNode graph) { + for (ElkNode child : graph.getChildren()) { + Iterable incomingEdges = ElkGraphUtil.allIncomingEdges(child); + if (!incomingEdges.iterator().hasNext()) { + return child; + } + } + return null; + } +} diff --git a/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p1yplacement/NodeYPlacer.java b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p1yplacement/NodeYPlacer.java new file mode 100644 index 0000000000..d0a4ce8842 --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p1yplacement/NodeYPlacer.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2023 Kiel University and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.elk.alg.vertiflex.p1yplacement; + +import org.eclipse.elk.alg.vertiflex.InternalProperties; +import org.eclipse.elk.alg.vertiflex.VertiFlexLayoutPhases; +import org.eclipse.elk.alg.vertiflex.options.VertiFlexOptions; +import org.eclipse.elk.core.alg.ILayoutPhase; +import org.eclipse.elk.core.alg.LayoutProcessorConfiguration; +import org.eclipse.elk.core.options.CoreOptions; +import org.eclipse.elk.core.util.IElkProgressMonitor; +import org.eclipse.elk.graph.ElkNode; + +/** + * Node placer to position nodes vertically. Nodes that have a vertical constraint are placed according to that + * constraint and other nodes are positioned automatically according to their position in the tree. + * + */ +public class NodeYPlacer implements ILayoutPhase { + + private double layerDistance; + private double nodeNodeSpacing; + + @Override + public void process(final ElkNode graph, final IElkProgressMonitor progressMonitor) { + + progressMonitor.begin("YPlacer", 1); + + layerDistance = graph.getProperty(VertiFlexOptions.LAYER_DISTANCE); + nodeNodeSpacing = graph.getProperty(CoreOptions.SPACING_NODE_NODE); + + if (!graph.getChildren().isEmpty()) { + ElkNode parent = graph.getProperty(InternalProperties.ROOT_NODE); + setYLevels(parent, 0.0); + } + + progressMonitor.done(); + } + + /** + * A Method to set the absolute Y coordinates of the nodes. + * Uses a default distance between the nodes. + * @param node and it's children are getting updated Y-coords. + * @param minHeight: Node gets minimum this height. + */ + private void setYLevels(final ElkNode node, double minHeight) { + if (node.hasProperty(VertiFlexOptions.VERTICAL_CONSTRAINT)) { + minHeight = node.getProperty(VertiFlexOptions.VERTICAL_CONSTRAINT); + } + node.setY(minHeight); + double newMinHeight = minHeight + layerDistance + node.getHeight() + + Math.max(node.getProperty(CoreOptions.MARGINS).bottom, nodeNodeSpacing); + for (int i = 0; i < node.getOutgoingEdges().size(); i++) { + ElkNode child = (ElkNode) node.getOutgoingEdges().get(i).getTargets().get(0); + setYLevels(child, newMinHeight); + } + } + + @Override + public LayoutProcessorConfiguration + getLayoutProcessorConfiguration(final ElkNode graph) { + return null; + } + +} diff --git a/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p1yplacement/NodeYPlacerStrategy.java b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p1yplacement/NodeYPlacerStrategy.java new file mode 100644 index 0000000000..0386907623 --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p1yplacement/NodeYPlacerStrategy.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2023 Kiel University and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.elk.alg.vertiflex.p1yplacement; + +import org.eclipse.elk.alg.vertiflex.VertiFlexLayoutPhases; +import org.eclipse.elk.core.alg.ILayoutPhase; +import org.eclipse.elk.core.alg.ILayoutPhaseFactory; +import org.eclipse.elk.graph.ElkNode; + +/** + * Vertical node placement strategies. + * + */ +public enum NodeYPlacerStrategy implements ILayoutPhaseFactory { + + /** + * Simple strategy for setting y coordinates of nodes. Vertical constraints are considered and if none are defined + * the fallback is to compute a position based on the node's location in the tree. + */ + SIMPLE_Y_PLACING; + + @Override + public ILayoutPhase create() { + switch (this) { + case SIMPLE_Y_PLACING: + return new NodeYPlacer(); + + default: + throw new IllegalArgumentException( + "No implementation is available for the node placer " + this.toString()); + } + } + +} \ No newline at end of file diff --git a/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p2relative/NodeComparator.java b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p2relative/NodeComparator.java new file mode 100644 index 0000000000..72f804c65a --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p2relative/NodeComparator.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2023 Kiel University and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.elk.alg.vertiflex.p2relative; + +import org.eclipse.elk.alg.vertiflex.InternalProperties; +import org.eclipse.elk.graph.ElkNode; + +/** + * Comparator for sorting ElkNodes according to their y positions and model order. + * + */ +class NodeComparator implements java.util.Comparator { + + private boolean invert = false; + + /** Default constructor */ + public NodeComparator() {} + + /** Constructor for inverted comparator. */ + public NodeComparator(boolean invert) { + this.invert = invert; + } + + @Override + public int compare(final ElkNode a, final ElkNode b) { + + int sortYresult; + if (!invert) { + sortYresult = Double.compare(a.getY(), b.getY()); + } else { + sortYresult = Double.compare(b.getY(), a.getY()); + } + if (sortYresult == 0) { + int intSortresult = Integer.compare(a.getProperty(InternalProperties.NODE_MODEL_ORDER), + b.getProperty(InternalProperties.NODE_MODEL_ORDER)); + return intSortresult; + } else { + return sortYresult; + } + } +} diff --git a/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p2relative/OutlineNode.java b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p2relative/OutlineNode.java new file mode 100644 index 0000000000..1403dcdb1c --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p2relative/OutlineNode.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (c) 2023 Kiel University and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.elk.alg.vertiflex.p2relative; + +/** + * An outline node is the basic building block of an outline. + * Outline nodes define the points on which the outline lies. + * Each outline node has a position and a reference to the next outline node. + * + */ +public class OutlineNode { + + /** X coordinates are maintained as relative coordinates with respect to their ancestors. */ + private double relativeX; + /** Y coordinates are maintained as absolute coordinates that stem from the given vertical constraints. */ + private double absoluteY; + private OutlineNode next; + + public OutlineNode(final double relativeX, final double absoluteY, final OutlineNode next){ + this.setRelativeX(relativeX); + this.setAbsoluteY(absoluteY); + this.setNext(next); + } + + /** + * @return the absoluteY + */ + public double getAbsoluteY() { + return absoluteY; + } + + /** + * @param absoluteY the absoluteY to set + */ + public void setAbsoluteY(final double absoluteY) { + this.absoluteY = absoluteY; + } + + /** + * @return the relativeX + */ + public double getRelativeX() { + return relativeX; + } + + /** + * @param relativeX the relativeX to set + */ + public void setRelativeX(final double relativeX) { + this.relativeX = relativeX; + } + + /** + * @return the next + */ + public OutlineNode getNext() { + return next; + } + + /** + * @param next the next to set + */ + public void setNext(final OutlineNode next) { + this.next = next; + } + + /** + * @return a string representation of this objects relative coordinates + */ + public String toString() { + return "X:" + relativeX + ", Y:" + absoluteY; + } + + /** + * + * @return if this OutlineNode has no "next" + */ + public boolean isLast() { + return next == null; + } + + /** + * Print a full outline. + */ + public void printFullOutline() { + System.out.println(this.toString()); + if (!this.isLast()) { + this.getNext().printFullOutline(); + } + } +} diff --git a/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p2relative/RelativeXPlacer.java b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p2relative/RelativeXPlacer.java new file mode 100644 index 0000000000..eb4bdffc74 --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p2relative/RelativeXPlacer.java @@ -0,0 +1,670 @@ +/******************************************************************************* + * Copyright (c) 2023 Kiel University and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.elk.alg.vertiflex.p2relative; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.elk.alg.vertiflex.InternalProperties; +import org.eclipse.elk.alg.vertiflex.VertiFlexLayoutPhases; +import org.eclipse.elk.alg.vertiflex.options.VertiFlexOptions; +import org.eclipse.elk.core.alg.ILayoutPhase; +import org.eclipse.elk.core.alg.LayoutProcessorConfiguration; +import org.eclipse.elk.core.math.ElkMargin; +import org.eclipse.elk.core.options.CoreOptions; +import org.eclipse.elk.core.util.IElkProgressMonitor; +import org.eclipse.elk.core.util.Pair; +import org.eclipse.elk.graph.ElkNode; + +/** + * Node placer that positions nodes horizontally using coordinates that are relative to parent nodes. + * + */ +public class RelativeXPlacer implements ILayoutPhase { + + private double spacingNodeNode; + private boolean considerNodeModelOrder; + + // a constant for moving every Outline to a minimal y-pos + private static final double MINIMAL_Y = -100.0; + + @Override + public void process(final ElkNode graph, final IElkProgressMonitor progressMonitor) { + + progressMonitor.begin("XPlacer", 1); + + spacingNodeNode = graph.getProperty(CoreOptions.SPACING_NODE_NODE); + considerNodeModelOrder = graph.getProperty(VertiFlexOptions.CONSIDER_NODE_MODEL_ORDER); + + if (!graph.getChildren().isEmpty()) { + ElkNode parent = graph.getProperty(InternalProperties.ROOT_NODE); + + switch (graph.getProperty(VertiFlexOptions.LAYOUT_STRATEGY)) { + case STRAIGHT: + recursiveStraightlinePlacement(parent); + break; + case BEND: + recursiveBentlinePlacement(parent); + break; + default: + break; + } + } + + progressMonitor.done(); + } + + /** Computes the distance between two outlines. */ + private double outlineDistance(final OutlineNode outline1, final OutlineNode outline2) { + + OutlineNode changedOutline1 = new OutlineNode(outline1.getRelativeX(), MINIMAL_Y, + new OutlineNode(0.0, outline1.getAbsoluteY(), outline1.getNext())); + OutlineNode changedOutline2 = new OutlineNode(outline2.getRelativeX(), MINIMAL_Y, + new OutlineNode(0.0, outline2.getAbsoluteY(), outline2.getNext())); + + // the return value + double dist = changedOutline1.getRelativeX() - changedOutline2.getRelativeX(); + + OutlineNode o1; + OutlineNode o2; + double x1; + double x2; + double deltaX, deltaY; + double newdist; + + + // first run (compare points of o1 with o2) + o1 = changedOutline1; + o2 = changedOutline2; + x1 = o1.getRelativeX(); + x2 = o2.getRelativeX(); + while (o1 != null && !o2.isLast()) { + if (o2.getNext().getAbsoluteY() > o1.getAbsoluteY()) { + // now we compare + deltaX = o2.getNext().getRelativeX(); + deltaY = o2.getNext().getAbsoluteY() - o2.getAbsoluteY(); + newdist = x1 - x2 - ((o1.getAbsoluteY() - o2.getAbsoluteY()) * deltaX) / deltaY; + + dist = Math.max(dist, newdist); + + // now change o1 + o1 = o1.getNext(); + if (o1 != null) { + x1 += o1.getRelativeX(); + } + } else { + o2 = o2.getNext(); + x2 += o2.getRelativeX(); + } + } + + // second run (compare points of o2 with o1) + o1 = changedOutline1; + o2 = changedOutline2; + x1 = o1.getRelativeX(); + x2 = o2.getRelativeX(); + while (o2 != null && !o1.isLast()) { + if (o1.getNext().getAbsoluteY() > o2.getAbsoluteY()) { + // now we compare + deltaX = o1.getNext().getRelativeX(); + deltaY = o1.getNext().getAbsoluteY() - o1.getAbsoluteY(); + newdist = x1 - x2 + ((o2.getAbsoluteY() - o1.getAbsoluteY()) * deltaX) / deltaY; + + dist = Math.max(dist, newdist); + + // now change o2 + o2 = o2.getNext(); + if (o2 != null) { + x2 += o2.getRelativeX(); + } + } else { + o1 = o1.getNext(); + x1 += o1.getRelativeX(); + } + + } + + return dist; + } + + /** + * This is the recursive function that calculates the layout for one node and it's children. + * Children are placed such that straight edges can later be drawn from their parent to each of them. + * + * If ConsiderModelOrder is set to false, all children are arranged in a semi-circle with the parent + * initially positioned above the lowest child and then shifted toward the center of the children as + * far as possible. + * + * If ConsiderModelOrder is set to true, groups of children are arranged such that they maintain their + * inherent model order. Furthermore, the reading direction is oriented left to right and top to bottom + * as far as possible without violating the vertical position constraints and the straight edge routing + * requirement. + */ + private void recursiveStraightlinePlacement(final ElkNode graph) { + + makeSimpleOutlines(graph); + + if (!graph.getOutgoingEdges().isEmpty()) { + + // get all children + List children = new ArrayList<>(); + for (int i = 0; i < graph.getOutgoingEdges().size(); i++) { + ElkNode child = (ElkNode) graph.getOutgoingEdges().get(i).getTargets().get(0); + recursiveStraightlinePlacement(child); + children.add(child); + } + // now the children of this node get sorted to form a semi-circle. This allows routing straight edges + // without overlaps while keeping the layout relatively compact. + sortSubTrees(children); + + // now the children get stuffed together, using the outlines. + for (int i = 0; i < children.size() - 1; i++) { + bundleChildren(children.get(0), children.get(i), children.get(i + 1)); + } + + // now we need to move the root to the middle of the nodes. + // we calculate the point of the child with the lowest y-position to avoid overlapping. + // if there is more than one lowest child, the root will be positioned in the middle of them. + int pos = 0; + double maxDepth = 0.0; + int maxDepthStartPos = 0; + while (pos < children.size() && children.get(pos).getY() >= maxDepth) { + if (children.get(pos).getY() > maxDepth) { + maxDepthStartPos = pos; + maxDepth = children.get(pos).getY(); + } + pos += 1; + } + double moveRoot = 0.0; + if (pos > 0) { + moveRoot = (children.get(maxDepthStartPos).getX() + children.get(pos - 1).getX()) / 2.0 + - graph.getX(); + } + + if (!graph.getProperty(VertiFlexOptions.CONSIDER_NODE_MODEL_ORDER)) { + double betterMoveRoot = (children.get(0).getX() + children.get(children.size() - 1).getX() + + children.get(children.size() - 1).getWidth() - graph.getWidth()) / 2.0 - graph.getX(); + double newMoveRoot; + + if (betterMoveRoot < moveRoot) { + OutlineNode rightOutline; + double rightOutlineX, posX; + for (int i = 0; i < maxDepthStartPos; i++) { + for (int j = i + 1; j < maxDepthStartPos + 1; j++) { + rightOutline = children.get(i).getProperty(InternalProperties.RIGHT_OUTLINE); + rightOutlineX = children.get(i).getX() + rightOutline.getRelativeX(); + posX = children.get(j).getX() + children.get(j).getWidth() / 2.0; + while (rightOutline != null && rightOutline.getAbsoluteY() < maxDepth) { + + newMoveRoot = posX - graph.getWidth() / 2.0 + (posX - rightOutlineX) * ((graph.getY() + + graph.getHeight()) - maxDepth) / (maxDepth - rightOutline.getAbsoluteY()); + betterMoveRoot = Math.max(betterMoveRoot, newMoveRoot); + + rightOutline = rightOutline.getNext(); + if (rightOutline != null) { + rightOutlineX += rightOutline.getRelativeX(); + } + } + } + } + moveRoot = betterMoveRoot; + } + + if (betterMoveRoot > moveRoot) { + OutlineNode leftOutline; + double leftOutlineX, posX; + for (int i = pos; i < children.size(); i++) { + for (int j = pos - 1; j < i; j++) { + leftOutline = children.get(i).getProperty(InternalProperties.LEFT_OUTLINE); + leftOutlineX = children.get(i).getX() + leftOutline.getRelativeX(); + posX = children.get(j).getX() + children.get(j).getWidth() / 2.0; + while (leftOutline != null && leftOutline.getAbsoluteY() < maxDepth) { + + newMoveRoot = posX - graph.getWidth() / 2.0 + (posX - leftOutlineX) * ((graph.getY() + + graph.getHeight()) - maxDepth) / (maxDepth - leftOutline.getAbsoluteY()); + betterMoveRoot = Math.min(betterMoveRoot, newMoveRoot); + + leftOutline = leftOutline.getNext(); + if (leftOutline != null) { + leftOutlineX += leftOutline.getRelativeX(); + } + } + } + } + moveRoot = betterMoveRoot; + } + } + + for (ElkNode child: children) { + child.setX(child.getX() - moveRoot); + } + + + double newX; + // left outline update + OutlineNode graphLeftOutline = graph.getProperty(InternalProperties.LEFT_OUTLINE); + OutlineNode leftChildOutline = children.get(0).getProperty(InternalProperties.LEFT_OUTLINE); + + newX = children.get(0).getX() + leftChildOutline.getRelativeX() - graphLeftOutline.getRelativeX(); + graphLeftOutline.getNext().getNext().getNext().setNext( + new OutlineNode(newX, leftChildOutline.getAbsoluteY(), leftChildOutline.getNext())); + + // right outline update + OutlineNode graphRightOutline = graph.getProperty(InternalProperties.RIGHT_OUTLINE); + OutlineNode rightChildOutline = children.get(children.size() - 1) + .getProperty(InternalProperties.RIGHT_OUTLINE); + + newX = children.get(children.size() - 1).getX() + + rightChildOutline.getRelativeX() - graphRightOutline.getRelativeX(); + graphRightOutline.getNext().getNext().getNext().setNext( + new OutlineNode(newX, rightChildOutline.getAbsoluteY(), rightChildOutline.getNext())); + + // update outlineMaxY + // update min und max for x and y + for (ElkNode child: children) { + graph.setProperty(InternalProperties.OUTLINE_MAX_DEPTH, Math.max(graph.getProperty(InternalProperties. + OUTLINE_MAX_DEPTH), child.getProperty(InternalProperties.OUTLINE_MAX_DEPTH))); + graph.setProperty(InternalProperties.MIN_X, Math.min(graph.getProperty(InternalProperties.MIN_X), + child.getX() + child.getProperty(InternalProperties.MIN_X))); + graph.setProperty(InternalProperties.MAX_X, Math.max(graph.getProperty(InternalProperties.MAX_X), + child.getX() + child.getProperty(InternalProperties.MAX_X))); + } + graph.setProperty(InternalProperties.MAX_Y, graph.getProperty(InternalProperties.OUTLINE_MAX_DEPTH)); + + } + } + + /** + * Place nodes while maintaining model order and computing bendpoints for the later edges. + * The model order is fully kept intact and bendpoints for the edges are computed so that + * overlap free edge routing is still possible. + */ + private void recursiveBentlinePlacement(final ElkNode graph) { + + // set up initial outlines for all nodes + makeSimpleOutlines(graph); + + // termination condition for the recursion, while a node has children continue + if (!graph.getOutgoingEdges().isEmpty()) { + + // get all children + List children = new ArrayList<>(); + for (int i = 0; i < graph.getOutgoingEdges().size(); i++) { + ElkNode child = (ElkNode) graph.getOutgoingEdges().get(i).getTargets().get(0); + recursiveBentlinePlacement(child); + children.add(child); + } + + int childrenSize = children.size(); + + + // now the children get stuffed together, using the outlines. + for (int i = 0; i < children.size() - 1; i++) { + bundleChildren(children.get(0), children.get(i), children.get(i + 1)); + } + + double moveRoot = (children.get(0).getX() + children.get(0).getWidth() / 2.0 + + children.get(children.size() - 1).getX() + children.get(children.size() - 1).getWidth() / 2.0 + - graph.getWidth()) / 2.0 - graph.getX(); + + for (ElkNode child: children) { + child.setX(child.getX() - moveRoot); + child.setProperty(InternalProperties.EDGE_BEND_HEIGHT, + child.getProperty(InternalProperties.LEFT_OUTLINE).getAbsoluteY()); + } + + // set bendHeights for children right of the parent + int i = 0; + while (i < childrenSize - 1 && children.get(i).getX() + children.get(i).getWidth() + + children.get(i).getProperty(CoreOptions.MARGINS).right - graph.getWidth() / 2.0 <= 0.0) { + i++; + } + + double globalBendHeight = children.get(i).getProperty(InternalProperties.EDGE_BEND_HEIGHT); + for (int a = 0; a < childrenSize; a++) { + if (globalBendHeight < children.get(a).getProperty(InternalProperties.EDGE_BEND_HEIGHT)) { + children.get(a).setProperty(InternalProperties.EDGE_BEND_HEIGHT, globalBendHeight); + } else { + globalBendHeight = children.get(a).getProperty(InternalProperties.EDGE_BEND_HEIGHT); + } + } + + // set bendHeights for children left of the parent + i = childrenSize - 1; + while (i > 0 && children.get(i).getX() - children.get(i).getProperty(CoreOptions.MARGINS).left + - graph.getWidth() / 2.0 >= 0.0) { + i--; + } + + if (i < childrenSize) { + for (int a = i; a >= 0; a--) { + + if (globalBendHeight < children.get(a).getProperty(InternalProperties.EDGE_BEND_HEIGHT)) { + children.get(a).setProperty(InternalProperties.EDGE_BEND_HEIGHT, globalBendHeight); + } else { + globalBendHeight = children.get(a).getProperty(InternalProperties.EDGE_BEND_HEIGHT); + } + } + } + + double newX; + OutlineNode newOutlinepart; + // left outline update + OutlineNode leftChildOutline = children.get(0).getProperty(InternalProperties.LEFT_OUTLINE); + OutlineNode graphLeftOutline = graph.getProperty(InternalProperties.LEFT_OUTLINE); + + newX = children.get(0).getX() + leftChildOutline.getRelativeX() + - graphLeftOutline.getRelativeX(); + newOutlinepart = new OutlineNode(0.0, leftChildOutline + .getAbsoluteY(), leftChildOutline.getNext()); + graphLeftOutline.getNext().getNext().getNext() + .setNext(new OutlineNode(newX, children.get(0).getProperty(InternalProperties.EDGE_BEND_HEIGHT), + newOutlinepart)); + + // right outline update + OutlineNode graphRightOutline = graph.getProperty(InternalProperties.RIGHT_OUTLINE); + OutlineNode rightChildOutline = children.get(childrenSize - 1).getProperty(InternalProperties.RIGHT_OUTLINE); + + newX = children.get(childrenSize - 1).getX() + rightChildOutline.getRelativeX() - graphRightOutline.getRelativeX(); + newOutlinepart = new OutlineNode(0.0, rightChildOutline.getAbsoluteY(), rightChildOutline.getNext()); + graphRightOutline.getNext().getNext().getNext().setNext( + new OutlineNode( + newX, children.get(childrenSize - 1).getProperty(InternalProperties.EDGE_BEND_HEIGHT), newOutlinepart + )); + + // update outlineMaxY + // update min und max for x and y + for (ElkNode child: children) { + graph.setProperty(InternalProperties.OUTLINE_MAX_DEPTH, Math.max(graph.getProperty(InternalProperties + .OUTLINE_MAX_DEPTH), child.getProperty(InternalProperties.OUTLINE_MAX_DEPTH))); + graph.setProperty(InternalProperties.MIN_X, Math.min(graph.getProperty(InternalProperties.MIN_X), + child.getX() + child.getProperty(InternalProperties.MIN_X))); + graph.setProperty(InternalProperties.MAX_X, Math.max(graph.getProperty(InternalProperties.MAX_X), + child.getX() + child.getProperty(InternalProperties.MAX_X))); + } + graph.setProperty(InternalProperties.MAX_Y, graph.getProperty(InternalProperties.OUTLINE_MAX_DEPTH)); + + } + + } + + /** Sorts the subTrees in a semi-circle. */ + private void sortSubTrees(final List children) { + + // first, we sort the SubTrees by the Y-coordinate of their root. + Collections.sort(children, new NodeComparator(false)); + + List a = new ArrayList<>(); + List b = new ArrayList<>(); + + if (considerNodeModelOrder) { + splitNodesWithModelOrder(children, a, b); + } else { + // now we need to put them in a V-shape + // the deepest element gets ignored in the calculation of the widths. + a.add(children.get(children.size() - 1)); + double widthA = 0.0, widthB = 0.0; + for (int i = 1; i < children.size(); i++) { + if (widthA <= widthB) { + a.add(children.get(children.size() - 1 - i)); + widthA += children.get(children.size() - 1 - i).getWidth(); + } else { + b.add(children.get(children.size() - 1 - i)); + widthB += children.get(children.size() - 1 - i).getWidth(); + } + } + Collections.reverse(a); + } + + Collections.sort(b, new NodeComparator(true)); + a.addAll(b); + for (int i = 0; i < children.size(); i++) { + children.set(i, a.get(i)); + } + + } + + /** Split nodes into two lists, while maintaining a sensible model order for nodes on the same height. */ + private void splitNodesWithModelOrder(List original, List left, List right) { + // identify next subgroup (all at same y) + //split group in it in the weighted middle (always add first half to left group, and second half to right group) + if (original.size() == 0) { + return; + } + if (original.size() == 1) { + left.add(original.get(0)); + } + if (original.size() == 2) { + // use model order to decide which node to put into which list regardless what the height ordering says + ElkNode first = original.get(0); + ElkNode second = original.get(1); + + if (first.getProperty(InternalProperties.NODE_MODEL_ORDER) + > second.getProperty(InternalProperties.NODE_MODEL_ORDER)) { + left.add(second); + right.add(first); + } else { + left.add(first); + right.add(second); + } + } + + List currentGroup = new ArrayList<>(); + Pair widthLeftRight = new Pair<>(); + widthLeftRight.setFirst(0.0); + widthLeftRight.setSecond(0.0); + ElkNode current = original.get(0); + currentGroup.add(current); + for (int i = 1; i < original.size(); i++) { + ElkNode next = original.get(i); + if (Double.compare(current.getY(), next.getY()) == 0) { + // add next node to group because it has the same height as the previous element + currentGroup.add(next); + } else { + // split and add entire group + int finalIndexOfLeft = splitGroup(currentGroup, widthLeftRight); + left.addAll(currentGroup.subList(0, finalIndexOfLeft + 1)); + right.addAll(currentGroup.subList(finalIndexOfLeft + 1, currentGroup.size())); + + // reset group + currentGroup = new ArrayList<>(); + currentGroup.add(next); + } + current = next; + + // if next element is last element split and add the current group now + if (i == original.size() - 1) { + int finalIndexOfLeft = splitGroup(currentGroup, widthLeftRight); + left.addAll(currentGroup.subList(0, finalIndexOfLeft + 1)); + right.addAll(currentGroup.subList(finalIndexOfLeft + 1, currentGroup.size())); + } + } + } + + /** Find a sensible splitting point to divide elements into a left and right list according to a given width of both + * lists. + * @param group the group to be split + * @param widthLeftRight the current widths of the left and right lists + * @return the index position at which to split the group + */ + private int splitGroup(List group, Pair widthLeftRight) { + if (group.size() == 1) { + return 0; + } else { + double widthLeft = widthLeftRight.getFirst(); + double widthRight = widthLeftRight.getSecond(); + + double totalNewWidth = 0; + for (ElkNode node : group) { + totalNewWidth += node.getWidth(); + } + + // linear equations to find desired widths to fill both lists so that they reach equal length + // I: a + x = b + y + // II: x + y = t + // where a and b are widthLeft and widthRight, x and y are the desired additions to left and right + // and t is the totalNewWidth + // solution: x = (t-a+b)/2, y = t - (t-a+b)/2 + + double desiredLeft = (totalNewWidth - widthLeft + widthRight) / 2; +// double desiredRight = totalNewWidth - desiredLeft; + + // add nodes to left side until desiredLeft is exceeded + // remove last element and compare both solutions, take the one which is closer to the desired solution + int i = 0; + double newLeftWidth = 0; + while (desiredLeft < newLeftWidth && i < group.size()) { + newLeftWidth += group.get(i).getWidth(); + } + + double exceed = newLeftWidth - desiredLeft; + double under = desiredLeft - (newLeftWidth - group.get(i).getWidth()); + + int resultIndex; + if (exceed > under) { + resultIndex = i; + } else { + resultIndex = i - 1; + } + + // add new widths to accumulated widths + widthLeftRight.setFirst(widthLeft + exceed); + double newRightWidth = 0; + for (int j = resultIndex + 1; j < group.size(); j++) { + newRightWidth += group.get(j).getWidth(); + } + widthLeftRight.setSecond(widthRight + newRightWidth); + + return resultIndex; + } + } + + /** Create the initial outlines around a node. */ + private void makeSimpleOutlines(final ElkNode graph) { + ElkMargin margins = graph.getProperty(CoreOptions.MARGINS); + + // set the properties for left and right outlines + OutlineNode endpart; + endpart = new OutlineNode(0.0, graph.getY() + graph.getHeight() + margins.bottom + spacingNodeNode / 2, + new OutlineNode(graph.getWidth() / 2.0, + graph.getY() + graph.getHeight() + margins.bottom + spacingNodeNode / 2, null)); + + graph.setProperty(InternalProperties.LEFT_OUTLINE, new OutlineNode((-margins.left - spacingNodeNode / 2) + + graph.getWidth() / 2.0, graph.getY() - margins.top - spacingNodeNode / 2, + new OutlineNode(-graph.getWidth() / 2.0, graph.getY() - margins.top, endpart))); + + endpart = new OutlineNode(0.0, graph.getY() + graph.getHeight() + margins.bottom, + new OutlineNode(-graph.getWidth() / 2.0, + graph.getY() + graph.getHeight() + margins.bottom + spacingNodeNode / 2, null)); + + graph.setProperty(InternalProperties.RIGHT_OUTLINE, new OutlineNode(graph.getWidth() / 2.0 + + margins.right + spacingNodeNode / 2, graph.getY() - margins.top, + new OutlineNode(graph.getWidth() / 2.0, graph.getY() - margins.top - spacingNodeNode / 2, endpart))); + + // set min and max values + graph.setProperty(InternalProperties.MIN_X, graph.getX() - margins.left); + graph.setProperty(InternalProperties.MAX_X, + graph.getX() + margins.right + graph.getWidth()); + graph.setProperty(InternalProperties.MIN_Y, graph.getY() - margins.top); + graph.setProperty(InternalProperties.MAX_Y, + graph.getY() + margins.bottom + graph.getHeight()); + graph.setProperty(InternalProperties.OUTLINE_MAX_DEPTH, graph.getProperty(InternalProperties.LEFT_OUTLINE) + .getNext().getNext().getAbsoluteY()); + + } + + /** + * Combines the individual outlines of several sibling nodes to form the outline of the tree that they belong to. + */ + private void bundleChildren(final ElkNode leftSubtree, final ElkNode a, final ElkNode b) { + + double deltaX, deltaY, change; + + // calculate distance between the two parts + double dist = outlineDistance(a.getProperty(InternalProperties.RIGHT_OUTLINE), + b.getProperty(InternalProperties.LEFT_OUTLINE)); + b.setX(a.getX() + dist); + + // enhance the left outline + if (leftSubtree.getProperty(InternalProperties.OUTLINE_MAX_DEPTH) + < b.getProperty(InternalProperties.OUTLINE_MAX_DEPTH)) { + OutlineNode lastL = leftSubtree.getProperty(InternalProperties.LEFT_OUTLINE); + double lAbsX = lastL.getRelativeX() + leftSubtree.getX(); + + // move to the end of leftSubtree + while (!lastL.isLast()) { + lastL = lastL.getNext(); + lAbsX += lastL.getRelativeX(); + } + // find fitting position in the left outline of b + OutlineNode bItterator = new OutlineNode(b.getProperty(InternalProperties.LEFT_OUTLINE).getRelativeX(), + MINIMAL_Y, b.getProperty(InternalProperties.LEFT_OUTLINE).getNext()); + double rAbsX = bItterator.getRelativeX() + b.getX(); + while (bItterator.getNext().getAbsoluteY() <= lastL.getAbsoluteY()) { + bItterator = bItterator.getNext(); + rAbsX += bItterator.getRelativeX(); + } + // now we calculate the change + deltaX = bItterator.getNext().getRelativeX(); + deltaY = bItterator.getNext().getAbsoluteY() - bItterator.getAbsoluteY(); + change = ((lastL.getAbsoluteY() - bItterator.getAbsoluteY()) * deltaX) / deltaY; + + // now we calculate the new points + double newX = -lAbsX + rAbsX + change; + OutlineNode newNext = new OutlineNode(bItterator.getNext().getRelativeX() - change, bItterator.getNext() + .getAbsoluteY(), bItterator.getNext().getNext()); + lastL.setNext(new OutlineNode(newX, lastL.getAbsoluteY(), newNext)); + + // now update outline_max_depth + leftSubtree.setProperty(InternalProperties.OUTLINE_MAX_DEPTH, + b.getProperty(InternalProperties.OUTLINE_MAX_DEPTH)); + } + + // enhance the right outline + if (b.getProperty(InternalProperties.OUTLINE_MAX_DEPTH) < a.getProperty(InternalProperties.OUTLINE_MAX_DEPTH)) { + OutlineNode lastB = b.getProperty(InternalProperties.RIGHT_OUTLINE); + double rAbsX = lastB.getRelativeX() + b.getX(); + + // move to the end of b + while (!lastB.isLast()) { + lastB = lastB.getNext(); + rAbsX += lastB.getRelativeX(); + } + // find fitting position in the right outline of a + OutlineNode aItterator = new OutlineNode(a.getProperty(InternalProperties.RIGHT_OUTLINE).getRelativeX(), + MINIMAL_Y, a.getProperty(InternalProperties.RIGHT_OUTLINE).getNext()); + double aAbsX = aItterator.getRelativeX() + a.getX(); + while (aItterator.getNext().getAbsoluteY() <= lastB.getAbsoluteY()) { + aItterator = aItterator.getNext(); + aAbsX += aItterator.getRelativeX(); + } + // now we calculate the change + deltaX = aItterator.getNext().getRelativeX(); + deltaY = aItterator.getNext().getAbsoluteY() - aItterator.getAbsoluteY(); + change = ((lastB.getAbsoluteY() - aItterator.getAbsoluteY()) * deltaX) / deltaY; + + // now we calculate the new points + double newX = aAbsX - rAbsX + change; + OutlineNode newNext = new OutlineNode(aItterator.getNext().getRelativeX() - change, + aItterator.getNext().getAbsoluteY(), aItterator.getNext().getNext()); + lastB.setNext(new OutlineNode(newX, lastB.getAbsoluteY(), newNext)); + // now update outline_max_depth + b.setProperty(InternalProperties.OUTLINE_MAX_DEPTH, a.getProperty(InternalProperties.OUTLINE_MAX_DEPTH)); + } + } + + @Override + public LayoutProcessorConfiguration + getLayoutProcessorConfiguration(final ElkNode graph) { + return null; + } + +} diff --git a/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p2relative/RelativeXPlacerStrategy.java b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p2relative/RelativeXPlacerStrategy.java new file mode 100644 index 0000000000..20d0bb2276 --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p2relative/RelativeXPlacerStrategy.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2023 Kiel University and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.elk.alg.vertiflex.p2relative; + +import org.eclipse.elk.alg.vertiflex.VertiFlexLayoutPhases; +import org.eclipse.elk.core.alg.ILayoutPhase; +import org.eclipse.elk.core.alg.ILayoutPhaseFactory; +import org.eclipse.elk.graph.ElkNode; + +/** + * Horizontal node placement strategies. + * + */ +public enum RelativeXPlacerStrategy implements ILayoutPhaseFactory { + + /** + * Simple strategy for setting the horizontal positions of nodes. These positions are relative to their parents + * and chosen such that overlaps are avoided. + */ + SIMPLE_X_PLACING; + + @Override + public ILayoutPhase create() { + switch (this) { + case SIMPLE_X_PLACING: + return new RelativeXPlacer(); + + default: + throw new IllegalArgumentException( + "No implementation is available for the node placer " + this.toString()); + } + } + +} \ No newline at end of file diff --git a/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p3absolute/AbsoluteXPlacer.java b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p3absolute/AbsoluteXPlacer.java new file mode 100644 index 0000000000..a80eacdfcf --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p3absolute/AbsoluteXPlacer.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2023 Kiel University and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.elk.alg.vertiflex.p3absolute; + +import org.eclipse.elk.alg.vertiflex.InternalProperties; +import org.eclipse.elk.alg.vertiflex.VertiFlexLayoutPhases; +import org.eclipse.elk.core.alg.ILayoutPhase; +import org.eclipse.elk.core.alg.LayoutProcessorConfiguration; +import org.eclipse.elk.core.util.IElkProgressMonitor; +import org.eclipse.elk.graph.ElkNode; + +/** + * Computes absolute x coordinates from the previously computed relative coordinates. + * + */ +public class AbsoluteXPlacer implements ILayoutPhase { + + @Override + public void process(final ElkNode graph, final IElkProgressMonitor progressMonitor) { + progressMonitor.begin("AbsolutPlacer", 1); + + if (!graph.getChildren().isEmpty()) { + ElkNode parent = graph.getProperty(InternalProperties.ROOT_NODE); + + // first, move the root + parent.setX(parent.getX() - findMinimalX(parent)); + // now we update the whole tree to absolute X + absoluteTreeCoords(parent); + } + + progressMonitor.done(); + } + + /** Find leftmost subtree. */ + private double findMinimalX(final ElkNode tree) { + int numOfChildren = tree.getOutgoingEdges().size(); + if (numOfChildren == 0) { + return tree.getX(); + } else { + double minSubtreeX = 0.0; + double testX = 0.0; + for (int i = 0; i < numOfChildren; i++) { + testX = findMinimalX((ElkNode) tree.getOutgoingEdges().get(i).getTargets().get(0)); + minSubtreeX = (testX < minSubtreeX) ? testX : minSubtreeX; + } + return minSubtreeX + tree.getX(); + } + } + + private void absoluteTreeCoords(final ElkNode tree) { + int numOfChildren = tree.getOutgoingEdges().size(); + if (numOfChildren > 0) { + ElkNode child; + for (int i = 0; i < numOfChildren; i++) { + child = (ElkNode) tree.getOutgoingEdges().get(i).getTargets().get(0); + child.setX(child.getX() + tree.getX()); + absoluteTreeCoords(child); + } + } + } + + + @Override + public LayoutProcessorConfiguration getLayoutProcessorConfiguration( + final ElkNode graph) { + return null; + } + +} diff --git a/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p3absolute/AbsoluteXPlacerStrategy.java b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p3absolute/AbsoluteXPlacerStrategy.java new file mode 100644 index 0000000000..a837274387 --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p3absolute/AbsoluteXPlacerStrategy.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2023 Kiel University and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.elk.alg.vertiflex.p3absolute; + +import org.eclipse.elk.alg.vertiflex.VertiFlexLayoutPhases; +import org.eclipse.elk.core.alg.ILayoutPhase; +import org.eclipse.elk.core.alg.ILayoutPhaseFactory; +import org.eclipse.elk.graph.ElkNode; + +/** + * Strategies for absolute node placement. + * + */ +public enum AbsoluteXPlacerStrategy implements ILayoutPhaseFactory { + + /** + * Compute absolute x-coordinates based on relative coordinates + */ + ABSOLUTE_XPLACING; + + @Override + public ILayoutPhase create() { + switch (this) { + case ABSOLUTE_XPLACING: + return new AbsoluteXPlacer(); + + default: + throw new IllegalArgumentException( + "No implementation is available for the node placer " + this.toString()); + } + } + +} \ No newline at end of file diff --git a/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p4edgerouting/BendEdgeRouter.java b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p4edgerouting/BendEdgeRouter.java new file mode 100644 index 0000000000..2083e4900f --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p4edgerouting/BendEdgeRouter.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2023 Kiel University and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.elk.alg.vertiflex.p4edgerouting; + +import org.eclipse.elk.alg.vertiflex.InternalProperties; +import org.eclipse.elk.alg.vertiflex.VertiFlexLayoutPhases; +import org.eclipse.elk.core.alg.ILayoutPhase; +import org.eclipse.elk.core.alg.LayoutProcessorConfiguration; +import org.eclipse.elk.core.options.CoreOptions; +import org.eclipse.elk.core.util.IElkProgressMonitor; +import org.eclipse.elk.graph.ElkEdge; +import org.eclipse.elk.graph.ElkEdgeSection; +import org.eclipse.elk.graph.ElkNode; +import org.eclipse.elk.graph.util.ElkGraphUtil; + +/** + * Implements edge routing that includes bendpoints when straight edges would cross nodes. + * + */ +public class BendEdgeRouter implements ILayoutPhase { + + @Override + public void process(final ElkNode graph, final IElkProgressMonitor progressMonitor) { + + progressMonitor.begin("BendEdgeRouter", 1); + + if (!graph.getChildren().isEmpty()) { + ElkNode parent = graph.getProperty(InternalProperties.ROOT_NODE); + + routeEdges(parent); + } + + progressMonitor.done(); + + } + + @Override + public LayoutProcessorConfiguration getLayoutProcessorConfiguration( + final ElkNode graph) { + return null; + } + + /** Route the edges with bendpoints. */ + private void routeEdges(final ElkNode node) { + for (ElkEdge edge : ElkGraphUtil.allOutgoingEdges(node)) { + ElkNode target = ElkGraphUtil.connectableShapeToNode(edge.getTargets().get(0)); + ElkEdgeSection section = ElkGraphUtil.firstEdgeSection(edge, true, true); + + + double startX = node.getX() + node.getWidth() / 2; + double startY = node.getY() + node.getHeight(); + double endX = target.getX() + target.getWidth() / 2; + double endY = target.getY(); + + section.setStartLocation(startX, startY); + section.setEndLocation(endX, endY); + + double bendheight = target.getProperty(InternalProperties.EDGE_BEND_HEIGHT); + double epsilon = 0.0001; + // if the node is low place a bendpoint above it + if (Math.abs(bendheight + - (endY - target.getParent().getProperty(CoreOptions.SPACING_NODE_NODE) / 2)) > epsilon) { + ElkGraphUtil.createBendPoint(section, endX, bendheight); + } + routeEdges(target); + } + } + +} diff --git a/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p4edgerouting/EdgerouterStrategy.java b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p4edgerouting/EdgerouterStrategy.java new file mode 100644 index 0000000000..c275d14d0d --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p4edgerouting/EdgerouterStrategy.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2023 Kiel University and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.elk.alg.vertiflex.p4edgerouting; + +import org.eclipse.elk.alg.vertiflex.VertiFlexLayoutPhases; +import org.eclipse.elk.core.alg.ILayoutPhase; +import org.eclipse.elk.core.alg.ILayoutPhaseFactory; +import org.eclipse.elk.graph.ElkNode; + +/** + * Edge routing strategies. + * + */ +public enum EdgerouterStrategy implements ILayoutPhaseFactory { + + /** + * Straight edge routing. + */ + DIRECT_ROUTING, + /** + * Routing with bendpoints if nodes are in the way. + */ + BEND_ROUTING; + + @Override + public ILayoutPhase create() { + switch (this) { + case DIRECT_ROUTING: + return new StraightEdgeRouter(); + case BEND_ROUTING: + return new BendEdgeRouter(); + default: + throw new IllegalArgumentException( + "No implementation is available for the edge router " + this.toString()); + } + } + +} \ No newline at end of file diff --git a/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p4edgerouting/StraightEdgeRouter.java b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p4edgerouting/StraightEdgeRouter.java new file mode 100644 index 0000000000..4187b4b64e --- /dev/null +++ b/plugins/org.eclipse.elk.alg.vertiflex/src/org/eclipse/elk/alg/vertiflex/p4edgerouting/StraightEdgeRouter.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2023 Kiel University and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.elk.alg.vertiflex.p4edgerouting; + +import org.eclipse.elk.alg.vertiflex.InternalProperties; +import org.eclipse.elk.alg.vertiflex.VertiFlexLayoutPhases; +import org.eclipse.elk.core.alg.ILayoutPhase; +import org.eclipse.elk.core.alg.LayoutProcessorConfiguration; +import org.eclipse.elk.core.util.IElkProgressMonitor; +import org.eclipse.elk.graph.ElkEdge; +import org.eclipse.elk.graph.ElkEdgeSection; +import org.eclipse.elk.graph.ElkNode; +import org.eclipse.elk.graph.util.ElkGraphUtil; + +/** + * An edge router that draws straight edges between nodes. + * + */ +public class StraightEdgeRouter implements ILayoutPhase { + + private IElkProgressMonitor myProgressMonitor; + + + @Override + public void process(final ElkNode graph, final IElkProgressMonitor progressMonitor) { + myProgressMonitor = progressMonitor; + myProgressMonitor.begin("StraightEdgeRouter", 1); + + if (!graph.getChildren().isEmpty()) { + ElkNode parent = graph.getProperty(InternalProperties.ROOT_NODE); + + routeEdges(parent); + } + + myProgressMonitor.done(); + } + + @Override + public LayoutProcessorConfiguration getLayoutProcessorConfiguration( + final ElkNode graph) { + return null; + } + + + /** Route the edges with with straight edges. */ + private void routeEdges(final ElkNode node) { + for (ElkEdge edge : ElkGraphUtil.allOutgoingEdges(node)) { + ElkNode target = ElkGraphUtil.connectableShapeToNode(edge.getTargets().get(0)); + ElkEdgeSection section = ElkGraphUtil.firstEdgeSection(edge, true, true); + + + double startX = node.getX() + node.getWidth() / 2; + double startY = node.getY() + node.getHeight(); + double endX = target.getX() + target.getWidth() / 2; + double endY = target.getY(); + + section.setStartLocation(startX, startY); + section.setEndLocation(endX, endY); + routeEdges(target); + } + } +} diff --git a/plugins/pom.xml b/plugins/pom.xml index 2dd26f55bb..30b228ddc7 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -37,6 +37,7 @@ org.eclipse.elk.alg.rectpacking org.eclipse.elk.alg.spore org.eclipse.elk.alg.topdownpacking + org.eclipse.elk.alg.vertiflex org.eclipse.elk.conn.gmf org.eclipse.elk.core org.eclipse.elk.core.debug diff --git a/test/org.eclipse.elk.alg.test/META-INF/MANIFEST.MF b/test/org.eclipse.elk.alg.test/META-INF/MANIFEST.MF index f8ca795720..a26fe56c2f 100644 --- a/test/org.eclipse.elk.alg.test/META-INF/MANIFEST.MF +++ b/test/org.eclipse.elk.alg.test/META-INF/MANIFEST.MF @@ -17,6 +17,7 @@ Require-Bundle: com.google.guava, org.eclipse.elk.alg.radial, org.eclipse.elk.alg.rectpacking, org.eclipse.elk.alg.spore, + org.eclipse.elk.alg.vertiflex, org.junit;bundle-version="4.12.0", org.eclipse.swt;bundle-version="3.107.0", org.eclipse.xtext;bundle-version="2.12.0", diff --git a/test/org.eclipse.elk.alg.test/src/org/eclipse/elk/alg/test/PlainJavaInitialization.java b/test/org.eclipse.elk.alg.test/src/org/eclipse/elk/alg/test/PlainJavaInitialization.java index 92c1b3f4b8..87b8e648c9 100644 --- a/test/org.eclipse.elk.alg.test/src/org/eclipse/elk/alg/test/PlainJavaInitialization.java +++ b/test/org.eclipse.elk.alg.test/src/org/eclipse/elk/alg/test/PlainJavaInitialization.java @@ -17,6 +17,7 @@ import org.eclipse.elk.alg.radial.options.RadialMetaDataProvider; import org.eclipse.elk.alg.rectpacking.options.RectPackingMetaDataProvider; import org.eclipse.elk.alg.spore.options.SporeMetaDataProvider; +import org.eclipse.elk.alg.vertiflex.options.VertiFlexMetaDataProvider; import org.eclipse.elk.core.data.ILayoutMetaDataProvider; import org.eclipse.elk.core.data.LayoutMetaDataService; import org.eclipse.elk.core.debug.grandom.GRandomStandaloneSetup; @@ -42,7 +43,8 @@ public final class PlainJavaInitialization { new RadialMetaDataProvider(), new RectPackingMetaDataProvider(), new SporeMetaDataProvider(), - new StressMetaDataProvider() + new StressMetaDataProvider(), + new VertiFlexMetaDataProvider() }; /**