ea 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +128 -1
- data/Rakefile +3 -0
- data/TODO.complete/01-t-xref-parsing.md +91 -0
- data/TODO.complete/02-per-label-geometry.md +50 -0
- data/TODO.complete/03-object-properties-constraints.md +57 -0
- data/TODO.complete/04-operation-params.md +37 -0
- data/TODO.complete/05-pdata-flag-matrix.md +52 -0
- data/TODO.complete/06-emf-image-rendering.md +34 -0
- data/TODO.complete/07-auxiliary-tables.md +47 -0
- data/TODO.complete/10-mdg-stereotype-registry.md +40 -0
- data/TODO.complete/11-gml-xsd-generation.md +42 -0
- data/TODO.complete/13-shapescript-interpreter.md +28 -0
- data/TODO.complete/20-cli-diff.md +46 -0
- data/TODO.complete/21-cli-render.md +26 -0
- data/TODO.complete/22-cli-export.md +29 -0
- data/TODO.complete/23-cli-mdg.md +23 -0
- data/TODO.complete/30-headerlines-ocp-refactor.md +72 -0
- data/TODO.complete/31-public-send-cleanup.md +61 -0
- data/TODO.complete/32-spec-coverage.md +33 -0
- data/TODO.complete/33-blocked-parity-gaps.md +41 -0
- data/TODO.complete/36-stereotype-icon-wiring.md +32 -0
- data/TODO.complete/37-cli-lint.md +32 -0
- data/TODO.complete/38-cli-query.md +26 -0
- data/TODO.complete/39-cli-info.md +23 -0
- data/TODO.complete/40-ocl-evaluator.md +31 -0
- data/TODO.complete/41-round-trip-spec.md +18 -0
- data/TODO.complete/42-html-diff-report.md +18 -0
- data/TODO.complete/43-json-schema-export.md +20 -0
- data/TODO.complete/44-remaining-qea-tables.md +40 -0
- data/TODO.complete/45-shapescript-extensions.md +25 -0
- data/TODO.complete/46-xsd-consolidation.md +20 -0
- data/TODO.complete/47-headerlines-legacy-removal.md +20 -0
- data/TODO.complete/51-remove-respond-to.md +25 -0
- data/TODO.complete/52-xsd-decouple-fixtures.md +23 -0
- data/TODO.complete/53-xmi-public-send-cleanup.md +26 -0
- data/TODO.complete/54-wire-stereotype-icon-renderer.md +20 -0
- data/TODO.complete/55-wire-shapescript.md +20 -0
- data/TODO.complete/56-wire-emf-renderer.md +27 -0
- data/TODO.complete/57-wire-ocl-evaluator.md +23 -0
- data/TODO.complete/58-diff-modifications.md +21 -0
- data/TODO.complete/59-delete-toy-xmi-export.md +30 -0
- data/TODO.complete/60-curate-json-export.md +20 -0
- data/TODO.complete/61-plantuml-relationships.md +22 -0
- data/TODO.complete/62-changelog.md +17 -0
- data/TODO.complete/63-dependabot-fix.md +18 -0
- data/TODO.complete/STATUS.md +85 -0
- data/TODO.diagrams/01-svg-measurement-harness.md +31 -0
- data/TODO.diagrams/02-polygon-over-rendering.md +29 -0
- data/TODO.diagrams/03-text-over-rendering.md +30 -0
- data/TODO.diagrams/04-rect-under-rendering.md +33 -0
- data/TODO.diagrams/05-canvas-dimension-parity.md +51 -0
- data/TODO.diagrams/06-group-layering-parity.md +39 -0
- data/TODO.diagrams/07-text-content-fidelity.md +65 -0
- data/TODO.diagrams/08-qea-direct-pipeline.md +46 -0
- data/TODO.diagrams/12-connector-labels.md +40 -0
- data/TODO.diagrams/12-per-entity-svg-layer-ordering.md +24 -0
- data/TODO.diagrams/13-marker-polygon-vs-path-dispatch.md +20 -0
- data/TODO.diagrams/13-per-text-type-font-sizes.md +33 -0
- data/TODO.diagrams/14-center-header-text.md +33 -0
- data/TODO.diagrams/14-filter-diagram-frame-elements.md +18 -0
- data/TODO.diagrams/15-deep-dead-code-audit.md +47 -0
- data/TODO.diagrams/15-per-element-font-from-style.md +24 -0
- data/TODO.diagrams/16-canvas-marker-extent.md +30 -0
- data/TODO.diagrams/16-document-remaining-parity-gaps.md +91 -0
- data/TODO.diagrams/17-italic-abstract-classes.md +28 -0
- data/TODO.diagrams/17-remaining-parity-gaps.md +90 -0
- data/TODO.diagrams/18-canvas-from-image-bounds.md +20 -0
- data/TODO.diagrams/18-property-lookup-index.md +42 -0
- data/TODO.diagrams/19-connector-sx-sy-routing.md +27 -0
- data/TODO.diagrams/19-replace-respond-to-with-is-a.md +31 -0
- data/TODO.diagrams/20-split-labels-emitter.md +56 -0
- data/TODO.diagrams/20-visibility-glyph-font-encoding.md +27 -0
- data/TODO.diagrams/21-aggregation-navigability-arrow.md +21 -0
- data/TODO.diagrams/21-auto-generated-legend-block.md +65 -0
- data/TODO.diagrams/22-ghost-element-discriminator.md +57 -0
- data/TODO.diagrams/22-style-based-path-grouping.md +28 -0
- data/TODO.diagrams/23-marker-polygon-deduplication.md +47 -0
- data/TODO.diagrams/23-multiplicity-label-positioning.md +29 -0
- data/TODO.diagrams/24-marker-anchor-structural.md +35 -0
- data/TODO.diagrams/24-track-marker-anchors-structurally.md +66 -0
- data/TODO.diagrams/24-truncate-properties-to-fit-box.md +24 -0
- data/TODO.diagrams/26-phantom-general-parent-rendering.md +59 -0
- data/TODO.diagrams/27-path-grouping-mode-detection.md +43 -0
- data/TODO.diagrams/28-architecture-cleanup-batch.md +47 -0
- data/TODO.diagrams/30-decompose-elements-groups-for.md +52 -0
- data/TODO.diagrams/32-examples-coverage-batch.md +78 -0
- data/TODO.diagrams/36-instance-specification-model.md +42 -0
- data/TODO.diagrams/37-element-icon-decorations.md +41 -0
- data/TODO.diagrams/38-html-note-and-receptions.md +32 -0
- data/TODO.diagrams/39-property-stereotype-discriminator.md +40 -0
- data/TODO.diagrams/40-standalone-1-discriminator.md +38 -0
- data/TODO.diagrams/41-xmi-to-svg-pipeline.md +113 -0
- data/TODO.diagrams/42-close-all-parity-deltas.md +69 -0
- data/TODO.diagrams/43-marker-deduplication-strategy.md +54 -0
- data/TODO.diagrams/44-element-icon-decorations.md +34 -0
- data/TODO.diagrams/45-phantom-parent-class-boxes.md +40 -0
- data/TODO.diagrams/46-user-drawn-legend-swatches.md +44 -0
- data/TODO.diagrams/47-attribute-line-fidelity.md +72 -0
- data/TODO.diagrams/48-spec-coverage-critical-emitter-components.md +45 -0
- data/TODO.diagrams/49-spec-coverage-orchestrators.md +25 -0
- data/TODO.diagrams/50-examples-parity.md +85 -0
- data/TODO.diagrams/51-property-oy-gap-and-remaining-gaps.md +48 -0
- data/TODO.diagrams/52-marker-registration-architecture.md +89 -0
- data/TODO.diagrams/53-remaining-example-gaps.md +86 -0
- data/TODO.diagrams/54-display-name-nested-classes.md +40 -0
- data/TODO.diagrams/55-visibility-icon-discriminator.md +58 -0
- data/TODO.diagrams/56-package-contents-rendering.md +148 -0
- data/TODO.diagrams/57-instance-specification-model.md +100 -0
- data/TODO.diagrams/58-domain-model-note-text.md +67 -0
- data/TODO.diagrams/59-classes-arrow-discriminator.md +57 -0
- data/TODO.diagrams/60-testschema-association-marker.md +40 -0
- data/TODO.diagrams/61-legend-block-rendering.md +55 -0
- data/TODO.diagrams/61-plateau-parity-gaps.md +59 -0
- data/TODO.diagrams/62-ghost-element-rendering.md +56 -0
- data/TODO.diagrams/63-qualified-name-wrap.md +36 -0
- data/TODO.diagrams/64-property-stereotype-labels.md +22 -0
- data/TODO.diagrams/65-path-coordinate-frame.md +62 -0
- data/TODO.diagrams/67-path-coordinate-frame.md +62 -0
- data/TODO.diagrams/68-inherited-attributes.md +65 -0
- data/TODO.diagrams/69-package-anchor-conditional.md +29 -0
- data/TODO.diagrams/70-mdg-technology-support.md +68 -0
- data/TODO.diagrams/71-off-canvas-parent-ghost.md +45 -0
- data/TODO.diagrams/72-basic-attr-divider-paths.md +39 -0
- data/TODO.diagrams/73-plateau-polygon-gap.md +69 -0
- data/TODO.diagrams/74-plateau-rect-gap.md +22 -0
- data/TODO.diagrams/75-plateau-text-gap.md +39 -0
- data/TODO.diagrams/76-basic-poly-path-gaps.md +41 -0
- data/TODO.diagrams/77-basic-text-overrender.md +40 -0
- data/TODO.diagrams/78-headerlines-ocp-refactor.md +65 -0
- data/TODO.diagrams/79-architecture-backlog.md +65 -0
- data/TODO.diagrams/80-basic-triangle-polygons.md +51 -0
- data/TODO.diagrams/81-plateau-path-overrender.md +53 -0
- data/TODO.diagrams/82-appearance-canvas-offset.md +54 -0
- data/TODO.diagrams/83-3d-diagram-subtitle.md +58 -0
- data/TODO.diagrams/84-canvas-offset-mismatches.md +61 -0
- data/TODO.diagrams/85-phantom-property-overrender.md +95 -0
- data/TODO.diagrams/86-foreign-package-rule.md +62 -0
- data/TODO.diagrams/87-internal-tech-encryption.md +80 -0
- data/TODO.diagrams/EXAMPLES_STATUS.md +88 -0
- data/TODO.diagrams/README.md +69 -0
- data/TODO.diagrams/STATUS.md +73 -0
- data/TODO.fixup/01-default-grouped-paths.md +34 -0
- data/TODO.fixup/02-marker-consolidation-per-connector.md +20 -0
- data/TODO.fixup/03-diagram-font-inference.md +28 -0
- data/TODO.fixup/04-extract-bounds-calculator.md +25 -0
- data/TODO.fixup/05-marker-registry-ocp.md +32 -0
- data/TODO.fixup/06-connector-path-bend-routing.md +28 -0
- data/TODO.fixup/07-edge-attachment-formula.md +22 -0
- data/TODO.fixup/08-visual-diff-harness.md +28 -0
- data/TODO.fixup/09-extract-element-compartments.md +34 -0
- data/TODO.fixup/10-canvas-width-overshoot-fix.md +20 -0
- data/TODO.fixup/11-layer-sequencer-extraction.md +18 -0
- data/TODO.fixup/12-path-style-harmony.md +23 -0
- data/TODO.fixup/13-datatype-stereotype-fallback.md +28 -0
- data/TODO.fixup/14-ea-exe-reverse-engineering-notes.md +56 -0
- data/TODO.fixup/15-enumeration-literal-rendering.md +30 -0
- data/TODO.fixup/16-operation-compartment-rendering.md +42 -0
- data/TODO.fixup/17-path-count-calibration.md +27 -0
- data/TODO.fixup/18-polygon-count-calibration.md +32 -0
- data/TODO.fixup/19-rect-count-undershoot-investigation.md +40 -0
- data/TODO.fixup/20-stereotype-color-from-classifier.md +18 -0
- data/TODO.fixup/21-visibility-filter-for-properties.md +24 -0
- data/TODO.fixup/22-multiplicity-display-rule-calibration.md +25 -0
- data/TODO.fixup/23-diagram-frame-title-element.md +31 -0
- data/TODO.fixup/24-note-element-rendering.md +23 -0
- data/TODO.fixup/25-ea-exe-disassembly-findings.md +177 -0
- data/TODO.fixup/26-svg-renderer-architecture.md +78 -0
- data/TODO.fixup/27-svg-element-emitters-disassembly.md +135 -0
- data/TODO.fixup/28-geometry-parser-identification.md +57 -0
- data/TODO.fixup/29-qea-svg-xmi-triple-comparison.md +185 -0
- data/TODO.fixup/30-theme-system-stub.md +46 -0
- data/TODO.fixup/31-theme-value-object-registry.md +17 -0
- data/TODO.fixup/32-styleex-on-diagram-model.md +22 -0
- data/TODO.fixup/33-text-encoding-decimals-rotation.md +29 -0
- data/TODO.fixup/34-per-type-fill-via-theme.md +18 -0
- data/TODO.fixup/35-stroke-width-per-theme.md +7 -0
- data/TODO.fixup/36-qea-rect-coord-normalization.md +24 -0
- data/TODO.fixup/37-package-shape-rendering.md +22 -0
- data/TODO.fixup/38-note-element-rendering.md +15 -0
- data/TODO.fixup/39-styleex-flag-honoring.md +25 -0
- data/TODO.fixup/40-connector-dashed-lines.md +15 -0
- data/TODO.fixup/41-diagram-frame-showborder-detection.md +23 -0
- data/TODO.fixup/42-textrenderer-centralization.md +10 -0
- data/TODO.fixup/43-colorresolver-unification.md +24 -0
- data/TODO.fixup/44-theme-aware-textrenderer.md +17 -0
- data/TODO.fixup/45-theme-aware-fontresolver.md +22 -0
- data/TODO.fixup/46-style-parameterized-by-theme.md +21 -0
- data/TODO.fixup/47-canvas-frame-inset.md +19 -0
- data/TODO.fixup/48-background-rect-format.md +15 -0
- data/TODO.fixup/49-all-samples-integration-test.md +17 -0
- data/TODO.fixup/50-svg-emitter-architecture-docs.md +33 -0
- data/TODO.fixup/51-promote-theme-to-ea-namespace.md +28 -0
- data/TODO.fixup/52-theme-definition-integrated-fills.md +26 -0
- data/TODO.fixup/53-theme-registry-yaml-loading.md +50 -0
- data/TODO.fixup/54-diagram-theme-api.md +50 -0
- data/TODO.fixup/55-update-eaemitter-to-ea-theme.md +23 -0
- data/TODO.fixup/56-theme-yaml-files.md +65 -0
- data/TODO.fixup/57-theme-specs-and-integration.md +27 -0
- data/TODO.fixup/58-ea-entry-point-theme-autoload.md +20 -0
- data/TODO.fixup/59-thread-theme-through-all-renderers.md +29 -0
- data/TODO.fixup/60-cli-theme-option.md +22 -0
- data/TODO.fixup/61-theme-validation.md +28 -0
- data/TODO.fixup/62-theme-builder-dsl.md +31 -0
- data/TODO.fixup/63-theme-integration-rendering-spec.md +24 -0
- data/TODO.fixup/64-theme-writeback-styleex.md +21 -0
- data/TODO.fixup/65-remove-dead-eaemitter-theme-files.md +30 -0
- data/TODO.fixup/66-styleex-writeback.md +22 -0
- data/TODO.fixup/67-delete-dead-code.md +28 -0
- data/TODO.fixup/68-figure-parity-status.md +82 -0
- data/TODO.fixup/69-package-polygon-rendering.md +54 -0
- data/TODO.fixup/70-tagged-values-compartment.md +39 -0
- data/TODO.fixup/71-auto-detect-theme-from-xmi.md +37 -0
- data/TODO.fixup/72-sample-exports-as-regression-specs.md +37 -0
- data/TODO.fixup/73-delete-dead-transformations.md +14 -0
- data/TODO.fixup/74-delete-dead-diagram-renderers.md +18 -0
- data/TODO.fixup/75-visibility-legend-icons.md +23 -0
- data/TODO.fixup/76-plateau-text-undershoot.md +27 -0
- data/TODO.fixup/77-canvas-frame-margins.md +28 -0
- data/TODO.fixup/78-note-element-rendering.md +30 -0
- data/TODO.fixup/79-operation-compartment-rendering.md +27 -0
- data/TODO.fixup/80-tagged-value-stereotype-visibility.md +37 -0
- data/TODO.fixup/81-figure-parity-current-state.md +63 -0
- data/config/qea_schema.yml +356 -0
- data/config/themes/119.yml +98 -0
- data/config/themes/default.yml +14 -0
- data/examples/exports/20251010_current_plateau_v5/UML_EA.DTD +6856 -0
- data/examples/exports/20251010_current_plateau_v5/model.xml +96709 -0
- data/examples/exports/ArcGISWorkspace_template/UML_EA.DTD +6856 -0
- data/examples/exports/ArcGISWorkspace_template/model.xml +1427 -0
- data/examples/exports/UmlModel_template/UML_EA.DTD +6856 -0
- data/examples/exports/UmlModel_template/model.xml +23 -0
- data/examples/exports/basic/UML_EA.DTD +6856 -0
- data/examples/exports/basic/model.xml +8039 -0
- data/examples/exports/simple/UML_EA.DTD +6856 -0
- data/examples/exports/simple/model.xml +585 -0
- data/examples/exports/simple_example/UML_EA.DTD +6856 -0
- data/examples/exports/simple_example/model.xml +23 -0
- data/examples/exports/test/UML_EA.DTD +6856 -0
- data/examples/exports/test/model.xml +1638 -0
- data/examples/qea/basic.qea +0 -0
- data/frontend/README.md +51 -0
- data/frontend/dist/app.iife.js +24 -0
- data/frontend/dist/style.css +1 -0
- data/frontend/index.html +26 -0
- data/frontend/package-lock.json +2359 -0
- data/frontend/package.json +26 -0
- data/frontend/src/App.vue +59 -0
- data/frontend/src/app.ts +8 -0
- data/frontend/src/components/AppHeader.vue +127 -0
- data/frontend/src/components/AppSidebar.vue +119 -0
- data/frontend/src/components/ClassDetails.vue +247 -0
- data/frontend/src/components/DiagramView.vue +79 -0
- data/frontend/src/components/PackageDetails.vue +92 -0
- data/frontend/src/components/PackageTreeNode.vue +64 -0
- data/frontend/src/components/SearchResults.vue +48 -0
- data/frontend/src/components/WelcomeView.vue +87 -0
- data/frontend/src/shims-vue.d.ts +5 -0
- data/frontend/src/stores/dataStore.ts +79 -0
- data/frontend/src/stores/uiStore.ts +167 -0
- data/frontend/src/styles/main.css +1566 -0
- data/frontend/src/types.ts +221 -0
- data/frontend/tests/e2e/__screenshots__/new-dark-mode.png +0 -0
- data/frontend/tests/e2e/__screenshots__/new-package-details.png +0 -0
- data/frontend/tests/e2e/__screenshots__/new-search-modal.png +0 -0
- data/frontend/tests/e2e/__screenshots__/new-sidebar-collapsed.png +0 -0
- data/frontend/tests/e2e/__screenshots__/new-welcome.png +0 -0
- data/frontend/tests/e2e/render.spec.ts +188 -0
- data/frontend/tsconfig.json +20 -0
- data/frontend/vite.config.ts +26 -0
- data/frontend/vitest.config.ts +8 -0
- data/lib/ea/cli/app.rb +57 -2
- data/lib/ea/cli/command/diagrams.rb +37 -28
- data/lib/ea/cli/command/diff.rb +46 -0
- data/lib/ea/cli/command/export.rb +101 -0
- data/lib/ea/cli/command/info.rb +75 -0
- data/lib/ea/cli/command/lint.rb +48 -0
- data/lib/ea/cli/command/mdg.rb +98 -0
- data/lib/ea/cli/command/query.rb +34 -0
- data/lib/ea/cli/command/render.rb +135 -0
- data/lib/ea/cli/command/svg.rb +8 -15
- data/lib/ea/cli/command.rb +7 -0
- data/lib/ea/diagram/display_config.rb +184 -0
- data/lib/ea/diagram.rb +4 -41
- data/lib/ea/diff/change.rb +30 -0
- data/lib/ea/diff/comparator.rb +109 -0
- data/lib/ea/diff/html_reporter.rb +91 -0
- data/lib/ea/diff.rb +15 -0
- data/lib/ea/export/json/generator.rb +118 -0
- data/lib/ea/export/json.rb +12 -0
- data/lib/ea/export/json_schema/generator.rb +77 -0
- data/lib/ea/export/json_schema.rb +12 -0
- data/lib/ea/export/plantuml/generator.rb +140 -0
- data/lib/ea/export/plantuml.rb +12 -0
- data/lib/ea/export/xsd/class_mapping.rb +65 -0
- data/lib/ea/export/xsd/generator.rb +137 -0
- data/lib/ea/export/xsd/namespace_registry.rb +82 -0
- data/lib/ea/export/xsd.rb +19 -0
- data/lib/ea/export.rb +13 -0
- data/lib/ea/image/emf_renderer.rb +42 -0
- data/lib/ea/image.rb +12 -0
- data/lib/ea/lint/engine.rb +30 -0
- data/lib/ea/lint/lint_rule.rb +38 -0
- data/lib/ea/lint/offense.rb +18 -0
- data/lib/ea/lint/rules/cyclic_generalization.rb +62 -0
- data/lib/ea/lint/rules/duplicate_name.rb +28 -0
- data/lib/ea/lint/rules/missing_stereotype.rb +40 -0
- data/lib/ea/lint/rules/naming_convention.rb +44 -0
- data/lib/ea/lint/rules/orphan_element.rb +28 -0
- data/lib/ea/lint/rules.rb +14 -0
- data/lib/ea/lint.rb +13 -0
- data/lib/ea/mdg/document.rb +120 -0
- data/lib/ea/mdg/loader.rb +118 -0
- data/lib/ea/mdg/registry.rb +98 -0
- data/lib/ea/mdg/stereotype_alias_registry.rb +77 -0
- data/lib/ea/mdg/xml/applies_to.rb +18 -0
- data/lib/ea/mdg/xml/apply.rb +18 -0
- data/lib/ea/mdg/xml/content.rb +18 -0
- data/lib/ea/mdg/xml/documentation.rb +24 -0
- data/lib/ea/mdg/xml/stereotype.rb +28 -0
- data/lib/ea/mdg/xml/stereotypes.rb +18 -0
- data/lib/ea/mdg/xml/tag.rb +28 -0
- data/lib/ea/mdg/xml/tagged_values.rb +18 -0
- data/lib/ea/mdg/xml/technology.rb +28 -0
- data/lib/ea/mdg/xml/uml_profile.rb +22 -0
- data/lib/ea/mdg/xml/uml_profiles.rb +18 -0
- data/lib/ea/mdg/xml.rb +24 -0
- data/lib/ea/mdg.rb +25 -0
- data/lib/ea/model/classifier.rb +4 -0
- data/lib/ea/model/constraint.rb +24 -0
- data/lib/ea/model/diagram.rb +85 -0
- data/lib/ea/model/diagram_connector.rb +34 -0
- data/lib/ea/model/diagram_element.rb +16 -0
- data/lib/ea/model/document.rb +47 -2
- data/lib/ea/model/ghost_label.rb +32 -0
- data/lib/ea/model/instance_specification.rb +34 -0
- data/lib/ea/model/legend.rb +43 -0
- data/lib/ea/model/legend_item.rb +26 -0
- data/lib/ea/model/note.rb +28 -0
- data/lib/ea/model/operation.rb +2 -0
- data/lib/ea/model/property.rb +2 -0
- data/lib/ea/model/relationship.rb +2 -0
- data/lib/ea/model/signal.rb +14 -0
- data/lib/ea/model/slot.rb +19 -0
- data/lib/ea/model.rb +8 -0
- data/lib/ea/ocl/evaluator.rb +94 -0
- data/lib/ea/ocl/nodes.rb +30 -0
- data/lib/ea/ocl/parser.rb +133 -0
- data/lib/ea/ocl/unsupported_error.rb +7 -0
- data/lib/ea/ocl.rb +13 -0
- data/lib/ea/qea/factory/document_builder.rb +24 -10
- data/lib/ea/qea/factory/generalization_builder.rb +9 -11
- data/lib/ea/qea/infrastructure/table_reader.rb +9 -0
- data/lib/ea/qea/models/ea_author.rb +35 -0
- data/lib/ea/qea/models/ea_glossary.rb +34 -0
- data/lib/ea/qea/models/ea_image.rb +53 -0
- data/lib/ea/qea/models/ea_implement.rb +32 -0
- data/lib/ea/qea/models/ea_list.rb +42 -0
- data/lib/ea/qea/models/ea_object_effort.rb +34 -0
- data/lib/ea/qea/models/ea_object_problem.rb +37 -0
- data/lib/ea/qea/models/ea_object_require.rb +34 -0
- data/lib/ea/qea/models/ea_object_resource.rb +34 -0
- data/lib/ea/qea/models/ea_object_risk.rb +34 -0
- data/lib/ea/qea/models/ea_object_scenario.rb +34 -0
- data/lib/ea/qea/models/ea_object_test.rb +35 -0
- data/lib/ea/qea/models/ea_object_trx.rb +34 -0
- data/lib/ea/qea/models/ea_operation.rb +7 -0
- data/lib/ea/qea/models/ea_palette.rb +30 -0
- data/lib/ea/qea/models/ea_palette_item.rb +36 -0
- data/lib/ea/qea/models/ea_phase.rb +40 -0
- data/lib/ea/qea/models/ea_role_constraint.rb +32 -0
- data/lib/ea/qea/models/ea_secrypt.rb +34 -0
- data/lib/ea/qea/models/ea_version.rb +39 -0
- data/lib/ea/qea/models/ea_xref.rb +11 -1
- data/lib/ea/qea/models.rb +19 -0
- data/lib/ea/qea/services/database_loader.rb +22 -1
- data/lib/ea/qea/validation/database/ocl_constraint_validator.rb +65 -0
- data/lib/ea/qea/validation/database.rb +2 -0
- data/lib/ea/qea/validation/validation_engine.rb +2 -0
- data/lib/ea/qea/validation.rb +2 -0
- data/lib/ea/query/builder.rb +127 -0
- data/lib/ea/query.rb +9 -0
- data/lib/ea/render/image_converter.rb +101 -0
- data/lib/ea/render.rb +10 -0
- data/lib/ea/shapescript/parser.rb +208 -0
- data/lib/ea/shapescript/renderer.rb +74 -0
- data/lib/ea/shapescript/shape.rb +34 -0
- data/lib/ea/shapescript.rb +24 -0
- data/lib/ea/sources/qea/adapter.rb +22 -5
- data/lib/ea/sources/qea/classifier_builder.rb +184 -7
- data/lib/ea/sources/qea/diagram_builder.rb +352 -24
- data/lib/ea/sources/qea/id_normalizer.rb +16 -1
- data/lib/ea/sources/qea/instance_builder.rb +113 -0
- data/lib/ea/sources/qea/legend_builder.rb +137 -0
- data/lib/ea/sources/qea/note_builder.rb +58 -0
- data/lib/ea/sources/qea/object_classifier_map.rb +6 -1
- data/lib/ea/sources/qea/operation_builder.rb +1 -0
- data/lib/ea/sources/qea/package_builder.rb +16 -0
- data/lib/ea/sources/qea/relationship_builder.rb +21 -5
- data/lib/ea/sources/qea/tagged_value_builder.rb +28 -9
- data/lib/ea/sources/qea/xref/legend_definition.rb +35 -0
- data/lib/ea/sources/qea/xref/parser.rb +150 -0
- data/lib/ea/sources/qea/xref/property_definition.rb +29 -0
- data/lib/ea/sources/qea/xref/record.rb +41 -0
- data/lib/ea/sources/qea/xref/stereotype_application.rb +37 -0
- data/lib/ea/sources/qea/xref.rb +27 -0
- data/lib/ea/sources/qea.rb +4 -0
- data/lib/ea/sources/xmi/adapter.rb +80 -2
- data/lib/ea/sources/xmi/classifier_builder.rb +10 -1
- data/lib/ea/sources/xmi/diagram_builder.rb +95 -18
- data/lib/ea/sources/xmi/extension_geometry_parser.rb +19 -2
- data/lib/ea/sources/xmi/extension_style_parser.rb +15 -2
- data/lib/ea/sources/xmi/note_builder.rb +46 -0
- data/lib/ea/sources/xmi/property_builder.rb +9 -0
- data/lib/ea/sources/xmi/stereotype_builder.rb +54 -0
- data/lib/ea/sources/xmi/tag_builder.rb +45 -0
- data/lib/ea/sources/xmi/umldi_keyword_extractor.rb +87 -0
- data/lib/ea/sources/xmi.rb +4 -0
- data/lib/ea/spa/output/sharded_multi_file_strategy.rb +18 -3
- data/lib/ea/spa/output/single_file_strategy.rb +8 -2
- data/lib/ea/spa/output/strategy.rb +34 -0
- data/lib/ea/svg/connector_router.rb +134 -0
- data/lib/ea/svg/ea_emitter/background.rb +2 -3
- data/lib/ea/svg/ea_emitter/bounds_calculator.rb +142 -0
- data/lib/ea/svg/ea_emitter/canvas.rb +56 -33
- data/lib/ea/svg/ea_emitter/color_resolver.rb +56 -0
- data/lib/ea/svg/ea_emitter/compartment/attributes.rb +28 -0
- data/lib/ea/svg/ea_emitter/compartment/constraints.rb +30 -0
- data/lib/ea/svg/ea_emitter/compartment/enum_literals.rb +86 -0
- data/lib/ea/svg/ea_emitter/compartment/header.rb +32 -0
- data/lib/ea/svg/ea_emitter/compartment/header_divider.rb +57 -0
- data/lib/ea/svg/ea_emitter/compartment/instance_slots.rb +96 -0
- data/lib/ea/svg/ea_emitter/compartment/instance_underline.rb +67 -0
- data/lib/ea/svg/ea_emitter/compartment/note_body.rb +52 -0
- data/lib/ea/svg/ea_emitter/compartment/note_text.rb +102 -0
- data/lib/ea/svg/ea_emitter/compartment/operations.rb +38 -0
- data/lib/ea/svg/ea_emitter/compartment/package_contents.rb +72 -0
- data/lib/ea/svg/ea_emitter/compartment/package_from_parent.rb +136 -0
- data/lib/ea/svg/ea_emitter/compartment/shape.rb +82 -0
- data/lib/ea/svg/ea_emitter/compartment/stereotype_icon.rb +32 -0
- data/lib/ea/svg/ea_emitter/compartment/tagged_values.rb +30 -0
- data/lib/ea/svg/ea_emitter/compartment.rb +60 -0
- data/lib/ea/svg/ea_emitter/connectors.rb +46 -12
- data/lib/ea/svg/ea_emitter/diagram_frame.rb +143 -0
- data/lib/ea/svg/ea_emitter/document.rb +49 -25
- data/lib/ea/svg/ea_emitter/element/attribute_line_builder.rb +117 -0
- data/lib/ea/svg/ea_emitter/element/attribute_renderer.rb +119 -0
- data/lib/ea/svg/ea_emitter/element/bcol_decoder.rb +29 -0
- data/lib/ea/svg/ea_emitter/element/compartment_geometry.rb +113 -0
- data/lib/ea/svg/ea_emitter/element/constraint_renderer.rb +53 -0
- data/lib/ea/svg/ea_emitter/element/divider_renderer.rb +17 -0
- data/lib/ea/svg/ea_emitter/element/enumeration_literal_renderer.rb +34 -0
- data/lib/ea/svg/ea_emitter/element/filter.rb +44 -0
- data/lib/ea/svg/ea_emitter/element/hand_draw_shape_renderer.rb +77 -0
- data/lib/ea/svg/ea_emitter/element/header_line_pipeline.rb +43 -0
- data/lib/ea/svg/ea_emitter/element/header_line_provider/instance_spec.rb +27 -0
- data/lib/ea/svg/ea_emitter/element/header_line_provider/name.rb +76 -0
- data/lib/ea/svg/ea_emitter/element/header_line_provider/parent_ghost.rb +25 -0
- data/lib/ea/svg/ea_emitter/element/header_line_provider/stereotype_label.rb +68 -0
- data/lib/ea/svg/ea_emitter/element/header_line_provider.rb +19 -0
- data/lib/ea/svg/ea_emitter/element/header_lines.rb +27 -0
- data/lib/ea/svg/ea_emitter/element/header_renderer.rb +48 -0
- data/lib/ea/svg/ea_emitter/element/icon_renderer.rb +109 -0
- data/lib/ea/svg/ea_emitter/element/legend_renderer.rb +177 -0
- data/lib/ea/svg/ea_emitter/element/note_shape_renderer.rb +112 -0
- data/lib/ea/svg/ea_emitter/element/operation_renderer.rb +100 -0
- data/lib/ea/svg/ea_emitter/element/package_shape_renderer.rb +181 -0
- data/lib/ea/svg/ea_emitter/element/row_icon_renderer.rb +156 -0
- data/lib/ea/svg/ea_emitter/element/shape_renderer.rb +17 -0
- data/lib/ea/svg/ea_emitter/element/stereotype_icon_renderer.rb +119 -0
- data/lib/ea/svg/ea_emitter/element/tagged_value_renderer.rb +50 -0
- data/lib/ea/svg/ea_emitter/element/text_escape.rb +20 -0
- data/lib/ea/svg/ea_emitter/element.rb +37 -0
- data/lib/ea/svg/ea_emitter/elements.rb +283 -95
- data/lib/ea/svg/ea_emitter/font_resolver.rb +111 -0
- data/lib/ea/svg/ea_emitter/ghost_labels.rb +66 -0
- data/lib/ea/svg/ea_emitter/label/end_label.rb +266 -0
- data/lib/ea/svg/ea_emitter/label/midpoint_label.rb +101 -0
- data/lib/ea/svg/ea_emitter/label/registry.rb +50 -0
- data/lib/ea/svg/ea_emitter/label.rb +23 -0
- data/lib/ea/svg/ea_emitter/labels.rb +93 -27
- data/lib/ea/svg/ea_emitter/layer.rb +20 -0
- data/lib/ea/svg/ea_emitter/layer_sequencer.rb +93 -0
- data/lib/ea/svg/ea_emitter/marker/arrow_path.rb +52 -0
- data/lib/ea/svg/ea_emitter/marker/diamond.rb +57 -0
- data/lib/ea/svg/ea_emitter/marker/kind.rb +35 -0
- data/lib/ea/svg/ea_emitter/marker/open_triangle.rb +27 -0
- data/lib/ea/svg/ea_emitter/marker/package_import.rb +39 -0
- data/lib/ea/svg/ea_emitter/marker/plus.rb +40 -0
- data/lib/ea/svg/ea_emitter/marker/registry.rb +42 -0
- data/lib/ea/svg/ea_emitter/marker.rb +37 -0
- data/lib/ea/svg/ea_emitter/markers.rb +351 -64
- data/lib/ea/svg/ea_emitter/render_context.rb +52 -0
- data/lib/ea/svg/ea_emitter/style.rb +15 -0
- data/lib/ea/svg/ea_emitter/text_renderer.rb +92 -0
- data/lib/ea/svg/ea_emitter.rb +33 -11
- data/lib/ea/svg/parity/checker.rb +105 -0
- data/lib/ea/svg/parity/source.rb +59 -0
- data/lib/ea/svg/parity/suite.rb +113 -0
- data/lib/ea/svg/parity.rb +14 -0
- data/lib/ea/svg.rb +2 -15
- data/lib/ea/theme/definition.rb +176 -0
- data/lib/ea/theme/loader.rb +125 -0
- data/lib/ea/theme/registry.rb +96 -0
- data/lib/ea/theme.rb +37 -0
- data/lib/ea/transformations.rb +5 -88
- data/lib/ea/validation/xmi_parity.rb +80 -0
- data/lib/ea/validation.rb +12 -0
- data/lib/ea/version.rb +4 -1
- data/lib/ea.rb +15 -4
- data/lib/tasks/svg_bench.rake +87 -0
- data/lutaml-uml-0.5.1.gem +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes-list.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-2-gradients.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-3-colors.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-4-appearance-fonts.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-4-appearance.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-5-behavior.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-6-sequence.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-2-objects.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-3-links.png +0 -0
- metadata +464 -26
- data/lib/ea/diagram/configuration.rb +0 -379
- data/lib/ea/diagram/element_renderers/base_renderer.rb +0 -77
- data/lib/ea/diagram/element_renderers/class_renderer.rb +0 -323
- data/lib/ea/diagram/element_renderers/connector_renderer.rb +0 -41
- data/lib/ea/diagram/element_renderers/package_renderer.rb +0 -61
- data/lib/ea/diagram/element_renderers.rb +0 -43
- data/lib/ea/diagram/extractor.rb +0 -566
- data/lib/ea/diagram/layout_engine.rb +0 -170
- data/lib/ea/diagram/path_builder.rb +0 -202
- data/lib/ea/diagram/style_parser.rb +0 -42
- data/lib/ea/diagram/style_resolver.rb +0 -291
- data/lib/ea/diagram/svg_renderer.rb +0 -274
- data/lib/ea/diagram/util.rb +0 -73
- data/lib/ea/svg/bounds_calculator.rb +0 -74
- data/lib/ea/svg/connector_path.rb +0 -138
- data/lib/ea/svg/element_box.rb +0 -256
- data/lib/ea/svg/renderer.rb +0 -77
- data/lib/ea/svg/style_resolver.rb +0 -72
- data/lib/ea/transformations/configuration.rb +0 -333
- data/lib/ea/transformations/format_registry.rb +0 -366
- data/lib/ea/transformations/parsers/base_parser.rb +0 -482
- data/lib/ea/transformations/parsers/qea_parser.rb +0 -401
- data/lib/ea/transformations/parsers/xmi_parser.rb +0 -243
- data/lib/ea/transformations/transformation_engine.rb +0 -390
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# TODO-D 07 - Full text content fidelity
|
|
2
|
+
|
|
3
|
+
## Status: PARTIAL (62% overlap) (2026-07-26)
|
|
4
|
+
|
|
5
|
+
## Current state
|
|
6
|
+
|
|
7
|
+
Text overlap (Jaccard index of text content sets between our SVG
|
|
8
|
+
and reference SVG):
|
|
9
|
+
|
|
10
|
+
- Average across 185 plateau diagrams: **62%**
|
|
11
|
+
- Best diagrams: ~95%
|
|
12
|
+
- Worst diagrams: ~20%
|
|
13
|
+
|
|
14
|
+
## What's working
|
|
15
|
+
|
|
16
|
+
- Classifier names and stereotypes render correctly when the
|
|
17
|
+
element is placed on the diagram.
|
|
18
|
+
- Attribute text matches when the element has Tag=0 (no tagged
|
|
19
|
+
values compartment).
|
|
20
|
+
- Visibility prefixes ("+ ", "- ") match.
|
|
21
|
+
- Multiplicity brackets match.
|
|
22
|
+
|
|
23
|
+
## What's still off
|
|
24
|
+
|
|
25
|
+
### 1. Tagged value visibility (mostly fixed, edge cases remain)
|
|
26
|
+
Reference SVGs don't render the "tags" header compartment except
|
|
27
|
+
on 2 diagrams. Our Tag-flag gating brought text overlap from 41%
|
|
28
|
+
to 62%. Remaining misses are likely from elements where the
|
|
29
|
+
`Tag=1` flag is set but the reference still doesn't render tags
|
|
30
|
+
— possibly tied to stereotype source (profile-applied vs
|
|
31
|
+
user-defined tagged values).
|
|
32
|
+
|
|
33
|
+
### 2. Qualified name vs simple name
|
|
34
|
+
Reference uses qualified names like
|
|
35
|
+
`uro::TrafficVolumeAttribute`. Our output sometimes uses the
|
|
36
|
+
short name only. The qualified_name attribute is set on the
|
|
37
|
+
Classifier model, but the renderer doesn't always pick it up
|
|
38
|
+
correctly when the element is placed on a sub-package diagram.
|
|
39
|
+
|
|
40
|
+
### 3. Attribute ordering
|
|
41
|
+
Within a classifier's attribute compartment, EA sorts attributes
|
|
42
|
+
by some criteria (possibly visibility then alphabetical). Our
|
|
43
|
+
ordering follows the XMI's `ownedAttribute` order, which may
|
|
44
|
+
differ.
|
|
45
|
+
|
|
46
|
+
### 4. Attribute visibility color
|
|
47
|
+
Reference uses different fill colors for public/protected/private
|
|
48
|
+
attributes (`#66413F` for some, `#595959` for others). Our
|
|
49
|
+
renderer uses a single text color from the theme.
|
|
50
|
+
|
|
51
|
+
## Path to 100% text overlap
|
|
52
|
+
|
|
53
|
+
1. Characterize the tagged value visibility rule by examining
|
|
54
|
+
which elements with `Tag=1` still don't render tags in
|
|
55
|
+
reference (estimated 5-10 diagrams).
|
|
56
|
+
|
|
57
|
+
2. Always use `classifier.qualified_name` for the header label
|
|
58
|
+
(currently mixed).
|
|
59
|
+
|
|
60
|
+
3. Sort attributes by visibility prefix, then alphabetical.
|
|
61
|
+
|
|
62
|
+
4. Apply theme.color_for_attribute_visibility for attribute text.
|
|
63
|
+
|
|
64
|
+
Each of these is a separate fix. None require architectural
|
|
65
|
+
changes.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# TODO-D 08-11 - QEA-direct pipeline
|
|
2
|
+
|
|
3
|
+
## Status: COMPLETE (2026-07-27)
|
|
4
|
+
|
|
5
|
+
## What was wired
|
|
6
|
+
|
|
7
|
+
1. **TODO-D 08**: QEA DiagramBuilder propagates StyleEx to
|
|
8
|
+
Diagram.style_ex. Theme=:119 is now correctly detected from QEA.
|
|
9
|
+
|
|
10
|
+
2. **TODO-D 09**: IdNormalizer.to_eaid converts `{GUID}` to
|
|
11
|
+
`EAID_<guid-with-underscores>` for matching reference SVG
|
|
12
|
+
filenames. The QEA stores diagram GUIDs in braces-dashes form;
|
|
13
|
+
the reference SVGs use the EAID_ underscore form.
|
|
14
|
+
|
|
15
|
+
3. **TODO-D 10**: New QEA NoteBuilder parses t_object rows with
|
|
16
|
+
object_type="Note" or "Text". These render as Package-shaped
|
|
17
|
+
diagram boxes (not dog-eared Notes — QEA's "Note" type is a
|
|
18
|
+
diagrammatic Package-shape box for free text, distinct from
|
|
19
|
+
XMI's uml:Note).
|
|
20
|
+
|
|
21
|
+
Also: connector_type from t_connector.Type is now propagated
|
|
22
|
+
to DiagramConnector so Marker::Diamond matches Aggregation
|
|
23
|
+
and Composition (was being dropped, all connectors fell back
|
|
24
|
+
to Association).
|
|
25
|
+
|
|
26
|
+
4. **TODO-D 11**: spec/ea/svg/qea_regression_spec.rb renders all
|
|
27
|
+
188 diagrams directly from the QEA against reference SVGs.
|
|
28
|
+
Passes at the 60 percent within-tolerance threshold.
|
|
29
|
+
|
|
30
|
+
## Parity delta from QEA-direct fixes
|
|
31
|
+
|
|
32
|
+
| Metric | Before | After |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| Polygon delta | n/a (was reading XMI) | -166 (was -842 at start) |
|
|
35
|
+
| Path delta | n/a | -181 |
|
|
36
|
+
| Text overlap avg | 10% (initial QEA-direct) | 56% |
|
|
37
|
+
| Within tolerance | 60.6% | 65.4% |
|
|
38
|
+
|
|
39
|
+
## Bonus fixes shipped alongside
|
|
40
|
+
|
|
41
|
+
- ClassifierBuilder no longer prepends package name to
|
|
42
|
+
qualified_name (QEA t_object.Name already includes the prefix).
|
|
43
|
+
- HeaderLines no longer renders fallback stereotype labels.
|
|
44
|
+
- AttributeRenderer no longer double-colons type names.
|
|
45
|
+
- bounds_from_rect uses min/max of rect values (QEA stores rect
|
|
46
|
+
with recttop > rectbottom).
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# TODO-D 12 - Connector role/multiplicity labels
|
|
2
|
+
|
|
3
|
+
## Status: COMPLETE (2026-07-27)
|
|
4
|
+
|
|
5
|
+
## What changed
|
|
6
|
+
|
|
7
|
+
Labels renderer refactored to support both XMI and QEA paths:
|
|
8
|
+
|
|
9
|
+
1. **Property lookup (XMI path)**: When the Association's
|
|
10
|
+
source_id/target_id reference Property IDs, look them up and
|
|
11
|
+
render the role name + multiplicity from the Property fields.
|
|
12
|
+
|
|
13
|
+
2. **Association fields (QEA path)**: Fall back to the
|
|
14
|
+
Association's own source_role_name, target_role_name,
|
|
15
|
+
source_multiplicity_lower/upper, target_multiplicity_lower/upper
|
|
16
|
+
fields. These are populated by QEA's t_connector.sourcerole/
|
|
17
|
+
destrole/sourcecard/destcard columns.
|
|
18
|
+
|
|
19
|
+
3. **Default label offset**: When label_boxes aren't populated
|
|
20
|
+
(QEA path — the geometry parser doesn't yet extract them),
|
|
21
|
+
use a default offset (anchor + 5, -10) so labels render near
|
|
22
|
+
the connector endpoints rather than being silently dropped.
|
|
23
|
+
|
|
24
|
+
## Acceptance
|
|
25
|
+
|
|
26
|
+
QEA-direct parity measurement:
|
|
27
|
+
|
|
28
|
+
| Metric | Before | After |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| Text delta vs ref | -2728 (14% under) | -883 (5% under) |
|
|
31
|
+
| Text overlap avg | 56.0% | 62.8% |
|
|
32
|
+
|
|
33
|
+
## Remaining
|
|
34
|
+
|
|
35
|
+
- QEA t_diagramlinks.Geometry parser doesn't extract LLB/LRB
|
|
36
|
+
boxes. Adding that would let labels render at EA's recorded
|
|
37
|
+
pixel positions rather than the default offset.
|
|
38
|
+
- The XMI-encoded `<text>` ordering within Labels is still
|
|
39
|
+
suboptimal — EA emits role name and multiplicity in a single
|
|
40
|
+
`<g>` block, we emit each as a separate text element.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# 12 - Per-Entity SVG Layer Ordering
|
|
2
|
+
|
|
3
|
+
## Status: DONE (2026-07-23)
|
|
4
|
+
|
|
5
|
+
## Outcome
|
|
6
|
+
|
|
7
|
+
Restructured `Ea::Svg::EaEmitter::Document` to emit a flat sequence
|
|
8
|
+
of top-level `<g>` elements matching EA's per-entity layering:
|
|
9
|
+
|
|
10
|
+
- `Elements#groups` returns Array of per-element `<g>` blocks
|
|
11
|
+
(shape → header → divider → attrs)
|
|
12
|
+
- `Connectors#groups` returns Array of one `<g>` per connector line
|
|
13
|
+
- `Markers#groups` returns Array of one `<g>` per connector marker
|
|
14
|
+
- `Document#connector_layers` interleaves line + marker per connector
|
|
15
|
+
|
|
16
|
+
Verified on Waterway: 50 top-level `<g>` (ours) vs 47 (ref) — the
|
|
17
|
+
3-group delta is due to the spurious frame element (TODO 14).
|
|
18
|
+
|
|
19
|
+
## Files changed
|
|
20
|
+
|
|
21
|
+
- `lib/ea/svg/ea_emitter/document.rb` — interleaves line/marker per connector
|
|
22
|
+
- `lib/ea/svg/ea_emitter/elements.rb` — `groups` method, per-element arrays
|
|
23
|
+
- `lib/ea/svg/ea_emitter/connectors.rb` — `groups` method, one `<g>` per connector
|
|
24
|
+
- `lib/ea/svg/ea_emitter/markers.rb` — `groups` method, one `<g>` per marker
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# 13 - Marker Encoding: Polygon vs Path by Shape
|
|
2
|
+
|
|
3
|
+
## Status: DONE (2026-07-23)
|
|
4
|
+
|
|
5
|
+
## Outcome
|
|
6
|
+
|
|
7
|
+
Refactored `Ea::Svg::EaEmitter::Markers` to dispatch marker shape
|
|
8
|
+
via a `Spec` value object. Each marker emits the correct element type:
|
|
9
|
+
|
|
10
|
+
- Diamond (Aggregation/Composition) → `<polygon>` 4 points
|
|
11
|
+
- Open triangle (Generalization/Realization/Dependency) → `<polygon>` 3 points, white fill
|
|
12
|
+
- Filled arrow (Association navigability) → `<path d="M .. L .. L .."/>` 3 points
|
|
13
|
+
|
|
14
|
+
Marker placement is direction-aware: "Destination -> Source" flips
|
|
15
|
+
which end holds the marker.
|
|
16
|
+
|
|
17
|
+
## Files changed
|
|
18
|
+
|
|
19
|
+
- `lib/ea/svg/ea_emitter/markers.rb` — Spec struct + dispatch
|
|
20
|
+
- `spec/ea/svg/ea_emitter/markers_spec.rb` — updated to reflect arrow emission
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# TODO-D 13 - Per-text-type font sizes
|
|
2
|
+
|
|
3
|
+
## Status: COMPLETE (2026-07-27)
|
|
4
|
+
|
|
5
|
+
## Context
|
|
6
|
+
|
|
7
|
+
Reference SVGs use different font sizes for different text types:
|
|
8
|
+
- 9pt for classifier compartments (header, attributes, operations,
|
|
9
|
+
enumeration literals, tagged values)
|
|
10
|
+
- 7pt for diagram-level text (frame label, swimlane names)
|
|
11
|
+
- 12pt for some classifier names (rare)
|
|
12
|
+
|
|
13
|
+
Theme :119 specifies font_size=7pt — that's the DIAGRAM-LEVEL font
|
|
14
|
+
size, not the element-level default. Element compartment text uses
|
|
15
|
+
9pt regardless of theme.
|
|
16
|
+
|
|
17
|
+
## What changed
|
|
18
|
+
|
|
19
|
+
- `FontResolver::DEFAULT_ELEMENT_FONT_SIZE = 9` — replaces the
|
|
20
|
+
previous default of 13 (which was the Yu Gothic UI locale default)
|
|
21
|
+
- `FontResolver#size_for` no longer falls back to `theme.font_size`
|
|
22
|
+
for elements — only diagram-level text uses theme font size
|
|
23
|
+
- `HeaderRenderer` and `AttributeRenderer` gain `size_unit:`
|
|
24
|
+
parameter (defaults to `"pt"`) and propagate it to TextRenderer
|
|
25
|
+
- `Elements#groups_for` reads `size_unit` from FontResolver and
|
|
26
|
+
passes through to all renderers
|
|
27
|
+
|
|
28
|
+
## Acceptance
|
|
29
|
+
|
|
30
|
+
- Reference text uses `font-size:9pt` for classifier compartments
|
|
31
|
+
- Our text now emits `font-size:9pt` (was `font-size:7px`)
|
|
32
|
+
- Text overlap metric unchanged (counts content, not formatting)
|
|
33
|
+
- 1612 specs pass
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# TODO-D 14 - Center classifier header text
|
|
2
|
+
|
|
3
|
+
## Status: COMPLETE (2026-07-27)
|
|
4
|
+
|
|
5
|
+
## Context
|
|
6
|
+
|
|
7
|
+
EA centers stereotype and classifier-name text horizontally within
|
|
8
|
+
the element bounds. SVG `<text x=>` is the LEFT edge of the text,
|
|
9
|
+
not the center, so we need to compute:
|
|
10
|
+
|
|
11
|
+
left_edge = bounds.center_x - text_width / 2
|
|
12
|
+
|
|
13
|
+
Our previous code emitted `x = bounds.center_x` directly, which
|
|
14
|
+
placed the LEFT EDGE at the center — making all text appear
|
|
15
|
+
right-of-center.
|
|
16
|
+
|
|
17
|
+
## What changed
|
|
18
|
+
|
|
19
|
+
`HeaderRenderer.center_x_for(text, bounds, size)` computes the
|
|
20
|
+
left edge from a text-width approximation:
|
|
21
|
+
|
|
22
|
+
text_width = text.length * size * 0.55
|
|
23
|
+
|
|
24
|
+
The factor 0.55 approximates average Carlito character width as a
|
|
25
|
+
fraction of point size. Not pixel-perfect (EA uses GDI text
|
|
26
|
+
metrics) but visually centered.
|
|
27
|
+
|
|
28
|
+
## Acceptance
|
|
29
|
+
|
|
30
|
+
- Stereotype label now visually centered in element box
|
|
31
|
+
- Classifier name now visually centered
|
|
32
|
+
- Close to reference x positions (within ~5px due to text-width
|
|
33
|
+
approximation)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# 14 - Filter Diagram-Frame / Note Elements
|
|
2
|
+
|
|
3
|
+
## Status: DONE (2026-07-23)
|
|
4
|
+
|
|
5
|
+
## Outcome
|
|
6
|
+
|
|
7
|
+
Added `Elements#frame_element?` predicate that skips elements
|
|
8
|
+
matching the diagram-frame pattern:
|
|
9
|
+
- `background_color == -1` (sentinel for "no fill / default"), AND
|
|
10
|
+
- Classifier name is nil/empty, AND
|
|
11
|
+
- Classifier has no properties
|
|
12
|
+
|
|
13
|
+
Verified: Waterway top-level `<g>` count drops 50→47, rect count
|
|
14
|
+
drops 10→9 — both now match EA reference exactly.
|
|
15
|
+
|
|
16
|
+
## Files changed
|
|
17
|
+
|
|
18
|
+
- `lib/ea/svg/ea_emitter/elements.rb` — `frame_element?` predicate
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# TODO-D 15 - Deep dead code audit
|
|
2
|
+
|
|
3
|
+
## Status: COMPLETE (2026-07-27)
|
|
4
|
+
|
|
5
|
+
## Audit findings
|
|
6
|
+
|
|
7
|
+
All production subsystems in `lib/ea/` are actively used:
|
|
8
|
+
|
|
9
|
+
| Subsystem | Used by | Status |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| `Ea::Model` | All adapters and renderers | KEEP |
|
|
12
|
+
| `Ea::Sources::Qea` | `Ea.parse`, `Ea::Sources::Qea::Adapter.from_path` | KEEP |
|
|
13
|
+
| `Ea::Sources::Xmi` | `Ea::Sources::Xmi::Adapter.from_path` | KEEP |
|
|
14
|
+
| `Ea::Svg::EaEmitter` | `ea svg` CLI command | KEEP |
|
|
15
|
+
| `Ea::Theme` | Diagram.theme resolution | KEEP |
|
|
16
|
+
| `Ea::Diagram::DisplayConfig` | `Diagram#display_config` | KEEP |
|
|
17
|
+
| `Ea::Qea` (SQLite layer) | `Ea::Sources::Qea::*` adapters | KEEP |
|
|
18
|
+
| `Ea::Xmi` | `Ea::Sources::Xmi::*` adapters | KEEP |
|
|
19
|
+
| `Ea::Spa` | `ea spa` CLI command | KEEP |
|
|
20
|
+
| `Ea::Transformers` | `ea convert` CLI command | KEEP |
|
|
21
|
+
| `Ea::Bridge` | `Ea::Transformations.to_uml` | KEEP |
|
|
22
|
+
| `Ea::Transformations` | `RepositoryBuilder` for bridge CLI | KEEP |
|
|
23
|
+
|
|
24
|
+
## Code quality audit
|
|
25
|
+
|
|
26
|
+
| Rule | Status |
|
|
27
|
+
|---|---|
|
|
28
|
+
| No `send` to call private methods | CLEAN |
|
|
29
|
+
| No `instance_variable_set`/`get` | CLEAN (only mentioned in a comment) |
|
|
30
|
+
| No `respond_to?` for type checks | CLEAN (replaced with `is_a?` earlier) |
|
|
31
|
+
| No `require_relative` for library code | CLEAN (one in `lib/ea.rb` for VERSION — standard gemspec pattern) |
|
|
32
|
+
| autoload for all internal loading | CLEAN |
|
|
33
|
+
|
|
34
|
+
## Architecture observations
|
|
35
|
+
|
|
36
|
+
The codebase follows OCP well:
|
|
37
|
+
- `Marker::Kind` subclasses registered via `Marker::Registry.register`
|
|
38
|
+
- `Theme::Definition` immutable value object with `#with` for variants
|
|
39
|
+
- `Theme::Registry` auto-loads from `config/themes/*.yml`
|
|
40
|
+
- `Element::*Renderer` classes are independent — adding a new
|
|
41
|
+
compartment type doesn't modify existing renderers
|
|
42
|
+
|
|
43
|
+
## DRY
|
|
44
|
+
|
|
45
|
+
Found one minor duplication: `Labels` and `AttributeRenderer` both
|
|
46
|
+
have text-emission logic. Consolidated into shared `TextRenderer`
|
|
47
|
+
calls. No further DRY violations observed.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# 15 - Per-Element Font from Style
|
|
2
|
+
|
|
3
|
+
## Status: DONE (2026-07-23)
|
|
4
|
+
|
|
5
|
+
## Outcome
|
|
6
|
+
|
|
7
|
+
Added `Ea::Svg::EaEmitter::FontResolver` that resolves font family +
|
|
8
|
+
size + weight + style per element, using EA's fallback chain:
|
|
9
|
+
|
|
10
|
+
1. Element-level `font_family` / `font_size` (set from EA's
|
|
11
|
+
`font=NAME;fontsz=PCT` style fields via ExtensionStyleParser)
|
|
12
|
+
2. Diagram-level default (most common non-nil value across elements)
|
|
13
|
+
3. Module default (`Yu Gothic UI`, `13`)
|
|
14
|
+
|
|
15
|
+
`Elements` emitter delegates font resolution to FontResolver so the
|
|
16
|
+
fallback rule lives in one place (MECE).
|
|
17
|
+
|
|
18
|
+
## Files changed
|
|
19
|
+
|
|
20
|
+
- `lib/ea/svg/ea_emitter/font_resolver.rb` — new resolver
|
|
21
|
+
- `lib/ea/svg/ea_emitter.rb` — autoload registration
|
|
22
|
+
- `lib/ea/svg/ea_emitter/elements.rb` — uses FontResolver
|
|
23
|
+
- `spec/ea/svg/ea_emitter/font_resolver_spec.rb` — 9 specs covering
|
|
24
|
+
explicit, fallback, and empty-diagram cases
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# 16 - Canvas Bounds Include Marker Extent
|
|
2
|
+
|
|
3
|
+
## Status: DONE (2026-07-23)
|
|
4
|
+
|
|
5
|
+
## Outcome
|
|
6
|
+
|
|
7
|
+
`Canvas.from` now extends the points list with `MARKER_EXTENT=15`
|
|
8
|
+
padding around each connector's source and target waypoints. This
|
|
9
|
+
prevents markers (diamonds, triangles, arrows) from being clipped
|
|
10
|
+
when they project beyond element bounds.
|
|
11
|
+
|
|
12
|
+
For Waterway this didn't change the canvas size (markers fit within
|
|
13
|
+
existing element bounds), but for diagrams where arrows extend below
|
|
14
|
+
or beside elements, the canvas now grows accordingly.
|
|
15
|
+
|
|
16
|
+
## Remaining diff
|
|
17
|
+
|
|
18
|
+
Waterway height: ours 869 vs ref 892 (23 px short). Root cause:
|
|
19
|
+
EA's renderer uses `image_bounds` (with 12 px image padding) for
|
|
20
|
+
certain elements while we use logical `bounds`. The 23 px diff
|
|
21
|
+
matches the difference between logical and image_bounds for the
|
|
22
|
+
lowest element (FacilityIdAttribute: logical bottom=895, image
|
|
23
|
+
bottom=918). To close this fully we'd need to compute canvas from
|
|
24
|
+
image_bounds union (matching EA's behavior), but this would also
|
|
25
|
+
require translating elements by image_bounds rather than logical
|
|
26
|
+
bounds — a larger change deferred to TODO 18.
|
|
27
|
+
|
|
28
|
+
## Files changed
|
|
29
|
+
|
|
30
|
+
- `lib/ea/svg/ea_emitter/canvas.rb` — `marker_extents` + concat into points
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# TODO-D 16 - Document all remaining parity gaps
|
|
2
|
+
|
|
3
|
+
## Status: LIVING DOCUMENT (2026-07-27)
|
|
4
|
+
|
|
5
|
+
## Current parity (QEA-direct, 188 diagrams)
|
|
6
|
+
|
|
7
|
+
| Metric | Value |
|
|
8
|
+
|---|---|
|
|
9
|
+
| Within shape-count tolerance | 123/188 (65.4%) |
|
|
10
|
+
| Text overlap avg | 62.8% |
|
|
11
|
+
| Polygon delta | -166 |
|
|
12
|
+
| Path delta | -181 |
|
|
13
|
+
| Text delta | -883 |
|
|
14
|
+
| Rect delta | -460 |
|
|
15
|
+
|
|
16
|
+
## Byte-level diff status (maintenance diagram)
|
|
17
|
+
|
|
18
|
+
The simplest diagram (`maintenance`, 1 classifier) now matches
|
|
19
|
+
reference byte-for-byte on:
|
|
20
|
+
|
|
21
|
+
- Canvas dimensions (254x177) ✓
|
|
22
|
+
- Element position (35, 40) ✓
|
|
23
|
+
- Background rect dimensions ✓
|
|
24
|
+
- Frame border path coordinates ✓
|
|
25
|
+
|
|
26
|
+
Remaining byte-level differences on maintenance:
|
|
27
|
+
|
|
28
|
+
### 1. Build ID
|
|
29
|
+
- Ours: `Build: 1628`
|
|
30
|
+
- Ref: `Build: 1624`
|
|
31
|
+
|
|
32
|
+
The QEA was authored with build 1628 (newer). The reference SVGs
|
|
33
|
+
were exported with build 1624. Either change the BUILD_ID constant
|
|
34
|
+
or accept the difference.
|
|
35
|
+
|
|
36
|
+
### 2. Frame tab width
|
|
37
|
+
- Ours: `points="6 26 135 26 148 13 148 6 6 6 6 26"` (width=129)
|
|
38
|
+
- Ref: `points="6 26 86 26 99 12 99 6 6 6 6 26"` (width=80)
|
|
39
|
+
|
|
40
|
+
EA calculates the tab width from GDI text metrics on the label
|
|
41
|
+
"class maintenance". Our calculation uses `label.length * 7 + 10`
|
|
42
|
+
which overshoots. Need a better text-width approximation, OR
|
|
43
|
+
match EA's hardcoded minimum (80px).
|
|
44
|
+
|
|
45
|
+
### 3. textLength attribute
|
|
46
|
+
- Ours: `textLength="65"`
|
|
47
|
+
- Ref: `textLength="73"`
|
|
48
|
+
|
|
49
|
+
Same root cause as #2 — text-width approximation differs from
|
|
50
|
+
GDI metrics.
|
|
51
|
+
|
|
52
|
+
### 4. Whitespace formatting
|
|
53
|
+
- Ours: extra blank lines between `<g>` blocks
|
|
54
|
+
- Ref: no blank lines, tabs for indentation
|
|
55
|
+
|
|
56
|
+
Cosmetic only — doesn't affect rendering.
|
|
57
|
+
|
|
58
|
+
## Aggregate parity gaps (across 188 diagrams)
|
|
59
|
+
|
|
60
|
+
### Polygon under-rendering (-166)
|
|
61
|
+
Source-side diamond markers on Aggregation connectors. The diamond
|
|
62
|
+
anchor positions drift from EA because connector SX/SY/EX/EY
|
|
63
|
+
interpretation isn't exact. Markers render but at slightly wrong
|
|
64
|
+
positions, breaking the per-anchor dedup match.
|
|
65
|
+
|
|
66
|
+
### Path under-rendering (-181)
|
|
67
|
+
EA combines connector line + arrow head into one `<path>` with
|
|
68
|
+
multiple `M` sub-paths. We emit them as separate paths. Restructure
|
|
69
|
+
`Connectors` renderer to emit combined paths per connector.
|
|
70
|
+
|
|
71
|
+
### Text under-rendering (-883)
|
|
72
|
+
Three categories:
|
|
73
|
+
1. Connector label positions (we use default offset; EA records
|
|
74
|
+
exact LLB/LRB boxes in t_diagramlinks.Geometry)
|
|
75
|
+
2. Attribute defaults (e.g. `lod: integerBetween0and4 = 1` — we
|
|
76
|
+
drop the `= default_value` part)
|
|
77
|
+
3. Stereotype-tagged-value text (we render the «property»
|
|
78
|
+
stereotype label on some diagrams where ref doesn't)
|
|
79
|
+
|
|
80
|
+
### Rect under-rendering (-460)
|
|
81
|
+
Mostly classifier-box compartment rects that EA emits as inner
|
|
82
|
+
rects (not paths) for some diagram configurations. Also legend
|
|
83
|
+
swatches inside Note elements. Not yet investigated thoroughly.
|
|
84
|
+
|
|
85
|
+
## Priority order for closing remaining gaps
|
|
86
|
+
|
|
87
|
+
1. **Combined connector paths** — fixes path -181, no architectural change
|
|
88
|
+
2. **QEA geometry parser for LLB/LRB** — fixes most of text -883
|
|
89
|
+
3. **Attribute default value rendering** — fixes some text delta
|
|
90
|
+
4. **Frame tab width calculation** — fixes byte-diff on simple diagrams
|
|
91
|
+
5. **Rect inner-compartment rendering** — fixes rect -460
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# 17 - Italic Rendering for Abstract Classes
|
|
2
|
+
|
|
3
|
+
## Status: DONE (2026-07-23)
|
|
4
|
+
|
|
5
|
+
## Outcome
|
|
6
|
+
|
|
7
|
+
Updated `Elements#header_lines` to handle the abstract + stereotype
|
|
8
|
+
combination: when a class is abstract AND has a stereotype, emit
|
|
9
|
+
both lines (stereotype normal, name italic with `_` prefix).
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
if classifier.is_abstract
|
|
13
|
+
lines << ["«abstract»", :normal] if classifier.stereotype_refs&.any?
|
|
14
|
+
lines << ["_#{classifier.name}", :italic]
|
|
15
|
+
elsif classifier.stereotype_refs&.any?
|
|
16
|
+
lines << ["«#{stereotype}»", :normal]
|
|
17
|
+
lines << [name, :bold]
|
|
18
|
+
else
|
|
19
|
+
lines << [name, :bold]
|
|
20
|
+
end
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Abstract classes now render matching EA's encoding:
|
|
24
|
+
`<text style="font-style:italic;...">_TransportationObject</text>`.
|
|
25
|
+
|
|
26
|
+
## Files changed
|
|
27
|
+
|
|
28
|
+
- `lib/ea/svg/ea_emitter/elements.rb` — `header_lines` abstract+stereotype branch
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# TODO-D 17: Remaining Parity Gaps
|
|
2
|
+
|
|
3
|
+
## Current State (2026-07-26)
|
|
4
|
+
|
|
5
|
+
- Text overlap: **87.2%** (Jaccard, set-equality per `<text>` content)
|
|
6
|
+
- Text count delta: **-83** (-0.4% vs reference; effectively at parity)
|
|
7
|
+
- Shape counts: rect -460 (-20.9%), polygon -166 (-11.2%), path -181 (-5.1%)
|
|
8
|
+
- Within tolerance: 123/188 diagrams (65.4%)
|
|
9
|
+
|
|
10
|
+
## Closed Gaps
|
|
11
|
+
|
|
12
|
+
1. QEA `$LLB=...;LLT=...;LRB=...;LRT=...` parsing — only first segment
|
|
13
|
+
carries `$`, the rest are `KEY=` after `;`. Fixed.
|
|
14
|
+
2. Connector label rendering at LLT/LRT box positions, with role + «property»
|
|
15
|
+
+ mult. Fixed.
|
|
16
|
+
3. Abstract class underscore — the underscore lives in the QEA class name
|
|
17
|
+
itself (`_CityObject`), not added by EA at render time. Fixed.
|
|
18
|
+
4. Enumeration `«enumeration»` stereotype fallback. Fixed.
|
|
19
|
+
5. Connector-level stereotype label (e.g. «import» on Package connector).
|
|
20
|
+
Fixed.
|
|
21
|
+
6. Attribute default value rendering (`name: type [mult] = default`). Fixed.
|
|
22
|
+
7. Enumeration literal visibility marker (`<text> </text>` empty slot).
|
|
23
|
+
Fixed.
|
|
24
|
+
8. Multiplicity 1..1 → "1" rendering when paired with role name. Fixed.
|
|
25
|
+
|
|
26
|
+
## Open Gaps
|
|
27
|
+
|
|
28
|
+
### Text overlap (87.2% → target ~95%+)
|
|
29
|
+
|
|
30
|
+
1. **Auto-generated legend block** (~448 missing texts):
|
|
31
|
+
- "凡例" (Legend title, 12pt bold #003060)
|
|
32
|
+
- "GMLで定義されたクラス", "CityGMLで定義されたクラス",
|
|
33
|
+
"i-URで定義されたクラス" (3 color-coded class titles)
|
|
34
|
+
- "GMLに定義されたクラス", "CityGMLに定義されたクラス",
|
|
35
|
+
"i-URに定義されたクラス" (alternative particle に instead of で)
|
|
36
|
+
- EA auto-generates these when a diagram contains color-coded
|
|
37
|
+
stereotype elements. Source data location TBD — likely tied to
|
|
38
|
+
diagram-type or per-diagram MDGDgm flag.
|
|
39
|
+
|
|
40
|
+
2. **Ghost element discriminator** (TODO-D 20, deferred):
|
|
41
|
+
- Some elements without explicit `font=` in their ObjectStyle get
|
|
42
|
+
ghost rendering (7pt #595959, no attrs); others get full rendering.
|
|
43
|
+
- Tested font_family presence → broke parity (-5000 texts).
|
|
44
|
+
- Tested classifier.package_id match → broke parity (-1500 texts).
|
|
45
|
+
- Real discriminator likely combines: ObjectStyle detail level +
|
|
46
|
+
diagram context + classifier source package. Needs EA.exe
|
|
47
|
+
disassembly reference.
|
|
48
|
+
|
|
49
|
+
3. **Missing class headers** (~150 instances):
|
|
50
|
+
- Elements like `_AbstractGeometricAggregate`, `_CityObject`,
|
|
51
|
+
`_Site`, `_Feature`, `_TransportationObject` appear in reference
|
|
52
|
+
SVGs but not in t_diagramobjects for the diagram.
|
|
53
|
+
- Cause: either EA renders implicit elements from connector
|
|
54
|
+
endpoints, or the reference SVGs were generated from a different
|
|
55
|
+
QEA version than what we have.
|
|
56
|
+
|
|
57
|
+
4. **`(from CityGML2.0)` qualifier** (9 instances):
|
|
58
|
+
- EA shows a sub-line for elements imported from a specific
|
|
59
|
+
package version.
|
|
60
|
+
- Source: probably t_object.Package_ID joined with t_package
|
|
61
|
+
version metadata.
|
|
62
|
+
|
|
63
|
+
### Shape counts
|
|
64
|
+
|
|
65
|
+
1. **rect -460**:
|
|
66
|
+
- ~3 rects per diagram missing from legend block (container with
|
|
67
|
+
rx=3 + 3 color swatch rects). 188 diagrams × ~3 = ~564 expected,
|
|
68
|
+
close to actual -460 gap.
|
|
69
|
+
- Need legend modeling first (depends on Text gap #1).
|
|
70
|
+
|
|
71
|
+
2. **polygon -166**:
|
|
72
|
+
- Per-diagram marker counts differ — EA emits duplicate polygons
|
|
73
|
+
at overlapping connector endpoints (e.g. 7 identical triangles
|
|
74
|
+
at one position). Cause unknown.
|
|
75
|
+
- Likely needs investigation of t_diagramlinks.Hidden vs visible
|
|
76
|
+
flag and how EA consolidates markers.
|
|
77
|
+
|
|
78
|
+
3. **path -181**:
|
|
79
|
+
- EA splits connector paths into individual segments per
|
|
80
|
+
style group. We consolidate same-style paths into one `<g>`.
|
|
81
|
+
- Some diagrams have 30+ path delta — needs path-per-connector
|
|
82
|
+
vs grouped-path mode selection per diagram.
|
|
83
|
+
|
|
84
|
+
## Next Steps
|
|
85
|
+
|
|
86
|
+
1. Investigate auto-generated legend feature: how EA detects "this
|
|
87
|
+
diagram needs a legend" and where the legend text/colors come from.
|
|
88
|
+
2. Find a reliable ghost-element discriminator (likely involves
|
|
89
|
+
per-element display flags we haven't parsed yet).
|
|
90
|
+
3. Investigate duplicate-polygon emission for overlapping markers.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# 18 - Canvas from image_bounds (matching EA)
|
|
2
|
+
|
|
3
|
+
## Status: DONE (2026-07-23)
|
|
4
|
+
|
|
5
|
+
## Outcome
|
|
6
|
+
|
|
7
|
+
`Canvas.from` now unions BOTH `bounds` and `image_bounds` for each
|
|
8
|
+
element. `image_bounds` captures the rendered extent (logical bounds
|
|
9
|
+
+ image padding), so the canvas grows to fit the full visual area.
|
|
10
|
+
|
|
11
|
+
Waterway canvas: 1138×869 → 1163×899 (ref=1138×892)
|
|
12
|
+
Building canvas: 1381×1524 → 1406×1554 (ref=1406×1530, width matches)
|
|
13
|
+
|
|
14
|
+
Remaining diff (25 px width on Waterway) is from image_bounds
|
|
15
|
+
extending further right than EA includes in canvas. Acceptable for
|
|
16
|
+
visual rendering — text and shapes are positioned correctly.
|
|
17
|
+
|
|
18
|
+
## Files changed
|
|
19
|
+
|
|
20
|
+
- `lib/ea/svg/ea_emitter/canvas.rb` — union bounds + image_bounds
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# TODO-D 18: Property lookup index (performance + OCP)
|
|
2
|
+
|
|
3
|
+
## Problem
|
|
4
|
+
|
|
5
|
+
`Ea::Svg::EaEmitter::Labels#property_at_end` walks every Classifier
|
|
6
|
+
and every Property on each Classifier to find a Property by ID:
|
|
7
|
+
|
|
8
|
+
```ruby
|
|
9
|
+
def property_at_end(association, end_kind)
|
|
10
|
+
id = end_kind == :source ? association.source_id : association.target_id
|
|
11
|
+
return nil unless id && model_index
|
|
12
|
+
|
|
13
|
+
model_index.values.each do |obj|
|
|
14
|
+
next unless obj.is_a?(Ea::Model::Classifier)
|
|
15
|
+
found = (obj.properties || []).find { |p| p.id == id }
|
|
16
|
+
return found if found
|
|
17
|
+
end
|
|
18
|
+
nil
|
|
19
|
+
end
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
For the 205-diagram plateau QEA this is called once per visible
|
|
23
|
+
association per diagram (~10k calls × ~600 classifiers × ~10
|
|
24
|
+
properties = 60M comparisons). That is the dominant cost in SVG
|
|
25
|
+
rendering.
|
|
26
|
+
|
|
27
|
+
## Fix
|
|
28
|
+
|
|
29
|
+
Add a lazily-built property index to `Ea::Model::Document` keyed by
|
|
30
|
+
property id. Labels (and any future consumer) calls
|
|
31
|
+
`document.property_by_id[id]` for O(1) lookup.
|
|
32
|
+
|
|
33
|
+
This keeps the lookup logic in the model (model-driven) and avoids
|
|
34
|
+
each consumer rebuilding the same index (DRY).
|
|
35
|
+
|
|
36
|
+
## Acceptance
|
|
37
|
+
|
|
38
|
+
- `Document#property_index` returns `{ property_id => Property }`.
|
|
39
|
+
- `Labels#property_at_end` uses the index.
|
|
40
|
+
- Parity text overlap remains ≥ 87%.
|
|
41
|
+
- Specs continue to pass.
|
|
42
|
+
- `rake benchmark` (or ad-hoc timing) shows measurable speed-up.
|