Documentation

Original Commit by inigo-selwood
This commit is contained in:
Aadi Desai 2022-03-20 15:11:26 +00:00
parent c43910e438
commit 464c09a7dc
No known key found for this signature in database
GPG key ID: CFFFE425830EF4D9

View file

@ -334,21 +334,38 @@ let RISegsToVertices (segList: RISeg list) =
|> List.scan getRISegEnd segList[0].Start |> List.scan getRISegEnd segList[0].Start
|> List.map (fun pos -> pos.X, pos.Y) |> List.map (fun pos -> pos.X, pos.Y)
/// Get initial list of wire vertices given port locations corresponding to the enpoints of a wire /// Get initial list of wire vertices given port locations corresponding to the
let initialWireVerticesFromPorts (startPort:XYPos) (endPort:XYPos) (routetype:routeType) = /// enpoints of a wire
let startX, startY, endX, endY = startPort.X, startPort.Y, endPort.X, endPort.Y let initialWireVerticesFromPorts
(startPort: XYPos)
(endPort: XYPos)
(routetype: routeType): (list<XYPos> * bool) =
match routetype with let startX, startY, endX, endY =
| Oppositeside -> startPort.X, startPort.Y, endPort.X, endPort.Y
// adjust length of segments 0 and 6 - the sticks - so that when two ports are aligned and close you still get left-to-right routing.
// Oppositeside -> the two ports face one another
if routetype = Oppositeside then
// Adjust length of segments 0 and 6 - the sticks - so that when two
// ports are aligned and close, you still get left-to-right routing
let stickLength = let stickLength =
if (endX - startX > 0.0) then if (endX - startX > 0.0) then
let d = List.max [ abs (startX - endX) ; abs (startY - endY) ; Wire.stickLength / 4.0 ] [
min d (Wire.stickLength / 2.0) abs (startX - endX)
abs (startY - endY)
Wire.stickLength / 4.0
]
|> List.max
|> min (Wire.stickLength / 2.0)
else else
Wire.stickLength / 2.0 Wire.stickLength / 2.0
// Wire travelling left to right (positive X) from output port to input
// port
// S - + - + - + - E
if endX - startX >= stickLength * 2.0 then if endX - startX >= stickLength * 2.0 then
[ // Wire travelling left to right (positive X) from output port to input port [
{X = startX; Y = startY} {X = startX; Y = startY}
{X = startX + stickLength; Y = startY}; {X = startX + stickLength; Y = startY};
{X = startX + stickLength; Y = startY} ; {X = startX + stickLength; Y = startY} ;
@ -357,10 +374,18 @@ let initialWireVerticesFromPorts (startPort:XYPos) (endPort:XYPos) (routetype:ro
{X = endX - stickLength; Y = endY} {X = endX - stickLength; Y = endY}
{X = endX - stickLength; Y = endY} {X = endX - stickLength; Y = endY}
{X = endX; Y = endY} {X = endX; Y = endY}
], true // left to right ],
true // left to right
// Wire travelling right to left (negative X), but ports are (almost)
// aligned vertically An offset is added to the main horizontal segment
// so it can be seen / dragged more easily
//
// E - + - + + - + - S
// | |
// + - +
elif abs (startY - endY) < 4.0 then elif abs (startY - endY) < 4.0 then
[ // Wire travelling right to left (negative X), but ports are (almost) aligned vertically [
// An offset is added to the main horizontal segment so it can be seen / dragged more easily
{X = startX; Y = startY} {X = startX; Y = startY}
{X = startX + Wire.stickLength; Y = startY} {X = startX + Wire.stickLength; Y = startY}
{X = startX + Wire.stickLength; Y = startY} {X = startX + Wire.stickLength; Y = startY}
@ -369,9 +394,16 @@ let initialWireVerticesFromPorts (startPort:XYPos) (endPort:XYPos) (routetype:ro
{X = endX - Wire.stickLength; Y = endY} {X = endX - Wire.stickLength; Y = endY}
{X = endX - Wire.stickLength; Y = endY} {X = endX - Wire.stickLength; Y = endY}
{X = endX; Y = endY} {X = endX; Y = endY}
], false // not left to right ],
false // not left to right
// Wire travelling right to left (negative X), bending back on itself
//
// + - + - S
// |
// E - + - +
else else
[ // Wire travelling right to left (negative X), bending back on itself [
{X = startX; Y = startY} {X = startX; Y = startY}
{X = startX + Wire.stickLength; Y = startY} {X = startX + Wire.stickLength; Y = startY}
{X = startX + Wire.stickLength; Y = startY} {X = startX + Wire.stickLength; Y = startY}
@ -380,9 +412,23 @@ let initialWireVerticesFromPorts (startPort:XYPos) (endPort:XYPos) (routetype:ro
{X = endX - Wire.stickLength; Y = endY} {X = endX - Wire.stickLength; Y = endY}
{X = endX - Wire.stickLength; Y = endY} {X = endX - Wire.stickLength; Y = endY}
{X = endX; Y = endY} {X = endX; Y = endY}
], false // not left to right ],
|Rightangle -> false // not left to right
if (abs(endX-startX) >= Wire.stickLength) && (abs(endY-startY)>=Wire.stickLength) then
// Rightangle -> there's a 90 degree angle between the two ports
elif routetype = Rightangle then
// If the angle is a longer than the stick length, add a kink to the
// wire which will space it out more evenly
//
// S - + - +
// |
// +
// |
// E
if (endX - startX >= Wire.stickLength)
&& (endY - startY >= Wire.stickLength) then
[ [
{X = startX; Y = startY}; {X = startX; Y = startY};
{X = startX + Wire.stickLength; Y = startY}; {X = startX + Wire.stickLength; Y = startY};
@ -392,7 +438,18 @@ let initialWireVerticesFromPorts (startPort:XYPos) (endPort:XYPos) (routetype:ro
{X = endX ; Y = endY - Wire.stickLength} {X = endX ; Y = endY - Wire.stickLength}
{X = endX ; Y = endY - Wire.stickLength} {X = endX ; Y = endY - Wire.stickLength}
{X = endX; Y = endY} {X = endX; Y = endY}
], true ],
true // Left-to-right
// Otherwise, if either X or Y delta is smaller than the stick length,
// add some creative meandering
//
// + ---- +
// | |
// | + - S
// + - +
// |
// E
else else
[ [
{X = startX; Y = startY}; {X = startX; Y = startY};
@ -403,9 +460,23 @@ let initialWireVerticesFromPorts (startPort:XYPos) (endPort:XYPos) (routetype:ro
{X = endX; Y = endY - Wire.stickLength}; {X = endX; Y = endY - Wire.stickLength};
{X = endX; Y = endY - Wire.stickLength}; {X = endX; Y = endY - Wire.stickLength};
{X = endX; Y = endY} {X = endX; Y = endY}
], false ],
| Sameside -> false // Not left-to-right
if abs (endX-startX) >= Wire.stickLength*2.0 && endY >= startY then
// Sameside -> the two ports are facing in the same direction
elif routetype = Sameside then
// If the X distance is more than twice the sticklength, and
// the output port is *above* the input port
//
// E E
// | |
// S + or + S
// | | | |
// + - + + - +
if abs (endX - startX) >= Wire.stickLength * 2.0
&& endY >= startY then
[ [
{X = startX; Y = startY}; {X = startX; Y = startY};
{X = startX ; Y = startY - Wire.stickLength}; {X = startX ; Y = startY - Wire.stickLength};
@ -415,7 +486,16 @@ let initialWireVerticesFromPorts (startPort:XYPos) (endPort:XYPos) (routetype:ro
{X = endX ; Y = endY - Wire.stickLength} {X = endX ; Y = endY - Wire.stickLength}
{X = endX ; Y = endY - Wire.stickLength} {X = endX ; Y = endY - Wire.stickLength}
{X = endX; Y = endY} {X = endX; Y = endY}
], true ],
true // Left-to-right
// Otherwise if the start port is above the end port:
//
// S S
// | |
// E + or + E
// | | | |
// + - + + - +
elif abs (endX - startX) >= Wire.stickLength * 2.0 then elif abs (endX - startX) >= Wire.stickLength * 2.0 then
[ [
{X = startX; Y = startY}; {X = startX; Y = startY};
@ -426,7 +506,17 @@ let initialWireVerticesFromPorts (startPort:XYPos) (endPort:XYPos) (routetype:ro
{X = endX ; Y = endY - Wire.stickLength} {X = endX ; Y = endY - Wire.stickLength}
{X = endX ; Y = endY - Wire.stickLength} {X = endX ; Y = endY - Wire.stickLength}
{X = endX; Y = endY} {X = endX; Y = endY}
], true ],
true // Left-to-right
// And last but not least, if the X distance is less than two stick
// lengths' worth:
//
// S E
// | |
// + - + E or S + - +
// | | | |
// + - + + - +
else else
[ [
{X = startX; Y = startY}; {X = startX; Y = startY};
@ -437,7 +527,12 @@ let initialWireVerticesFromPorts (startPort:XYPos) (endPort:XYPos) (routetype:ro
{X = endX; Y = endY - Wire.stickLength}; {X = endX; Y = endY - Wire.stickLength};
{X = endX; Y = endY - Wire.stickLength}; {X = endX; Y = endY - Wire.stickLength};
{X = endX; Y = endY} {X = endX; Y = endY}
], false ],
false // Not left-to-right
else
failwith "route type not recognized"
/// Infer whether wire is LeftToRight from vertices /// Infer whether wire is LeftToRight from vertices
let inferOrientationFromVertices (xyVerticesList: XYPos list) : bool option = let inferOrientationFromVertices (xyVerticesList: XYPos list) : bool option =
@ -667,11 +762,22 @@ let makeASegPos (seg : ASeg) =
let makeRISegPos (seg: RISeg) = let makeRISegPos (seg: RISeg) =
{ seg with Start = absXYPos seg.Start } { seg with Start = absXYPos seg.Start }
/// Initial list of absolute segments based on positions of ports to be connected /// Initial list of absolute segments based on positions of ports to be
/// connected.
/// Does some cool stuff to allow for routing between ports of rotated
/// components using reflection/rotation of 3 basic patterns
let makeInitialASegList (hostId: ConnectionId) let makeInitialASegList (hostId: ConnectionId)
(inputPort: Symbol.PortOrientation * XYPos) (outputPort: Symbol.PortOrientation * XYPos) : list<ASeg> = (inputPort: Symbol.PortOrientation * XYPos)
let inputPortPos, (inputPortOri:Symbol.PortOrientation), outputPortPos,(outputPortOri:Symbol.PortOrientation) = snd inputPort, fst inputPort, snd outputPort, fst outputPort (outputPort: Symbol.PortOrientation * XYPos)
: list<ASeg> =
// Get (input, output) port positions and orientations
let inputPortPos, outputPortPos = snd inputPort, snd outputPort
let (inputPortOri: Symbol.PortOrientation),
(outputPortOri: Symbol.PortOrientation) =
fst inputPort, fst outputPort
// Lil' cheeky functor to flip positions about the x axis
let reverse_rotate = let reverse_rotate =
function function
| PosY -> PosY | PosY -> PosY
@ -679,27 +785,39 @@ let makeInitialASegList (hostId: ConnectionId)
| NegY -> NegY | NegY -> NegY
| NegX -> PosX | NegX -> PosX
// There's 3 types of route conditions:
// - SameSide
// - RightAngle
// - OppositeSide
//
// Based on the direction of the port coming out of the input (and into the
// output), we pick a shape of route, a rotation direction, and whether or
// not the wire requires reflection.
let routetype, rotation, yreflect = let routetype, rotation, yreflect =
match outputPortOri, inputPortOri with match outputPortOri, inputPortOri with
| Symbol.Top, Symbol.Top -> Sameside, PosY, false | Symbol.Top, Symbol.Top -> Sameside, PosY, false
| Symbol.Top, Symbol.Right -> Rightangle, NegX, true | Symbol.Top, Symbol.Right -> Rightangle, NegX, true
| Symbol.Top, Symbol.Bottom -> Oppositeside, NegX, false | Symbol.Top, Symbol.Bottom -> Oppositeside, NegX, false
| Symbol.Top, Symbol.Left -> Rightangle, NegX, false | Symbol.Top, Symbol.Left -> Rightangle, NegX, false
| Symbol.Right, Symbol.Top -> Rightangle, PosY, false | Symbol.Right, Symbol.Top -> Rightangle, PosY, false
| Symbol.Right, Symbol.Right -> Sameside, PosX, false | Symbol.Right, Symbol.Right -> Sameside, PosX, false
| Symbol.Right, Symbol.Bottom -> Rightangle,NegY, true | Symbol.Right, Symbol.Bottom -> Rightangle,NegY, true
| Symbol.Right, Symbol.Left -> Oppositeside, PosY, false | Symbol.Right, Symbol.Left -> Oppositeside, PosY, false
| Symbol.Bottom, Symbol.Top -> Oppositeside, PosX, false | Symbol.Bottom, Symbol.Top -> Oppositeside, PosX, false
| Symbol.Bottom, Symbol.Right -> Rightangle, PosX, false | Symbol.Bottom, Symbol.Right -> Rightangle, PosX, false
| Symbol.Bottom, Symbol.Bottom -> Sameside, NegY, false | Symbol.Bottom, Symbol.Bottom -> Sameside, NegY, false
| Symbol.Bottom, Symbol.Left -> Rightangle, PosX, true | Symbol.Bottom, Symbol.Left -> Rightangle, PosX, true
| Symbol.Left, Symbol.Top -> Rightangle, PosY, true | Symbol.Left, Symbol.Top -> Rightangle, PosY, true
| Symbol.Left, Symbol.Right -> Oppositeside, NegY, false | Symbol.Left, Symbol.Right -> Oppositeside, NegY, false
| Symbol.Left, Symbol.Bottom -> Rightangle, NegY, false | Symbol.Left, Symbol.Bottom -> Rightangle, NegY, false
| Symbol.Left, Symbol.Left -> Sameside, NegX, false | Symbol.Left, Symbol.Left -> Sameside, NegX, false
let inputPortPos' = // Get the adjusted input port position, applying any rotations and
// reflections
let inputPortPos': XYPos =
let relativePos = let relativePos =
inputPortPos - outputPortPos inputPortPos - outputPortPos
|> rotate_rel (reverse_rotate rotation) |> rotate_rel (reverse_rotate rotation)
@ -707,11 +825,24 @@ let makeInitialASegList (hostId: ConnectionId)
relativePos + outputPortPos relativePos + outputPortPos
(*
printfn $"outputPortPos:{outputPortPos}, inputPortPos':{inputPortPos'}, inputPortPos:{inputPortPos}" printfn $"outputPortPos:{outputPortPos}, inputPortPos':{inputPortPos'}, inputPortPos:{inputPortPos}"
printfn $"inputPortOri:{inputPortOri}, outputPortOri:{outputPortOri}" printfn $"inputPortOri:{inputPortOri}, outputPortOri:{outputPortOri}"
printfn $"routetype:{routetype}, rotation:{rotation}, yreflect:{yreflect}" printfn $"routetype:{routetype}, rotation:{rotation}, yreflect:{yreflect}"
let xyPairs, isLeftToRight = initialWireVerticesFromPorts outputPortPos inputPortPos' routetype *)
xyPairs |> convertVerticesToASegs hostId isLeftToRight routetype rotation yreflect outputPortPos
let (xyPairs: list<XYPos>), (isLeftToRight: bool) =
initialWireVerticesFromPorts outputPortPos inputPortPos' routetype
// Does a thing
convertVerticesToASegs
hostId
isLeftToRight
routetype
rotation
yreflect
outputPortPos
xyPairs
// TODO: native RISeg implementation // TODO: native RISeg implementation
// Initial list of rotation invariant segments based on positions of ports to be connected // Initial list of rotation invariant segments based on positions of ports to be connected
@ -1872,30 +2003,52 @@ let update (msg : Msg) (model : Model) : Model * Cmd<Msg> =
|> Map.filter (fun id _ -> not (List.contains id connectionIds)) |> Map.filter (fun id _ -> not (List.contains id connectionIds))
{model with WX = newWX}, Cmd.ofMsg BusWidths {model with WX = newWX}, Cmd.ofMsg BusWidths
// Handles wire dragging request
| DragWire (connId : ConnectionId, mMsg: MouseT) -> | DragWire (connId : ConnectionId, mMsg: MouseT) ->
match mMsg.Op with match mMsg.Op with
// On a mouse press, select that given segment
| Down -> | Down ->
let segId = getClickedSegment model connId mMsg.Pos let segId = getClickedSegment model connId mMsg.Pos
{model with SelectedSegment = segId }, Cmd.none {model with SelectedSegment = segId }, Cmd.none
// On a mouse drag, move the segment the mouse is hovering over
| Drag -> | Drag ->
let aSeg =
let aSegOption = // Get the segment
let aSeg: ASeg =
// Picks the segment being selected from a list of all the
// wire's segments
let aSegOption: option<ASeg> =
let choiceFunctor (segment: ASeg): option<ASeg> =
if segment.Id = model.SelectedSegment then Some segment
else None
riSegWireToASegs model.WX[connId] riSegWireToASegs model.WX[connId]
|> List.choose ( fun aSeg -> if aSeg.Id = model.SelectedSegment then Some aSeg else None ) |> List.choose choiceFunctor
|> List.tryExactlyOne |> List.tryExactlyOne
// Make sure a segment was found
match aSegOption with match aSegOption with
| Some aSeg -> aSeg | Some aSeg -> aSeg
| None -> failwithf "Error: Segment Id not found in segment list" | None -> failwithf "Error: Segment Id not found in list"
// Check the segment is draggable; otherwise, do nothing
if aSeg.Draggable then if aSeg.Draggable then
// Evaluate the drag distance (perpendicular to the segment's
// direction) to the mouse position
let distanceToMove = let distanceToMove =
match aSeg.Dir with match aSeg.Dir with
| Horizontal -> mMsg.Pos.Y - abs aSeg.Start.Y | Horizontal -> mMsg.Pos.Y - abs aSeg.Start.Y
| Vertical -> mMsg.Pos.X - abs aSeg.Start.X | Vertical -> mMsg.Pos.X - abs aSeg.Start.X
// Create a new wire segment by dragging the current one, and
// insert it into the model
let newWire = moveSegment aSeg distanceToMove model let newWire = moveSegment aSeg distanceToMove model
let newWX = Map.add aSeg.HostId newWire model.WX let newWX = Map.add aSeg.HostId newWire model.WX
{model with WX = newWX}, Cmd.none {model with WX = newWX}, Cmd.none
else else
model, Cmd.none model, Cmd.none