Updated demo.md and refactored symbol.fs

This commit is contained in:
Archontis Pantelopoulos 2022-03-26 02:11:43 +00:00
parent 03fbd6f690
commit bef11d21a2
2 changed files with 90 additions and 146 deletions

View file

@ -12,13 +12,13 @@
## Symbol ## Symbol
- New Types: add extra info (Rotation, Orientation, New Component, AportOffsetMap) - New Types: (Rotation, PortOrientation, PortOrientationOffset, New Component -> +R + SI , AportOffsetMap)
- Rotation: add info - Rotation: All symbols can be rotated except for Split/MergeWire and Custom (since you can alter the ports' positions any way you like)
- Mux + Adder with ports on different edges - Mux + Adder with ports on different edges
- Clock on custom -> NO - Clock on custom -> NO
- APortOffsetMap: Map which uses as key the port name and value the PortOrientationOffset which consists of the Port Side Offset from top left corner and index from list of ports on that symbol side. - APortOffsetMap: used for all drawing functions, for loading components, and allows easy change of ports' locations
- UI to rotate : This can be accessed by either pressing the keyboard combination SHIFT+R or accessing this through View>Rotate Symbol. - UI to rotate : This can be accessed by either pressing the keyboard combination SHIFT+R or accessing this through View>Rotate Symbol.
- Move ports of custom : This can be accessed through the Symbol properties tab and selecting the port and preferred side to be moved to. - Move ports of custom : This can be accessed through the Symbol properties tab and selecting the port and preferred side to be moved to. Also by selecting the same side a port currently is it will move it to be the first port in that side.
- Auto-align : Not implemented. - Auto-align : Not implemented.
- Bounding box : Bounding box height and width was changed to take into account the rotation of the symbol. This can be seen by rotating the symbol and testing the new bouding box. - Bounding box : Bounding box height and width was changed to take into account the rotation of the symbol. This can be seen by rotating the symbol and testing the new bouding box.

View file

@ -1,21 +1,4 @@
//keep old drawing style but with new functions -> DONE (*
//genAportoffsetmap -> different for mux adder (ports not on LHS/RHS), -> easy to change symbols in the future
//rotation of these components is different as well -> TO ADD
//add new addClock -> work with floats instead of ints
//complete rotation for all symbols -> pending 6 + 7 points symbols
//Output same rotation as input with rotation (o+2)%4
//function to create map for custom components port names -> DONE
//add extensions as Maps in PortNamesMap
// change in points the w,h to floats in the begining??
//change names and if found better types
//why adder ports needs different rotation function???
//---------------------------------------------------------------------------------//
//--------------------AP1919 CODE SECTION STARTS-------------------------------------//
//---------------------------------------------------------------------------------//
(*
This module draws schematics component symbols. Each symbol is associated with a unique Issie component. This module draws schematics component symbols. Each symbol is associated with a unique Issie component.
*) *)
@ -40,9 +23,9 @@ let GridSize = 30
type PortOrientation = Right | Bottom | Left | Top type PortOrientation = Right | Bottom | Left | Top
type PortOrientationOffset = { type PortOrientationOffset = {
Side: PortOrientation // Designated which side of symbol port is on (0 -> right, 1 -> top, 2 -> left, 3 -> bottom). to have coherency with STransform. Side: PortOrientation // Designated which side of symbol port is on (Right, Bottom, Left, Top)
Offset: XYPos Offset: XYPos
SideIndex: int SideIndex: int //used for custom symbols -> order of ports in each side //Defaults to Empty for all other components
} }
type Symbol = type Symbol =
@ -87,8 +70,8 @@ type Msg =
| ShowPorts of ComponentId list | ShowPorts of ComponentId list
| SelectSymbols of ComponentId list// Issie interface | SelectSymbols of ComponentId list// Issie interface
| RotateSymbols of ComponentId list //First Attempt at implementing a way to rotate symbol. | RotateSymbols of ComponentId list //First Attempt at implementing a way to rotate symbol.
// | FlipHSymbols of ComponentId list //First Attempt at implementing a way to flip symbol horizontally. // | FlipHSymbols of ComponentId list //NOT IMPLEMENTED
// | FlipVSymbols of ComponentId list //First Attempt at implementing a way to flip symbol vertically. // | FlipVSymbols of ComponentId list //NOT IMPLEMENTED
| SymbolsHaveError of sIds: ComponentId list | SymbolsHaveError of sIds: ComponentId list
| ChangeLabel of sId : ComponentId * newLabel : string | ChangeLabel of sId : ComponentId * newLabel : string
| ChangePort of sId : ComponentId * portName: string * portSide:string | ChangePort of sId : ComponentId * portName: string * portSide:string
@ -113,9 +96,9 @@ let posAdd (a:XYPos) (b:XYPos) =
let posOf x y = {X=x;Y=y} let posOf x y = {X=x;Y=y}
//STransform Finite State Machine
///STransform Finite State Machine
let stransform_fsm (prev_state:Rotation) (comp: ComponentType) : Rotation = let stransform_fsm (prev_state:Rotation) (comp: ComponentType) : Rotation =
let stransformUpdate(prev_state:Rotation):Rotation = let stransformUpdate(prev_state:Rotation):Rotation =
match prev_state with match prev_state with
@ -127,6 +110,7 @@ let stransform_fsm (prev_state:Rotation) (comp: ComponentType) : Rotation =
|Custom _ |MergeWires |SplitWire _ -> prev_state |Custom _ |MergeWires |SplitWire _ -> prev_state
|_ -> stransformUpdate prev_state |_ -> stransformUpdate prev_state
///Helper function for port orientation -> int 0-3 (used when storing sides in component, necessary for correct loading of comps)
let orientationEncoder (orientation:PortOrientation) : int = let orientationEncoder (orientation:PortOrientation) : int =
match orientation with match orientation with
| Right -> 0 | Right -> 0
@ -134,6 +118,7 @@ let orientationEncoder (orientation:PortOrientation) : int =
| Left -> 2 | Left -> 2
| Top -> 3 | Top -> 3
///Helper function for int 0-3 -> portOrientation (used when loading ports of a symbol)
let orientationDecoder (orientation:int) : PortOrientation = let orientationDecoder (orientation:int) : PortOrientation =
match orientation with match orientation with
| 0 -> Right | 0 -> Right
@ -241,7 +226,7 @@ let portNamesMap (comp:Component) =
let inline roundToZ (z : int) (number : int) = //IMPLEMENT IT INSIDE ARGS??? -> DETELE IT??? let inline roundToZ (z : int) (number : int) = //IMPLEMENT IT INSIDE ARGS??? -> DETELE IT???
number + abs((number % z) - z) number + abs((number % z) - z)
//Find the custom component's I/O label with the maximum size ///Find the custom component's I/O label with the maximum size
let customCompMaxLabel (lst : (string * int) list) = let customCompMaxLabel (lst : (string * int) list) =
let labelList = List.map (fst >> String.length) lst let labelList = List.map (fst >> String.length) lst
if List.isEmpty labelList then 0 //if a component has no inputs or outputs list max will fail if List.isEmpty labelList then 0 //if a component has no inputs or outputs list max will fail
@ -293,17 +278,17 @@ let createComponent (pos: XYPos) (comptype: ComponentType) (id:string) (label:st
| DFFE -> ( 2 , 1, 3*GridSize , 3*GridSize) | DFFE -> ( 2 , 1, 3*GridSize , 3*GridSize)
| Register (a) -> ( 1 , 1, 3*GridSize , 4*GridSize ) | Register (a) -> ( 1 , 1, 3*GridSize , 4*GridSize )
| RegisterE (a) -> ( 2 , 1, 3*GridSize , 4*GridSize) | RegisterE (a) -> ( 2 , 1, 3*GridSize , 4*GridSize)
| AsyncROM1 (a) -> ( 1 , 1, 3*GridSize , 4*GridSize) | AsyncROM1 (a) -> ( 1 , 1, 3*GridSize , 5*GridSize)
| ROM1 (a) -> ( 1 , 1, 3*GridSize , 4*GridSize) | ROM1 (a) -> ( 1 , 1, 3*GridSize , 5*GridSize)
| RAM1 (a) | AsyncRAM1 a -> ( 3 , 1, 3*GridSize , 4*GridSize) | RAM1 (a) | AsyncRAM1 a -> ( 3 , 1, 3*GridSize , 5*GridSize)
| NbitsXor (n) -> ( 2 , 1, 3*GridSize , 4*GridSize) | NbitsXor (n) -> ( 2 , 1, 3*GridSize , 4*GridSize)
| NbitsAdder (n) -> ( 3 , 2, 3*GridSize , 4*GridSize) | NbitsAdder (n) -> ( 3 , 2, 3*GridSize , 4*GridSize)
| Custom x -> | Custom x ->
let h = GridSize + GridSize * (List.max [List.length x.InputLabels; List.length x.OutputLabels]) let h = GridSize + GridSize * (List.max [List.length x.InputLabels; List.length x.OutputLabels])
let maxInLength, maxOutLength = customCompMaxLabel x.InputLabels, customCompMaxLabel x.OutputLabels let maxInLength, maxOutLength = customCompMaxLabel x.InputLabels, customCompMaxLabel x.OutputLabels
let maxW = maxInLength + maxOutLength + label.Length let maxName = max maxInLength maxOutLength
let scaledW = roundToZ GridSize (maxW * GridSize / 5) //Divide by 5 is just abitrary as otherwise the symbols would be too wide let maxW = (maxName*14 + label.Length*10)
let w = max scaledW (GridSize * 4) //Ensures a minimum width if the labels are very small let w = max maxW (GridSize * 4) //Ensures a minimum width if the labels are very small
( List.length x.InputLabels, List.length x.OutputLabels, h , w) ( List.length x.InputLabels, List.length x.OutputLabels, h , w)
@ -320,7 +305,7 @@ let createComponent (pos: XYPos) (comptype: ComponentType) (id:string) (label:st
H = h H = h
W = w W = w
R = rotation R = rotation
SI = [] SI = [] //field used to store side and SideIndex after APortOffsetMap has been created
} }
createComponent' characteristics label rotation createComponent' characteristics label rotation
@ -355,16 +340,14 @@ let addPortsToModel (model: Model) (symbol: Symbol) =
//////////////////////KEEP ONLY SO THAT THE CODE COMPILES -> IT AFFECTS 2nd part of symbol (lines: 750 - END) ///////////////////////////////////
//-----------------------------------------GET PORT POSITION--------------------------------------------------- //-----------------------------------------GET PORT POSITION---------------------------------------------------
// Function that calculates the positions of the ports
/// hack so that bounding box of splitwire, mergewires can be smaller height relative to ports /// hack so that bounding box of splitwire, mergewires can be smaller height relative to ports
let inline getPortPosEdgeGap (ct: ComponentType) = let inline getPortPosEdgeGap (ct: ComponentType) =
match ct with match ct with
| MergeWires | SplitWire _ -> 0.25 | MergeWires | SplitWire _ -> 0.25
| _ -> 1.0 | _ -> 1.0
/// Function that calculates the positions of the ports
let getPortPos (comp: Component) (port:Port) = let getPortPos (comp: Component) (port:Port) =
let (ports, posX) = let (ports, posX) =
if port.PortType = (PortType.Input) then if port.PortType = (PortType.Input) then
@ -377,9 +360,11 @@ let getPortPos (comp: Component) (port:Port) =
{X = posX; Y = posY} {X = posX; Y = posY}
let getPortPosModel (model: Model) (port:Port) = let getPortPosModel (model: Model) (port:Port) =
getPortPos (Map.find (ComponentId port.HostId) model.Symbols).Compo port getPortPos (Map.find (ComponentId port.HostId) model.Symbols).Compo port
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//---------------------------------------APortOffsetMap HELPERS ----------------------------------------------// //---------------------------------------APortOffsetMap HELPERS ----------------------------------------------//
///Helper function to find XYPos of ports on the RHS/LHS
///Helper function to find XYPos of ports on the RHS/LHS (all symbols except MUX + Adder)
let offsethelper (comp: Component) orientation (port:Port) = let offsethelper (comp: Component) orientation (port:Port) =
let inline getPortPosEdgeGap (ct: ComponentType) = let inline getPortPosEdgeGap (ct: ComponentType) =
match ct with match ct with
@ -412,6 +397,7 @@ let portListToMap (portList: Port List) (symbol: Symbol) : Map<string,PortOrient
else ( [0..(portList.Length-1)] |> List.collect (fun x -> (adder symbol portList[x])) ) |> Map.ofList else ( [0..(portList.Length-1)] |> List.collect (fun x -> (adder symbol portList[x])) ) |> Map.ofList
/// APortOffsetsMap generator /// APortOffsetsMap generator
/// All symbols with ports NOT on Right-Left need a different map generator (as for Mux and Adder below)
let genAPortOffsets (symbol: Symbol) (cType: ComponentType) : Map<string,PortOrientationOffset> = let genAPortOffsets (symbol: Symbol) (cType: ComponentType) : Map<string,PortOrientationOffset> =
//generator for MUX //generator for MUX
@ -438,22 +424,23 @@ let genAPortOffsets (symbol: Symbol) (cType: ComponentType) : Map<string,PortOri
|NbitsAdder _ -> genAPortOffsetsAdder symbol |NbitsAdder _ -> genAPortOffsetsAdder symbol
|_ -> genAPortOffsets' symbol |_ -> genAPortOffsets' symbol
/// Rotates port posistion (given the symbol rotation) by updating the APortOffsetsMap /// Rotates port posistion (given the symbol's newRotation) by updating the APortOffsetsMap
///Mux and Adder need different functions as their ports are not either on full Height/Width (Sel of mux) or in the middle of their side (cin cout of Adder)
let rotatePortMap (map:Map<string,PortOrientationOffset>) newRotation (comp:Component) = let rotatePortMap (map:Map<string,PortOrientationOffset>) newRotation (comp:Component) =
let rotatePortMapMux (map:Map<string,PortOrientationOffset>) newRotation (comp:Component) = let rotatePortMapMux (map:Map<string,PortOrientationOffset>) newRotation (comp:Component) =
match newRotation with match newRotation with
|R0 -> Map.ofList [ ("I0", {Side=Left;Offset={X=0.0;Y=(float(comp.H)/3.0)};SideIndex= -1});("I1", {Side=Left;Offset={X=0.0;Y=(float(comp.H)*2.0/3.0)};SideIndex= -1});("I2", {Side=Bottom;Offset={X=float(comp.W)/2.0;Y=float(comp.H)*0.9};SideIndex= -1});("O0", {Side=Right;Offset={X=float(comp.W);Y=float(comp.H)/2.0};SideIndex= -1})]
|R90 -> Map.ofList [ ("I0", {Side=Top;Offset={X=(float(comp.H)*2.0/3.0);Y=(0.0)};SideIndex= -1});("I1", {Side=Top;Offset={X=(float(comp.H)/3.0);Y=(0.0)};SideIndex= -1});("I2", {Side=Left;Offset={X=float(comp.H)*0.1;Y=float(comp.W)/2.0};SideIndex= -1});("O0", {Side=Bottom;Offset={X=float(comp.H)/2.0;Y=float(comp.W)};SideIndex= -1})] |R90 -> Map.ofList [ ("I0", {Side=Top;Offset={X=(float(comp.H)*2.0/3.0);Y=(0.0)};SideIndex= -1});("I1", {Side=Top;Offset={X=(float(comp.H)/3.0);Y=(0.0)};SideIndex= -1});("I2", {Side=Left;Offset={X=float(comp.H)*0.1;Y=float(comp.W)/2.0};SideIndex= -1});("O0", {Side=Bottom;Offset={X=float(comp.H)/2.0;Y=float(comp.W)};SideIndex= -1})]
|R180 -> Map.ofList [ ("I0", {Side=Right;Offset={X=float(comp.W);Y=(float(comp.H)*2.0/3.0)};SideIndex= -1});("I1", {Side=Right;Offset={X=float(comp.W);Y=(float(comp.H)/3.0)};SideIndex= -1});("I2", {Side=Top;Offset={X=float(comp.W)/2.0;Y=float(comp.H)*0.1};SideIndex= -1});("O0", {Side=Left;Offset={X=0.0;Y=float(comp.H)/2.0};SideIndex= -1})] |R180 -> Map.ofList [ ("I0", {Side=Right;Offset={X=float(comp.W);Y=(float(comp.H)*2.0/3.0)};SideIndex= -1});("I1", {Side=Right;Offset={X=float(comp.W);Y=(float(comp.H)/3.0)};SideIndex= -1});("I2", {Side=Top;Offset={X=float(comp.W)/2.0;Y=float(comp.H)*0.1};SideIndex= -1});("O0", {Side=Left;Offset={X=0.0;Y=float(comp.H)/2.0};SideIndex= -1})]
|R270 -> Map.ofList [ ("I0", {Side=Bottom;Offset={X=(float(comp.H)/3.0);Y=float(comp.W)};SideIndex= -1});("I1", {Side=Bottom;Offset={X=(float(comp.H)*2.0/3.0);Y=float(comp.W)};SideIndex= -1});("I2", {Side=Right;Offset={X=float(comp.H)*0.9;Y=float(comp.W)/2.0};SideIndex= -1});("O0", {Side=Top;Offset={X=float(comp.H)/2.0;Y=0.0};SideIndex= -1})] |R270 -> Map.ofList [ ("I0", {Side=Bottom;Offset={X=(float(comp.H)/3.0);Y=float(comp.W)};SideIndex= -1});("I1", {Side=Bottom;Offset={X=(float(comp.H)*2.0/3.0);Y=float(comp.W)};SideIndex= -1});("I2", {Side=Right;Offset={X=float(comp.H)*0.9;Y=float(comp.W)/2.0};SideIndex= -1});("O0", {Side=Top;Offset={X=float(comp.H)/2.0;Y=0.0};SideIndex= -1})]
|R0 -> Map.ofList [ ("I0", {Side=Left;Offset={X=0.0;Y=(float(comp.H)/3.0)};SideIndex= -1});("I1", {Side=Left;Offset={X=0.0;Y=(float(comp.H)*2.0/3.0)};SideIndex= -1});("I2", {Side=Bottom;Offset={X=float(comp.W)/2.0;Y=float(comp.H)*0.9};SideIndex= -1});("O0", {Side=Right;Offset={X=float(comp.W);Y=float(comp.H)/2.0};SideIndex= -1})]
let rotatePortMapAdder (map:Map<string,PortOrientationOffset>) newRotation (comp:Component) = let rotatePortMapAdder (map:Map<string,PortOrientationOffset>) newRotation (comp:Component) =
match newRotation with match newRotation with
|R0 -> Map.ofList [ ("I0", {Side=Bottom;Offset={X=float(comp.W)/3.0;Y=float(comp.H)};SideIndex= -1});("I1", {Side=Left;Offset={X=0.0;Y=float(comp.H)/3.0};SideIndex= -1}); ("I2", {Side=Left;Offset={X=0.0;Y=float(comp.H)*2.0/3.0};SideIndex= -1}); ("O0", {Side=Right;Offset={X=float(comp.W);Y=float(comp.H)/3.0};SideIndex= -1});("O1", {Side=Top;Offset={X=float(comp.W)-30.0;Y=0.0};SideIndex= -1})]
|R90 -> Map.ofList [ ("I0", {Side=Left;Offset={X=0.0;Y=float(comp.W)/3.0};SideIndex= -1});("I1", {Side=Top;Offset={X=float(comp.H)*2.0/3.0;Y=0.0};SideIndex= -1}); ("I2", {Side=Top;Offset={X=float(comp.H)/3.0;Y=0.0};SideIndex= -1}); ("O0", {Side=Bottom;Offset={X=float(comp.H)*2.0/3.0;Y=float(comp.W)};SideIndex= -1});("O1", {Side=Right;Offset={X=(comp.H);Y=float(comp.W)-30.0};SideIndex= -1})] |R90 -> Map.ofList [ ("I0", {Side=Left;Offset={X=0.0;Y=float(comp.W)/3.0};SideIndex= -1});("I1", {Side=Top;Offset={X=float(comp.H)*2.0/3.0;Y=0.0};SideIndex= -1}); ("I2", {Side=Top;Offset={X=float(comp.H)/3.0;Y=0.0};SideIndex= -1}); ("O0", {Side=Bottom;Offset={X=float(comp.H)*2.0/3.0;Y=float(comp.W)};SideIndex= -1});("O1", {Side=Right;Offset={X=(comp.H);Y=float(comp.W)-30.0};SideIndex= -1})]
|R180 -> Map.ofList [ ("I0", {Side=Top;Offset={X=float(comp.W)*2.0/3.0;Y=0.0};SideIndex= -1});("I1", {Side=Right;Offset={X=float(comp.W);Y=float(comp.H)*2.0/3.0};SideIndex= -1}); ("I2", {Side=Right;Offset={X=float(comp.W);Y=float(comp.H)/3.0};SideIndex= -1}); ("O0", {Side=Left;Offset={X=0.0;Y=float(comp.H)*2.0/3.0};SideIndex= -1});("O1", {Side=Bottom;Offset={X=30.0;Y=float(comp.H)};SideIndex= -1})] |R180 -> Map.ofList [ ("I0", {Side=Top;Offset={X=float(comp.W)*2.0/3.0;Y=0.0};SideIndex= -1});("I1", {Side=Right;Offset={X=float(comp.W);Y=float(comp.H)*2.0/3.0};SideIndex= -1}); ("I2", {Side=Right;Offset={X=float(comp.W);Y=float(comp.H)/3.0};SideIndex= -1}); ("O0", {Side=Left;Offset={X=0.0;Y=float(comp.H)*2.0/3.0};SideIndex= -1});("O1", {Side=Bottom;Offset={X=30.0;Y=float(comp.H)};SideIndex= -1})]
|R270 -> Map.ofList [ ("I0", {Side=Right;Offset={X=float(comp.H);Y=float(comp.W)*2.0/3.0};SideIndex= -1});("I1", {Side=Bottom;Offset={X=float(comp.H)/3.0;Y=float(comp.W)};SideIndex= -1}); ("I2", {Side=Bottom;Offset={X=float(comp.H)*2.0/3.0;Y=float(comp.W)};SideIndex= -1}); ("O0", {Side=Top;Offset={X=float(comp.H)/3.0;Y=0.0};SideIndex= -1});("O1", {Side=Left;Offset={X=0.0;Y=30.0};SideIndex= -1})] |R270 -> Map.ofList [ ("I0", {Side=Right;Offset={X=float(comp.H);Y=float(comp.W)*2.0/3.0};SideIndex= -1});("I1", {Side=Bottom;Offset={X=float(comp.H)/3.0;Y=float(comp.W)};SideIndex= -1}); ("I2", {Side=Bottom;Offset={X=float(comp.H)*2.0/3.0;Y=float(comp.W)};SideIndex= -1}); ("O0", {Side=Top;Offset={X=float(comp.H)/3.0;Y=0.0};SideIndex= -1});("O1", {Side=Left;Offset={X=0.0;Y=30.0};SideIndex= -1})]
|R0 -> Map.ofList [ ("I0", {Side=Bottom;Offset={X=float(comp.W)/3.0;Y=float(comp.H)};SideIndex= -1});("I1", {Side=Left;Offset={X=0.0;Y=float(comp.H)/3.0};SideIndex= -1}); ("I2", {Side=Left;Offset={X=0.0;Y=float(comp.H)*2.0/3.0};SideIndex= -1}); ("O0", {Side=Right;Offset={X=float(comp.W);Y=float(comp.H)/3.0};SideIndex= -1});("O1", {Side=Top;Offset={X=float(comp.W)-30.0;Y=0.0};SideIndex= -1})]
let rotatePortMap' (map:Map<string,PortOrientationOffset>) (comp:Component) = let rotatePortMap' (map:Map<string,PortOrientationOffset>) (comp:Component) =
map |> Map.map (fun key port -> map |> Map.map (fun key port ->
@ -472,17 +459,19 @@ let rotatePortMap (map:Map<string,PortOrientationOffset>) newRotation (comp:Comp
///NOT IMPLEMENTED -> functions for flipping symbols
let flipHPortMap (map:Map<string,PortOrientationOffset>) (symbol:Symbol) = let flipHPortMap (map:Map<string,PortOrientationOffset>) (symbol:Symbol) =
map |> Map.map (fun key port -> failwithf "Not implemented Yet"
match port.Side with
|Right -> {port with Side=Left}
|Left -> {port with Side=Right}
|_ -> port)
let flipVPortMap (map:Map<string,PortOrientationOffset>) (symbol:Symbol) = let flipVPortMap (map:Map<string,PortOrientationOffset>) (symbol:Symbol) =
failwithf "Not implemented Yet" failwithf "Not implemented Yet"
////////////////////////////////////////////////////
/// Helper function to change the side/ordering of ports on custom components
/// First it inverts the name map to find the key of the port which should change
/// If the newside submitted matches the current side then the SideIndex fields of the ports on that side are altered accordingly to bring the port in the beggining of the specific side
/// If the newside is different then all ports in the oldside and the newside are altered accordingly
/// NOTE: Offset is changed in the redefineCustomPortsOffset function
let changePortSide (map:Map<string,PortOrientationOffset>) (portName: string) (newSide:PortOrientation) (symbol:Symbol) = let changePortSide (map:Map<string,PortOrientationOffset>) (portName: string) (newSide:PortOrientation) (symbol:Symbol) =
let rev map: Map<string,string> = let rev map: Map<string,string> =
Map.fold (fun m key value -> m.Add(value,key)) Map.empty map Map.fold (fun m key value -> m.Add(value,key)) Map.empty map
@ -506,11 +495,6 @@ let changePortSide (map:Map<string,PortOrientationOffset>) (portName: string) (n
| Some s -> Some {Side=newSide;Offset=s.Offset;SideIndex= 0} //CHECK | Some s -> Some {Side=newSide;Offset=s.Offset;SideIndex= 0} //CHECK
| None -> None | None -> None
) )
// map |> Map.change portId (fun x ->
// match x with
// | Some s -> Some {Side=newSide;Offset=s.Offset;SideIndex= -1} //CHECK
// | None -> None
// )
else else
let temp = map |> Map.map (fun key port -> let temp = map |> Map.map (fun key port ->
match port.Side with match port.Side with
@ -524,6 +508,8 @@ let changePortSide (map:Map<string,PortOrientationOffset>) (portName: string) (n
| None -> None | None -> None
) )
/// Transforms Side from PortOrientation -> string ("R","L","T","B")
/// Result used in countsides function
let getSides (map:Map<string,PortOrientationOffset>) = let getSides (map:Map<string,PortOrientationOffset>) =
let lst = Map.toList map let lst = Map.toList map
let sides = lst |> List.map (fun x -> let sides = lst |> List.map (fun x ->
@ -538,7 +524,9 @@ let getSides (map:Map<string,PortOrientationOffset>) =
|Bottom->"B" |Bottom->"B"
) )
let countsides (map:Map<string,PortOrientationOffset>) = /// counts number of ports on each side
/// Used to resize custom components and define ports' offset
let countPorts (map:Map<string,PortOrientationOffset>) =
let sides = getSides map let sides = getSides map
let countmap = List.countBy id sides |> Map.ofList let countmap = List.countBy id sides |> Map.ofList
let counts = [Map.tryFind "R" countmap; Map.tryFind "B" countmap; Map.tryFind "L" countmap; Map.tryFind "T" countmap] let counts = [Map.tryFind "R" countmap; Map.tryFind "B" countmap; Map.tryFind "L" countmap; Map.tryFind "T" countmap]
@ -547,81 +535,52 @@ let countsides (map:Map<string,PortOrientationOffset>) =
|Some a -> a |Some a -> a
|None -> 0 |None -> 0
) )
// t
(t[0],t[1],t[2],t[3]) (t[0],t[1],t[2],t[3])
/// Helper function to find the length of the largest port name based on which the Height and Width is defined
let getMaxPortNameLength (map:Map<string,string>) = let getMaxPortNameLength (map:Map<string,string>) =
let labelList = List.map (snd >> String.length) (map |> Map.toList) let labelList = List.map (snd >> String.length) (map |> Map.toList)
if List.isEmpty labelList then 0 //if a component has no inputs or outputs list max will fail if List.isEmpty labelList then 0 //if a component has no inputs or outputs list max will fail
else List.max labelList else List.max labelList
//find max name.length in all ports, not input + output /// Redefines the Height and Width of custom components after a change in port locations by the user
//height is defined by (max_ton_ports_se_Right_kai_left + 2) => gap gia port names on top/bottom
//width = max_name_size + max_name_size + (max_name_size) * max_ton_ports_se_top_kai_bottom
////////// LEFT RIGTH TOP/BOTTOM
//Rearrange map
//otan allazei ena port thelei -> let symbol' = {symbol with map = changeportside} -> let symbol'' = {redefineCustomHW} -> {symbol'' with map = redefineportmap}
let redefineCustomHW symbol = let redefineCustomHW symbol =
// let altercomponent comp nh nw =
// {comp with
// H = nh
// W = nw}
let namesMap = portNamesMap symbol.Compo let namesMap = portNamesMap symbol.Compo
let maxname = getMaxPortNameLength namesMap let maxName = getMaxPortNameLength namesMap //name with largest length
let r,b,l,t = countsides symbol.APortOffsetsMap let r,b,l,t = countPorts symbol.APortOffsetsMap //number of ports in each side
let maxRL = max r l let maxRL = max r l
let maxTB = max t b let maxTB = max t b
let heightNew = (GridSize + GridSize * maxRL) let heightNew = (GridSize + GridSize * maxRL)
// printf "%A" maxname let maxW = max (maxName*14 + symbol.Compo.Label.Length*10) (maxName*14 + maxName*maxTB*7) //find width required to fit everything
let widthN = max (maxname*14 + symbol.Compo.Label.Length*10) (maxname*14 + maxname*maxTB*7) //find width required to fit everything let widthNew = max maxW (GridSize * 4) //ensure minimum width if names too small
// printf "%A" widthNew let newcompo = {symbol.Compo with H = heightNew; W = widthNew}
let widthNew = max widthN (GridSize * 4) //ensure minimum width if names too small {symbol with Compo = newcompo}
let newcompo = {symbol.Compo with H = heightNew}
let newcompo'= {newcompo with W = widthNew}
{symbol with Compo = newcompo'}
/// Helper of redefineCustomPortsOffset
let customOffsetHelper w h side sideIndex r l b t : XYPos= let customOffsetHelper w h side sideIndex r l b t : XYPos=
let all = let all =
match side with match side with
|Right -> r |Right -> r
|Left -> l |Left -> l
|Top -> t |Top -> t
|Bottom -> b |Bottom -> b
let gap = 1.0 let gap = 1.0
let offY = (float(h))* (( float(sideIndex) + gap )/( float( all ) + 2.0*gap - 1.0)) // the ports are created so that they are equidistant let offY = (float(h))* (( float(sideIndex) + gap )/( float( all ) + 2.0*gap - 1.0)) // the ports are created so that they are equidistant
let offX = (float(w))* (( float(sideIndex) + gap )/( float( all ) + 2.0*gap - 1.0)) let offX = (float(w))* (( float(sideIndex) + gap )/( float( all ) + 2.0*gap - 1.0))
// {X=50.0;Y=50.0}
match side with match side with
|Left -> {X=0.0;Y=offY} |Left -> {X=0.0;Y=offY}
|Top -> {X=offX;Y=0.0} |Top -> {X=offX;Y=0.0}
|Right -> {X=float(w);Y=offY} |Right -> {X=float(w);Y=offY}
|Bottom -> {X=offX;Y=float(h)} |Bottom -> {X=offX;Y=float(h)}
let redefineCustomPorts symbol (map:Map<string,PortOrientationOffset>) : Map<string,PortOrientationOffset> = /// Redefines the ports' offset in APortOffsetMap of custom components after the Side and SideIndex field have been modified
let redefineCustomPortsOffset symbol (map:Map<string,PortOrientationOffset>) : Map<string,PortOrientationOffset> =
let keys = map |> Map.toList |> List.map fst let keys = map |> Map.toList |> List.map fst
let values = map |> Map.toList |> List.map snd let values = map |> Map.toList |> List.map snd
let r,b,l,t = countsides map let r,b,l,t = countPorts map
let w,h = symbol.Compo.W, symbol.Compo.H //it needs the new height and width here based on spec above let w,h = symbol.Compo.W, symbol.Compo.H
// let mutable valuesNew = []
// for v in values do
// valuesNew <- (valuesNew @ [{Side=v.Side;Offset=(customOffsetHelper w h v.Side v.SideIndex r l b t);SideIndex= v.SideIndex}])
// printf $"IL: %i{il}"
let valuesNew = List.map (fun v -> {Side=v.Side;Offset=(customOffsetHelper w h v.Side v.SideIndex r l b t);SideIndex= v.SideIndex}) values let valuesNew = List.map (fun v -> {Side=v.Side;Offset=(customOffsetHelper w h v.Side v.SideIndex r l b t);SideIndex= v.SideIndex}) values
// printf $"New Y Offset: %f{valuesNew[0].Offset.Y}"
// for i in valuesNew do
// printf $"New Y Offset: %f{i.Offset.Y}"
// valuesNew
(keys, valuesNew) ||> List.map2 (fun x y -> (x,y)) |> Map.ofList (keys, valuesNew) ||> List.map2 (fun x y -> (x,y)) |> Map.ofList
// map
//----------------------------------------ROTATION HELPERS----------------------------------------------- //----------------------------------------ROTATION HELPERS-----------------------------------------------
@ -735,7 +694,7 @@ let drawClock w h rotation colour opacity =
|> List.append (clocktext w h rotation) |> List.append (clocktext w h rotation)
let addInvertor w h rotation colour opacity = let drawInvertor w h rotation colour opacity =
let points = let points =
match rotation with match rotation with
|R0 -> [w;h/2.0;w+9.0;h/2.0;w;h/2.0-8.0] |R0 -> [w;h/2.0;w+9.0;h/2.0;w;h/2.0-8.0]
@ -745,7 +704,7 @@ let addInvertor w h rotation colour opacity =
createPolygon (getPointsString points) colour opacity createPolygon (getPointsString points) colour opacity
let addConstantLine w h rotation opacity = let drawConstantLine w h rotation opacity =
let points = let points =
match rotation with match rotation with
|R0 -> [w/2.0;h/2.0;w;h/2.0] |R0 -> [w/2.0;h/2.0;w;h/2.0]
@ -770,7 +729,7 @@ let outlineColor (color:string) =
printfn $"color={color}" printfn $"color={color}"
c c
let addHorizontalColorLine posX1 posX2 posY opacity (color:string) = // TODO: Line instead of polygon? let drawHorizontalColorLine posX1 posX2 posY opacity (color:string) = // TODO: Line instead of polygon?
let points = (sprintf "%i,%f %i,%f" posX1 posY posX2 posY) let points = (sprintf "%i,%f %i,%f" posX1 posY posX2 posY)
let olColor = outlineColor color let olColor = outlineColor color
[makePolygon points {defaultPolygon with Fill = "olcolor"; Stroke=olColor; StrokeWidth = "2.0"; FillOpacity = opacity}] [makePolygon points {defaultPolygon with Fill = "olcolor"; Stroke=olColor; StrokeWidth = "2.0"; FillOpacity = opacity}]
@ -793,7 +752,6 @@ let drawSymbol (symbol:Symbol) (comp:Component) (colour:string) (showInputPorts:
let rotation = symbol.STransform let rotation = symbol.STransform
let hR,wR = match symbol.STransform with |R90|R270 -> w,h |_ -> h,w //new height,width after rotation let hR,wR = match symbol.STransform with |R90|R270 -> w,h |_ -> h,w //new height,width after rotation
// let hR,wR = h,w
let mergeSplitLine posX1 posX2 posY msb lsb = let mergeSplitLine posX1 posX2 posY msb lsb =
let text = let text =
@ -801,7 +759,7 @@ let drawSymbol (symbol:Symbol) (comp:Component) (colour:string) (showInputPorts:
| _, false -> "" | _, false -> ""
| true, _ -> sprintf $"({msb})" | true, _ -> sprintf $"({msb})"
| false, _ -> sprintf $"({msb}:{lsb})" | false, _ -> sprintf $"({msb}:{lsb})"
addHorizontalColorLine posX1 posX2 (posY*float(h)) opacity colour @ drawHorizontalColorLine posX1 posX2 (posY*float(h)) opacity colour @
addText (float (posX1 + posX2)/2.0) (posY*float(h)-11.0) text "middle" "bold" "9px" addText (float (posX1 + posX2)/2.0) (posY*float(h)-11.0) text "middle" "bold" "9px"
// Points that specify each symbol // Points that specify each symbol
@ -825,8 +783,8 @@ let drawSymbol (symbol:Symbol) (comp:Component) (colour:string) (showInputPorts:
// Helper function to add certain characteristics on specific symbols (inverter, enables, clocks) // Helper function to add certain characteristics on specific symbols (inverter, enables, clocks)
let extras = let extras =
match comp.Type with match comp.Type with
| Constant1 (_,_,txt) -> (addConstantLine (float(wR)) (float(hR)) rotation opacity @ addText (float (float(w)/2.0)-5.0) (float(h)-8.0) txt "middle" "normal" "12px") | Constant1 (_,_,txt) -> (drawConstantLine (float(wR)) (float(hR)) rotation opacity @ addText (float (float(w)/2.0)-5.0) (float(h)-8.0) txt "middle" "normal" "12px")
| Nand | Nor | Xnor |Not -> (addInvertor (float(wR)) (float(hR)) rotation colour opacity) | Nand | Nor | Xnor |Not -> (drawInvertor (float(wR)) (float(hR)) rotation colour opacity)
| MergeWires -> | MergeWires ->
let lo, hi = let lo, hi =
match symbol.InWidth0, symbol.InWidth1 with match symbol.InWidth0, symbol.InWidth1 with
@ -921,12 +879,6 @@ let view (model : Model) (dispatch : Msg -> unit) =
|> TimeHelpers.instrumentInterval "SymbolView" start |> TimeHelpers.instrumentInterval "SymbolView" start
//---------------------------------------------------------------------------------//
//--------------------AP1919 CODE SECTION ENDS-------------------------------------//
//---------------------------------------------------------------------------------//
//------------------------GET BOUNDING BOXES FUNCS--------------------------------used by sheet. //------------------------GET BOUNDING BOXES FUNCS--------------------------------used by sheet.
@ -1382,19 +1334,10 @@ let update (msg : Msg) (model : Model): Model*Cmd<'a> =
let newRotation = stransform_fsm model.Symbols[sId].STransform compo.Type let newRotation = stransform_fsm model.Symbols[sId].STransform compo.Type
Map.add sId {model.Symbols[sId] with Compo = newcompo ; STransform = newRotation ; APortOffsetsMap = rotatePortMap model.Symbols[sId].APortOffsetsMap newRotation model.Symbols[sId].Compo} prevSymbols) resetSymbols compList Map.add sId {model.Symbols[sId] with Compo = newcompo ; STransform = newRotation ; APortOffsetsMap = rotatePortMap model.Symbols[sId].APortOffsetsMap newRotation model.Symbols[sId].Compo} prevSymbols) resetSymbols compList
{ model with Symbols = newSymbols }, Cmd.none { model with Symbols = newSymbols }, Cmd.none
// | FlipHSymbols compList -> // NEW: flip a symbol Horizontally
// let resetSymbols = Map.map (fun _ sym -> { sym with Colour = "Lightgray"; Opacity = 1.0 }) model.Symbols // | FlipHSymbols compList -> NOT IMPLEMETED -> flip a symbol Horizontally
// let newSymbols =
// List.fold (fun prevSymbols sId -> // | FlipVSymbols compList -> NOT IMPLEMETED -> flip a symbol vertically
// Map.add sId model.Symbols[sId] prevSymbols) resetSymbols compList //NEED TO DO APPROPRIATE CHANGES HERE, SEE ROTATION FOR INSPIRATION
// { model with Symbols = newSymbols }, Cmd.none
//
// | FlipVSymbols compList ->
// let resetSymbols = Map.map (fun _ sym -> { sym with Colour = "Lightgray"; Opacity = 1.0 }) model.Symbols
// let newSymbols =
// List.fold (fun prevSymbols sId ->
// Map.add sId model.Symbols[sId] prevSymbols) resetSymbols compList //NEED TO DO APPROPRIATE CHANGES HERE, SEE ROTATION FOR INSPIRATION
// { model with Symbols = newSymbols }, Cmd.none
| ErrorSymbols (errorCompList,selectCompList,isDragAndDrop) -> | ErrorSymbols (errorCompList,selectCompList,isDragAndDrop) ->
let resetSymbols = Map.map (fun _ sym -> { sym with Colour = "Lightgray"; Opacity = 1.0 }) model.Symbols let resetSymbols = Map.map (fun _ sym -> { sym with Colour = "Lightgray"; Opacity = 1.0 }) model.Symbols
@ -1417,13 +1360,15 @@ let update (msg : Msg) (model : Model): Model*Cmd<'a> =
let addsym = {tempsym with Compo = newcompo} let addsym = {tempsym with Compo = newcompo}
{ model with Symbols = Map.add sId addsym model.Symbols }, Cmd.none { model with Symbols = Map.add sId addsym model.Symbols }, Cmd.none
| ChangePort (sId, portName, portSide) -> | ChangePort (sId, portName, portSide) ->
let extract map =
//extract info required from Map to store to SI field of Component
let extractToSI map =
let lst = map |> Map.toList let lst = map |> Map.toList
lst |> List.map (fun x -> lst |> List.map (fun x ->
match x with match x with
|(a,{Side=b;Offset=c;SideIndex=d}) -> ((orientationEncoder b),d) |(a,{Side=b;Offset=c;SideIndex=d}) -> ((orientationEncoder b),d)
) )
let tempsym = Map.find sId model.Symbols let targetSymbol = Map.find sId model.Symbols
printf $"Selected Port: %s{portName}" printf $"Selected Port: %s{portName}"
printf $"Selected Side: %s{portSide}" printf $"Selected Side: %s{portSide}"
let newSide = let newSide =
@ -1434,11 +1379,11 @@ let update (msg : Msg) (model : Model): Model*Cmd<'a> =
| "Right" -> Right | "Right" -> Right
| _ -> failwithf "Side not implemented" | _ -> failwithf "Side not implemented"
let symbol' = {tempsym with APortOffsetsMap = (changePortSide tempsym.APortOffsetsMap portName newSide tempsym)} let symbol' = {targetSymbol with APortOffsetsMap = (changePortSide targetSymbol.APortOffsetsMap portName newSide targetSymbol)} //change ports' Side and SideIndex fields
let symbol'' = redefineCustomHW symbol' let symbol'' = redefineCustomHW symbol' //change Height Width based on new sides (total ports on each side)
let symbol''' = {symbol'' with APortOffsetsMap = redefineCustomPorts symbol'' symbol'.APortOffsetsMap} let symbol''' = {symbol'' with APortOffsetsMap = redefineCustomPortsOffset symbol'' symbol'.APortOffsetsMap} //change Offset of each port in the map based on new Height Width Side and SideIndex
let newcompo = {symbol'''.Compo with SI=extract symbol'''.APortOffsetsMap} let newcompo = {symbol'''.Compo with SI=extractToSI symbol'''.APortOffsetsMap}
let symbol'''' = {symbol''' with Compo = newcompo} let symbol'''' = {symbol''' with Compo = newcompo} //add the new Side and SideIndex fields in the SI field of component to store the information
{ model with Symbols = Map.add sId symbol'''' model.Symbols }, Cmd.none { model with Symbols = Map.add sId symbol'''' model.Symbols }, Cmd.none
| PasteSymbols compList -> | PasteSymbols compList ->
@ -1472,17 +1417,20 @@ let update (msg : Msg) (model : Model): Model*Cmd<'a> =
| ResetModel -> { model with Symbols = Map.empty; Ports = Map.empty }, Cmd.none | ResetModel -> { model with Symbols = Map.empty; Ports = Map.empty }, Cmd.none
| LoadComponents comps -> | LoadComponents comps ->
//returns the correct port map according to the orientation of symbol
let findrotatedportmap symbol rotation = let findrotatedportmap symbol rotation =
let once = rotatePortMap (genAPortOffsets symbol symbol.Compo.Type) symbol.STransform symbol.Compo let once = rotatePortMap (genAPortOffsets symbol symbol.Compo.Type) symbol.STransform symbol.Compo
let twice = rotatePortMap once symbol.STransform symbol.Compo let twice = rotatePortMap once symbol.STransform symbol.Compo
let th = rotatePortMap twice symbol.STransform symbol.Compo let thrice = rotatePortMap twice symbol.STransform symbol.Compo
match rotation with match rotation with
|R0 -> genAPortOffsets symbol symbol.Compo.Type |R0 -> genAPortOffsets symbol symbol.Compo.Type
|R90 -> once |R90 -> once
|R180 -> twice |R180 -> twice
|R270 -> th |R270 -> thrice
let totalsides sidesString = //return total ports per side
let countPortsFromString sidesString =
let countmap = List.countBy id sidesString |> Map.ofList let countmap = List.countBy id sidesString |> Map.ofList
let counts = [Map.tryFind "R" countmap; Map.tryFind "B" countmap; Map.tryFind "L" countmap; Map.tryFind "T" countmap] let counts = [Map.tryFind "R" countmap; Map.tryFind "B" countmap; Map.tryFind "L" countmap; Map.tryFind "T" countmap]
let t = counts |> List.map (fun x -> let t = counts |> List.map (fun x ->
@ -1490,9 +1438,9 @@ let update (msg : Msg) (model : Model): Model*Cmd<'a> =
|Some a -> a |Some a -> a
|None -> 0 |None -> 0
) )
// t
(t[0],t[1],t[2],t[3]) (t[0],t[1],t[2],t[3])
//return the correct port map for Custom Components based on saved Side and SideIndex
let reconstructCustomPortMap lst map w h = let reconstructCustomPortMap lst map w h =
let keys = map |> Map.toList |> List.map fst let keys = map |> Map.toList |> List.map fst
let sides = List.map (fun (side,index)->side) lst let sides = List.map (fun (side,index)->side) lst
@ -1504,13 +1452,9 @@ let update (msg : Msg) (model : Model): Model*Cmd<'a> =
|2 -> "L" |2 -> "L"
|3 -> "T" |3 -> "T"
|_ -> "R" |_ -> "R"
) )
let r,b,l,t = countPortsFromString sidesString
let r,b,l,t = totalsides sidesString
// let w,h = symbol.Compo.W, symbol.Compo.H //it needs the new height and width here based on spec above
let valuesNew = List.map (fun (side,index) -> {Side=(orientationDecoder side);Offset=(customOffsetHelper w h (orientationDecoder side) index r l b t);SideIndex= index}) lst let valuesNew = List.map (fun (side,index) -> {Side=(orientationDecoder side);Offset=(customOffsetHelper w h (orientationDecoder side) index r l b t);SideIndex= index}) lst
(keys, valuesNew) ||> List.map2 (fun x y -> (x,y)) |> Map.ofList (keys, valuesNew) ||> List.map2 (fun x y -> (x,y)) |> Map.ofList
let compIdsWithSymbols = let compIdsWithSymbols =