# distribution of rectangles with remains

## Recommended Posts

Hello to all,

I have a new request for you...

I would like to create a small program (parametric symbol) to calculate the need for panels on a floor.

The principle is quite simple because it is enough to add panels in a row.

However they must cross each other in order to be more stable and to use the remains.

I enclose a picture to illustrate the problem.

If someone has already done it or has an idea of the tools I can use I'm listening... 😉

Greetings

Raph

##### Link to comment

Try this one as a starting point.  Very poorly scripted, but it seems to work.

Procedure TileRects;

{November 11, 2022}
{©2022 Patrick Stanford pat@coviana.com}
{Licensed under the GNU Lesser General Public License}

{No Warranty Expressed of Implied. Use at your own risk.}
{Very limited testing.}
{Tiles a rectangular area with a set of rectangles}
{the beginning of each row is the "cutoff" from the}
{end of the row above.}

VAR        X1,X2,Y1,Y2                :Real;
FX1,FX2,FY1,FY2            :Real;  {Floor Dims}
RX1,RX2,RY1,RY2            :Real;  {Rect Dims}
Hd1                        :Handle;
W1, H1                    :Real;  {panel width and height}
NP                        :Integer; {number of full panels in row}
Extra                    :Real;
CurrentX, CurrentY        :Real;
SheetEndX, SheetEndY     :Real;
RemainderX, RemainderY    :Real;
ThisY                    :Real;
Done                    :Boolean;

BEGIN
PtDialog('Enter the size of panel', '2500mm', '675mm', W1, H1);

Hd1:=FSActLayer;
If Hd1 <> Nil THEN
BEGIN
GetBBox(Hd1, FX1, FY1, FX2, FY2);
CurrentX:=FX1;
CurrentY:=FY1;
SheetEndX:=FX1+W1;
SheetEndY:=FY1-H1;
RemainderX:=0;
RemainderY:=0;
NP:=1;
Done:=False;
SetDSelect(Hd1);
WHILE Not Done DO
BEGIN
While SheetEndX <= FX2 DO
BEGIN
ThisY := Max(CurrentY-H1, FY2);
Rect(CurrentX, CurrentY, CurrentX + W1, ThisY);
CurrentX:=CurrentX + W1;
SheetEndX:=CurrentX+W1;
NP:=NP+1;
End;

RemainderX:=W1-(FX2-CurrentX);
Rect(CurrentX, CurrentY, FX2,Max(CurrentY - H1,FY2));

If ((SheetEndX <> FX2) and (SheetEndY <> FY2)) then
Begin
CurrentY:=Max(CurrentY-H1, FY2);
CurrentX:=FX1+RemainderX;
SheetEndY:=Max(CurrentY-H1,FY2);
Rect(FX1,CurrentY,CurrentX,SheetEndY);
SheetEndX:=CurrentX+W1;
END
Else Done:=True;
End;
End;
End;

Run(TileRects);

```Procedure TileRects;

{November 11, 2022}
{©2022 Patrick Stanford pat@coviana.com}
{Licensed under the GNU Lesser General Public License}

{No Warranty Expressed of Implied. Use at your own risk.}
{Very limited testing.}
{Tiles a rectangular area with a set of rectangles}
{the beginning of each row is the "cutoff" from the}
{end of the row above.}

VAR		X1,X2,Y1,Y2				:Real;
FX1,FX2,FY1,FY2			:Real;  {Floor Dims}
RX1,RX2,RY1,RY2			:Real;  {Rect Dims}
Hd1						:Handle;
W1, H1					:Real;  {panel width and height}
NP						:Integer; {number of full panels in row}
Extra					:Real;
CurrentX, CurrentY		:Real;
SheetEndX, SheetEndY 	:Real;
RemainderX, RemainderY	:Real;
ThisY					:Real;
Done					:Boolean;

BEGIN
PtDialog('Enter the size of panel', '2500mm', '675mm', W1, H1);

Hd1:=FSActLayer;
If Hd1 <> Nil THEN
BEGIN
GetBBox(Hd1, FX1, FY1, FX2, FY2);
CurrentX:=FX1;
CurrentY:=FY1;
SheetEndX:=FX1+W1;
SheetEndY:=FY1-H1;
RemainderX:=0;
RemainderY:=0;
NP:=1;
Done:=False;
SetDSelect(Hd1);
WHILE Not Done DO
BEGIN
While SheetEndX <= FX2 DO
BEGIN
ThisY := Max(CurrentY-H1, FY2);
Rect(CurrentX, CurrentY, CurrentX + W1, ThisY);
CurrentX:=CurrentX + W1;
SheetEndX:=CurrentX+W1;
NP:=NP+1;
End;

RemainderX:=W1-(FX2-CurrentX);
Rect(CurrentX, CurrentY, FX2,Max(CurrentY - H1,FY2));

If ((SheetEndX <> FX2) and (SheetEndY <> FY2)) then
Begin
CurrentY:=Max(CurrentY-H1, FY2);
CurrentX:=FX1+RemainderX;
SheetEndY:=Max(CurrentY-H1,FY2);
Rect(FX1,CurrentY,CurrentX,SheetEndY);
SheetEndX:=CurrentX+W1;
END
Else Done:=True;
End;
End;
End;

Run(TileRects);

```

##### Link to comment

Hi Pat,

Thanks for this program, it works very well.

I have already adapted with an additional condition that removes 4mm from the remaining panels.

This is to deduct the thickness of the blade.

I am now working on putting an additional condition that will make it so that if the panel at the end of the line is smaller than X (200mm) it will start the row with a whole panel.

thanks you very much for your help
your base allows me to move forward

Raph

##### Link to comment

I am glad it helped.

I basically brute forced it.  You can probably optimize that script a lot.

##### Link to comment

Hi Pat,

just a question....

why didn't you make the program in python language?

Are there points that are easier to code with VectorScript or just out of habit?

Well... that's 2 questions sorry

##### Link to comment

Hello,

I made some changes

1. a deduction in the remaining panel of the thickness of the blade (ThBl:4mm)
2. a minimum dimension at the end of a line that allows to decide if the line starts with a new panel (WmaxSold:200mm)

```Procedure TileRects;

{November 11, 2022}
{©2022 Patrick Stanford pat@coviana.com}
{Licensed under the GNU Lesser General Public License}

{No Warranty Expressed of Implied. Use at your own risk.}
{Very limited testing.}
{Tiles a rectangular area with a set of rectangles}
{the beginning of each row is the "cutoff" from the}
{end of the row above.}

{Modified by Raph_N November 17, 2022}
1. a deduction in the remaining panel of the thickness of the blade (ThBl:4mm)
2. a minimum dimension at the end of a line that allows to decide if the line starts with a new panel (WmaxSold:200mm).}

VAR     X1,X2,Y1,Y2               	:Real;
FX1,FX2,FY1,FY2           	:Real;  	{Floor Dims}
RX1,RX2,RY1,RY2           	:Real;  	{Rect Dims}
ThBl			          	:Real;  	{Thikness of the blade Dims}
Hd1                       	:Handle;
W1, H1						:Real;  	{panel width and height}
NP                       	:Integer; 	{number of full panels in Total}
NProw                       :Integer; 	{number of full panels in row}
Extra                   	:Real;
CurrentX, CurrentY        	:Real;
SheetEndX, SheetEndY     	:Real;
RemainderX, RemainderY   	:Real;
RemainderX2				  	:Real;
ThisY                 	  	:Real;
WmaxSold                 	:Real;   	{maximum weight of the sold}
Done                  		:Boolean;
NewLine                  	:Boolean;

BEGIN
PtDialog('Enter the size of panel', '2500mm', '675mm', W1, H1);

Hd1:=FSActLayer;
If Hd1 <> Nil THEN
BEGIN
GetBBox(Hd1, FX1, FY1, FX2, FY2);
CurrentX:=FX1;
CurrentY:=FY1;
SheetEndX:=FX1+W1;
SheetEndY:=FY1-H1;
ThBl:=4;
RemainderX:=0;
RemainderY:=0;
NP:=1;
NProw:= Trunc((FX2-FX1)/W1);
WmaxSold:= ((FX2-FX1)-(NProw*W1));
Done:=False;
SetDSelect(Hd1);

WHILE Not Done DO
BEGIN

RemainderX2:=W1-WmaxSold;
NProw:= Trunc(((FX2-FX1)-(W1-WmaxSold))/W1);
WmaxSold:= ((FX2-FX1)-(NProw*W1)-RemainderX2);

While SheetEndX <= FX2 DO
BEGIN
If ((NP <> 1) and (WmaxSold<200)) then
BEGIN
RemainderX:=0;
NewLine:=True;
END
ELSE	;

ThisY := Max(CurrentY-H1, FY2);
Rect(CurrentX, CurrentY, CurrentX + W1, ThisY);
CurrentX:=CurrentX + W1;
SheetEndX:=CurrentX + W1;
NP:=NP+1;
End;

RemainderX:=W1-(FX2-CurrentX)-ThBl;
Rect(CurrentX, CurrentY, FX2, Max(CurrentY - H1,FY2));

If ((SheetEndX <> FX2) and (SheetEndY <> FY2)) then
Begin
If (NewLine = true) then
BEGIN
CurrentX:=FX1+W1;
NewLine:=False;
NProw:= Trunc((FX2-FX1)/W1);
WmaxSold:= ((FX2-FX1)-(NProw*W1));
END
ELSE  CurrentX:=FX1+RemainderX;

CurrentY:=Max(CurrentY-H1, FY2);
SheetEndY:=Max(CurrentY-H1,FY2);
Rect(FX1,CurrentY,CurrentX,SheetEndY);
SheetEndX:=CurrentX+W1;
NP:=NP+1;

END
Else Done:=True;

End;
End;
End;

Run(TileRects);```

Edited by Raph
##### Link to comment
11 minutes ago, Raph said:

just a question....

why didn't you make the program in python language?

I have been programming in Vectorscript (Pascal) for over 35 years. It is just more comfortable for me.

I have three major problems with Python.

1. It is case sensitive.  I am not a great typist and making sure I always use the same capITAlizATION in all of my variable names is a challenge.

2. It is white space delimited. Changing the number of spaces a block of code is indented changes what block it is in and how a loop may perform. I much prefer the explicit Begin/End construction of VS. VS also allows me to throw in debugging code that is left aligned so I can go back and find/change/delete it easily later.

3. Variables are not typed.  In VS the type of each variable must be explicitly declared (boolean, string, integer, real, etc) If I try to assign a different type of value to that variable I get an error. In Python, variables are more dynamic. If I use a variable to hold a number and then get confused and later assign a string to it it does not complain. Especially in my quick and dirty coding, this can lead to improper execution and debugging issues.

If you don't need to do anything outside of VW, then VS and Python are equivalent (Python uses VS calls for handling all VW objects). Or almost equivalent as there are a few things that Python can't do well (wait for user input is one). If you need to do anything outside of VW (pull in data from the web, do array calculations, use libraries like SciPy or Pandas) then Python is the only way to go.

While I was able to create the above in about an hour in VS (due to my experience) my guess is it would have taken me 2 to 5 times as long in Python (due to my inexperience).

If you are familiar with Python, it is fairly easy to convert the VS code into Python.

I like your modifications.

One suggestion. If you are pasting code into the forum use a code block

```Then your code will show up in a monospaced font and it will handle tabs as well as
spaces for indentation

Like this.```

##### Link to comment

Hi Pat,

Thanks for your reply, i unterstand your preferences and the reasons that push you to continue on VS.

Is it possible to link VS code with Marionette?

Or is it only possible with Python?

My basic idea was to create a parametric symbol (Marionette) where you just have to change the input variables (Floor dimensions and Panel dimensions) to recalculate the tile distribution. So now I try to write it in Python.

You wrote:

"If you are familiar with Python, it is fairly easy to convert the VS code into Python."

No, it's not... I've done VBA instead.

So the declaration of variables I also like a lot 😉

With python I tried to add two values and it tells me it's impossible because one time it's an 'int' and another is in 'list'??? grrr

Thank you for your suggestion, I have corrected the post directly

Kind regards

Raph

##### Link to comment

Unfortunately, Marionette nodes are Python only.

If you have a script that works, it can be converted into a Plug-in Object with just a few modifications to the script.

Go to the Plug-in Manager and create a new Rectangle Object.

You will by default get two parameters, LineLength and BoxWidth. These will automatically change when you reshape the "rectangle" of the object. Use them to draw the outline of the room.

Create two new parameter for the sheet width and height (what you are currently getting from the PtDialog).

Paste your script into the Script window of the PIO.

Change the FSActLayer to draw a rectangle using the LineLength and BoxWidth parameters.  You have to place as letter p (pLineLength, pBoxWidth) in front so that the compiler recognizes them as parameters and not just variables. Don't start any of your variable names with the letter p unless they are parameters.

Remove the PtDialog and change that to read the parameters you entered.

it SHOULD be EASY.  It won't be, but you will learn a lot and it will be far easier than starting from scratch and trying to do this in Marionette since you already have VS that works.

Ask again when you get stuck.

Welcome to the club. 😉

##### Link to comment

Hi Pat,

No, it's not easy... but very interesting and formative.

Can I really ask you the questions that come to me during this process?

I begin with the first one,

you say:

"Go to the Plug-in Manager and create a new Rectangle Object.

You will by default get two parameters, LineLength and BoxWidth. These will automatically change when you reshape the "rectangle" of the object. Use them to draw the outline of the room."

ok i have make that, but I have a blank file with no text in it!

Is this normal? see image in attached file

Thank you for your wishes (welcome)

Regards Raph

##### Link to comment

Start with setting the Langue: to Vectorscript and then paste in the script that you have running.

Then from there start making the changes necessary to make it work as a PIO.

Change the PtDialog to just setting the W1 and H1 variables to the height and width parameters you set.

Change the HD1:=FSActLayer to instead use the LineLength and BoxWidth parameters to draw the rectangle and set HD1 to a handle to the rectangle you draw.

If you are still stuck, let me know and I can make you a version that works. Maybe I will do it as a video for others as well.

##### Link to comment

Hi Pat,

It was very helpful.

I think I'm not too far from success. missing me 1-2 hour

Attached is a picture of my Marionette network.

It gives an idea of what I want to be able to set up.

I have adapted the code a bit as I thought

My code below:

```# November 11, 2022
# ©2022 Patrick Stanford pat@coviana.com
# Licensed under the GNU Lesser General Public License

# No Warranty Expressed of Implied. Use at your own risk.
# Very limited testing.
# Tiles a rectangular area with a set of rectangles
# the beginning of each row is the "cutoff" from the
# end of the row above.

# Modified by Raph_N November 17, 2022
# added two parameters:
# 1. a deduction in the remaining panel of the thickness of the blade (ThBl:4mm)
# 2. a minimum dimension at the end of a line that allows to decide if the line starts with a new panel (WmaxSold:200mm)

@Marionette.NodeDefinition
class Params(metaclass=Marionette.OrderedClass):
# APPEARANCE
# Name
this = Marionette.Node("TileRects_OSB")
this.SetDescription(
'This node performs a tiles a rectangular area with a set of rectangles the beginning of each row is the "cutoff" from the end of the row above.')

# Input Ports
in0 = Marionette.PortIn(vs.Handle(0), 'hObj1')
in0.SetDescription('A list of objects to be operated on (blanks)')

inWf = Marionette.PortIn(1, 'n_Wfloor')
inWf.SetDescription('A dimension of the width (Pannels)')
inHf = Marionette.PortIn(1, 'n_Hfloor')
inHf.SetDescription('A dimension of the height (Pannels)')

inWp = Marionette.PortIn(1, 'n_Wpan')
inWp.SetDescription('A dimension of the width (Pannels)')
inHp = Marionette.PortIn(1, 'n_Hpan')
inHp.SetDescription('A dimension of the height (Pannels)')

inThBl = Marionette.PortIn(1, 'nBlade')
inThBl.SetDescription('A dimension with a thickness of a (Blade)')

# Output Ports
out = Marionette.PortOut('hObj')
out.SetDescription('The resulting objects')

# BEHAVIOR
# this.SetListAbsorb()

def RunNode(self):
# inputs
FX2 = self.Params.inWf.value
FY2 = self.Params.inHf.value
W1 = self.Params.inWp.value
H1 = self.Params.inHp.value
ThBl = self.Params.inThBl.value

# script
in0 = vs.FSActLayer()

if in0 is not None:
FX1 = 0
FY1 = 0
CurrentX = FX1
CurrentY = FY1
SheetEndX = FX1 + W1
SheetEndY = FY1 + H1
RemainderX = 0
RemainderY = 0
NP = 1
NProw = ((FX2-FX1)/W1)
WmaxSold = ((FX2-FX1)-(NProw*W1))
Done = False
NewLine = False

vs.Rect(FX1, FY1, FX2, FY2)

while not Done:
RemainderX2 = W1 - WmaxSold
NProw = vs.Trunc(((FX2 - FX1) - (W1 - WmaxSold)) / W1)
WmaxSold = ((FX2 - FX1) - (NProw * W1) - RemainderX2)

while SheetEndX <= FX2:
if NP != 1 and WmaxSold<200:
RemainderX = 0
NewLine = True

else:
Number = ((CurrentY - H1), FY2)
ThisY = max(Number)
vs.Rect(CurrentX, CurrentY, CurrentX + W1, ThisY)
CurrentX = CurrentX + W1
SheetEndX = CurrentX + W1
NP = NP + 1

RemainderX = W1 - (FX2 - CurrentX) - ThBl
vs.Rect(CurrentX, CurrentY, FX2, ThisY)

if SheetEndX != FX2 and SheetEndY != FY2:
if NewLine == True:
CurrentX = FX1 + W1
NewLine = False
NProw = Trunc((FX2 - FX1) / W1)
WmaxSold = ((FX2 - FX1) - (NProw * W1))

else:
CurrentX = FX1 + RemainderX

Number = ((CurrentY - H1), FY2)
CurrentY = max(Number)
CurrentX = FX1 + RemainderX
SheetEndY = max(Number)
vs.Rect(FX1, CurrentY, CurrentX, SheetEndY)

SheetEndX = CurrentX + W1
NP = NP + 1

else:
Done = True

# outputs
```

Edited by Raph
##### Link to comment

Hello,

Well.... I have made good progress

I'm just blocked to finish the Y loop

by changing the parameter "max" in "min" the loop runs without end, I think since VW crashes.

Does anyone have an idea?
Pat? I know that Python is not your favorite field but you have more experience than me😉

I tried to put a "if" SheetEndX > FX2 Do SheetEndX = FX2

but nothing works!!!

file and printscreen attached

Kind regards

##### Link to comment

Hello,

OK I finished my program🤩

See attached file!!!

Thank you Pat for your very valuable help

I remain open to any possible improvement

Greetings to all

• 1
• 1
##### Link to comment

Hello,

I would still like to export a "worksheet" list of the panels with the number and the dimension.

Does anyone have an idea on the functions to use to make this happen?

greetings

Raph

Edited by Raph
##### Link to comment

As long as this is 2D and the rectangles are perpendicular to the axes, it is pretty easy.

Create a worksheet.

Right Click in one of the Row Headers (I like to start with Row 3 so there is room above for headers and titles when I need them.).

Set it to be a Database Row.

Edit the criteria to select only the rectangles you want. Modify your Marionette to put them in a Class or on a Layer or attach a Record so you can separate them out from all the other rectangles in the file.

In the database header row ( the one that is just 3, not 3.1, 3.2, etc) column 1 enter a formula of =Width.  In column 2 put in a formula of =Height.  In column 3 put in a formula of =Count

Recalculate the worksheet.

You should now have a list of all the rectangles with their widths and heights and a count of 1 next to each of them.

Click on the black disclosure triangle in the width column and click the SUMmarize check box. You should now have a much smaller list that shows a single subrow for everything with the same width and the Count column counting the number of pieces with the same width.

Repeat on checking the SUMmarize box in the Height column. Your list should expand and now you will have two rows for every width, one for the ones in the main body, and one for the trimmed bottom row rectangles.

Ask again if this is not clear enough.

HTH.

##### Link to comment

Bonjour,

Je n'ai pas encore essayé Marionette mais ça donne envie!

Vous trouverez ci-joint un exemple de tableau qui récupère la largeur, la hauteur, la teinte et des options possibles de hauteur et de largeur.

La somme des options pose un problème vu qu'elle viennent d'une liste déroulante mais après un export excel cela fonctionne.

Fonctionne avec des rectangles, une base de données et une étiquette de données qui est liée au rectangle.

Peut être que ça peut vous aider pour réaliser votre tableau.

Fichier exemple en pièce jointe.

Bonne journée!

Hello,

I haven't tried Marionette yet but it makes me want to!

Attached is an example table that retrieves the width, height, tint and possible height and width options.

The sum of the options poses a problem since it comes from a drop-down list but after an excel export it works.

Works with rectangles, a database, and a data label that is bound to the rectangle.

Sample file attached.

Have a good day!

Thomas

##### Link to comment

Thanks for your quick feedback

My idea was to create it with vs.python code

Pat an idea? create a table in VS?

😁

##### Link to comment

Yes, it can be done.

This link is to the most recent version of a script I posted that makes a worksheet via script.  You probably want to read through the entire thread.

And this one shows how to set a row to be a database and set the criteria.  Take a look at the line that sets the variable FORMULA and then how that is used.

• 1
• 1
##### Link to comment

Hi Pat,

Hi Everybody,

Here is the last parametric symbol that generates a worksheet

Thanks Pat for your help

As usual, if anyone has any suggestions for improvements, we'd love to hear from you

greetings

Raph

##### Link to comment

Great Guys
How cool is That! I will for sure use it soon to lay floor-panels soon in my basement hobby-room. Don't forget to share in the gallery.

Edited by DomC

## Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Restore formatting

Only 75 emoji are allowed.

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×

• KBASE
• #### MARIONETTE

×
• Create New...