Clip Rectangle To Rectangle

  In this example, we're clipping the background rectangle to the foreground rectangle. This results in 16 possible layouts that the pair of rectangles can have in relation to each other. The goal is to output a list of areas that represent the visible portion of the background rectangle without overlapping any pixels



PlayBASIC Code:
; PROJECT : Clip Foreground Rectangle TO Background Rectangle
; AUTHOR  : Kev Picone - https://PlayBASIC.com
; CREATED : 8/04/2023
; EDITED  : 9/04/2023
; ---------------------------------------------------------------------

    loadfont "courier new",1, 40

    Type tRect
            x1,y1
            x2,y2
            Colour
    EndType
    
    Dim Rects(16) as tRect

    Global RectCount    =0

    do


        Dim Back as tRect Pointer
        Back = new TRect

        w= rndrange(100,500)
        h= rndrange(100,500)
        X=rnd( getscreenwidth() * 0.60)
        Y=rnd(getscreenheight() * 0.60)
        Back.x1 = x
        Back.y1 = y
        Back.x2 = x+w
        Back.y2 = y+h
        Back.colour =rndrgb()    

        Dim Front as tRect Pointer
        Front = new TRect
    
        W= 500
        H= 150
        
        // --------------------------------------------------------
        Do
        // --------------------------------------------------------
            cls $203040
        
                Boxc Back.x1,Back.y1,Back.x2,Back.y2,true,Back.Colour
    
    
                Front.x1=mousex()
                    Front.y1=mousey()
                Front.x2=Front.x1+W
                Front.y2=Front.y1+H
    
                box Front.x1,Front.y1,Front.x2,Front.y2,true
    
    
                inkmode 1+1024
                Status =ClipRectangles(Front,Back)
                inkmode 1
    
                for lp =0 to Status-1
                    X1=Rects(lp).x1
                        y1=Rects(lp).y1    
                    x2=Rects(lp).x2    
                    y2=Rects(lp).y2
                    boxc x1,y1,x2,y2,false, $00ff00
                    boxc x1+1,y1+1,x2-1,y2-1,false, $00ff00

                    s$ =" X1="+str$(X1)
                    s$+=" Y1="+str$(Y1)
                    s$+=" Y1="+str$(X2)
                    s$+=" Y1="+str$(Y2)

                    Print "#"+str$(lp)+s$
                            
                next

                if Status=-2
                    Print "Foreground covers background"
                endif

                if mousebutton()=2
                        w=rndrange(50,500)
                        h=rndrange(50,350)
                endif
    
            sync

        // --------------------------------------------------------
        loop spacekey()
        // --------------------------------------------------------

        free front
        free back

            
loop    




Function ClipRectangles(Front as tRect Pointer, Back as tRect Pointer)

        RectCount    =0
        Count = -1    

        if int(Front)=0 or int(Back)=0 then ExitFunction -1

        // chec if the Front rect to the left or right of te back rect
        if Front.X2<Back.X1 then exitfunction Count
        if Front.X1>Back.X2 then exitfunction Count
    
        //  check if the FRONT is ABOVE or BELLOW the BACK rect
        if Front.Y2<Back.Y1 then exitfunction Count
        if Front.Y1>Back.Y2 then exitfunction Count


        //  Make bit pattern for what side each point is to its patern
        Layout    = (Front.X1>=Back.X1 << 1)+ ( Front.X2>Back.X2) 
        Layout    =Layout<<2

        Layout+= Front.Y1>=Back.Y1 << 1
        Layout+= Front.Y2>Back.Y2 

        Filled    =true
        static ThisRGB    
        
        ThisRGB = -1
        
        print bin$(Layout)
        
        Select LayOut

                // ---------------------------------------------
                case %0000
                // ---------------------------------------------

                        //  front is covering back to left and 
                        //  above and bellow back
                        SetBox( Front.x2    ,Back.y1        ,back.x2    ,front.y2    , ThisRGB)
                        SetBox( Back.x1    ,front.y2    ,back.x2    ,back.y2        , ThisRGB)

                // ---------------------------------------------
                case %0001
                // ---------------------------------------------

                        //  front is covering back to left and 
                        //  above and bellow back
                        SetBox( Front.x2,Back.y1    ,back.x2    ,back.y2, ThisRGB )



                // ---------------------------------------------
                case %0010
                // ---------------------------------------------

                        // top chunk
                        SetBox( Back.x1,Back.y1    ,back.x2    , front.y1, ThisRGB )

                        // bottom chunk
                        SetBox( Back.x1,front.y2    ,back.x2    , back.y2, ThisRGB )

                        //  middle chuck to the right of the front rect
                        SetBox( Front.x2,front.y1    ,back.x2    ,front.y2, ThisRGB )

        

                // ---------------------------------------------
                case %0011
                // ---------------------------------------------

                        //  The front rect is covering back rect
                        SetBox( Back.x1,Back.y1    ,Back.x2    ,Front.y1, ThisRGB )
                        SetBox( front.x2,front.y1,back.x2,back.y2    ,ThisRGB )

                // ---------------------------------------------
                case %0100
                // ---------------------------------------------

                        //  visible left edge of back
                        SetBox( Back.x1,front.y2    ,back.x2    ,back.y2, ThisRGB )


            
                // ---------------------------------------------
                case %0101
                // ---------------------------------------------

                        // draw nothing// front overlaps backdrop
                        exitfunction -2
        


            
                // ---------------------------------------------
                case %0110
                // ---------------------------------------------

                        // Top 
                        SetBox( Back.x1,back.y1    ,back.x2    ,front.y1, ThisRGB )

                        // bottom 
                        SetBox( Back.x1,front.y2    ,back.x2    ,back.y2, ThisRGB )

                // ---------------------------------------------
                case %0111
                // ---------------------------------------------

                        //  visible left edge of back
                        SetBox( Back.x1,back.y1    ,back.x2    ,front.y1, ThisRGB )



                // ---------------------------------------------
                case %1000
                // ---------------------------------------------


                        // chunks of either side
                        SetBox( Back.x1    ,Back.y1    ,front.x1    ,front.y2, ThisRGB )
                        SetBox( front.x2    ,Back.y1    ,back.x2    , front.y2, ThisRGB )
    
                        // bottom section
                        SetBox( Back.x1    ,front.y2    ,back.x2    ,back.y2, ThisRGB )
                                                


                // ---------------------------------------------
                case %1001
                // ---------------------------------------------
                        SetBox( Back.x1,Back.y1    ,front.x1    ,back.y2, ThisRGB )
                        SetBox( front.x2,Back.y1    ,back.x2    ,back.y2, ThisRGB )


                // ---------------------------------------------
                case %1010
                // ---------------------------------------------

                        // front rect is inside the background rect
                        // Top Chunk
                        SetBox( Back.x1,Back.y1    ,back.x2    ,front.y1, ThisRGB )
                        // bottom
                        SetBox( Back.x1,front.y2    ,back.x2    ,back.y2, ThisRGB )

                        // Left chunk
                        SetBox( Back.x1,front.y1    ,front.x1    ,front.y2, ThisRGB )

                        //  right chunk
                        SetBox( front.x2,front.y1    ,back.x2    ,front.y2, ThisRGB )


                // ---------------------------------------------
                case %1011
                // ---------------------------------------------

                        // top section
                        SetBox( Back.x1,back.y1    ,back.x2    ,front.y1, ThisRGB )

                        //  left and right blocks
                        SetBox( Back.x1,front.y1    ,front.x1    ,back.y2, ThisRGB )
                        SetBox( front.x2,front.y1    ,back.x2    ,back.y2, ThisRGB )
        
        
                // ---------------------------------------------
                case %1100
                // ---------------------------------------------

                        //  visible left edge of back
                        SetBox( Back.x1,Back.y1    ,front.x1    ,back.y2, ThisRGB )

                        //  visible bottom strip of bacl
                        SetBox( front.x1,front.y2    ,back.x2    ,back.y2, ThisRGB )


        

                // ---------------------------------------------
                case %1101
                // ---------------------------------------------

                        //  front is covering back to left and 
                        //  above and bellow back
                        SetBox( Back.x1,Back.y1    ,front.x1    ,back.y2, ThisRGB )

        

                // ---------------------------------------------
                case %1110
                // ---------------------------------------------
                        // top part
                        SetBox( Back.x1,Back.y1    ,Back.x2    ,Front.y1, ThisRGB )

                        //  bottom part
                        SetBox( Back.x1,front.y2    ,Back.x2    ,back.y2, ThisRGB )

                        // left hand box
                        SetBox( Back.x1,front.y1    ,front.x1    ,Front.y2, ThisRGB )
    
        
                // ---------------------------------------------
                case %1111
                // ---------------------------------------------

                        //  The front rect is covering back rect
                        SetBox( Back.x1,Back.y1    ,Back.x2    ,Front.y1, ThisRGB )
                        SetBox( Back.x1,front.y1,front.x1,back.y2    ,ThisRGB )

        EndSelect
        
    
        Count=RectCount
        ThisRGB+=$112233
    
EndFunction Count



function SetBox(X1,Y1,X2,Y2,Colour)
    
        if Rects(RectCount)=0
                Rects(RectCount) = new tRect
        endif
        Rects(RectCount).x1=x1    
        Rects(RectCount).y1=y1    
        Rects(RectCount).x2=x2    
        Rects(RectCount).y2=y2    
        Rects(RectCount).Colour=Colour    
        RectCount++    

      Boxc x1,y1,x2,y2,true,Colour

EndFunction