Scenegraph - Tutorial - Using Boundary Constructs

SBoundary implements boundaries for use in scene graph

This defines the outer extent of the scene or of an element in the scene or of some branch in the scene.

The difference between this boundary and an n-dimensional surface, such as IFS, is that boundary must always have a well defined inside and an outside.

SBoundary does not necessarily follow the exact outer contours of the shape but just constructs a simple boundary shape where all points of the shape are guaranteed to be inside the boundary. Currently there are 3 boundary forms:

In future we may add other boundary shapes, we may also allow a boundary to consist of a union of these other shapes.

rectangle ellipse

In the case of box it is specified by two points, on opposite ends of diagonal, where edges are aligned with coordinate axes.

In the case of ellipse: first parameter is centre and second determines the radius aligned with each coordinate axis (half the full height and width).

The uses of SBoundary are:

First we create some types to work with

(1) -> DF ==> DoubleFloat
                                                             Type: Void
(2) -> PT ==> SCartesian(2)
                                                             Type: Void
(3) -> B ==> SBoundary PT
                                                             Type: Void

As discussed above SBoundary can have one of three forms: a null boundary, a box boundary and an ellipoid boundary. These 3 forms can be constructed as in 3,4 and 5 below:

(4) -> B1 := nullBoundary()$B
   (4)  bound none
                                         Type: SBoundary(SCartesian(2))

(5) -> B2 := boxBoundary(spnt(20::DF,-20::DF),spnt(10::DF,10::DF))$B
   (5)  bound box:pt(10.0,- 20.0)->pt(20.0,10.0)
                                         Type: SBoundary(SCartesian(2))

(6) -> B3 := ellipseBoundary(spnt(30::DF,10::DF),spnt(25::DF,5::DF))$B
   (6)  bound ellipoid:pt(30.0,10.0)->pt(25.0,5.0)
                                         Type: SBoundary(SCartesian(2))

We can now do various operations on the boundaries that we have constructed.

Line (7) construct a union of two boundaries, that is, a boundary that completely encloses the input boundaries.

Line (8) is also a union, but this time, one of the operands is a point. We can think of this as extending the boundary to include the point.

Lines (9) and (10) demonstrate how we can test if a point is inside the boundary.

(7) -> B4 := sunion(B2,B3)
   (7)  bound box:pt(5.0,- 20.0)->pt(55.0,15.0)
                                         Type: SBoundary(SCartesian(2))

(8) -> B5 := extendToPoint(B2,spnt(30::DF,10::DF))$B
   (8)  bound box:pt(10.0,- 20.0)->pt(30.0,10.0)
                                         Type: SBoundary(SCartesian(2))

(9) -> containsPoint?(B2,spnt(15::DF,5::DF))$B
   (9)  true
                                                          Type: Boolean

(10) -> containsPoint?(B2,spnt(0::DF,5::DF))$B
   (10)  false
                                                          Type: Boolean

To show how boundary is used in a scenegraph, we first create some shapes:

In (12) we create the root node with a boundary so that we know what part we are interested in.

(11) -> view := boxBoundary(sipnt(-1,-1)$PT,sipnt(3,1)$PT)
   (11)  bound box:pt(- 1.0,- 1.0)->pt(3.0,1.0)
                                         Type: SBoundary(SCartesian(2))

(12) -> sc := createSceneRoot(view)$Scene(PT)
   (12)  scene root bound box:pt(- 1.0,- 1.0)->pt(3.0,1.0) #ch=0
                                             Type: Scene(SCartesian(2))

(13) -> SHAPE ==> Record(shptype:Symbol,centre:PT,size:PT,fill:Boolean)
                                                             Type: Void

(14) -> sh1:SHAPE := ["ellipse"::Symbol,_
                   spnt(0::DF,0::DF)$PT,spnt(0.1::DF,0.2::DF)$PT,false]
   (14)  [shptype= ellipse,_
                     centre= pt(0.0,0.0),size= pt(0.1,0.2),fill= false]
                                         Type: Record(shptype: Symbol,_
               centre: SCartesian(2),size: SCartesian(2),fill: Boolean)

(15) -> ellipse := addSceneShape(sc,sh1)$Scene(PT)
   (15)  scene shape type=ellipse pt1=pt(0.0,0.0) pt2=pt(0.1,0.2) #ch=0
                                             Type: Scene(SCartesian(2))

(16) -> text1 := addSceneText(sc,"long text",32::NNI,_
                   spnt(0.5::DF,0.4::DF)$PT)$Scene(PT)
   (16)  scene text="long text" sz=32 p=pt(0.5,0.4) npt=[] #ch=0
                                             Type: Scene(SCartesian(2))

(17) -> text2 := addSceneText(sc,"A",32::NNI,_
                   spnt(0.1::DF,0.3::DF)$PT)$Scene(PT)
   (17)  scene text="A" sz=32 p=pt(0.1,0.3) npt=[] #ch=0
                                             Type: Scene(SCartesian(2))

(18) -> line := addSceneLine(sc,_
                   [spnt(0.3::DF,0.7::DF)$PT,spnt(0.1::DF,0.9::DF)$PT])
   (18)  scene line [[pt(0.3,0.7),pt(0.1,0.8999999999999999)]] #ch=0
                                             Type: Scene(SCartesian(2))

(19) -> arrow := addSceneArrows(sc,_
               [[spnt(0.5::DF,-0.2::DF)$PT,spnt(1.5::DF,0.5::DF)$PT]],_
               "fixed"::Symbol,2::DF)
   (19)  scene arrows pts=[[pt(0.5,- 0.2),_
                                    pt(1.5,0.5)]] m=fixed sz=2.0 #ch=0
                                             Type: Scene(SCartesian(2))

We have now created various nodes:

We can now go on to get the boundaries for these nodes and draw them under the material node (so that they are drawn in blue).

(20) -> mt2 := addSceneMaterial(sc,3::DF,"blue","green")$Scene(PT)
   (20)  scene material lw=3.0 lc="blue" fc="green" mo=1.0 #ch=0
                                             Type: Scene(SCartesian(2))

(21) -> scenebd:SBoundary(PT) := boundary(sc)
   (21)  bound box:pt(- 0.1,- 0.2)->pt(1.5,0.8999999999999999)
                                         Type: SBoundary(SCartesian(2))

(22) -> addSceneShape(mt2,scenebd)
   (22)
   scene shape type=rect pt1=pt(- 0.1,- 0.2)_
                         pt2=vec(1.6,1.0999999999999999)
      #ch=0
                                             Type: Scene(SCartesian(2))

(23) -> ellipsebd:SBoundary(PT) := boundary(ellipse)
   (23)  bound ellipoid:pt(0.0,0.0)->pt(0.1,0.2)
                                         Type: SBoundary(SCartesian(2))

(24) -> addSceneShape(mt2,ellipsebd)
   (24)  scene shape type=rect pt1=pt(0.0,0.0) pt2=vec(0.1,0.2) #ch=0
                                             Type: Scene(SCartesian(2))

(25) -> text1bd:SBoundary(PT) := boundary(text1)
   (25)  bound box:pt(0.5,0.4)->pt(1.076,0.528)
                                         Type: SBoundary(SCartesian(2))

(26) -> addSceneShape(mt2,text1bd)
   (26)
   scene shape type=rect pt1=pt(0.5,0.4)_
                               pt2=vec(0.5760000000000001,0.128) #ch=0
                                             Type: Scene(SCartesian(2))

(27) -> text2bd:SBoundary(PT) := boundary(text2)
   (27)  bound box:pt(0.1,0.3)->pt(0.164,0.428)
                                         Type: SBoundary(SCartesian(2))

(28) -> addSceneShape(mt2,text2bd)
   (28)  scene shape type=_
                       rect pt1=pt(0.1,0.3) pt2=vec(0.064,0.128) #ch=0
                                             Type: Scene(SCartesian(2))

(29) -> linebd:SBoundary(PT) := boundary(line)
   (29)  bound box:pt(0.1,0.7)->pt(0.3,0.8999999999999999)
                                         Type: SBoundary(SCartesian(2))

(30) -> addSceneShape(mt2,linebd)
   (30)
   scene shape type=rect pt1=pt(0.1,0.7) pt2=
     vec(0.19999999999999998,0.19999999999999996)
      #ch=0
                                             Type: Scene(SCartesian(2))

(31) -> arrowbd:SBoundary(PT) := boundary(arrow)
   (31)  bound box:pt(0.5,- 0.2)->pt(1.5,0.5)
                                         Type: SBoundary(SCartesian(2))

(32) -> addSceneShape(mt2,arrowbd)
   (32)  scene shape type=rect pt1=pt(0.5,- 0.2) pt2=vec(1.0,0.7) #ch=0
                                             Type: Scene(SCartesian(2))

(33) -> writeSvg(sc,"testGraph/boundary1.svg")
                                                             Type: Void
boundary So here are the shapes that we constructed with their boundaries drawn in blue.

We will now construct some more shapes and this time we will draw arrows between them:

(34) -> sc2 := createSceneRoot(view)$Scene(PT)
   (34)  scene root bound box:pt(- 1.0,- 1.0)->pt(3.0,1.0) #ch=0
                                             Type: Scene(SCartesian(2))

(35) -> sh2:SHAPE := ["ellipse"::Symbol,_
                   spnt(0::DF,0::DF)$PT,spnt(0.1::DF,0.2::DF)$PT,false]
   (35)  [shptype= ellipse,_
                     centre= pt(0.0,0.0),size= pt(0.1,0.2),fill= false]
                                         Type: Record(shptype: Symbol,_
               centre: SCartesian(2),size: SCartesian(2),fill: Boolean)

(36) -> ellipse2 := addSceneShape(sc2,sh2)$Scene(PT)
   (36)  scene shape type=ellipse pt1=pt(0.0,0.0) pt2=pt(0.1,0.2) #ch=0
                                             Type: Scene(SCartesian(2))

(37) -> sh3:SHAPE := ["rect"::Symbol,_
              spnt(0.4::DF,-0.2::DF)$PT,spnt(0.2::DF,0.4::DF)$PT,false]
   (37)  [shptype= rect,_
                   centre= pt(0.4,- 0.2),size= pt(0.2,0.4),fill= false]
                                         Type: Record(shptype: Symbol,_
               centre: SCartesian(2),size: SCartesian(2),fill: Boolean)

(38) -> ellipse3 := addSceneShape(sc2,sh3)$Scene(PT)
   (38)  scene shape type=rect pt1=pt(0.4,- 0.2) pt2=pt(0.2,0.4) #ch=0
                                             Type: Scene(SCartesian(2))

(39) -> sh4:SHAPE := ["rect"::Symbol,_
              spnt(-0.1::DF,0.3::DF)$PT,spnt(0.2::DF,0.4::DF)$PT,false]
   (39)  [shptype= rect,_
                   centre= pt(- 0.1,0.3),size= pt(0.2,0.4),fill= false]
                                         Type: Record(shptype: Symbol,_
               centre: SCartesian(2),size: SCartesian(2),fill: Boolean)

(40) -> ellipse4 := addSceneShape(sc2,sh4)$Scene(PT)
   (40)  scene shape type=rect pt1=pt(- 0.1,0.3) pt2=pt(0.2,0.4) #ch=0
                                             Type: Scene(SCartesian(2))

(41) -> sh5:SHAPE := ["ellipse"::Symbol,_
               spnt(0.5::DF,0.5::DF)$PT,spnt(0.1::DF,0.2::DF)$PT,false]
   (41)  [shptype= ellipse,_
                     centre= pt(0.5,0.5),size= pt(0.1,0.2),fill= false]
                                         Type: Record(shptype: Symbol,_
               centre: SCartesian(2),size: SCartesian(2),fill: Boolean)

(42) -> ellipse5 := addSceneShape(sc2,sh5)$Scene(PT)
   (42)  scene shape type=ellipse pt1=pt(0.5,0.5) pt2=pt(0.1,0.2) #ch=0
                                             Type: Scene(SCartesian(2))

Having constructed the shapes we will now get their boundaries:

(43) -> ellipsebd2:SBoundary(PT) := boundary(ellipse2)
   (43)  bound ellipoid:pt(0.0,0.0)->pt(0.1,0.2)
                                         Type: SBoundary(SCartesian(2))

(44) -> ellipsebd3:SBoundary(PT) := boundary(ellipse3)
   (44)  bound box:pt(0.4,- 0.2)->pt(0.6000000000000001,0.2)
                                         Type: SBoundary(SCartesian(2))

(45) -> ellipsebd4:SBoundary(PT) := boundary(ellipse4)
   (45)  bound box:pt(- 0.1,0.3)->pt(0.1,0.7)
                                         Type: SBoundary(SCartesian(2))

(46) -> ellipsebd5:SBoundary(PT) := boundary(ellipse5)
   (46)  bound ellipoid:pt(0.5,0.5)->pt(0.1,0.2)
                                         Type: SBoundary(SCartesian(2))

(47) -> line2:List PT := link(ellipsebd2,ellipsebd3)
   (47)  [pt(0.10000000000000002,0.0),pt(0.39999999999999997,0.0)]
                                              Type: List(SCartesian(2))

(48) -> line3:List PT := link(ellipsebd2,ellipsebd4)
   (48)  [pt(0.0,0.20000000000000004),pt(0.0,0.30000000000000004)]
                                              Type: List(SCartesian(2))

(49) -> line4:List PT := link(ellipsebd3,ellipsebd5)
   (49)  [pt(0.5,0.2),pt(0.5,0.29999999999999993)]
                                              Type: List(SCartesian(2))

(50) -> line5:List PT := link(ellipsebd4,ellipsebd5)
   (50)  [pt(0.1,0.5),pt(0.39999999999999997,0.5)]
                                              Type: List(SCartesian(2))

(51) -> line6:List PT := link(ellipsebd2,ellipsebd5)
   (51)
   [pt(0.0894427190999916,0.0894427190999916),
    pt(0.4105572809000084,0.4105572809000084)]
                                              Type: List(SCartesian(2))

(52) -> line7:List PT := link(ellipsebd3,ellipsebd4)
   (52)  [pt(0.39999999999999997,0.10000000000000003),pt(0.1,0.4)]
                                              Type: List(SCartesian(2))

(53) -> mt3 := addSceneMaterial(sc2,3::DF,"red","green")$Scene(PT)
   (53)  scene material lw=3.0 lc="red" fc="green" mo=1.0 #ch=0
                                             Type: Scene(SCartesian(2))

We can now draw arrows between the shapes:

(54) -> arrow2 := addSceneArrows(mt3,[line2],"fixed"::Symbol,2::DF)
   (54)
   scene arrows pts=[[_
              pt(0.10000000000000002,0.0),pt(0.39999999999999997,0.0)]]
      m=fixed sz=2.0
      #ch=0
                                             Type: Scene(SCartesian(2))
(50) -> arrow3 := addSceneArrows(mt3,[line3],"fixed"::Symbol,2::DF)
   (55)
   scene arrows pts=[[_
              pt(0.0,0.20000000000000004),pt(0.0,0.30000000000000004)]]
      m=fixed sz=2.0
      #ch=0
                                             Type: Scene(SCartesian(2))
(50) -> arrow4 := addSceneArrows(mt3,[line4],"fixed"::Symbol,2::DF)
   (56)
   scene arrows pts=[[_
              pt(0.5,0.2),pt(0.5,0.29999999999999993)]] m=fixed sz=2.0
      #ch=0
                                             Type: Scene(SCartesian(2))
(50) -> arrow5 := addSceneArrows(mt3,[line5],"fixed"::Symbol,2::DF)
   (57)
   scene arrows pts=[[_
               pt(0.1,0.5),pt(0.39999999999999997,0.5)]] m=fixed sz=2.0
      #ch=0
                                             Type: Scene(SCartesian(2))
(50) -> arrow6 := addSceneArrows(mt3,[line6],"fixed"::Symbol,2::DF)
   (58)
   scene arrows pts=
     [
       [pt(0.0894427190999916,0.0894427190999916),
        pt(0.4105572809000084,0.4105572809000084)]
       ]
      m=fixed sz=2.0
      #ch=0
                                             Type: Scene(SCartesian(2))
(50) -> arrow7 := addSceneArrows(mt3,[line7],"fixed"::Symbol,2::DF)
   (59)
   scene arrows pts=[[_
             pt(0.39999999999999997,0.10000000000000003),pt(0.1,0.4)]]
      m=fixed sz=2.0
      #ch=0
                                             Type: Scene(SCartesian(2))
(60) -> writeSvg(sc2,"testGraph/boundary2.svg")
                                                             Type: Void
boundary So we can see that this form of addSceneArrows draws the arrow upto the boundary of the nodes that it is drawing the arrows between.

metadata block
see also:
Correspondence about this page

This site may have errors. Don't use for critical systems.

Copyright (c) 1998-2023 Martin John Baker - All rights reserved - privacy policy.