# Diagram

Rectangles represent software components.

Circles represent ports.

• Green circles represent input ports.
• Yellow circles represent output ports.

Port circles are situated on the edges of component rectangles.

[Ports will be connected together as discussed in a future essay.]

[Design Rule checking - aka error checking - is briefly touched upon below, and will be discussed in detail in a future essay.]

# Contains Relationships

The diagram editor only knows about rectangles and circles (and colors)1.

We create a compiler phase that associates circles with rectangles.

In this case, we say that a circle is contained by a rectangle if exactly 3 sides of the bounding box of the circle are inside the rectangle.

The code (PROLOG) below emits `contains` relationships for each circle that meets the above conditions.

Again, to emphasize the point, this is not rocket science, but is grade-school math.

We want something that is easy to write and easy to understand.

Optimization Engineers can rewrite the code if necessary (albeit unlikely with modern hardware).

``````containsport(R,C):-
rightsideinsideBB(C,R).
containsport(R,C):-
leftsideinsideBB(C,R).
containsport(R,C):-
bottomsideinsideBB(C,R).
containsport(R,C):-
topsideinsideBB(C,R).

rightsideinsideBB(Circle,Rect):-
rect(Rect,''),
ellipse(Circle,''),
l(Rect,Rl),   t(Rect,Rt),   r(Rect,Rr),   b(Rect,Rb),
l(Circle,Cl), t(Circle,Ct), r(Circle,Cr), b(Circle,Cb),
Cl =< Rl,
Ct >= Rt, Ct =< Rb,
Cr >= Rl, Cr =< Rr,
Cb >= Rt, Cb =< Rb.
leftsideinsideBB(Circle,Rect):-
rect(Rect,''),
ellipse(Circle,''),
l(Rect,Rl),   t(Rect,Rt),   r(Rect,Rr),   b(Rect,Rb),
l(Circle,Cl), t(Circle,Ct), r(Circle,Cr), b(Circle,Cb),
Cl =< Rr, Cl >= Rl,
Ct >= Rt, Ct =< Rb,
Cr >= Rr,
Cb >= Rt, Cb =< Rb.
bottomsideinsideBB(Circle,Rect):-
rect(Rect,''),
ellipse(Circle,''),
l(Rect,Rl),   t(Rect,Rt),   r(Rect,Rr),   b(Rect,Rb),
l(Circle,Cl), t(Circle,Ct), r(Circle,Cr), b(Circle,Cb),
Cl >= Rl, Cl =< Rr,
Ct =< Rt,
Cr >= Rl, Cr =< Rr,
Cb >= Rt, Cb =< Rb.
topsideinsideBB(Circle,Rect):-
rect(Rect,''),
ellipse(Circle,''),
l(Rect,Rl),   t(Rect,Rt),   r(Rect,Rr),   b(Rect,Rb),
l(Circle,Cl), t(Circle,Ct), r(Circle,Cr), b(Circle,Cb),
Cl >= Rl, Cl =< Rr,
Ct >= Rt, Ct =< Rb,
Cr >= Rl, Cr =< Rr,
Cb >= Rb.

allPortContains(B):-
bagof([R,C],containsport(R,C),B).

printAllPortContains:-
allPortContains(B),
printPortContains(B).
printAllPortContains.

printPortContains([]).
printPortContains([H|T]) :-
format("contains(~w,~w).~n",H),
printPortContains(T).

``````

# Port Direction Relationships

Circles colored green are given `input` relationships.

Circles colored yellow are given `output` relationships.

The code below creates these relationships. The rule `portdirection` recognizes the relationships. The rest of the code prints the relationships.

``````portdirection([P,'input']):-
ellipse(P,''),
color(P,"green").
portdirection([P,'output']):-
ellipse(P,''),
color(P,"yellow").
allDirections(Bag):-
bagof(Pair,portdirection(Pair),Bag).

printDirection([]).
printDirection([H|T]):-
format("portdirection(~w,~w).~n", H),
printDirection(T).

printAllDirections:-
allDirections(Bag),
printDirection(Bag).
printAllDirections.

``````

# Design Rules - Error Checks

We want to check for certain error conditions.

General type-checking is insufficient for our purposes.

We use the phrase `design rules` to mean error checks that are problem-specific.

We want to be able to compose design rule checks and snap them onto the code base.

This issue will be discussed in another essay.

# Run.bash

The script `run.bash`, at this point, is composed of 4 elements

1. Infer rectangles as components.
2. Infer circles as ports.
3. Infer the direction of ports, base on their color (`input` and `output` ; green and yellow, resp.)
4. Perform a design-rule check, quitting the script (the diagram compiler) if any orphan ports are found.

The top-level script is:

``````#!/bin/bash
./runrects.bash
mv fb.pl rects-fb.pl
./runports.bash
cat rects-fb.pl fb.pl >temp.pl
sort temp.pl >fb.pl

./rundesignrule.bash

``````

and the `runports.bash` script is

``````#!/bin/bash
sort ports.pl >fb.pl

./bb.bash >fb-bb.pl
cat fb.pl fb-bb.pl >temp.pl
sort temp.pl >fb.pl

swipl -g 'consult(fb).' \
-g 'consult(containsport).' \
-g 'printAllPortContains.' \
-g 'halt.' \
> fb-portcontains.pl

cat fb.pl fb-portcontains.pl >temp.pl
sort temp.pl >fb.pl
swipl -g 'consult(fb).' \
-g 'consult(portdirection).' \
-g 'printAllDirections.' \
-g 'halt.' \
> fb-directions.pl

cat fb.pl fb-directions.pl >temp.pl
sort temp.pl >fb.pl

``````

Reiterating: each phase of the diagram compiler produces a PROLOG-edible fb.pl file.

[Many PROLOG gurus would try to combine all of the phases into one. This would be an optimization, and an obfuscation. It is easier to think of each phase as a single, drop-dead simple entity. The DI (architecture) should retain this simplicity.]

# Appendix - Github

https://github.com/guitarvydas/diagram-parsing