• No results found

3.5 Drawing each pattern

3.5.2 Share Two Edges

It is only possible for circles, stars and paths to share two edges. There are two separate methods for drawing circles sharing two edges, depending on if these edges are consecutive. Paths may also share two edges with the drawn set.

3.5.2.1 Consecutive Shared Edges

This scenario exists where a circle shares two spokes of a star. A decision had to be made regarding the order in which the star or circle should be drawn. One possible option is to draw the patterns in a similar way to Figure 3.43a. However, this requires changing the main drawing order (as stars are drawn before circles). It was felt that it was unwise to change the order, as this could have a large number of implications. It was also decided that it was not sensible to introduce an exception for this type, as that defeats the object of having a fixed drawing order. Therefore, the drawing order had to be such that circles are drawn after stars, which produces a similar layout to Figure 3.43b.

oA ,./0

/0

,./0 ,./0

/0

(a) Star drawn around a Circle

oA 12 34 12 34 34 12 34 34

(b) Circle drawn around a Star

Figure 3.43: Possible drawing methods for patterns sharing two edges The method follows a process similar to the One Edge Sharing drawing method (see Section 3.5.1.2) for Circles. Firstly, the middle node of the star is found and a virtual edge is created between the other two shared nodes (i.e. the outside nodes). This is used to enable compatibility with the One Edge Shared method. The pattern (with the exception of the centre node) is then drawn in its

ideal layout, centred on the origin of the graph (i.e. the point(0, 0)). The circle is then scaled so that the virtual edge is the same length as it was before the circle was drawn. This ensures that the pattern does not distort the currently drawn set.

The pattern is then rotated to match the original orientation of the virtual edge and then moved into the correct location. Once this is complete, an ori- entation check is completed. A measure of the edge crossings and occlusion is taken (see Section 3.6.3). If there are no edge crossings or occlusion, then the drawing is complete. If not, the pattern is reflected along the virtual edge. An- other calculation of the edge crossings and occlusion is taken. If this is lower than the previous calculation, then this layout is chosen. If not, the pattern is reflected back and the method is complete. This completes the algorithm, ex- amples of which can be seen in Figure 3.44 and is detailed in Algorithm 3.9. The time complexity of this algorithm isO(Vp)as it must iterate through all nodes

56 7 86 7 9: ;6 7 <: ;6 7 =:; 5oAsB 0oA 5sB > ? @ 1oAsB 7oAsB A ? @ B C D? @ EC D 0sB 1sB 2oAsB FGHIJ KGH 5oAsB 0oAsB 1oAsB 2sB LMN OPQMN 5sB R PQ 7sB SPQ TPQ

Figure 3.44: Examples of the Multiple Edge Sharing algorithm

Algorithm 3.9: Share Two Edges - Consecutive Shared Edges

01: functionDRAWPATTERN(Gp)

02: G← (V, E)

03: drawnPatterns← {g|gG, drawn(g)}

04: Gp← (Vp, Ep) ⊲The pattern about to be drawn 05: Es← {e|eE, eEp} ⊲Shared Edges 06: vm← {v|vVp, connectedTo(Es[0]), connectedTo(Es[1])} ⊲The middle node between the

two shared edges

07: middleNodeLocationlocation(vm)

08: evirtual← (oppositeEnd(Es[0], vm), oppositeEnd(Es[1], vm)) ⊲Virtual edge between the two

non-connected ends of the shared edges

09: originalEdgeLocationcurrentLocation(evirtual)

10: originalEdgeAnglecurrentAngle(evirtual)

11: originalEdgeSizecurrentLength(evirtual)

12: originalScore←CALCULATESCORE(drawnPatterns) ⊲See Algorithm 3.26

13: drawInIdealLayout(Gp\vm) ⊲Draw pattern in ideal layout, ignoring vm 14: scalePattern(Gp, originalEdgeSize)

15: rotatePattern(Gp, originalEdgeAngle)

16: movePattern(Gp, originalEdgeLocation)

18: drawnPatternsdrawnPatternsGp

19: f inalScore←CALCULATESCORE(drawnPatterns)See Algorithm 3.26

20: iforiginalScore6= f inalScore thenGpmay be drawn around the drawn patterns

21: reflectPattern(Gp, evirtual) ⊲Reflect Gpalong the shared edge

22: iff inalScore≤CALCULATESCORE(drawnPatterns) thenIf there is a worse score now, then

the best location was the previous one, See Algorithm 3.26

23: reflectPattern(Gp, evirtual) ⊲Reflect back

3.5.2.2 Non-Consecutive Shared Edges

When the shared edges are not consecutive, a different approach is taken. Firstly, all the nodes between the two shared edges are identified (i.e. in Figure 3.45, nodes 8-oA-oC & 11-oA-oC (highlighted in green) and 13-oB-oC & 15-oB-oC (highlighted in yellow)). These nodes are then drawn in a straight line between the shared edges. Once drawn, these are adjusted in a similar way to paths (see Section 3.5.8), with several curves being attempted before the curve with the lowest score is accepted. The algorithm is detailed in Algorithm 3.10, with a time complexity of O(Vp), due to the algorithm iterating through all nodes in

the pattern several times order to determine the correct location (Lines 45 and 46).

Algorithm 3.10: Share Two Edges — Non-Consecutive Shared Edges

01: functionDRAWPATTERN(Gp)

02: G← (V, E)

03: drawnPatterns← {g|gG, drawn(g)}

04: Gp← (Vp, Ep) ⊲The pattern about to be drawn 05: Es← {e|eE, eEp} ⊲Shared Edges 06: Pair1, Pair2← (null, null) ⊲Node Pairs for use later 07: Vm1, Vm2← [ ] ⊲Nodes between these pairs 08: iAindexOf(Vp, startNode(Es[0]))

09: iBindexOf(Vp, endNode(Es[0]))

10: iCindexOf(Vp, startNode(Es[1]))

0-oA-oB-cD-cF 1-cD 2-cD 3-oA-oB-cD-cE4-cF 5-cE 6-oB-oC-cF 7-oA-oC-cE 8-oA-oC 9-oA-oC-cF 10 11-oA-oC 12-oB-oC-cE 13-oB-oC 14 15-oB-oC

Figure 3.45: Example of Two Shared Non-Consecutive Edges

12: if((iA+1) mod|Vp|) =iBthenSearch forwards 13: iiB 14: while(i mod|Vp|) 6=iAdo 15: Vm1Vm1Vp[i mod|Vp|] 16: if(i mod|Vp|) =iCthen 17: Pair1← (Vp[iB], Vp[iC]) 18: Pair2← (Vp[iD], Vp[iA]) 19: Vm2← {v|vVp, v /Vm1} 20: Break while

21: else if(i mod|Vp|) =iDthen

22: Pair1← (Vp[iB], Vp[iD])

23: Pair2← (Vp[iC], Vp[iA])

24: Vm2← {v|vVp, v /Vm1}

25: Break while

26: ii+1

27: elseSearch backwards

28: iiB+ |Vp| 29: while(i mod|Vp|) 6=iAdo 30: Vm1Vm1Vp[i mod|Vp|] 31: if(i mod|Vp|) =iCthen 32: Pair1← (Vp[iC], Vp[iB]) 33: Pair2← (Vp[iA], Vp[iD])

34: Vm1reverseOrder(Vm1) ⊲Searching backwards, but drawing forwards 35: Vm2← {v|vVp, v /Vm1}

36: Break while

37: else if(i mod|Vp|) =iDthen

38: Pair1← (Vp[iD], Vp[iB])

39: Pair2← (Vp[iA], Vp[iC])

40: Vm1reverseOrder(Vm1) ⊲Searching backwards, but drawing forwards 41: Vm2← {v|vVp, v /Vm1}

42: Break while

43: ii−1

44: drawnPatternsdrawnPatternsGp

45: DRAWBETWEENNODES(Pair1, Vm1) ⊲See Below 46: DRAWBETWEENNODES(Pair2, Vm2) ⊲See Below 47:

48: functionDRAWBETWEENNODES((vstart, vf inish), Vm)

49: G← (V, E)

50: drawnPatterns← {g|gG, drawn(g)}

51: Gp← (Vp, Ep) ⊲The pattern about to be drawn

52: bestScore←CALCULATESCORE(drawnPatterns)See Algorithm 3.26

53: bestLayout←0

54: ∆x← (v

f inishxvstartx) ÷ (|Vm| −1)

55: ∆y← (v

f inishyvstarty) ÷ (|Vm| −1)

56: for eachvVm,{i|i0, i<|Vm|}doDraw nodes in a straight line 57: vxvstartx+ (i×∆x)

58: vyvstarty+ (i×∆y)

59: oldLocation(n) ←currentLocation(n)

60: forj∈ {1, 2, .., 6}do7 different locations to test (Location 0 is the current one) 61: TRYPATHLOCATIONS(vstart, vf inish, Vm, j)See Algorithm 3.19

62: currentScore←CALCULATESCORE(drawnPatterns)See Algorithm 3.26

63: ifcurrentScore<bestScore then

64: bestLayoutj

65: bestScorecurrentScore

66: TRYPATHLOCATIONS(vstart, vf inish, Vm, bestLocation)Draw in best location. See Algorithm 3.19