mirror of
https://github.com/supleed2/ELEC60015-HLP-CW.git
synced 2024-11-10 02:05:48 +00:00
Merge in yhp19's code
This commit is contained in:
parent
72955fe300
commit
89b75418b9
|
@ -21,6 +21,9 @@ let minSegLen = 5.
|
||||||
|
|
||||||
type Orientation = Horizontal | Vertical
|
type Orientation = Horizontal | Vertical
|
||||||
|
|
||||||
|
/// In Wire.Rotation: PosY: 0, PosX: 90, NegY: 180, NegX: 270 degree clockwise rotation
|
||||||
|
type Direction = PosX | PosY | NegX | NegY
|
||||||
|
|
||||||
type SnapPosition = High | Mid | Low
|
type SnapPosition = High | Mid | Low
|
||||||
|
|
||||||
/// Absolute Segment
|
/// Absolute Segment
|
||||||
|
@ -115,6 +118,9 @@ type Wire =
|
||||||
OutputPort: OutputPortId
|
OutputPort: OutputPortId
|
||||||
Color: HighLightColor
|
Color: HighLightColor
|
||||||
Width: int
|
Width: int
|
||||||
|
Rotation: Direction
|
||||||
|
/// True = Reflected along y axis , False = Not Reflected
|
||||||
|
YReflect: bool
|
||||||
Segments: ASeg list
|
Segments: ASeg list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,11 +156,86 @@ type Msg =
|
||||||
| DragWire of ConnectionId * MouseT
|
| DragWire of ConnectionId * MouseT
|
||||||
| ColorWires of ConnectionId list * HighLightColor
|
| ColorWires of ConnectionId list * HighLightColor
|
||||||
| ErrorWires of ConnectionId list
|
| ErrorWires of ConnectionId list
|
||||||
| ResetJumps of ConnectionId list
|
|
||||||
| MakeJumps of ConnectionId list
|
|
||||||
| ResetModel // For Issie Integration
|
| ResetModel // For Issie Integration
|
||||||
| LoadConnections of Connection list // For Issie Integration
|
| LoadConnections of Connection list // For Issie Integration
|
||||||
|
|
||||||
|
//----------------------------Helper Functions-----------------------------------//
|
||||||
|
|
||||||
|
/// Transform a wire with its RISegs list to a list of ASegs
|
||||||
|
let riSegWireToASegs (wire:Wire) =
|
||||||
|
|
||||||
|
let getStartEnd (seg:RISeg)=
|
||||||
|
match seg.Dir with
|
||||||
|
| Horizontal -> (seg.Start,{seg.Start with X = seg.Start.X+seg.Length})
|
||||||
|
| Vertical -> (seg.Start,{seg.Start with Y = seg.Start.Y+seg.Length})
|
||||||
|
|
||||||
|
let rotate (pos:XYPos) =
|
||||||
|
match wire.Rotation with
|
||||||
|
| PosX -> {pos with X = pos.Y ; Y = -pos.X}
|
||||||
|
| NegX -> {pos with X = -pos.Y ; Y = pos.X}
|
||||||
|
| PosY -> pos
|
||||||
|
| NegY -> {pos with X = -pos.X; Y = -pos.Y}
|
||||||
|
|
||||||
|
let yReflect (pos:XYPos) =
|
||||||
|
if wire.YReflect then
|
||||||
|
{pos with X = -pos.X}
|
||||||
|
else
|
||||||
|
pos
|
||||||
|
|
||||||
|
let check_Orientation (pos: XYPos * XYPos)=
|
||||||
|
let pos1 = fst pos
|
||||||
|
let pos2 = snd pos
|
||||||
|
if abs (pos1.X - pos2.X) <= XYPos.epsilon
|
||||||
|
then Vertical
|
||||||
|
else Horizontal
|
||||||
|
|
||||||
|
let lstOfPos =
|
||||||
|
List.map getStartEnd (List.map aSegToRISeg wire.Segments)
|
||||||
|
|> List.map (fun (s,e) -> (rotate s, rotate e))
|
||||||
|
|> List.map (fun (s,e) -> (yReflect s, yReflect e))
|
||||||
|
|
||||||
|
let posToASegs (pos: XYPos * XYPos) (riSeg: RISeg) : ASeg =
|
||||||
|
{
|
||||||
|
Id = riSeg.Id;
|
||||||
|
Index = riSeg.Index;
|
||||||
|
Start = fst pos;
|
||||||
|
End = snd pos;
|
||||||
|
Dir = check_Orientation pos;
|
||||||
|
HostId = riSeg.HostId;
|
||||||
|
JumpCoordinateListA = List.map(fun (len, id) -> (len + (fst pos).X) , id) riSeg.JumpDistanceListRI;
|
||||||
|
Draggable = riSeg.Draggable;
|
||||||
|
ManualRoute = riSeg.ManualRoute
|
||||||
|
}
|
||||||
|
|
||||||
|
(lstOfPos,(List.map aSegToRISeg wire.Segments)) ||> List.map2 posToASegs
|
||||||
|
|
||||||
|
/// Transform a list of ASegs to RISegs list (default Rotation: PosY, YReflect: False)
|
||||||
|
let aSegListToRISegList (aSegList: ASeg list) =
|
||||||
|
let toRISeg (seg: ASeg) =
|
||||||
|
let direction, length =
|
||||||
|
let xChange = seg.End.X - seg.Start.X
|
||||||
|
let yChange = seg.End.Y - seg.Start.Y
|
||||||
|
match xChange, yChange with
|
||||||
|
| x, y when x = 0 -> Vertical, y
|
||||||
|
| x, y when y = 0 -> Horizontal, x
|
||||||
|
// default orientation for unused segments?
|
||||||
|
| x, _ -> Horizontal, x
|
||||||
|
|
||||||
|
{
|
||||||
|
Id = seg.Id
|
||||||
|
Index = seg.Index
|
||||||
|
Length = length
|
||||||
|
Start = seg.Start
|
||||||
|
Dir = direction
|
||||||
|
HostId = seg.HostId
|
||||||
|
JumpDistanceListRI = List.map(fun (x, id) -> (x - seg.Start.X) , id) seg.JumpCoordinateListA
|
||||||
|
Draggable = seg.Draggable
|
||||||
|
ManualRoute = seg.ManualRoute
|
||||||
|
}
|
||||||
|
|
||||||
|
aSegList
|
||||||
|
|> List.map toRISeg
|
||||||
|
|
||||||
//-------------------------Debugging functions---------------------------------//
|
//-------------------------Debugging functions---------------------------------//
|
||||||
|
|
||||||
let ppSId (sId:SegmentId) =
|
let ppSId (sId:SegmentId) =
|
||||||
|
@ -206,7 +287,7 @@ let ppSeg seg (model: Model) =
|
||||||
let wire = model.WX[cid]
|
let wire = model.WX[cid]
|
||||||
let sg = List.find (fun (s: ASeg) -> s.Id = sid ) wire.Segments
|
let sg = List.find (fun (s: ASeg) -> s.Id = sid ) wire.Segments
|
||||||
let pxy (xy: XYPos) = sprintf $"{(xy.X,xy.Y)}"
|
let pxy (xy: XYPos) = sprintf $"{(xy.X,xy.Y)}"
|
||||||
sprintf $"""[{ppSId sg.Id}: {pxy sg.Start}->{pxy sg.End}]-{match sg.Dir with | Vertical -> "V" | _ -> "H"}-{sg.Index}"""
|
sprintf $"""[{ppSId sg.Id}: {pxy sg.Start}]-{match sg.Dir with | Horizontal -> "Horizontal" | Vertical -> "Vertical" }-{sg.Index}"""
|
||||||
|
|
||||||
let pp segs (model: Model)=
|
let pp segs (model: Model)=
|
||||||
segs
|
segs
|
||||||
|
@ -216,7 +297,7 @@ let pp segs (model: Model)=
|
||||||
match List.tryFind (fun (s: ASeg) -> s.Id = sid ) wire.Segments with
|
match List.tryFind (fun (s: ASeg) -> s.Id = sid ) wire.Segments with
|
||||||
| Some sg ->
|
| Some sg ->
|
||||||
let pxy (xy: XYPos) = sprintf $"{(xy.X,xy.Y)}"
|
let pxy (xy: XYPos) = sprintf $"{(xy.X,xy.Y)}"
|
||||||
sprintf $"""[{pxy sg.Start}->{pxy sg.End}]-{match sg.Dir with | Vertical -> "V" | _ -> "H"}-{sg.Index}"""
|
sprintf $"""[{pxy sg.Start}]-{match sg.Dir with | Horizontal -> "Horizontal" | Vertical -> "Vertical" }-{sg.Index}"""
|
||||||
| None -> "XX")
|
| None -> "XX")
|
||||||
|> String.concat ";"
|
|> String.concat ";"
|
||||||
|
|
||||||
|
@ -328,10 +409,10 @@ let convertVerticesToASegs connId (isLeftToRight: bool) (xyVerticesList: XYPos l
|
||||||
ManualRoute = false
|
ManualRoute = false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// TODO: native RISeg implementation
|
||||||
let convertVerticesToRISegs connId (isLeftToRight: bool) (verticesList: XYPos list) : RISeg list =
|
let convertVerticesToRISegs connId (isLeftToRight: bool) (verticesList: XYPos list) : RISeg list =
|
||||||
convertVerticesToASegs connId isLeftToRight verticesList
|
convertVerticesToASegs connId isLeftToRight verticesList
|
||||||
|> List.map aSegToRISeg
|
|> List.map aSegToRISeg
|
||||||
// TODO: native RISeg implementation
|
|
||||||
|
|
||||||
/// Convert a (possibly legacy) issie Connection stored as a list of vertices to Absolute Segments
|
/// Convert a (possibly legacy) issie Connection stored as a list of vertices to Absolute Segments
|
||||||
let issieVerticesToASegs connId (verticesList: (float * float) list) : ASeg list =
|
let issieVerticesToASegs connId (verticesList: (float * float) list) : ASeg list =
|
||||||
|
@ -356,11 +437,11 @@ let issieVerticesToASegs connId (verticesList: (float * float) list) : ASeg list
|
||||||
printfn "Converting unknown"
|
printfn "Converting unknown"
|
||||||
makeNewSegmentsFromPorts XYPosList
|
makeNewSegmentsFromPorts XYPosList
|
||||||
|
|
||||||
|
// TODO: native RISeg implementation
|
||||||
/// Convert a (possibly legacy) issie Connection stored as a list of vertices to Rotation Invariant Segments
|
/// Convert a (possibly legacy) issie Connection stored as a list of vertices to Rotation Invariant Segments
|
||||||
let issieVerticesToRISegs connId (verticesList: (float * float) list) : RISeg list =
|
let issieVerticesToRISegs connId (verticesList: (float * float) list) : RISeg list =
|
||||||
issieVerticesToASegs connId verticesList
|
issieVerticesToASegs connId verticesList
|
||||||
|> List.map aSegToRISeg
|
|> List.map aSegToRISeg
|
||||||
// TODO: native RISeg implementation
|
|
||||||
|
|
||||||
//----------------------interface to Issie-----------------------//
|
//----------------------interface to Issie-----------------------//
|
||||||
// Section of functions that offer an interface between our implementation and Issie
|
// Section of functions that offer an interface between our implementation and Issie
|
||||||
|
@ -434,11 +515,11 @@ let makeInitialASegList (hostId: ConnectionId) (portCoords: XYPos * XYPos) : ASe
|
||||||
let xyPairs, isLeftToRight = initialWireVerticesFromPorts portCoords
|
let xyPairs, isLeftToRight = initialWireVerticesFromPorts portCoords
|
||||||
xyPairs |> convertVerticesToASegs hostId isLeftToRight
|
xyPairs |> convertVerticesToASegs hostId isLeftToRight
|
||||||
|
|
||||||
|
// 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
|
||||||
let makeInitialRISegList (hostId: ConnectionId) (portCoords: XYPos * XYPos) : RISeg list =
|
let makeInitialRISegList (hostId: ConnectionId) (portCoords: XYPos * XYPos) : RISeg list =
|
||||||
makeInitialASegList hostId portCoords
|
makeInitialASegList hostId portCoords
|
||||||
|> List.map aSegToRISeg
|
|> List.map aSegToRISeg
|
||||||
// TODO: native RISeg implementation
|
|
||||||
|
|
||||||
/// Render given Rotation Invariant Segment using colour and width properties given
|
/// Render given Rotation Invariant Segment using colour and width properties given
|
||||||
/// Takes in 2 connecting segments to add rounded corners if appropriate
|
/// Takes in 2 connecting segments to add rounded corners if appropriate
|
||||||
|
@ -500,7 +581,6 @@ let renderRISegAndCorner (colour: string) (width: string) (segments: RISeg * RIS
|
||||||
|
|
||||||
g [] segmentElements
|
g [] segmentElements
|
||||||
|
|
||||||
|
|
||||||
/// Takes in a Rotation Invariant Segment List and renders the resulting React Element List, with rounded corners if appropriate
|
/// Takes in a Rotation Invariant Segment List and renders the resulting React Element List, with rounded corners if appropriate
|
||||||
let renderRISegList (colour: string) (width: string) (segs: RISeg list) : ReactElement list =
|
let renderRISegList (colour: string) (width: string) (segs: RISeg list) : ReactElement list =
|
||||||
let riSegs =
|
let riSegs =
|
||||||
|
@ -587,10 +667,6 @@ let view (model: Model) (dispatch: Dispatch<Msg>) =
|
||||||
g [] [(g [] wires); symbols]
|
g [] [(g [] wires); symbols]
|
||||||
|> TimeHelpers.instrumentInterval "WireView" start
|
|> TimeHelpers.instrumentInterval "WireView" start
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------- Inigo Selwood
|
|
||||||
|
|
||||||
|
|
||||||
/// Gets the intersection point between two segments, or None if the segments
|
/// Gets the intersection point between two segments, or None if the segments
|
||||||
/// don't intersect
|
/// don't intersect
|
||||||
let segmentIntersectsSegmentCoordinates
|
let segmentIntersectsSegmentCoordinates
|
||||||
|
@ -622,7 +698,6 @@ let segmentIntersectsSegmentCoordinates
|
||||||
else
|
else
|
||||||
None
|
None
|
||||||
|
|
||||||
|
|
||||||
/// Given a bounding box, find the top-left and bottom-right corners.
|
/// Given a bounding box, find the top-left and bottom-right corners.
|
||||||
/// Note: finding the (min, max) vertex values seems a little redundant, but
|
/// Note: finding the (min, max) vertex values seems a little redundant, but
|
||||||
/// maybe the (width, height) values can be negative? Either way, I haven't
|
/// maybe the (width, height) values can be negative? Either way, I haven't
|
||||||
|
@ -649,7 +724,6 @@ let getTopLeftAndBottomRightCorner (box : BoundingBox) : XYPos * XYPos =
|
||||||
|
|
||||||
(topLeft, bottomRight)
|
(topLeft, bottomRight)
|
||||||
|
|
||||||
|
|
||||||
/// Given a segment and a bounding box, evaluates:
|
/// Given a segment and a bounding box, evaluates:
|
||||||
/// - (false, None) if there's no intersection
|
/// - (false, None) if there's no intersection
|
||||||
/// - (true, None) if it's fully inside the box
|
/// - (true, None) if it's fully inside the box
|
||||||
|
@ -704,7 +778,6 @@ let segmentIntersectsBoundingBoxCoordinates
|
||||||
else
|
else
|
||||||
true, Some (List.head intersectionList)
|
true, Some (List.head intersectionList)
|
||||||
|
|
||||||
|
|
||||||
/// Given a point and a segment, calculate the distance between the two
|
/// Given a point and a segment, calculate the distance between the two
|
||||||
let distanceFromPointToSegment (point: XYPos) (segment: ASeg): float =
|
let distanceFromPointToSegment (point: XYPos) (segment: ASeg): float =
|
||||||
|
|
||||||
|
@ -734,7 +807,6 @@ let distanceFromPointToSegment (point: XYPos) (segment: ASeg): float =
|
||||||
|
|
||||||
(abs alpha) / (sqrt beta)
|
(abs alpha) / (sqrt beta)
|
||||||
|
|
||||||
|
|
||||||
/// Given the model's state and a list of wire IDs to remap,
|
/// Given the model's state and a list of wire IDs to remap,
|
||||||
/// reroute those wires with default shapes between
|
/// reroute those wires with default shapes between
|
||||||
let routeGivenWiresBasedOnPortPositions
|
let routeGivenWiresBasedOnPortPositions
|
||||||
|
@ -774,7 +846,6 @@ let routeGivenWiresBasedOnPortPositions
|
||||||
|
|
||||||
{model with WX = newWX}
|
{model with WX = newWX}
|
||||||
|
|
||||||
|
|
||||||
/// For a given connection ID and bounding box: find the segments of the wire
|
/// For a given connection ID and bounding box: find the segments of the wire
|
||||||
/// that intersect the boundary (in a given model)
|
/// that intersect the boundary (in a given model)
|
||||||
let getIntersectingSegments
|
let getIntersectingSegments
|
||||||
|
@ -789,7 +860,6 @@ let getIntersectingSegments
|
||||||
// Filter for only the segments which intersect
|
// Filter for only the segments which intersect
|
||||||
List.filter segmentFilter model.WX[wireId].Segments
|
List.filter segmentFilter model.WX[wireId].Segments
|
||||||
|
|
||||||
|
|
||||||
/// Finds the closest segment in a wire to a point (using euclidean distance)
|
/// Finds the closest segment in a wire to a point (using euclidean distance)
|
||||||
let getClosestSegment
|
let getClosestSegment
|
||||||
(model: Model)
|
(model: Model)
|
||||||
|
@ -800,7 +870,6 @@ let getClosestSegment
|
||||||
distanceFromPointToSegment pos segment
|
distanceFromPointToSegment pos segment
|
||||||
List.minBy distanceToPoint (model.WX[wireId].Segments)
|
List.minBy distanceToPoint (model.WX[wireId].Segments)
|
||||||
|
|
||||||
|
|
||||||
/// Gets the ID of the wire clicked
|
/// Gets the ID of the wire clicked
|
||||||
/// Note: presumes we already know a wire has been clicked on, and just need
|
/// Note: presumes we already know a wire has been clicked on, and just need
|
||||||
/// its ID
|
/// its ID
|
||||||
|
@ -826,7 +895,6 @@ let getClickedSegment
|
||||||
| true -> (getClosestSegment model wireID position).Id
|
| true -> (getClosestSegment model wireID position).Id
|
||||||
| false -> (List.head intersectingSegments).Id
|
| false -> (List.head intersectingSegments).Id
|
||||||
|
|
||||||
|
|
||||||
/// Verifies that the segment is aligned with the axis it's meant to lie on
|
/// Verifies that the segment is aligned with the axis it's meant to lie on
|
||||||
let checkSegmentAngle (segment: ASeg) (name: string): unit =
|
let checkSegmentAngle (segment: ASeg) (name: string): unit =
|
||||||
|
|
||||||
|
@ -844,17 +912,14 @@ let checkSegmentAngle (segment: ASeg) (name: string): unit =
|
||||||
if not isAligned then
|
if not isAligned then
|
||||||
printfn $"Weird segment '{name}':\n{segment}\n\n fails angle checking"
|
printfn $"Weird segment '{name}':\n{segment}\n\n fails angle checking"
|
||||||
|
|
||||||
|
|
||||||
/// Checks whether a segment points to the left
|
/// Checks whether a segment points to the left
|
||||||
let segPointsLeft (segment: ASeg): bool =
|
let segPointsLeft (segment: ASeg): bool =
|
||||||
(abs segment.Start.X > abs segment.End.X) && (segment.Dir = Horizontal)
|
(abs segment.Start.X > abs segment.End.X) && (segment.Dir = Horizontal)
|
||||||
|
|
||||||
|
|
||||||
/// Checks the segment's length along the X axis
|
/// Checks the segment's length along the X axis
|
||||||
let segXDelta (segment: ASeg): float =
|
let segXDelta (segment: ASeg): float =
|
||||||
(abs segment.End.X) - (abs segment.Start.X)
|
(abs segment.End.X) - (abs segment.Start.X)
|
||||||
|
|
||||||
|
|
||||||
/// Given two segments which are joined at a given position, change the X
|
/// Given two segments which are joined at a given position, change the X
|
||||||
/// coordinate of that coordinate (compensating for negative values)
|
/// coordinate of that coordinate (compensating for negative values)
|
||||||
let moveXJoinPos
|
let moveXJoinPos
|
||||||
|
@ -873,7 +938,6 @@ let moveXJoinPos
|
||||||
{segment2 with Start = changeXKeepingSign segment2.Start}
|
{segment2 with Start = changeXKeepingSign segment2.Start}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
/// Picks the outermost segment (usually segment 1, unless isAtEnd [of wire])
|
/// Picks the outermost segment (usually segment 1, unless isAtEnd [of wire])
|
||||||
/// and ensures it's at least a Wire.stickLength long by moving the point where
|
/// and ensures it's at least a Wire.stickLength long by moving the point where
|
||||||
/// it meets the other (innermost) segment
|
/// it meets the other (innermost) segment
|
||||||
|
@ -916,7 +980,6 @@ let changeLengths
|
||||||
else
|
else
|
||||||
[segment1; segment2]
|
[segment1; segment2]
|
||||||
|
|
||||||
|
|
||||||
/// Called for segments [1:5] -- if they're vertical and can move horizontally.
|
/// Called for segments [1:5] -- if they're vertical and can move horizontally.
|
||||||
/// Returns the distance value once it's been moderated to prevent wires
|
/// Returns the distance value once it's been moderated to prevent wires
|
||||||
/// moving into components.
|
/// moving into components.
|
||||||
|
@ -967,7 +1030,6 @@ let getSafeDistanceForMove
|
||||||
| 3 -> distance |> max minimumDistance |> min maximumDistance
|
| 3 -> distance |> max minimumDistance |> min maximumDistance
|
||||||
| _ -> distance
|
| _ -> distance
|
||||||
|
|
||||||
|
|
||||||
/// Remove pairs of adjacent segments which are aligned but not of the same
|
/// Remove pairs of adjacent segments which are aligned but not of the same
|
||||||
/// sign
|
/// sign
|
||||||
let removeRedundantSegments (segments: ASeg list) =
|
let removeRedundantSegments (segments: ASeg list) =
|
||||||
|
@ -1021,7 +1083,6 @@ let removeRedundantSegments (segments: ASeg list) =
|
||||||
@ segments[2..4]
|
@ segments[2..4]
|
||||||
@ reduce segments[5] segments[6]
|
@ reduce segments[5] segments[6]
|
||||||
|
|
||||||
|
|
||||||
/// Moves a wire segment a given amount perpendicular to its orientation.
|
/// Moves a wire segment a given amount perpendicular to its orientation.
|
||||||
/// Used to manually adjust routing by dragging with the mouse.
|
/// Used to manually adjust routing by dragging with the mouse.
|
||||||
let moveSegment (segment: ASeg) (distance:float) (model:Model) =
|
let moveSegment (segment: ASeg) (distance:float) (model:Model) =
|
||||||
|
@ -1095,7 +1156,6 @@ let moveSegment (segment: ASeg) (distance:float) (model:Model) =
|
||||||
// Create a new wire with the moved and reduced segments
|
// Create a new wire with the moved and reduced segments
|
||||||
{wire with Segments = newSegments}
|
{wire with Segments = newSegments}
|
||||||
|
|
||||||
|
|
||||||
/// Initialisatiton with no wires
|
/// Initialisatiton with no wires
|
||||||
let init () =
|
let init () =
|
||||||
let symbols, _ = Symbol.init()
|
let symbols, _ = Symbol.init()
|
||||||
|
@ -1115,7 +1175,6 @@ let init () =
|
||||||
|
|
||||||
(model, Cmd.none)
|
(model, Cmd.none)
|
||||||
|
|
||||||
|
|
||||||
/// Returns the wires connected to a list of components
|
/// Returns the wires connected to a list of components
|
||||||
let getConnectedWires (model : Model) (componentIDs : ComponentId list) =
|
let getConnectedWires (model : Model) (componentIDs : ComponentId list) =
|
||||||
|
|
||||||
|
@ -1131,7 +1190,6 @@ let getConnectedWires (model : Model) (componentIDs : ComponentId list) =
|
||||||
|> List.map (fun wire -> wire.Id)
|
|> List.map (fun wire -> wire.Id)
|
||||||
|> List.distinct
|
|> List.distinct
|
||||||
|
|
||||||
|
|
||||||
/// Returns 3 tuples:
|
/// Returns 3 tuples:
|
||||||
/// - wires connected only to inputs
|
/// - wires connected only to inputs
|
||||||
/// - those connected only to outputs
|
/// - those connected only to outputs
|
||||||
|
@ -1172,7 +1230,6 @@ let filterWiresByCompMoved (model: Model) (componentIDs: ComponentId list) =
|
||||||
|
|
||||||
(inputWires, outputWires, fullyConnected)
|
(inputWires, outputWires, fullyConnected)
|
||||||
|
|
||||||
|
|
||||||
/// Returns a newly autorouted wire given a model and wire
|
/// Returns a newly autorouted wire given a model and wire
|
||||||
let autorouteWire (model: Model) (wire: Wire): Wire =
|
let autorouteWire (model: Model) (wire: Wire): Wire =
|
||||||
|
|
||||||
|
@ -1187,7 +1244,6 @@ let autorouteWire (model: Model) (wire: Wire): Wire =
|
||||||
Segments = makeInitialASegList wire.Id locations
|
Segments = makeInitialASegList wire.Id locations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Reverse the segment order, as well as (start, end) coordinates
|
/// Reverse the segment order, as well as (start, end) coordinates
|
||||||
let revSegments (segments: ASeg list) =
|
let revSegments (segments: ASeg list) =
|
||||||
let invert (segment: ASeg) : ASeg =
|
let invert (segment: ASeg) : ASeg =
|
||||||
|
@ -1200,7 +1256,6 @@ let revSegments (segments: ASeg list) =
|
||||||
List.rev segments
|
List.rev segments
|
||||||
|> List.map invert
|
|> List.map invert
|
||||||
|
|
||||||
|
|
||||||
// ====================================================================================================================
|
// ====================================================================================================================
|
||||||
//
|
//
|
||||||
// WIRE SEGMENTS FOR ROUTING
|
// WIRE SEGMENTS FOR ROUTING
|
||||||
|
@ -1228,7 +1283,6 @@ let revSegments (segments: ASeg list) =
|
||||||
//
|
//
|
||||||
// ======================================================================================================================
|
// ======================================================================================================================
|
||||||
|
|
||||||
|
|
||||||
/// Create a position, the sum of two other positions
|
/// Create a position, the sum of two other positions
|
||||||
let inline addPosPos (position1: XYPos) (position2: XYPos): XYPos =
|
let inline addPosPos (position1: XYPos) (position2: XYPos): XYPos =
|
||||||
{
|
{
|
||||||
|
@ -1236,7 +1290,6 @@ let inline addPosPos (position1: XYPos) (position2: XYPos): XYPos =
|
||||||
Y = position1.Y + position2.Y
|
Y = position1.Y + position2.Y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Applies a mover function to the end of a segment at a given index
|
/// Applies a mover function to the end of a segment at a given index
|
||||||
let inline moveEnd (mover: XYPos -> XYPos) (setIndex: int) =
|
let inline moveEnd (mover: XYPos -> XYPos) (setIndex: int) =
|
||||||
|
|
||||||
|
@ -1251,7 +1304,6 @@ let inline moveEnd (mover: XYPos -> XYPos) (setIndex: int) =
|
||||||
|
|
||||||
List.mapi setEndAtIndex
|
List.mapi setEndAtIndex
|
||||||
|
|
||||||
|
|
||||||
/// Applies a mover function to the start of a segment at a given index
|
/// Applies a mover function to the start of a segment at a given index
|
||||||
let inline moveStart (mover: XYPos -> XYPos) (setIndex: int) =
|
let inline moveStart (mover: XYPos -> XYPos) (setIndex: int) =
|
||||||
|
|
||||||
|
@ -1266,7 +1318,6 @@ let inline moveStart (mover: XYPos -> XYPos) (setIndex: int) =
|
||||||
|
|
||||||
List.mapi setStartAtIndex
|
List.mapi setStartAtIndex
|
||||||
|
|
||||||
|
|
||||||
/// Applies a mover function to the (start, end) of a segment at a given index
|
/// Applies a mover function to the (start, end) of a segment at a given index
|
||||||
let inline moveAll (mover: XYPos -> XYPos) (setIndex: int) =
|
let inline moveAll (mover: XYPos -> XYPos) (setIndex: int) =
|
||||||
|
|
||||||
|
@ -1282,7 +1333,6 @@ let inline moveAll (mover: XYPos -> XYPos) (setIndex: int) =
|
||||||
|
|
||||||
List.mapi setAllAtIndex
|
List.mapi setAllAtIndex
|
||||||
|
|
||||||
|
|
||||||
/// Applies (X, Y) transformations to a point
|
/// Applies (X, Y) transformations to a point
|
||||||
let transformXY
|
let transformXY
|
||||||
(xTransform: float -> float)
|
(xTransform: float -> float)
|
||||||
|
@ -1295,7 +1345,6 @@ let transformXY
|
||||||
Y = yTransform point.Y
|
Y = yTransform point.Y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Applies (X, Y) transformations to the start and end of a segment
|
/// Applies (X, Y) transformations to the start and end of a segment
|
||||||
let transformSeg
|
let transformSeg
|
||||||
(xTransform: float -> float)
|
(xTransform: float -> float)
|
||||||
|
@ -1310,14 +1359,12 @@ let transformSeg
|
||||||
End = transform segment.End
|
End = transform segment.End
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Gets a tuple, the pair of directions in each axis
|
/// Gets a tuple, the pair of directions in each axis
|
||||||
let topology (position1: XYPos) (position2: XYPos): int * int =
|
let topology (position1: XYPos) (position2: XYPos): int * int =
|
||||||
let delta (point0: float) (point1: float): int =
|
let delta (point0: float) (point1: float): int =
|
||||||
sign (abs point0 - abs point1)
|
sign (abs point0 - abs point1)
|
||||||
(delta position1.X position2.X), (delta position1.Y position2.Y)
|
(delta position1.X position2.X), (delta position1.Y position2.Y)
|
||||||
|
|
||||||
|
|
||||||
/// Performs a partial autoroute. Will fail (returning None) if a full
|
/// Performs a partial autoroute. Will fail (returning None) if a full
|
||||||
/// autoroute is needed -- or if there are manually dragged segments in the
|
/// autoroute is needed -- or if there are manually dragged segments in the
|
||||||
/// way.
|
/// way.
|
||||||
|
@ -1428,7 +1475,6 @@ let partialAutoRoute
|
||||||
|> Option.bind checkTopology
|
|> Option.bind checkTopology
|
||||||
|> Option.bind preEndScale
|
|> Option.bind preEndScale
|
||||||
|
|
||||||
|
|
||||||
/// Returns the new positions keeping manual coordinates negative, and auto
|
/// Returns the new positions keeping manual coordinates negative, and auto
|
||||||
/// coordinates positive
|
/// coordinates positive
|
||||||
let negXYPos (position: XYPos) (difference: XYPos): XYPos =
|
let negXYPos (position: XYPos) (difference: XYPos): XYPos =
|
||||||
|
@ -1442,7 +1488,6 @@ let negXYPos (position: XYPos) (difference: XYPos): XYPos =
|
||||||
else
|
else
|
||||||
newPosition
|
newPosition
|
||||||
|
|
||||||
|
|
||||||
/// Moves a wire by a specified amount by adding a XYPos to each start and end
|
/// Moves a wire by a specified amount by adding a XYPos to each start and end
|
||||||
/// point of each segment
|
/// point of each segment
|
||||||
let moveWire (wire : Wire) (difference : XYPos): Wire =
|
let moveWire (wire : Wire) (difference : XYPos): Wire =
|
||||||
|
@ -1459,7 +1504,6 @@ let moveWire (wire : Wire) (difference : XYPos): Wire =
|
||||||
Segments = List.map transformer wire.Segments
|
Segments = List.map transformer wire.Segments
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Re-routes a wire in the model when its ports have moved. Tries to preserve
|
/// Re-routes a wire in the model when its ports have moved. Tries to preserve
|
||||||
/// manual routing when it makes sense to do so -- otherwise, use auto-routing.
|
/// manual routing when it makes sense to do so -- otherwise, use auto-routing.
|
||||||
let updateWire (model: Model) (wire: Wire) (isInput: bool) =
|
let updateWire (model: Model) (wire: Wire) (isInput: bool) =
|
||||||
|
@ -1485,112 +1529,38 @@ let updateWire (model: Model) (wire: Wire) (isInput: bool) =
|
||||||
|> Option.map (fun segs -> {wire with Segments = segs})
|
|> Option.map (fun segs -> {wire with Segments = segs})
|
||||||
|> Option.defaultValue (autorouteWire model wire)
|
|> Option.defaultValue (autorouteWire model wire)
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------ / Inigo Selwood
|
|
||||||
|
|
||||||
let makeAllJumps (wiresWithNoJumps: ConnectionId list) (model: Model) =
|
|
||||||
let mutable newWX = model.WX
|
|
||||||
// Arrays are faster to check than lists
|
|
||||||
let wiresWithNoJumpsA = List.toArray wiresWithNoJumps
|
|
||||||
let changeJumps wid index jumps =
|
|
||||||
let jumps = List.sortDescending jumps
|
|
||||||
let changeSegment segs =
|
|
||||||
List.mapi (fun i x -> if i <> index then x else { x with JumpCoordinateListA = jumps }) segs
|
|
||||||
|
|
||||||
newWX <- Map.add wid { newWX[wid] with Segments = changeSegment newWX[wid].Segments } newWX
|
|
||||||
|
|
||||||
let segs =
|
|
||||||
model.WX
|
|
||||||
|> Map.toArray
|
|
||||||
|> Array.map (fun (_wid, w) -> List.toArray w.Segments)
|
|
||||||
|
|
||||||
for w1 in 0 .. segs.Length - 1 do
|
|
||||||
for h in segs[w1] do
|
|
||||||
if h.Dir = Horizontal then
|
|
||||||
// work out what jumps this segment should have
|
|
||||||
let mutable jumps: (float * SegmentId) list = []
|
|
||||||
|
|
||||||
if not (Array.contains h.HostId wiresWithNoJumpsA) then
|
|
||||||
for w2 in 0 .. segs.Length - 1 do
|
|
||||||
// everything inside the inner loop should be very highly optimised
|
|
||||||
// it is executed n^2 time where n is the number of segments (maybe 5000)
|
|
||||||
// the abs here are because segment coordinates my be negated to indicate manual routing
|
|
||||||
for v in segs[w2] do
|
|
||||||
if not (Array.contains v.HostId wiresWithNoJumpsA) then
|
|
||||||
match v.Dir with
|
|
||||||
| Vertical ->
|
|
||||||
let x, x1, x2 = abs v.Start.X, abs h.Start.X, abs h.End.X
|
|
||||||
let y, y1, y2 = abs h.Start.Y, abs v.Start.Y, abs v.End.Y
|
|
||||||
let xhi, xlo = max x1 x2, min x1 x2
|
|
||||||
let yhi, ylo = max y1 y2, min y1 y2
|
|
||||||
//printfn $"{[xlo;x;xhi]}, {[ylo;y;yhi]}"
|
|
||||||
if x < xhi - 5.0 && x > xlo + 5.0 && y < yhi - 5.0 && y > ylo + 5.0 then
|
|
||||||
//printfn "found a jump!"
|
|
||||||
jumps <- (x, v.Id) :: jumps
|
|
||||||
| _ -> ()
|
|
||||||
// compare jumps with what segment now has, and change newWX if need be
|
|
||||||
// note that if no change is needed we do not update WX
|
|
||||||
// simple cases are done without sort for speed, proably not necessary!
|
|
||||||
// The jump list is sorted in model to enable easier rendering of segments
|
|
||||||
match jumps, h.JumpCoordinateListA with
|
|
||||||
| [], [] -> ()
|
|
||||||
| [ a ], [ b ] when a <> b -> changeJumps h.HostId h.Index jumps
|
|
||||||
| [], _ -> changeJumps h.HostId h.Index jumps
|
|
||||||
| _, [] -> // in this case we need to sort the jump list
|
|
||||||
changeJumps h.HostId h.Index (List.sort jumps)
|
|
||||||
| newJumps, oldJ ->
|
|
||||||
let newJ = List.sort newJumps
|
|
||||||
// oldJ is already sorted (we only ever write newJ back to model)
|
|
||||||
if newJ <> oldJ then changeJumps h.HostId h.Index newJumps else ()
|
|
||||||
|
|
||||||
{ model with WX = newWX }
|
|
||||||
|
|
||||||
let updateWireSegmentJumps (_wireList: ConnectionId list) (wModel: Model) : Model =
|
|
||||||
let startT = TimeHelpers.getTimeMs()
|
|
||||||
let model = makeAllJumps [] wModel
|
|
||||||
TimeHelpers.instrumentTime "UpdateJumps" startT
|
|
||||||
model
|
|
||||||
|
|
||||||
/// This function updates the wire model by removing from the stored lists of intersections
|
|
||||||
/// all those generated by wireList wires.
|
|
||||||
/// intersetcions are stored in maps on the model and on the horizontal segments containing the jumps
|
|
||||||
let resetWireSegmentJumps (wireList: ConnectionId list) (wModel: Model) : Model =
|
|
||||||
makeAllJumps wireList wModel
|
|
||||||
|
|
||||||
/// Re-routes the wires in the model based on a list of components that have been altered.
|
/// Re-routes the wires in the model based on a list of components that have been altered.
|
||||||
/// If the wire input and output ports are both in the list of moved components, does not re-route wire but instead translates it.
|
/// If the wire input and output ports are both in the list of moved components, does not re-route wire but instead translates it.
|
||||||
/// Keeps manual wires manual (up to a point).
|
/// Keeps manual wires manual (up to a point).
|
||||||
/// Otherwise it will auto-route wires connected to components that have moved
|
/// Otherwise it will auto-route wires connected to components that have moved
|
||||||
let updateWires (model: Model) (compIdList: ComponentId list) (diff: XYPos) =
|
let updateWires (model: Model) (compIdList: ComponentId list) (diff: XYPos) =
|
||||||
|
let (inputWires, outputWires, fullyConnectedWires) = filterWiresByCompMoved model compIdList
|
||||||
let (inputWires, outputWires, fullyConnected) = filterWiresByCompMoved model compIdList
|
|
||||||
|
|
||||||
let newWires =
|
let newWires =
|
||||||
model.WX
|
model.WX
|
||||||
|> Map.toList
|
|> Map.toList
|
||||||
|> List.map (fun (cId, wire) ->
|
|> List.map (fun (cId, wire) ->
|
||||||
if List.contains cId fullyConnected //Translate wires that are connected to moving components on both sides
|
if List.contains cId fullyConnectedWires then // Translate wires that are connected to moving components on both sides
|
||||||
then (cId, moveWire wire diff)
|
(cId, moveWire wire diff)
|
||||||
elif List.contains cId inputWires //Only route wires connected to ports that moved for efficiency
|
elif List.contains cId inputWires then // Only route wires connected to ports that moved for efficiency
|
||||||
then (cId, updateWire model wire true)
|
(cId, updateWire model wire true)
|
||||||
elif List.contains cId outputWires
|
elif List.contains cId outputWires then
|
||||||
then (cId, updateWire model wire false)
|
(cId, updateWire model wire false)
|
||||||
else (cId, wire))
|
else
|
||||||
|
(cId, wire))
|
||||||
|> Map.ofList
|
|> Map.ofList
|
||||||
|
|
||||||
{model with WX = newWires}
|
{model with WX = newWires}
|
||||||
|
|
||||||
///
|
/// Update the Model according to the message received, return a tuple of new Model and Msg
|
||||||
let update (msg : Msg) (model : Model) : Model*Cmd<Msg> =
|
let update (msg : Msg) (model : Model) : Model * Cmd<Msg> =
|
||||||
|
|
||||||
match msg with
|
match msg with
|
||||||
| Symbol sMsg ->
|
| Symbol sMsg ->
|
||||||
let sm,sCmd = Symbol.update sMsg model.Symbol
|
let sm,sCmd = Symbol.update sMsg model.Symbol
|
||||||
{model with Symbol=sm}, Cmd.map Symbol sCmd
|
{model with Symbol=sm}, Cmd.map Symbol sCmd
|
||||||
|
|
||||||
|
| UpdateWires (componentIdList, diff) -> updateWires model componentIdList diff, Cmd.none
|
||||||
| UpdateWires (componentIdList, diff) ->
|
|
||||||
updateWires model componentIdList diff, Cmd.none
|
|
||||||
|
|
||||||
| AddWire ( (inputId, outputId) : (InputPortId * OutputPortId) ) ->
|
| AddWire ( (inputId, outputId) : (InputPortId * OutputPortId) ) ->
|
||||||
let portOnePos, portTwoPos = Symbol.getTwoPortLocations model.Symbol inputId outputId // TODO: Symbol fn in BusWire
|
let portOnePos, portTwoPos = Symbol.getTwoPortLocations model.Symbol inputId outputId // TODO: Symbol fn in BusWire
|
||||||
|
@ -1604,16 +1574,17 @@ let update (msg : Msg) (model : Model) : Model*Cmd<Msg> =
|
||||||
OutputPort = outputId
|
OutputPort = outputId
|
||||||
Color = HighLightColor.DarkSlateGrey
|
Color = HighLightColor.DarkSlateGrey
|
||||||
Width = 1
|
Width = 1
|
||||||
|
Rotation = PosY
|
||||||
|
YReflect = false
|
||||||
Segments = segmentList
|
Segments = segmentList
|
||||||
}
|
}
|
||||||
|
|
||||||
let wireAddedMap = Map.add newWire.Id newWire model.WX
|
let wireAddedMap = Map.add newWire.Id newWire model.WX
|
||||||
let newModel = updateWireSegmentJumps [wireId] {model with WX = wireAddedMap}
|
let newModel = {model with WX = wireAddedMap}
|
||||||
|
|
||||||
newModel, Cmd.ofMsg BusWidths
|
newModel, Cmd.ofMsg BusWidths
|
||||||
|
|
||||||
| BusWidths ->
|
| BusWidths ->
|
||||||
|
|
||||||
let processConWidths (connWidths: ConnectionsWidth) =
|
let processConWidths (connWidths: ConnectionsWidth) =
|
||||||
let addWireWidthFolder (wireMap: Map<ConnectionId, Wire>) _ wire =
|
let addWireWidthFolder (wireMap: Map<ConnectionId, Wire>) _ wire =
|
||||||
let width =
|
let width =
|
||||||
|
@ -1629,10 +1600,10 @@ let update (msg : Msg) (model : Model) : Model*Cmd<Msg> =
|
||||||
let symbol = m[symId]
|
let symbol = m[symId]
|
||||||
|
|
||||||
match symbol.Compo.Type with
|
match symbol.Compo.Type with
|
||||||
| SplitWire _n ->
|
| SplitWire _ ->
|
||||||
match inPort.PortNumber with
|
match inPort.PortNumber with
|
||||||
| Some 0 -> {symbol with InWidth0 = Some wire.Width}
|
| Some 0 -> {symbol with InWidth0 = Some wire.Width}
|
||||||
| x -> failwithf $"What? wire found with input port {x} other than 0 connecting to SplitWire"
|
| x -> failwithf $"Error: wire found with input port {x} other than 0 connecting to SplitWire"
|
||||||
|> (fun sym -> Map.add symId sym m)
|
|> (fun sym -> Map.add symId sym m)
|
||||||
| MergeWires ->
|
| MergeWires ->
|
||||||
match inPort.PortNumber with
|
match inPort.PortNumber with
|
||||||
|
@ -1640,24 +1611,20 @@ let update (msg : Msg) (model : Model) : Model*Cmd<Msg> =
|
||||||
Map.add symId {symbol with InWidth0 = Some wire.Width} m
|
Map.add symId {symbol with InWidth0 = Some wire.Width} m
|
||||||
| Some 1 ->
|
| Some 1 ->
|
||||||
Map.add symId {symbol with InWidth1 = Some wire.Width} m
|
Map.add symId {symbol with InWidth1 = Some wire.Width} m
|
||||||
| x -> failwithf $"What? wire found with input port {x} other than 0 or 1 connecting to MergeWires"
|
| x -> failwithf $"Error: wire found with input port {x} other than 0 or 1 connecting to MergeWires"
|
||||||
| _ -> m
|
| _ -> m
|
||||||
|
|
||||||
let newWX = ((Map.empty, model.WX) ||> Map.fold addWireWidthFolder)
|
let newWX = ((Map.empty, model.WX) ||> Map.fold addWireWidthFolder)
|
||||||
|
let symbolsWithWidths = (model.Symbol.Symbols, newWX) ||> Map.fold addSymbolWidthFolder
|
||||||
let symbolsWithWidths =
|
|
||||||
(model.Symbol.Symbols, newWX) ||> Map.fold addSymbolWidthFolder
|
|
||||||
|
|
||||||
{ model with
|
{ model with
|
||||||
WX = newWX; Notifications = None ;
|
WX = newWX; Notifications = None ;
|
||||||
ErrorWires=[];
|
ErrorWires=[];
|
||||||
Symbol = {model.Symbol with Symbols = symbolsWithWidths}}, Cmd.none
|
Symbol = {model.Symbol with Symbols = symbolsWithWidths}
|
||||||
|
}, Cmd.none
|
||||||
|
|
||||||
|
|
||||||
let canvasState = (Symbol.extractComponents model.Symbol, extractConnections model )
|
let canvasState = (Symbol.extractComponents model.Symbol, extractConnections model )
|
||||||
|
|
||||||
|
|
||||||
match BusWidthInferer.inferConnectionsWidth canvasState with
|
match BusWidthInferer.inferConnectionsWidth canvasState with
|
||||||
| Ok connWidths ->
|
| Ok connWidths ->
|
||||||
processConWidths connWidths
|
processConWidths connWidths
|
||||||
|
@ -1687,7 +1654,7 @@ let update (msg : Msg) (model : Model) : Model*Cmd<Msg> =
|
||||||
let newWX =
|
let newWX =
|
||||||
model.WX
|
model.WX
|
||||||
|> Map.map
|
|> Map.map
|
||||||
(fun id wire ->
|
( fun id wire ->
|
||||||
if List.contains id model.ErrorWires then
|
if List.contains id model.ErrorWires then
|
||||||
if List.contains id connectionIds then
|
if List.contains id connectionIds then
|
||||||
{wire with Color = HighLightColor.Brown}
|
{wire with Color = HighLightColor.Brown}
|
||||||
|
@ -1702,11 +1669,10 @@ let update (msg : Msg) (model : Model) : Model*Cmd<Msg> =
|
||||||
{model with WX = newWX}, Cmd.none
|
{model with WX = newWX}, Cmd.none
|
||||||
|
|
||||||
| DeleteWires (connectionIds : ConnectionId list) ->
|
| DeleteWires (connectionIds : ConnectionId list) ->
|
||||||
let newModel = resetWireSegmentJumps (connectionIds) (model)
|
|
||||||
let newWX =
|
let newWX =
|
||||||
newModel.WX
|
model.WX
|
||||||
|> Map.filter (fun id _wire -> not (List.contains id connectionIds))
|
|> Map.filter (fun id _ -> not (List.contains id connectionIds))
|
||||||
{newModel with WX = newWX}, Cmd.ofMsg BusWidths
|
{model with WX = newWX}, Cmd.ofMsg BusWidths
|
||||||
|
|
||||||
| DragWire (connId : ConnectionId, mMsg: MouseT) ->
|
| DragWire (connId : ConnectionId, mMsg: MouseT) ->
|
||||||
match mMsg.Op with
|
match mMsg.Op with
|
||||||
|
@ -1714,20 +1680,23 @@ let update (msg : Msg) (model : Model) : Model*Cmd<Msg> =
|
||||||
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
|
||||||
| Drag ->
|
| Drag ->
|
||||||
let segId = model.SelectedSegment
|
let aSeg =
|
||||||
let rec getSeg (segList: ASeg list) =
|
let aSegOption =
|
||||||
match segList with
|
riSegWireToASegs model.WX[connId]
|
||||||
| h::t -> if h.Id = segId then h else getSeg t
|
|> List.choose ( fun aSeg -> if aSeg.Id = model.SelectedSegment then Some aSeg else None )
|
||||||
| _ -> failwithf "segment Id not found in segment list"
|
|> List.tryExactlyOne
|
||||||
let seg = getSeg model.WX[connId].Segments
|
match aSegOption with
|
||||||
if seg.Draggable then
|
| Some aSeg -> aSeg
|
||||||
let distanceToMove =
|
| None -> failwithf "Error: Segment Id not found in segment list"
|
||||||
match seg.Dir with
|
|
||||||
| Horizontal -> mMsg.Pos.Y - abs seg.Start.Y
|
|
||||||
| Vertical -> mMsg.Pos.X - abs seg.Start.X
|
|
||||||
|
|
||||||
let newWire = moveSegment seg distanceToMove model
|
if aSeg.Draggable then
|
||||||
let newWX = Map.add seg.HostId newWire model.WX
|
let distanceToMove =
|
||||||
|
match aSeg.Dir with
|
||||||
|
| Horizontal -> mMsg.Pos.Y - abs aSeg.Start.Y
|
||||||
|
| Vertical -> mMsg.Pos.X - abs aSeg.Start.X
|
||||||
|
|
||||||
|
let newWire = moveSegment aSeg distanceToMove model
|
||||||
|
let newWX = Map.add aSeg.HostId newWire model.WX
|
||||||
|
|
||||||
{model with WX = newWX}, Cmd.none
|
{model with WX = newWX}, Cmd.none
|
||||||
else
|
else
|
||||||
|
@ -1735,7 +1704,6 @@ let update (msg : Msg) (model : Model) : Model*Cmd<Msg> =
|
||||||
|
|
||||||
| _ -> model, Cmd.none
|
| _ -> model, Cmd.none
|
||||||
|
|
||||||
|
|
||||||
| ColorWires (connIds, color) -> // Just Changes the colour of the wires, Sheet calls pasteWires before this
|
| ColorWires (connIds, color) -> // Just Changes the colour of the wires, Sheet calls pasteWires before this
|
||||||
let newWires =
|
let newWires =
|
||||||
(List.fold (fun prevWires cId ->
|
(List.fold (fun prevWires cId ->
|
||||||
|
@ -1748,87 +1716,66 @@ let update (msg : Msg) (model : Model) : Model*Cmd<Msg> =
|
||||||
Map.add cId { oldWire with Color = color } prevWires) model.WX connIds)
|
Map.add cId { oldWire with Color = color } prevWires) model.WX connIds)
|
||||||
{ model with WX = newWires }, Cmd.none
|
{ model with WX = newWires }, Cmd.none
|
||||||
|
|
||||||
| ResetJumps connIds ->
|
|
||||||
printfn $"resetting jumps on {connIds.Length} wires"
|
|
||||||
|
|
||||||
let newModel =
|
|
||||||
model
|
|
||||||
|> resetWireSegmentJumps connIds
|
|
||||||
|
|
||||||
newModel, Cmd.none
|
|
||||||
|
|
||||||
| MakeJumps connIds ->
|
|
||||||
printfn $"making jumps on {connIds.Length} wires"
|
|
||||||
|
|
||||||
let newModel =
|
|
||||||
model
|
|
||||||
|> updateWireSegmentJumps connIds
|
|
||||||
|
|
||||||
newModel, Cmd.none
|
|
||||||
|
|
||||||
| ResetModel -> { model with WX = Map.empty; ErrorWires = []; Notifications = None }, Cmd.none
|
| ResetModel -> { model with WX = Map.empty; ErrorWires = []; Notifications = None }, Cmd.none
|
||||||
|
|
||||||
| LoadConnections conns -> // we assume components (and hence ports) are loaded before connections
|
| LoadConnections conns -> // we assume components (and hence ports) are loaded before connections
|
||||||
let posMatchesVertex (pos:XYPos) (vertex: float*float) =
|
let posMatchesVertex (pos:XYPos) (vertex: float*float) =
|
||||||
let epsilon = 0.00001
|
let epsilon = 0.00001
|
||||||
abs (abs pos.X - abs (fst vertex)) < epsilon &&
|
abs (abs pos.X - abs (fst vertex)) < epsilon && abs (abs pos.Y - abs (snd vertex)) < epsilon
|
||||||
abs (abs pos.Y - abs (snd vertex)) < epsilon
|
|
||||||
|> (fun b -> if not b then printf $"Bad wire endpoint match on {pos} {vertex}"; b else b)
|
|> (fun b -> if not b then printf $"Bad wire endpoint match on {pos} {vertex}"; b else b)
|
||||||
let newWX =
|
let newWX =
|
||||||
conns
|
let connsToWX conn =
|
||||||
|> List.map ( fun conn ->
|
let inputId = InputPortId conn.Target.Id
|
||||||
let inputId = InputPortId conn.Target.Id
|
let outputId = OutputPortId conn.Source.Id
|
||||||
let outputId = OutputPortId conn.Source.Id
|
let connId = ConnectionId conn.Id
|
||||||
let connId = ConnectionId conn.Id
|
let aSegs = issieVerticesToASegs connId conn.Vertices
|
||||||
let segments = issieVerticesToASegs connId conn.Vertices
|
let riSegs = aSegListToRISegList aSegs
|
||||||
let makeWirePosMatchSymbol inOut (wire:Wire) =
|
let makeWirePosMatchSymbol inOut (wire:Wire) =
|
||||||
match inOut with
|
match inOut with
|
||||||
| true -> posMatchesVertex
|
| true -> posMatchesVertex
|
||||||
(Symbol.getInputPortLocation model.Symbol inputId)
|
(Symbol.getInputPortLocation model.Symbol inputId)
|
||||||
(List.head conn.Vertices)
|
(List.head conn.Vertices)
|
||||||
| false ->
|
| false -> posMatchesVertex
|
||||||
posMatchesVertex
|
(Symbol.getOutputPortLocation model.Symbol outputId)
|
||||||
(Symbol.getOutputPortLocation model.Symbol outputId)
|
(List.last conn.Vertices)
|
||||||
(List.last conn.Vertices)
|
|> (fun b ->
|
||||||
|> (fun b ->
|
if b then
|
||||||
if b then
|
wire
|
||||||
wire
|
else
|
||||||
else
|
let getS (connId:string) =
|
||||||
let getS (connId:string) =
|
Map.tryFind connId model.Symbol.Ports
|
||||||
Map.tryFind connId model.Symbol.Ports
|
|> Option.map (fun port -> port.HostId)
|
||||||
|> Option.map (fun port -> port.HostId)
|
|> Option.bind (fun symId -> Map.tryFind (ComponentId symId) model.Symbol.Symbols)
|
||||||
|> Option.bind (fun symId -> Map.tryFind (ComponentId symId) model.Symbol.Symbols)
|
|> Option.map (fun sym -> sym.Compo.Label)
|
||||||
|> Option.map (fun sym -> sym.Compo.Label)
|
printfn $"Updating loaded wire from {getS conn.Source.Id}->{getS conn.Target.Id} of wire "
|
||||||
printfn $"Updating loaded wire from {getS conn.Source.Id}->{getS conn.Target.Id} of wire "
|
updateWire model wire inOut
|
||||||
updateWire model wire inOut)
|
|
||||||
|
|
||||||
|
|
||||||
connId,
|
|
||||||
{
|
|
||||||
Id = ConnectionId conn.Id
|
|
||||||
InputPort = inputId
|
|
||||||
OutputPort = outputId
|
|
||||||
Color = HighLightColor.DarkSlateGrey
|
|
||||||
Width = 1
|
|
||||||
Segments = segments
|
|
||||||
}
|
|
||||||
|> makeWirePosMatchSymbol false
|
|
||||||
|> makeWirePosMatchSymbol true
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
connId,
|
||||||
|
{ Id = ConnectionId conn.Id
|
||||||
|
InputPort = inputId
|
||||||
|
OutputPort = outputId
|
||||||
|
Color = HighLightColor.DarkSlateGrey
|
||||||
|
Width = 1
|
||||||
|
Rotation = PosY
|
||||||
|
YReflect = false
|
||||||
|
Segments = List.map riSegToASeg riSegs
|
||||||
|
}
|
||||||
|
|> makeWirePosMatchSymbol false
|
||||||
|
|> makeWirePosMatchSymbol true
|
||||||
|
|
||||||
|
conns
|
||||||
|
|> List.map connsToWX
|
||||||
|> Map.ofList
|
|> Map.ofList
|
||||||
|
|
||||||
let connIds =
|
{ model with WX = newWX }, Cmd.none
|
||||||
conns
|
|
||||||
|> List.map (fun conn -> ConnectionId conn.Id)
|
|
||||||
|
|
||||||
{ model with WX = newWX }, Cmd.ofMsg (MakeJumps connIds)
|
|
||||||
|
|
||||||
//---------------Other interface functions--------------------//
|
//---------------Other interface functions--------------------//
|
||||||
|
|
||||||
///
|
|
||||||
let wireIntersectsBoundingBox (w : Wire) (bb : BoundingBox) =
|
let wireIntersectsBoundingBox (w : Wire) (bb : BoundingBox) =
|
||||||
let boolList = List.map (fun seg -> fst(segmentIntersectsBoundingBoxCoordinates seg bb)) w.Segments
|
w.Segments
|
||||||
List.contains true boolList
|
|> List.map ( fun seg -> fst (segmentIntersectsBoundingBoxCoordinates seg bb) )
|
||||||
|
|> List.contains true
|
||||||
|
|
||||||
///
|
///
|
||||||
let getIntersectingWires (wModel : Model) (selectBox : BoundingBox) : ConnectionId list =
|
let getIntersectingWires (wModel : Model) (selectBox : BoundingBox) : ConnectionId list =
|
||||||
|
@ -1884,7 +1831,7 @@ let pasteWires (wModel : Model) (newCompIds : ComponentId list) : (Model * Conne
|
||||||
|
|
||||||
{ wModel with WX = newWireMap }, pastedConnIds
|
{ wModel with WX = newWireMap }, pastedConnIds
|
||||||
|
|
||||||
///
|
///Given the Model and the connectionID list, return the tuple of InputPortId list and OutputPortId list
|
||||||
let getPortIdsOfWires (model: Model) (connIds: ConnectionId list) : (InputPortId list * OutputPortId list) =
|
let getPortIdsOfWires (model: Model) (connIds: ConnectionId list) : (InputPortId list * OutputPortId list) =
|
||||||
(([], []), connIds)
|
(([], []), connIds)
|
||||||
||> List.fold (fun (inputPorts, outputPorts) connId ->
|
||> List.fold (fun (inputPorts, outputPorts) connId ->
|
||||||
|
|
|
@ -649,7 +649,6 @@ let mDownUpdate (model: Model) (mMsg: MouseT) : Model * Cmd<Msg> =
|
||||||
Cmd.batch [ symbolCmd (Symbol.SelectSymbols [])
|
Cmd.batch [ symbolCmd (Symbol.SelectSymbols [])
|
||||||
wireCmd (BusWire.SelectWires [ connId ])
|
wireCmd (BusWire.SelectWires [ connId ])
|
||||||
wireCmd (BusWire.DragWire (connId, mMsg))
|
wireCmd (BusWire.DragWire (connId, mMsg))
|
||||||
wireCmd (BusWire.ResetJumps [ connId ] )
|
|
||||||
Cmd.ofMsg msg]
|
Cmd.ofMsg msg]
|
||||||
| Canvas ->
|
| Canvas ->
|
||||||
let newComponents, newWires =
|
let newComponents, newWires =
|
||||||
|
@ -677,7 +676,7 @@ let mDragUpdate (model: Model) (mMsg: MouseT) : Model * Cmd<Msg> =
|
||||||
| InitialiseMoving _ ->
|
| InitialiseMoving _ ->
|
||||||
let movingWires = BusWire.getConnectedWires model.Wire model.SelectedComponents
|
let movingWires = BusWire.getConnectedWires model.Wire model.SelectedComponents
|
||||||
let newModel, cmd = moveSymbols model mMsg
|
let newModel, cmd = moveSymbols model mMsg
|
||||||
newModel, Cmd.batch [ cmd; wireCmd (BusWire.ResetJumps movingWires) ]
|
newModel, cmd
|
||||||
| MovingSymbols | DragAndDrop ->
|
| MovingSymbols | DragAndDrop ->
|
||||||
moveSymbols model mMsg
|
moveSymbols model mMsg
|
||||||
| ConnectingInput _ ->
|
| ConnectingInput _ ->
|
||||||
|
@ -724,8 +723,7 @@ let mUpUpdate (model: Model) (mMsg: MouseT) : Model * Cmd<Msg> = // mMsg is curr
|
||||||
match model.Action with
|
match model.Action with
|
||||||
| MovingWire connId ->
|
| MovingWire connId ->
|
||||||
{ model with Action = Idle ; UndoList = appendUndoList model.UndoList newModel; RedoList = [] },
|
{ model with Action = Idle ; UndoList = appendUndoList model.UndoList newModel; RedoList = [] },
|
||||||
Cmd.batch [ wireCmd (BusWire.DragWire (connId, mMsg))
|
wireCmd (BusWire.DragWire (connId, mMsg))
|
||||||
wireCmd (BusWire.MakeJumps [ connId ] ) ]
|
|
||||||
| Selecting ->
|
| Selecting ->
|
||||||
let newComponents = findIntersectingComponents model model.DragToSelectBox
|
let newComponents = findIntersectingComponents model model.DragToSelectBox
|
||||||
let newWires = BusWire.getIntersectingWires model.Wire model.DragToSelectBox
|
let newWires = BusWire.getIntersectingWires model.Wire model.DragToSelectBox
|
||||||
|
@ -748,7 +746,6 @@ let mUpUpdate (model: Model) (mMsg: MouseT) : Model * Cmd<Msg> = // mMsg is curr
|
||||||
// Reset Movement State in Model
|
// Reset Movement State in Model
|
||||||
match model.ErrorComponents with
|
match model.ErrorComponents with
|
||||||
| [] ->
|
| [] ->
|
||||||
let movingWires = BusWire.getConnectedWires model.Wire model.SelectedComponents
|
|
||||||
{model with
|
{model with
|
||||||
// BoundingBoxes = Symbol.getBoundingBoxes model.Wire.Symbol
|
// BoundingBoxes = Symbol.getBoundingBoxes model.Wire.Symbol
|
||||||
Action = Idle
|
Action = Idle
|
||||||
|
@ -757,7 +754,7 @@ let mUpUpdate (model: Model) (mMsg: MouseT) : Model * Cmd<Msg> = // mMsg is curr
|
||||||
UndoList = appendUndoList model.UndoList newModel
|
UndoList = appendUndoList model.UndoList newModel
|
||||||
RedoList = []
|
RedoList = []
|
||||||
AutomaticScrolling = false },
|
AutomaticScrolling = false },
|
||||||
wireCmd (BusWire.MakeJumps movingWires)
|
Cmd.none
|
||||||
| _ ->
|
| _ ->
|
||||||
let movingWires = BusWire.getConnectedWires model.Wire model.SelectedComponents
|
let movingWires = BusWire.getConnectedWires model.Wire model.SelectedComponents
|
||||||
{model with
|
{model with
|
||||||
|
@ -768,8 +765,7 @@ let mUpUpdate (model: Model) (mMsg: MouseT) : Model * Cmd<Msg> = // mMsg is curr
|
||||||
AutomaticScrolling = false },
|
AutomaticScrolling = false },
|
||||||
Cmd.batch [ symbolCmd (Symbol.MoveSymbols (model.SelectedComponents, (posDiff model.LastValidPos mMsg.Pos)))
|
Cmd.batch [ symbolCmd (Symbol.MoveSymbols (model.SelectedComponents, (posDiff model.LastValidPos mMsg.Pos)))
|
||||||
symbolCmd (Symbol.SelectSymbols (model.SelectedComponents))
|
symbolCmd (Symbol.SelectSymbols (model.SelectedComponents))
|
||||||
wireCmd (BusWire.UpdateWires (model.SelectedComponents, posDiff model.LastValidPos mMsg.Pos))
|
wireCmd (BusWire.UpdateWires (model.SelectedComponents, posDiff model.LastValidPos mMsg.Pos)) ]
|
||||||
wireCmd (BusWire.MakeJumps movingWires) ]
|
|
||||||
| ConnectingInput inputPortId ->
|
| ConnectingInput inputPortId ->
|
||||||
let cmd, undoList ,redoList =
|
let cmd, undoList ,redoList =
|
||||||
if model.TargetPortId <> "" // If a target has been found, connect a wire
|
if model.TargetPortId <> "" // If a target has been found, connect a wire
|
||||||
|
|
Loading…
Reference in a new issue