mirror of
https://github.com/supleed2/ELEC60015-HLP-CW.git
synced 2024-12-22 21:45:49 +00:00
Add Rounded Corners Wire Rendering Implementation
This commit is contained in:
parent
7bbed7cde7
commit
8cf10dfd9e
|
@ -118,7 +118,9 @@ type Wire =
|
||||||
Segments: ASeg list
|
Segments: ASeg list
|
||||||
}
|
}
|
||||||
|
|
||||||
with static member stickLength = 16.0
|
with
|
||||||
|
static member stickLength = 16.0
|
||||||
|
static member arcSize = 8.0
|
||||||
|
|
||||||
///
|
///
|
||||||
type Model =
|
type Model =
|
||||||
|
@ -438,131 +440,82 @@ let makeInitialRISegList (hostId: ConnectionId) (portCoords: XYPos * XYPos) : RI
|
||||||
|> List.map aSegToRISeg
|
|> List.map aSegToRISeg
|
||||||
// TODO: native RISeg implementation
|
// TODO: native RISeg implementation
|
||||||
|
|
||||||
/// Render given segment using colour and width properties given
|
/// Render given Rotation Invariant Segment using colour and width properties given
|
||||||
let renderSegment (segment: ASeg) (colour: string) (width: string) : ReactElement =
|
/// Takes in 2 connecting segments to add rounded corners if appropriate
|
||||||
let wOpt = EEExtensions.String.tryParseWith System.Int32.TryParse width
|
let renderRISegAndCorner (colour: string) (width: string) (segments: RISeg * RISeg * RISeg) : ReactElement =
|
||||||
let renderWidth =
|
let prevSeg, segment', nextSeg = segments
|
||||||
match wOpt with
|
let segment = {segment' with Start = absXYPos segment'.Start}
|
||||||
| Some 1 -> 1.5
|
let widthOption = EEExtensions.String.tryParseWith System.Int32.TryParse width
|
||||||
| Some n when n < int "8" -> 2.5
|
let renderWidth, halfWidth =
|
||||||
| _ -> 3.5
|
match widthOption with
|
||||||
let halfWidth = (renderWidth/2.0) - (0.75)
|
| Some 1 -> 1.5, 0.25
|
||||||
|
| Some n when n < int "8" -> 2.5, 0.5
|
||||||
|
| _ -> 3.5, 1.0
|
||||||
let lineParameters = { defaultLine with Stroke = colour; StrokeWidth = string renderWidth }
|
let lineParameters = { defaultLine with Stroke = colour; StrokeWidth = string renderWidth }
|
||||||
let circleParameters = { defaultCircle with R = halfWidth; Stroke = colour; Fill = colour }
|
let circleParameters = { defaultCircle with R = halfWidth; Stroke = colour; Fill = colour }
|
||||||
|
|
||||||
if segment.Dir = Horizontal then
|
|
||||||
let pathParameters = { defaultPath with Stroke = colour; StrokeWidth = string renderWidth }
|
let pathParameters = { defaultPath with Stroke = colour; StrokeWidth = string renderWidth }
|
||||||
|
|
||||||
let renderWireSubSegment (vertex1 : XYPos) (vertex2 : XYPos) : ReactElement list =
|
// If first segment / previous or current segment too short / collinear with previous segment -> no corner
|
||||||
let Xa, Ya, Xb, Yb = vertex1.X, vertex1.Y, vertex2.X, vertex2.Y
|
let startCorner = not (prevSeg.Index = -1 || (min (abs prevSeg.Length) (abs segment.Length)) < (Wire.arcSize * 2.0) || prevSeg.Dir = segment.Dir)
|
||||||
makeLine Xa Ya Xb Yb lineParameters
|
|
||||||
::
|
let endCorner =
|
||||||
makeCircle Xa Ya circleParameters
|
// If last segment / current or next segment too short / collinear with next segment -> no corner
|
||||||
::
|
if nextSeg.Index = 0 || (min (abs segment.Length) (abs nextSeg.Length)) < (Wire.arcSize * 2.0) || segment.Dir = nextSeg.Dir then
|
||||||
|
let endPoint = getRISegEnd segment.Start segment
|
||||||
[
|
[
|
||||||
makeCircle Xb Yb circleParameters
|
makeCircle endPoint.X endPoint.Y circleParameters
|
||||||
]
|
], false
|
||||||
|
else // Corner
|
||||||
let segmentJumpHorizontalSize = 9.0
|
let arcStart =
|
||||||
let segmentJumpVerticalSize = 6.0
|
match segment.Length with
|
||||||
|
| l when l < 0 -> getRISegEnd segment.Start {segment with Length = segment.Length + Wire.arcSize}
|
||||||
let renderSingleSegmentJump (intersectionCoordinate : XYPos) : ReactElement list =
|
| _ -> getRISegEnd segment.Start {segment with Length = segment.Length - Wire.arcSize}
|
||||||
let x, y = intersectionCoordinate.X, intersectionCoordinate.Y
|
let arcMid = nextSeg.Start
|
||||||
|
let arcEnd =
|
||||||
let startingPoint = {X = x - segmentJumpHorizontalSize/2.0; Y = y}
|
match nextSeg.Length with
|
||||||
let startingControlPoint = {X = x - segmentJumpHorizontalSize/2.0; Y = y - segmentJumpVerticalSize}
|
| l when l < 0 -> getRISegEnd nextSeg.Start {nextSeg with Length = - Wire.arcSize}
|
||||||
let endingControlPoint = {X = x + segmentJumpHorizontalSize/2.0; Y = y - segmentJumpVerticalSize}
|
| _ -> getRISegEnd nextSeg.Start {nextSeg with Length = Wire.arcSize}
|
||||||
let endingPoint = {X = x + segmentJumpHorizontalSize/2.0; Y = y}
|
|
||||||
|
|
||||||
makePath startingPoint startingControlPoint endingControlPoint endingPoint pathParameters
|
|
||||||
::
|
|
||||||
makeCircle startingPoint.X startingPoint.Y circleParameters
|
|
||||||
::
|
|
||||||
[
|
[
|
||||||
makeCircle endingPoint.X endingPoint.Y circleParameters
|
makeCircle arcStart.X arcStart.Y circleParameters
|
||||||
]
|
makePath arcStart arcMid arcEnd arcEnd pathParameters
|
||||||
|
makeCircle arcEnd.X arcEnd.Y circleParameters
|
||||||
|
], true
|
||||||
|
|
||||||
let rec renderMultipleSegmentJumps (segmentJumpCoordinateList : float list) (segmentJumpYCoordinate : float) : ReactElement list =
|
|
||||||
|
|
||||||
match segmentJumpCoordinateList with
|
|
||||||
|
|
||||||
| [] -> []
|
|
||||||
|
|
||||||
|
|
||||||
| [singleElement] ->
|
|
||||||
renderSingleSegmentJump {X = singleElement; Y = segmentJumpYCoordinate}
|
|
||||||
|
|
||||||
|
|
||||||
| firstElement :: secondElement :: tailList ->
|
|
||||||
|
|
||||||
if (segment.Start.X > segment.End.X) then
|
|
||||||
renderSingleSegmentJump {X = firstElement; Y = segmentJumpYCoordinate}
|
|
||||||
@
|
|
||||||
renderWireSubSegment {X = firstElement - segmentJumpHorizontalSize/2.0; Y = segmentJumpYCoordinate} {X = secondElement + segmentJumpHorizontalSize/2.0; Y = segmentJumpYCoordinate}
|
|
||||||
@
|
|
||||||
renderMultipleSegmentJumps (secondElement :: tailList) (segmentJumpYCoordinate)
|
|
||||||
|
|
||||||
else
|
|
||||||
renderSingleSegmentJump {X = firstElement; Y = segmentJumpYCoordinate}
|
|
||||||
@
|
|
||||||
renderWireSubSegment {X = firstElement + segmentJumpHorizontalSize/2.0; Y = segmentJumpYCoordinate} {X = secondElement - segmentJumpHorizontalSize/2.0; Y = segmentJumpYCoordinate}
|
|
||||||
@
|
|
||||||
renderMultipleSegmentJumps (secondElement :: tailList) (segmentJumpYCoordinate)
|
|
||||||
|
|
||||||
|
|
||||||
let completeWireSegmentRenderFunction (seg : ASeg) : ReactElement list =
|
|
||||||
|
|
||||||
let jumpCoordinateList =
|
|
||||||
if (segment.Start.X > segment.End.X) then
|
|
||||||
seg.JumpCoordinateListA
|
|
||||||
|> List.map fst
|
|
||||||
|> List.sortDescending
|
|
||||||
|
|
||||||
else
|
|
||||||
seg.JumpCoordinateListA
|
|
||||||
|> List.map fst
|
|
||||||
|> List.sort
|
|
||||||
|
|
||||||
match jumpCoordinateList with
|
|
||||||
| [] -> renderWireSubSegment seg.Start seg.End
|
|
||||||
|
|
||||||
| lst ->
|
|
||||||
let y = seg.Start.Y // SHOULD be equal to seg.End.Y since ONLY horizontal segments have jumps
|
|
||||||
let firstSegmentJumpCoordinate = lst[0]
|
|
||||||
let lastSegmentJumpCoordinate = lst[(List.length lst) - 1]
|
|
||||||
|
|
||||||
if (segment.Start.X > segment.End.X) then
|
|
||||||
renderWireSubSegment seg.Start {X = firstSegmentJumpCoordinate + segmentJumpHorizontalSize/2.0; Y = y}
|
|
||||||
@
|
|
||||||
renderMultipleSegmentJumps lst y
|
|
||||||
@
|
|
||||||
renderWireSubSegment {X = lastSegmentJumpCoordinate - segmentJumpHorizontalSize/2.0; Y = y} seg.End
|
|
||||||
|
|
||||||
else
|
|
||||||
renderWireSubSegment seg.Start {X = firstSegmentJumpCoordinate - segmentJumpHorizontalSize/2.0; Y = y}
|
|
||||||
@
|
|
||||||
renderMultipleSegmentJumps lst y
|
|
||||||
@
|
|
||||||
renderWireSubSegment {X = lastSegmentJumpCoordinate + segmentJumpHorizontalSize/2.0; Y = y} seg.End
|
|
||||||
|
|
||||||
|
|
||||||
let wireSegmentReactElementList = segment
|
|
||||||
|> completeWireSegmentRenderFunction
|
|
||||||
|
|
||||||
g [] wireSegmentReactElementList
|
|
||||||
|
|
||||||
else
|
|
||||||
let Xa, Ya, Xb, Yb = segment.Start.X, segment.Start.Y, segment.End.X, segment.End.Y
|
|
||||||
let segmentElements =
|
let segmentElements =
|
||||||
makeLine Xa Ya Xb Yb lineParameters
|
let segStart =
|
||||||
::
|
match startCorner, segment.Length with
|
||||||
makeCircle Xa Ya circleParameters
|
| true, l when l < 0 -> getRISegEnd segment.Start {segment with Length = - Wire.arcSize}
|
||||||
::
|
| true, _ -> getRISegEnd segment.Start {segment with Length = Wire.arcSize}
|
||||||
|
| false, _ -> segment.Start
|
||||||
|
let segEnd =
|
||||||
|
match (snd endCorner), segment.Length with
|
||||||
|
| true, l when l < 0 -> getRISegEnd segment.Start {segment with Length = segment.Length + Wire.arcSize}
|
||||||
|
| true, _ -> getRISegEnd segment.Start {segment with Length = segment.Length - Wire.arcSize}
|
||||||
|
| false, _ -> getRISegEnd segment.Start segment
|
||||||
[
|
[
|
||||||
makeCircle Xb Yb circleParameters
|
makeLine segStart.X segStart.Y segEnd.X segEnd.Y lineParameters
|
||||||
]
|
]
|
||||||
|
@
|
||||||
|
fst endCorner
|
||||||
|
|
||||||
g [] segmentElements
|
g [] segmentElements
|
||||||
|
|
||||||
|
|
||||||
|
/// 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 riSegs =
|
||||||
|
segs
|
||||||
|
|> List.filter ( fun seg -> seg.Length <> 0.0 )
|
||||||
|
|> List.mapi (fun i seg -> {seg with Index = i})
|
||||||
|
|> List.toSeq
|
||||||
|
let dummyStartRISeg = {Seq.head riSegs with Index = -1; Length = 0.0}
|
||||||
|
let dummyEndRISeg = {Seq.head riSegs with Index = 0; Length = 0.0}
|
||||||
|
let riSegTriplets =
|
||||||
|
Seq.zip3 (Seq.append [dummyStartRISeg] riSegs) riSegs (Seq.append (Seq.tail riSegs) [dummyEndRISeg])
|
||||||
|
|> List.ofSeq
|
||||||
|
riSegTriplets
|
||||||
|
|> List.map ( fun segTrip -> renderRISegAndCorner colour width segTrip )
|
||||||
|
|
||||||
///
|
///
|
||||||
type WireRenderProps =
|
type WireRenderProps =
|
||||||
{
|
{
|
||||||
|
@ -578,8 +531,8 @@ let singleWireView =
|
||||||
fun (props: WireRenderProps) ->
|
fun (props: WireRenderProps) ->
|
||||||
let renderWireSegmentList : ReactElement list =
|
let renderWireSegmentList : ReactElement list =
|
||||||
props.Segments
|
props.Segments
|
||||||
|> List.map ( fun (segment: ASeg) -> renderSegment segment (props.ColorP.Text()) (string props.StrokeWidthP) )
|
|> List.map aSegToRISeg
|
||||||
// Call render helper functions on each segment, including jump rendering
|
|> renderRISegList (props.ColorP.Text()) (string props.StrokeWidthP)
|
||||||
|
|
||||||
let renderWireWidthText : ReactElement =
|
let renderWireWidthText : ReactElement =
|
||||||
let textParameters =
|
let textParameters =
|
||||||
|
|
Loading…
Reference in a new issue