Jump to content
Developer Wiki and Function Reference Links ×

distribution of rectangles with remains


Raph

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

 

GraphiqueCollé-1.pdf

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);
				
						

 

  • Like 1
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

  • Like 2
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}
{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).}



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 

 

image.png.f43657c3246c366fb478b864299233f1.png

 

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

image.png.3d627e6d13f25d3be37cf82f35c82cb6.png

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,


Thanks for your answers and your time

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.SetLinksObjects()
# 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
	

 

image.thumb.png.d69027aac2e41f38845d9c0d8019940a.png

TileRectsFloor_v2.vwx

Edited by Raph
  • Like 1
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

 

image.png.39d35aa6d77c5e53dbe163992cde2f41.png

 

TileRectsFloor_v5.vwx

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?


Thanks in advance

greetings

 

Raph

 

image.png

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.

Maybe it can help you to make your table.

Sample file attached.

 

Have a good day!

 

Thomas

1178991603_captureexemple.thumb.png.53ec05d42888897c94f65d87908591de.png

Exemple simple panneau de façade et tableau v2.vwx

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.

 

 

  • Like 1
  • Love 1
Link to comment

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

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

×
×
  • Create New...