Exit Full View

Vectorial / todo.txt

todo.txt
========

Current commit
==============


Geometry.controlPoints() looks odd. Is this different to Shape.controlPoints?

Bugs
====

Fix Shape.delete() - It should remove from the selection if need be.
    Maybe have a deleteOnly() method too.
    See ShapeButton.
See ControlPointButton - another ugly, and slightly wrong code.

Can't move groups

Application crashes on old laptop which doesn't support multi-sample OpenGL.
    Should replace with a scaled up Texture as an intermediate instead.

How do we break connections to deleted shapes?

Not really a "bug", but if you are in the "middle" of History, and then change the selection
    e.g. by clicking to clear the selection,
    then all future is lost.
    We could have a "Tree" structure, and only throw away other branches when non Skippable changes are made.
        Redo will prefer the "other" branch
        When adding a new Batch, check if it is Skippable, copy the future to another list
            otherwise, throw away the other list (if there is one).
        canRedo and redo check the "other" list first, and then the "main" list.

Debug doesn't update when shapes are added/deleted.

Application hangs when an exception is thrown during draw().

Next
====

ControlPointToolBar to use a label of EdgeConnectionType, not the name.

When making a connection, if Ctrl is LIFTED, then make the connection NOW.

Copyright headers

Allow shapes to be added DIRECTLY to a diagram (without layers)
    Remove the tests for "last layer" in DeleteLayer
    Diagram becomes a ShapeParent

Select All should only select from the current layer.
    SelectEverything should be Select from all layers

DebugDockable should have the same items selected as the current selection.
    Therefore, it needs Multi-selection model.
    When you select from the DebugDockable, that should change the selection.
        Ignore while processing SelectionChanges though!

GuideLine is a bit of a bodge, with a LARGE delta to ensure you can't see the ends.
    Maybe it should be a Shape, not a Geometry, and/or have special code in the main draw() method?
    NOTE, there will be similar problems when we introduce other "construction lines", such as tangent to a circle.
Also, it's a bit of a bodge to put the guidelines at the start, and all other shapes later.
    But I guess when layers are implemented, all guides/construction lines can be put in their own layer?

Load/Save SVG
    Requires :
        Path to be implemented first!
        Transformations for non-trivial svg files.
        Layer *could* be ignored for now though?
    Parse "regular" svg, so all attributes use Constant Expressions.
    Use an intermediate representation using "data" classes. Using one of these APIs :
        https://simple.sourceforge.net/download/stream/doc/tutorial/tutorial.php
        https://www.baeldung.com/jaxb

        At a later stage, we can add additional data (using a new `vectorial` namespace),
            for non-constant attributes. In this case, the "plain" svg will contain the evaluation of the points
            (i.e. redundant data for vectorial, but useful for non-vectorial applications).
        Only include "vectorial" extra stuff in the output if there are non-constants in shapes attributes.

Edit layer names

When changing numeric attributes via text fields, each change will be a new batch,
but subsequent changes (of merge-able types) should merge with the previous BATCH.
    Instead of "now", use "nowMergeBatch".
    Maybe include a time aspect too. If the previous batch was AGES ago, then don't merge.
Maybe a preference to only update when ENTER is pressed, or the field loses focus?
    Or maybe ALWAYS do that!?!
Also, scroll-wheel to adjust numbers.

Next major goal is to draw a class diagram. Requirements :
    Copy/Paste, so that we can create multiple copies of lines/boxes.
        Make a copy of the shape(s), initially reusing the same expression instances for each attribute.
        As we go, make a mapping between src and dest attributes
        Make a second pass through every attribute of the dest, and reassign their expressions using this mapping
            This will be recursive, as every Expression can have child expressions.
            e.g. Constant<*>.copy( mapping ) = this
            BinaryFunction.copy( mapping ) = BinaryFunction(label, a.copy(mapping), b.copy(mapping))
    Dashed strokes
        A minor concern - we could just use a different color line for now.
    Add User defined connection points (control points, which do nothing!).
        These will generally be placed "along" an Edge.
    Smart Shapes
        Maybe have a "special" diagram, where each layer is a different smart shape
            (remember, layer is a subclass of group, and SmartShape would be a subclass of Layer)
            OR add them to the regular diagram, but omit SmartShapes from the list of regular layers
                Therefore they will never be drawn, nor seen in the LayersDockable.
            As smartShapes are a Group (which has no ControlPoints of its own), then
                adding custom ControlPoints will be "obvious"
            Pro - smart shapes would be incapable of having Shapes on different layers
        Smart Sheets have different varieties, which differ by how you place them :
            Lines are placed by dragging the start and end points
            Fixed-Size are placed by clicking where you want the object.
            Rectangular placed similar to how Rectangle is placed.
                Maybe subdivided into centered and corner-based.
        Use a different background color for each type.
        Note :
            Fixed-size would have a 'position'
            Centered would have 'center' and 'size'
            Corner-based would have 'startCorner' and 'endCorner'
            Lines would have start/end
            So we could define an interface/subclass for each. (sealed class)

    TextShape
        Damn. We need to create meshes of each glyph. I was hoping we could avoid that!
        I guess we could use outlines only for a while!
    Nice to have features :
        Custom attributes
            An extra Attributes instance per Shape.
            Hmm, Shape doesn't have attributes of its own at the moment! Should it?
        "Inherited" attributes.
            When we copy/paste, any tagged as inherited are not COPIED, but referenced.
                i.e. the copy uses src.attribute instead of src.attribute.expression.copy( mapping )
            This will let us

Instead of preventing ControlPoints to be connected to the same SHAPE,
    check if the connection depends on the ControlPoints attribute.

MainWindow should only handle 1 Document
    Open a new window to edit a second document

DebugDockable
    Has been neutered due to lack of Expression.dependencies.
        We could add it back as a function, which implementation can choose to implement if they wish.
            e.g. BinaryFunction.dependencies() = listOf( a, b )
            But maybe as a String->Expression Map e.g. = mapOf ("a" to a, "b" to b )
    Probably better to wait till the parser and reverse parser has been implemented
    When an expression is a UnaryFunction or BinaryFunction,
        expand children, to form a gui like so :
             ( a + b ) / ( -c )
        Instead of :
            ( a / b )
            where [a] can be expanded to ( a + b )
            and b can be expanded to -a
    Not nearly enough data is included. e.g. Connector's data.

ConnectionPoints
    e.g. The point where a rounded corner meets the straight edge.
    These could be implemented as ExpressionControlPoint??
        As the expression is not a Connection, they will appear fixed
        We can also have ConnectionPoint.isBreakable(), which will return false.

Rounded corners on Rectangle.
    We will have a Vector2 for the cornerRadius, but the control points will only affect either x or y.
        We should be able to change the cornerRadius Attribute in a "sensible" way, so that each can be
        changed individually.
    Vector2Expression.xFrom(...) and yFrom(...) should create a "special" class
        Vector2SplitExpression( xExpression, yExpression )
    We can then change each independently.

Consider adding a transformation matrix to all Shapes.
    Have worldToLocal and localToWorld methods to convert.
    The matrix should be an attribute?

NormalAt / TangentAt of a control point
    For Bezier start/end points
        Include a "distance" parameter, so arrows at the end of tight bends look good.
            i.e. the line is still in the center of arrow.


Implement Path class
    I was going to build them from Line and Bezier, but I'm not sure that's a good idea.
    Each Node can have a RADIUS, or CHAMFER - implemented in toPolyline, and is NOT part of the geometry.
        Also have a DEFAULT rounding for all corners
        Similarly, for Quadrilateral and Polygon,


Add GUI to build paths

Port polyclipping to Kotlin :
    https://sourceforge.net/projects/polyclipping/
    Offsetting included ;-)

Shape has ONE mesh for fill, but many for stroke. Why?
    Why does Mesh have a thickness?
        I think it was when I was trying to do anti-aliasing, and is no longer needed.
    Why does Mesh have a length?
        For gradients along the line?
            But that still doesn't make sense, all we need are UV values in the range 0..1
        So I think this was for anti-aliasing too, and is no longer needed.
    Therefore, stroke only needs 1 mesh too.
        We should ensure that we don't need to concatenate meshes, but ADD to them instead.
            But at the moment, Mesh uses immutable lists.
        This may not be a big deal, as meshes are only rebuilt as the shape changes.


Design Questions
================

Do we need the Attributes class?
    Can we not just have a simple list of Attribute?
    It is used to invalidate polylines/meshes/bounding boxes.
        So that means that any expression that affects the meshes/polylines must be an Attribute.
            NOTE. Path will have to listen to every section's Attributes, and invalidate the Paths cache too.

Should Attribute have access to the Shape (or Diagram etc.) that it belongs to?
    No. Only the Parser needs to know the "context", so that expression can refer to other expressions in the Shape.

Should we send out a message for every Change, or every Batch?
    Change is needed for redrawing.

Visio makes a distinction between 2D and 1D shapes, but Vectorial doesn't.
    Is this a problem?

When do we remove Expression.usedBy?
    We create Shapes before adding them to Diagrams, so there can be connections. Eek!

It's not clear how ShapeStyle should be implemented.
    At the moment, `fill` and `stroke` are simple ColorAttributes.
    At some point, these will be replaced by `Paint` objects, which will have their own Attributes.


Later
=====

Each shape to have a "visible" BooleanAttribute
    We'd also need a toggle to show invisible shapes!

Mate two edges together???
    Can this also be applied to tessellate the new "Einstein" tile, and Penrose tiles?
        For Einstein, we would need to flip too :-(

Split vectorial-graphics into :
    vectorial-javafx, vectorial-opengl and vectorial-javafx-opengl ???
    vectorial-javafx-opengl contains glue which ties them together.
    DiagramView needs a Renderer interface to draw to.
        But the Renderer interface won't have a way to pass the result back as a JavaFX Image, nor renderer it onto a display.
    DiagramView would need to be given something, which given a Renderer can return a JavaFX Image.
        So an ImageMaker interface in -javafx, which is implemented in -javafx-opengl

When dragging a bezier's control point, whose start/end is a ConnectionToEdge,
    show the tangent, and allow it to be constrained along it.
    How do we reset it when start/end connection is broken?

Another EdgeConnection Type(s)
    For complex shapes, such as Paths and Stars/Polygons, we could connect as a ratio around the whole shape
    Also, connect from a given direction
        We should be able to connect between two "boxes" of arbitrary shape, so that the line touches the
            "correct" edge.

Create Visio style custom reusable objects.

Implement the Parser.
    Note, Change could be one of the basic types supported.
    A custom ControlPoint could have "actions", by having a ChangeExpression.
        Use "and" operator to combine lots of changes together.

Implement Group : Shape
    Also need to be able to "enter" a group.

Layers
    Implement as a subclass of Group.

AddNodeMode - Add nodes by clicking along the path.

Implement TextShape

When exporting our images to pngs, we need a DPI-like scaling factor, to translate from world coordinates to pixels.
Maybe also have a String for the world units. e.g. "mm" (default is blank?")

How are "inset/outset" shapes implemented?
    Listener to the source's geometry, and rebuild the geometry (lazily).
        But if other shapes are connected to it, then the connections will be orphaned.
        So we would need to reuse the existing Attribute instances.
            This would get tricky, and I would need to write the outset function :-(
    OR Have a Shape of type Outset, and do post-processing whenever it is converted to Polylines.
        In this case it wouldn't be a Shape (as it has no geometry of its own)
        Therefore we couldn't connect to it directly.
        BUT, Maybe we could still connect to it with a special AlongOutsetExpression.
    See TouchingToken above/below.
        Instead of having a single threshold, have an offset AND a threshold.
            i.e. the distance has to be in the range offset +/- threshold
                NOTE, the distance must be signed!
            But this wouldn't work well near corners (without extra work)
                Also, an inset can even make holes close up (disappear).

Other Zoom options - Fit, Fit width, Fit height, Fit selection.
    (Include hard-coded margins?)
    Make Zoom Reset a SplitMenuButton, with other zoom options as menu items???

Geometry.DEFAULT_XXX_TOLERANCE could be a preference
    Also, consider multiple preferences e.g. for editing and for final rendering.
    NOTE, We would need to clear cached polygons/meshes when changing from one to another.

A shortcut select all guidelines.

VectorialPreference
    Save to Java Preferences.
    Add a GUI to edit these preferences from within the application.

Load/Save diagrams.
    Consider saving as SVG, with addition data added for all non-constant expressions.
        Similar to sodipodi: and inkscape: tags.
    Use History.savesIndex to know when the diagram has changed since the last save.

Much Later
==========

Warping Shapes
    Start with the inner's bounding box, and allow it to be transformed into any 4 sided polygon
    Then allow each side of the "polygon" to be bezier curves ;-)
        Maybe a Quad, rather than the usual Cubic??
        And/Or constrained to avoid nasty edge cases? - e.g. down let the control point go above or below the quadrilateral.
    We need WarpedShape, as well as WarpedGeometryShape.
        WarpedShape should magically convert between the different coordinates using a special Attributes
        implementation.
        Hmm, maybe Geometry should BE an implementation of Attributes, rather than HAVING Attributes?

Customisation for toolbars (part of fxessentials).
    To hide/show buttons based on a BooleanProperty, we also need to use the auto-hide thingy!
Make toolbars draggable to any side of the main window. Perhaps as part of HarbourFX?
    Each side should be capable of having many toolbars.

Allow a document to have multiple diagrams.
    Each diagram has a unique name.
    Diagram.create()
    AddDiagramChange ...

A command line option, which lets vectorial be launched from other applications.
    e.g. Send it a diagram, and on save, it returns the diagram
        Either via data on stdout, or just the filename on stdout.
        Maybe with an option for using SVG instead of Vectorial file type.

Code Review
===========

Check all to dos
Test coverage
    All of -core should be covered using JUnit
Are Dokka comments sufficient
Are names of functions/classes etc sensible?
    e.g. Centered isn't!
Look for potential memory leaks
    JavaFX listeners are a likely source
Draw Class Diagrams for key classes.