Filling Modules in a Trapezoid Shape Using Excel VBA

excelnoob192

New Member
Joined
Sep 2, 2024
Messages
1
Office Version
  1. 2021
Hello everyone,

I am still quite inexperienced in Excel VBA and have encountered a problem. The background:

I would like to fill various shapes with small rectangles (‘modules’). The modules should always be the same size and their size is predefined. A minimum distance between the modules and to the edge of the respective shape is also specified. Taking these conditions into account, as many modules as possible should be generated symmetrically in the shape. The size of the mould should be variable so that the maximum number of modules can always be generated.

This is not a problem with a rectangular shape (see ‘Sheet1’ and sub ‘GenerateModulesSquare’.

Next, I tried my hand at a trapezoid. I first determined the 4 corner points of the trapezoid to determine the edges. I then used a loop to query whether there was room for another module + two safety distances to the edge (see subs ‘TrapezoidTooManyModules’ and ‘TrapezoidNotEnoughModules’).

Especially with ‘TrapezoidNotEnoughModules’ I don't understand why gaps are left where there would actually be enough space for further modules.
‘TrapezoidTooManyModules’ looks better at first glance, but exceeds the edges of the trapezoid.
Depending on whether you enlarge or reduce the size of the trapezoid, the malfunction becomes clearer. Neither of the two approaches works.

I suspect that I am not calculating the left and right edges accurately and therefore the If queries are correct, but have the wrong basis.

I would be very grateful for any advice! :)

Attached are the three subs mentioned and 3 pictures:

VBA Code:
Sub GenerateModulesSquare()
    Dim roofShape As Shape
    Dim moduleShape As Shape
    Dim moduleWidth As Single, moduleHeight As Single
    Dim clearance As Single
    Dim xPosLeft As Single, xPosRight As Single, yPos As Single
    Dim centerX As Single, roofBottom As Single
    Dim moduleNumber As Integer
    Dim xPosStart As Single
    Dim spaceLeft As Single, spaceRight As Single
   
    ' Set the roof shape (existing shape on the worksheet)
    Set roofShape = ThisWorkbook.Sheets("Sheet1").Shapes("RoofShape") ' Adjust the name of the roof shape
   
    ' Set module size (width and height) and clearance
    moduleWidth = 30 ' Width of the module
    moduleHeight = 50 ' Height of the module
    clearance = 5
    moduleNumber = 1
   
    ' Calculate the center of the roof shape and the bottom edge
    centerX = roofShape.Left + (roofShape.width / 2)
    roofBottom = roofShape.Top + roofShape.height - clearance
   
    ' Starting point for y (begin from the top)
    yPos = roofShape.Top + clearance
   
    ' Starting position for x in the center
    xPosStart = centerX - (moduleWidth / 2)
   
    ' Generate modules symmetrically from the center
    Do While yPos + moduleHeight <= roofBottom
        ' Place modules to the left of the center
        xPosLeft = xPosStart
        spaceLeft = centerX - roofShape.Left
        Do While xPosLeft >= roofShape.Left + clearance
            Set moduleShape = ThisWorkbook.Sheets("Sheet1").Shapes.AddShape(msoShapeRectangle, xPosLeft, yPos, moduleWidth, moduleHeight)
            moduleShape.Name = "Module_" & moduleNumber
            moduleShape.TextFrame2.TextRange.Text = "Module" & moduleNumber
            FormatModule moduleShape
            moduleNumber = moduleNumber + 1
            xPosLeft = xPosLeft - moduleWidth - clearance
        Loop
       
        ' Place modules to the right of the center
        xPosRight = xPosStart + moduleWidth + clearance
        spaceRight = roofShape.Left + roofShape.width - xPosRight
        Do While spaceRight >= moduleWidth + clearance
            Set moduleShape = ThisWorkbook.Sheets("Sheet1").Shapes.AddShape(msoShapeRectangle, xPosRight, yPos, moduleWidth, moduleHeight)
            moduleShape.Name = "Module_" & moduleNumber
            moduleShape.TextFrame2.TextRange.Text = "Module" & moduleNumber
            FormatModule moduleShape
            moduleNumber = moduleNumber + 1
            xPosRight = xPosRight + moduleWidth + clearance
            spaceRight = spaceRight - moduleWidth - clearance
        Loop
       
        ' Calculate the next y-position (move down)
        yPos = yPos + moduleHeight + clearance
       
        ' Reset xPos to the left side
        xPosStart = centerX - (moduleWidth / 2)
    Loop
End Sub
VBA Code:
Sub TrapezoidTooManyModules()
    Dim ws As Worksheet
    Dim shp As Shape
    Dim moduleWidth As Single, moduleHeight As Single
    Dim clearance As Single
    Dim xPos As Single, yPos As Single
    Dim moduleNumber As Integer
    Dim trapezoidTopLeftX As Single, trapezoidTopLeftY As Single
    Dim trapezoidTopRightX As Single, trapezoidTopRightY As Single
    Dim trapezoidBottomLeftX As Single, trapezoidBottomLeftY As Single
    Dim trapezoidBottomRightX As Single, trapezoidBottomRightY As Single
    Dim m1 As Double, b1 As Double, m2 As Double, b2 As Double
    Dim xLeftLimit As Single, xRightLimit As Single
    Dim midX As Single

    ' Set worksheet (Sheet2)
    Set ws = ThisWorkbook.Sheets("Sheet2")

    ' Set trapezoid shape
    Set shp = ws.Shapes("TrapezoidShape")
   
    ' Set module size (moduleWidth & moduleHeight) and clearance (clearance)
    moduleWidth = 30
    moduleHeight = 50
    clearance = 5
    moduleNumber = 1

    ' Calculate trapezoid coordinates
    trapezoidTopLeftX = shp.Left + ((shp.width - (shp.width * (1 - shp.Adjustments(1)))) / 2)
    trapezoidTopLeftY = shp.Top
    trapezoidTopRightX = trapezoidTopLeftX + (shp.width * (1 - shp.Adjustments(1)))
    trapezoidTopRightY = shp.Top
    trapezoidBottomLeftX = shp.Left
    trapezoidBottomLeftY = shp.Top + shp.height
    trapezoidBottomRightX = shp.Left + shp.width
    trapezoidBottomRightY = shp.Top + shp.height

    ' Calculate slopes (m) and intercepts (b) of the left and right edges
    m1 = (trapezoidBottomLeftY - trapezoidTopLeftY) / (trapezoidBottomLeftX - trapezoidTopLeftX)
    b1 = trapezoidTopLeftY - m1 * trapezoidTopLeftX
   
    m2 = (trapezoidBottomRightY - trapezoidTopRightY) / (trapezoidBottomRightX - trapezoidTopRightX)
    b2 = trapezoidTopRightY - m2 * trapezoidTopRightX
   
    ' Start from the middle of the top row
    yPos = trapezoidTopLeftY + clearance
   
    ' Generate modules from top to bottom and from the center to the left and right
    Do While yPos + moduleHeight + clearance <= trapezoidBottomLeftY
        ' Calculate the x-limits for the current y-position
        xLeftLimit = (yPos - b1) / m1 + clearance
        xRightLimit = (yPos - b2) / m2 - clearance
       
        ' Start from the center
        midX = (xLeftLimit + xRightLimit) / 2
        xPos = midX - moduleWidth / 2
       
        ' Generate modules to the right
        Do While xPos + moduleWidth <= xRightLimit
            If xPos + moduleWidth <= xRightLimit Then
                Set shpModule = ws.Shapes.AddShape(msoShapeRectangle, xPos, yPos, moduleWidth, moduleHeight)
                shpModule.Name = "Module_" & moduleNumber
                shpModule.TextFrame2.TextRange.Text = "Module" & moduleNumber
                moduleNumber = moduleNumber + 1
            End If
            xPos = xPos + moduleWidth + clearance
        Loop
       
        ' Start from the center
        xPos = midX - moduleWidth / 2 - (moduleWidth + clearance)
       
        ' Generate modules to the left
        Do While xPos >= xLeftLimit
            If xPos >= xLeftLimit Then
                Set shpModule = ws.Shapes.AddShape(msoShapeRectangle, xPos, yPos, moduleWidth, moduleHeight)
                shpModule.Name = "Module_" & moduleNumber
                shpModule.TextFrame2.TextRange.Text = "Module" & moduleNumber
                moduleNumber = moduleNumber + 1
            End If
            xPos = xPos - (moduleWidth + clearance)
        Loop
       
        ' Move to the next row
        yPos = yPos + moduleHeight + clearance
    Loop
End Sub



VBA Code:
Sub TrapezoidNotEnoughModules()
    Dim ws As Worksheet
    Dim shp As Shape
    Dim moduleWidth As Single, moduleHeight As Single
    Dim clearance As Single
    Dim xPos As Single, yPos As Single
    Dim moduleNumber As Integer
    Dim trapezoidTopLeftX As Single, trapezoidTopLeftY As Single
    Dim trapezoidTopRightX As Single, trapezoidTopRightY As Single
    Dim trapezoidBottomLeftX As Single, trapezoidBottomLeftY As Single
    Dim trapezoidBottomRightX As Single, trapezoidBottomRightY As Single
    Dim m1 As Double, b1 As Double, m2 As Double, b2 As Double
    Dim xLeftLimit As Single, xRightLimit As Single
    Dim midX As Single

    ' Set worksheet (Sheet2)
    Set ws = ThisWorkbook.Sheets("Sheet2")

    ' Set background shape (Trapezoid)
    Set shp = ws.Shapes("TrapezoidShape")
   
    ' Set module size (moduleWidth & moduleHeight) and clearance (clearance)
    moduleWidth = 30
    moduleHeight = 50
    clearance = 5
    moduleNumber = 1

    ' Calculate trapezoid coordinates
    trapezoidTopLeftX = shp.Left + ((shp.width - (shp.width * (1 - shp.Adjustments(1)))) / 2)
    trapezoidTopLeftY = shp.Top
    trapezoidTopRightX = trapezoidTopLeftX + (shp.width * (1 - shp.Adjustments(1)))
    trapezoidTopRightY = shp.Top
    trapezoidBottomLeftX = shp.Left
    trapezoidBottomLeftY = shp.Top + shp.height
    trapezoidBottomRightX = shp.Left + shp.width
    trapezoidBottomRightY = shp.Top + shp.height

    ' Calculate slopes (m) and intercepts (b) of the left and right edges
    m1 = (trapezoidBottomLeftY - trapezoidTopLeftY) / (trapezoidBottomLeftX - trapezoidTopLeftX)
    b1 = trapezoidTopLeftY - m1 * trapezoidTopLeftX
   
    m2 = (trapezoidBottomRightY - trapezoidTopRightY) / (trapezoidBottomRightX - trapezoidTopRightX)
    b2 = trapezoidTopRightY - m2 * trapezoidTopRightX

    ' Start from the middle of the top row
    yPos = trapezoidTopLeftY + clearance
   
    ' Generate modules from top to bottom and from the center to the left and right
    Do While yPos + moduleHeight + clearance <= trapezoidBottomLeftY
        ' Calculate the x-limits for the current y-position
        xLeftLimit = (yPos - b1) / m1 + clearance
        xRightLimit = (yPos - b2) / m2 - clearance
       
        ' Start from the center
        midX = (xLeftLimit + xRightLimit) / 2
        xPos = midX - moduleWidth / 2
       
        ' Generate modules to the right
        Do While xPos + moduleWidth / 2 <= xRightLimit
            ' Check if there is enough space for another module
            If (xRightLimit - (xPos + moduleWidth) >= moduleWidth + 2 * clearance) Then
                Set shpModule = ws.Shapes.AddShape(msoShapeRectangle, xPos, yPos, moduleWidth, moduleHeight)
                shpModule.Name = "Module_" & moduleNumber
                shpModule.TextFrame2.TextRange.Text = "Module" & moduleNumber
                moduleNumber = moduleNumber + 1
            Else
                Exit Do ' If there is not enough space, exit the loop for placing modules to the right
            End If
            xPos = xPos + moduleWidth + clearance
        Loop
       
        ' Start from the center
        xPos = midX - moduleWidth / 2 - (moduleWidth + clearance)
       
        ' Generate modules to the left
        Do While xPos >= xLeftLimit
            ' Check if there is enough space for another module
            If ((xPos - xLeftLimit) >= moduleWidth + 2 * clearance) Then
                Set shpModule = ws.Shapes.AddShape(msoShapeRectangle, xPos, yPos, moduleWidth, moduleHeight)
                shpModule.Name = "Module_" & moduleNumber
                shpModule.TextFrame2.TextRange.Text = "Module" & moduleNumber
                moduleNumber = moduleNumber + 1
            Else
                Exit Do ' If there is not enough space, exit the loop for placing modules to the left
            End If
            xPos = xPos - (moduleWidth + clearance)
        Loop
       
        ' Move to the next row
        yPos = yPos + moduleHeight + clearance
    Loop
End Sub


Greetings
 

Attachments

  • Unbenannt1.PNG
    Unbenannt1.PNG
    57.4 KB · Views: 5
  • Unbenannt2.PNG
    Unbenannt2.PNG
    65.7 KB · Views: 5
  • Unbenannt3.PNG
    Unbenannt3.PNG
    64.8 KB · Views: 4
Last edited by a moderator:

Excel Facts

How to change case of text in Excel?
Use =UPPER() for upper case, =LOWER() for lower case, and =PROPER() for proper case. PROPER won't capitalize second c in Mccartney
Welcome to the MrExcel Message Board!

Cross-posting (posting the same question in more than one forum) is not against our rules, but the method of doing so is covered by #13 of the Forum Rules.

Be sure to follow & read the link at the end of the rule too!

Cross posted at: Filling Modules in a Trapezoid Shape Using Excel VBA
There is no need to repeat the link(s) provided above but if you have posted the question at other places, please provide links to those as well.

If you do cross-post in the future and also provide links, then there shouldn’t be a problem.
 
Upvote 0

Forum statistics

Threads
1,224,743
Messages
6,180,686
Members
452,994
Latest member
Janick

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top