Skip to content

Commit

Permalink
Add opt and or expressions.
Browse files Browse the repository at this point in the history
  • Loading branch information
q-uint committed Apr 10, 2024
1 parent ed895b4 commit e9a6fbd
Show file tree
Hide file tree
Showing 19 changed files with 409 additions and 312 deletions.
18 changes: 14 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# Railroad Diagrams
# Railroad Diagrams (or Syntax Diagrams)

Railroad diagrams are a way to visualize context-free grammars.

## How to Read

Expand All @@ -9,14 +11,22 @@ The following conventions are used:

- The following diagram shows values `A`, `B` and `C`, which must be specified. The required values are defined on the
main line of the diagram. (_ABNF_: `and = A B C`)
![explain-and](./testdata/explain-and.svg)

<img src="./testdata/explain-and.svg" alt="explain-and" height="100">

- The following diagram shows the optional value `A`. The value can be bypassed by following the empty path.
(_ABNF_: `opt = [A] B `)
![explain-optional](./testdata/explain-optional.svg)

<img src="./testdata/explain-optional.svg" alt="explain-optional" height="150">

- In the example below `A`, `B` and `C` are options. The value can be chosen from the options.
(_ABNF_: `or = A / B / C`)

<img src="./testdata/explain-or.svg" alt="explain-or" height="200">

## Example

![example-svg](./testdata/example1.svg)
<img src="./testdata/example1.svg" alt="example1" height="200">

## References

Expand Down
36 changes: 13 additions & 23 deletions internal/svg/bypass.go
Original file line number Diff line number Diff line change
@@ -1,39 +1,29 @@
package svg

import "fmt"
import (
"fmt"
)

type Bypass struct {
Element SVGable
}

func (b Bypass) SVG(start Point) (string, Point, Box) {
wrappedStart := Point{X: start.X + curveRadius*2, Y: start.Y}
wrappedSVG, wrappedEnd, wrappedBox := b.Element.SVG(wrappedStart)
_, _, wrappedBox := b.Element.SVG(start)
l := start.Y - wrappedBox.Position.Y + curveRadius

l := wrappedBox.Size.Y + (wrappedBox.Position.Y - start.Y) - curveRadius

curveStartSVG, curveStart, curveStartBox := CurveInvS{L: l}.SVG(start)
curveEndSVG, curveEnd, curveEndBox := CurveS{
L: curveStart.Y - wrappedEnd.Y - 2*curveRadius,
}.SVG(Point{
X: curveStart.X + wrappedBox.Size.X,
Y: curveStart.Y,
})
return fmt.Sprintf(
`<g class="rr-bypass">
<line x1="%.1f" y1="%.1f" x2="%.1f" y2="%.1f" stroke="black"/>
%s
<line x1="%.1f" y1="%.1f" x2="%.1f" y2="%.1f" stroke="black"/>
curveStartSVG, curveStart, curveStartBox := Line{RelativeEnd: Point{X: 2 * curveRadius, Y: l}}.SVG(start)
wrappedSVG, wrappedEnd, wrappedBox := b.Element.SVG(curveStart)
curveEndSVG, curveEnd, curveEndBox := Line{RelativeEnd: Point{X: 2 * curveRadius, Y: -l}}.SVG(wrappedEnd)
return fmt.Sprintf(`
<g class="rr-bypass">
<line x1="%.1f" y1="%.1f" x2="%.1f" y2="%.1f" stroke="black"/>%s
%s
<line x1="%.1f" y1="%.1f" x2="%.1f" y2="%.1f" stroke="black"/>
%s
</g>`,
start.X, start.Y, wrappedStart.X, wrappedStart.Y,
wrappedSVG,
wrappedEnd.X, wrappedEnd.Y, curveEnd.X, curveEnd.Y,

start.X, start.Y, curveEnd.X, curveEnd.Y,
curveStartSVG,
curveStart.X, curveStart.Y, curveStart.X+wrappedBox.Size.X, curveStart.Y,
wrappedSVG,
curveEndSVG,
), curveEnd, curveStartBox.Combine(wrappedBox).Combine(curveEndBox)
}
53 changes: 0 additions & 53 deletions internal/svg/curve.go

This file was deleted.

5 changes: 5 additions & 0 deletions internal/svg/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ func SetCurveRadius(r float64) {
curveRadius = r
}

// GetCurveRadius returns the configured curve radius.
func GetCurveRadius() float64 {
return curveRadius
}

// SetStrokeWidth sets the stroke width of the curve.
func SetStrokeWidth(w float64) {
strokeWidth = w
Expand Down
6 changes: 3 additions & 3 deletions internal/svg/svg.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ type SVGable interface {
func DebugSVG(element SVGable, start Point) (string, Point, Box) {
svgElement, end, box := element.SVG(start)
return fmt.Sprintf(
`<g class="debug">
<circle cx="%.1f" cy="%.1f" r="2" fill="transparent" stroke="green" stroke-width="0.5"/>
%s
`
<g class="debug">
<circle cx="%.1f" cy="%.1f" r="2" fill="transparent" stroke="green" stroke-width="0.5"/>%s
<circle cx="%.1f" cy="%.1f" r="2" fill="transparent" stroke="green" stroke-width="0.5"/>
<rect x="%.1f" y="%.1f" width="%.1f" height="%.1f" fill="transparent" stroke="red" stroke-width="0.5"/>
</g>`,
Expand Down
26 changes: 6 additions & 20 deletions internal/svg/svg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,6 @@ import (

func TestCurve(t *testing.T) {
if os.Getenv("GENERATE_SVG") != "" {
for idx, e := range []struct {
element SVGable
start Point
}{
{CurveS{L: 10}, Point{X: 10, Y: 30}},
{CurveInvS{L: 10}, Point{X: 10, Y: 10}},
} {
svg, _, box := DebugSVG(e.element, e.start)
_ = os.WriteFile(fmt.Sprintf("testdata/curve%d.svg", idx), []byte(
fmt.Sprintf(
`<svg width="%.1f" height="%.1f" xmlns="http://www.w3.org/2000/svg">%s</svg>`,
box.Size.X+20, box.Size.Y+20, svg,
),
), 0644)
}

t.Run("lines", func(t *testing.T) {
for _, size := range []float64{1, 10} {
var combinedSVG string
Expand Down Expand Up @@ -55,7 +39,8 @@ func TestCurve(t *testing.T) {
}
_ = os.WriteFile(fmt.Sprintf("testdata/lines%.0f.svg", size), []byte(
fmt.Sprintf(
`<svg viewBox="%.1f %.1f %.1f %.1f" xmlns="http://www.w3.org/2000/svg">%s</svg>`,
`<svg viewBox="%.1f %.1f %.1f %.1f" xmlns="http://www.w3.org/2000/svg">%s
</svg>`,
combinedBox.Position.X-10, combinedBox.Position.Y-10,
combinedBox.Size.X+20, combinedBox.Size.Y+20,
combinedSVG,
Expand All @@ -70,15 +55,15 @@ func TestCurve(t *testing.T) {
combinedBox := Box{Position: start}
for _, e := range []SVGable{
Start{},
CurveS{L: 10},
Line{RelativeEnd: Point{X: 10, Y: -10}},
Line{RelativeEnd: Point{X: 10, Y: 10}},
Bypass{
Element: TextBox{Text: "Hello,"},
},
Line{RelativeEnd: Point{X: 10, Y: -10}},
TextBox{Text: "World!", RoundedBorders: true},
Line{RelativeEnd: Point{X: 10}},
CurveInvS{L: 10},
Line{RelativeEnd: Point{X: 10, Y: 10}},
End{},
} {
svg, end, box := DebugSVG(e, start)
Expand All @@ -89,7 +74,8 @@ func TestCurve(t *testing.T) {
}
_ = os.WriteFile("testdata/total.svg", []byte(
fmt.Sprintf(
`<svg viewBox="%.1f %.1f %.1f %.1f" xmlns="http://www.w3.org/2000/svg">%s</svg>`,
`<svg viewBox="%.1f %.1f %.1f %.1f" xmlns="http://www.w3.org/2000/svg">%s
</svg>`,
combinedBox.Position.X-10, combinedBox.Position.Y-10,
combinedBox.Size.X+20, combinedBox.Size.Y+20,
combinedSVG,
Expand Down
6 changes: 0 additions & 6 deletions internal/svg/testdata/curve0.svg

This file was deleted.

6 changes: 0 additions & 6 deletions internal/svg/testdata/curve1.svg

This file was deleted.

99 changes: 50 additions & 49 deletions internal/svg/testdata/lines1.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit e9a6fbd

Please sign in to comment.