• [JS] Paths rentagles

# [JS] Paths rentagles

Enthusiast ,
Jun 15, 2017 Jun 15, 2017

Copied

Hello everyone,

I try to remove points in a rectangle I use "toutPath", monomele the following the first coordinates are not always the first point in the top left, and the direction is not always from left to right !!

Comment Is it possible to have the position of the point in the top left and to put the following in the top right?

Thanks to you, I'm looking for

Philippe

/--------

Bonjour Ć  tous,

Je cherche Ć  supprimĆ©  des points dans un rectangle j'utilise "entirePath", mon problĆØme est le suivant les premiĆØres coordonnĆ© ne sont pas toujour le premier point en haut Ć  gauche, et la direction n'est pas toujours de gauche Ć  droit !!

Comment est-il possible d'avoir la position du point en haut Ć  gauche et de remettre le suivant en haut Ć  droit?

Merci Ć  vous, je cherche encors

Philippe

TOPICS
Scripting

Views

2.2K

Likes

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more

Guide , Jun 20, 2017 Jun 20, 2017
Hi Liphou and Uwe,Maybe we could make a basic assumption. In the figure below, the problem is to find the point A within the path sequence.It seems to me that AB = DC (in vector terms) is a necessary & sufficient condition.Once A is determined (this is an index i in the path), we just have to remove points i-1, i-2, i-3 (modulo 7). More generally, if the quasi-rectangle is a polygon based on 4+x points (x represents the number of extra points used for the arrow), we'll need to remove items i-1, ...

Likes

21 Replies 21
Enthusiast ,
Jun 15, 2017 Jun 15, 2017

Copied

Try this,

app.selection[0].paths.item(0).pathPoints[0].remove();

Likes

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Enthusiast ,
Jun 15, 2017 Jun 15, 2017

Copied

This command function, we agree but ...
When I create a rectangle with a script:

Cette commende fonction, on est dāaccros mais ...

Quand je crĆ©e un rectangle avec un script :

`var doc = app.activeDocument;    var leBloc = doc.spreads.firstItem().rectangles.add();    leBloc.paths.firstItem().entirePath = [[20,20],[50,20],[50,100],[20,100]]; `

And I delete a dot with the following code:

et que je supprime un point avec le code suivant :

`app.selection[0].paths.item(0).pathPoints.item(1).remove();  `

The result is triangle 1 but when I create a block with the rectangle tool it gives me the triangle 2!

le rĆ©sulta est le triangle 1 mais quand je crĆ©e un bloc avec l'outil rectangle il me donne le triangle 2!

So how do we know who is the first or last point?

Donc comment savoir qui est le premier point ou le dernier?

to be continued / Ć  suivre

Likes

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Jun 15, 2017 Jun 15, 2017

Copied

Hi Liphou,

your rectangle could be also flipped perhaps. So the order of path points could be changed from what you think they should be.

FWIW: For a not rotated and not sheared rectangle we can cheat š using the code of my first snippet.
Do a string comparison of the anchor values of all path points with the geometric bounds' top right x/y coordinates:

`var rect = app.selection[0];var anchors = rect.paths[0].pathPoints.everyItem().anchor;var gB = rect.geometricBounds;var topRight = [gB[3],gB[0]];for(var n=0;n<anchors.length;n++){    if(topRight.toString() == anchors.toString() )    {        rect.paths[0].pathPoints.remove();        break    };};`

Ok. Then have a look at the code below where I try to factor in rotated and sheared rectangles that could be also pasted inside other rotated and sheared objects. First I thought it would not work for anchored rectangles, but my tests are showing that it does:

`var rect= app.selection[0];var index=0;var rotAngle = rect.absoluteRotationAngle;var shearAngle = rect.absoluteShearAngle;if(rotAngle < 0){ rect.rotationAngle = 180 }else { rect.rotationAngle = 0 };rect.shearAngle = 0;var anchors = rect.paths[0].pathPoints.everyItem().anchor;var gB = rect.geometricBounds;var topRight = [gB[3],gB[0]];for(var n=0;n<anchors.length;n++){    if(topRight.toString() == anchors.toString() ){ index = n ; break };};rect.absoluteShearAngle = shearAngle;rect.absoluteRotationAngle = rotAngle;rect.paths[0].pathPoints[index].remove();`

However, if the rectangles would be constructed with more than 4 path points the result may be no triangle.

Regards,
Uwe

PS: It will not matter much, but I forgot to insert a break in the loop of my second snippet. Now I did.

Likes

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Jun 15, 2017 Jun 15, 2017

Copied

Ok. Already found a flaw in my second snippet.
Guess, I have to revert to complexer x/y coordinate comparison methodsā¦

Uwe

Likes

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Enthusiast ,
Jun 16, 2017 Jun 16, 2017

Copied

Hi Laubenderā,

Thanks for your code, it will already be easier to locate points

Merci pour votre code, il me sera dĆ©jĆ  plus facile de localisĆ© des points

Merci

Likes

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Jun 16, 2017 Jun 16, 2017

Copied

Hi Liphou,

strange, I found no difference by adding the rectangle to the page by scripting or by the UI.
The order of path points is always the same. Tested with CS6 v 8.1.0 on Mac OS X.

Draw out a rectangle and run this code:

`// Draw out a rectangle:var rect = app.selection[0];var doc = app.documents[0];var spread = doc.layoutWindows[0].activeSpread;var anchors = rect.paths[0].pathPoints.everyItem().anchor;for(var n=0;n<anchors.length;n++){    var tf = spread.textFrames.add    (        {            geometricBounds : [0,0,10,10] ,            contents : ""+n ,            fillColor : "None"        }    );    tf.move(anchors)};`

This is my result. And it's always the same, no matter if I start drawing from top-to-down/left-to-right or from a different direction.

Regards,
Uwe

Likes

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Enthusiast ,
Jun 16, 2017 Jun 16, 2017

Copied

Merci pour votre script il est trĆØs visuel c'est plus facile

Thanks for your script it is very visual it is easier

See my explanation above on my bad block creation the two lines of code does not give the same meaning to the block ...

Voir mon explication plus haut sur ma mauvaise crĆ©ation de bloc les deux lignes de code ne donne pas le mĆŖme sens au bloc ...

`leBloc.paths.firstItem().entirePath = [[20,20],[50,20],[50,100],[20,100]]; leBloc.paths.firstItem().entirePath = [[20,20],[20,100],[50,100],[50,20]]; `

Likes

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Jun 16, 2017 Jun 16, 2017

Copied

Hi,

ah, now I understand.

Ok. With your line 1 using:

`[[20,20],[50,20],[50,100],[20,100]]`

it's the same as if you draw a rectangle using the pen tool, start with the upper left corner, and draw the rectangle clockwise.

I would not call it bad rectangle creation.
It's just that you created the path clockwise.

Optically one can see the difference in the position of the yellow corner widget.
From a rectangle with corners ABCD in drawing order of the path points the widget is always positioned at segment CD closer to D than to C.

EDIT: Screenshot added with a rectangle created from the entirePath array that you did:

Regards,
Uwe

Likes

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Enthusiast ,
Jun 15, 2017 Jun 15, 2017

Copied

I begin to understand with my first command line, I draw the block in the direction of drawing 2/

Je commence Ć  comprendre avec ma premiĆØre ligne de commande, je dessine le bloc dans la direction  du dessin 2

`leBloc.paths.firstItem().entirePath = [[20,20],[50,20],[50,100],[20,100]]; `

With the second I draw in the opposite direction drawing 1/

avec la deuxiĆØme, je dessin dans le sens inverse dessin 1

`leBloc.paths.firstItem().entirePath = [[20,20],[20,100],[50,100],[50,20]]; `

et Indesign dessin les blocs dans le sens antihoraire !! Ok quand on le sait, c'est beaucoup mieux.

Likes

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Guide ,
Jun 19, 2017 Jun 19, 2017

Copied

Hi Liphou,

As Uwe has shown above, InDesign's regular rectangle is a closed path that satisfiesāamong othersāthe following properties*:

1. Its first path point (index 0) is in TOP-LEFT position.

2. Its path points are counterclockwise oriented, so the last one (index 3) is TOP-RIGHT.

* [Position and orientation here expressed in the ruler perspective and assuming no angular transformation is involved.]

But InDesign's regular rectangle is one thing, while rectangular shapes you may produce defining your own path points (or via entirePath) are another thing. Given the path points of a regular polygon, you can both reverse their order (reversed path) or apply any cycle to the sequence. You then get a custom shape that perfectly fits the original although no longer in sync with InDesign's default stuff.

So, to answer your question, given a rectangle which may result from either a native tool or a computed sequence of coordinates, you can make no assumption about the actual location of a point just considering its index in the path. Such relationship is purely conventional in the default case, and not reliable at all in the general case.

Now make it simple. If you have to identify the TOP-LEFT corner of a polygon that happens to be a rectangle along the ruler axes, just find the pathpoint having the minimal X and the minimal Y coordinate (in the ruler system). This can be done easily in looking for the PathPoint index where (X+Y) meets a minimum.

`function topLeftIndex(/*xy[]*/a,  m,i,t,r){    for( m=1/0, i=a.length ; i-- ; m > (t=a[0]+a[1]) && (m=t, r=i) );    return r;}// Usage// ---var ep = myRectangle.paths[0].entirePath,    iTopLeft = topLeftIndex(ep);myRectangle.paths[0].pathPoints[iTopLeft].remove();`

(Interestingly this code still works if the rectangle is flipped or undergoes a Ā±90Ā° rotation.)

@+

Marc

Likes

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Enthusiast ,
Jun 19, 2017 Jun 19, 2017

Copied

Hello Marc, Hello Laubender,

Marc, I am always attentive to your interventions clear and precise, they allow me as much else evolved.

Actually I came across the case last night, the top left is not my zero points !!! Which gives me no choice but to rethink my approach !! I will test your code and take back that of Laubender ... I will come back (hopefully) with an efficient and flawless algorithm.

Here is my code that is not good !!

/----------------------------------------------------

Bonjour  Marc, Bonjour Laubender,

Marc, je suis toujours attentif Ć  vos intervention claire et prĆ©cis, elles me permette comme bien d'autre dāĆ©voluĆ©.

Effectivement je suis tombĆ© sur le cas hier soir, le point supĆ©rieur gauche n'est pas mon points zĆ©ro !!! ce qui me donne pas d'autre choix que de repense mon approche !! je vais donc tester votre code et reprendre celui de Laubender ... je reviendrai (j'espĆØre) avec un algorithme efficace et sans faille.

Voici mon code qui n'est pas bon !!

`function modificationBloc (leBloc) {      \$.writeln("modificationBloc () : " + leBloc.constructor.name +' ā geometricBounds : ' + leBloc.geometricBounds);      // Etape 1       //    ā > Supretion de la FlĆØche       //  Etape 2       //    ā > creation de la FlĆØche  // apple Ć  function            var topLeft = [leBloc.geometricBounds[3],leBloc.geometricBounds[1]];        var sel_path = leBloc.paths[0].entirePath;            \$.writeln('sel_path.length : '+ sel_path.length );        // contrĆ“l 1        if (sel_path.length == 7) { // if 01             \$.writeln('sel_path.length : '+ sel_path.length );                if (sel_path[1][0].toFixed(2) == sel_path[0][0].toFixed(2)  && sel_path[1][1].toFixed(2) < sel_path[2][1].toFixed(2)) { // cĆ“tĆ© gauche  // if 02                                            \$.writeln('Gauche');                                  } else if  (sel_path[1][1].toFixed(2) == sel_path[2][1].toFixed(2) && sel_path[2][0].toFixed(2) < sel_path[3][0].toFixed(2)) { // cĆ“tĆ© bat // if 02                                             \$.writeln('Bat');                                  } else if  (sel_path[2][0].toFixed(2) == sel_path[3][0].toFixed(2) && sel_path[3][1].toFixed(2) > sel_path[0][1].toFixed(2) ) { // cĆ“tĆ© droit // if 02                                                \$.writeln('Droit');                 } else if (sel_path[0][1].toFixed(2) == sel_path[sel_path.length-1][1].toFixed(2) && sel_path[sel_path.length-1][0].toFixed(2) < sel_path[2][0].toFixed(2) &&  sel_path[sel_path.length-1][0].toFixed(2) > sel_path[0][0].toFixed(2)) { // cĆ“tĆ© haut                                                  \$.writeln('haut');                                 } else {                            \$.writeln('Sortie');                            \$.writeln(sel_path.length + ' ā Test 1 : '+ sel_path[0][1].toFixed(2)+ ' ā Test 2 : '+ sel_path[1][1].toFixed(2)+ ' ā ' + sel_path);                                                                    }// fin du if 02                        } // fin du if 01    }//`

Here is my case ...

voici mon cas de figure ...

Another small detail, I had to use the function .toFixed (2), for values that was identical in the console (12 digits after the decimal point) but a comparison test of values always returned a negative result.

/-----------------------------

Autre petit dĆ©tail, j'ai du utilise la fonction .toFixed(2), pour des valeurs qui Ć©tait identique dans la console (12 chiffres aprĆØs la virgule) mais un test de comparaison de valeurs me retournĆ© toujours un rĆ©sulta nĆ©gatif.

Thanks to follow

Likes

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Enthusiast ,
Jun 20, 2017 Jun 20, 2017

Copied

The goal is to remove the arrow and the recreation to erase a possible deformation, the arrow can be on any side, point outward or inward.

Here is more precision ...

thank you

/--------------------------

voici donc plus de prĆ©cision ...

Merci Ć  vous

Likes

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Jun 20, 2017 Jun 20, 2017

Copied

Hi Liphou,

with a construction like that I would do a comparison with the geometricBounds of the object.

The conditions would be:
Either x or y is the same as one of the "corner points" of geometricBounds.
Never both.

( Provided the object is not rotated, sheared or imprecisely* constructed )

* for that you could provide a threshold.

Scratch this. No good ideaā¦

Regards,
Uwe

Likes

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Enthusiast ,
Jun 20, 2017 Jun 20, 2017

Copied

I will have to go through a comparison of the lengths of lines or other, the deletion of the points is not top, to delete the arrow ....
repair

/*****

Je vais devoir passĆ© par une comparaison des longueurs des lignes ou autre,  la suppression des points n'est pas top,  pour supprimĆ© la flĆ©chĆ©  ....

Likes

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Guide ,
Jun 20, 2017 Jun 20, 2017

Copied

Hi Liphou and Uwe,

Maybe we could make a basic assumption. In the figure below, the problem is to find the point A within the path sequence.

It seems to me that AB = DC (in vector terms) is a necessary & sufficient condition.

Once A is determined (this is an index i in the path), we just have to remove points i-1, i-2, i-3 (modulo 7). More generally, if the quasi-rectangle is a polygon based on 4+x points (x represents the number of extra points used for the arrow), we'll need to remove items i-1, i-2... i-x (modulo 4+x).

So let's try this:

`function removeArrow(/*Polygon*/poly,  pp,ep,n,i,p,q,a,m,t,r){    const mABS = Math.abs;    ep = (pp=poly.paths[0].pathPoints).everyItem().anchor;    n = ep.length;        if( n <= 4 ) throw "Invalid polygon. Should have at least 5 points."    // Vector sequence (avoid recalculations later.)    // ---    for( a=[], i=-1 ; ++i < n ; )    {        p = ep;        q = ep[(1+i)%n];        a = [ q[0]-p[0], q[1]-p[1] ];    }    // Find p, q[i+2]  s.t |p + q| minimal.    // ---    for( m=1/0, i=-1 ; ++i < n ; )    {        p = a;        q = a[(2+i)%n];        t = mABS(p[0]+q[0])+mABS(p[1]+q[1]);        t < m && ( m=t, r=i );    }        // Remove points r-1, r-2... (modulo n.)    // ---    for( t=n-4 ; t-- ; pp[r=-1+(r||n--)].remove() );}var poly = app.selection[0];removeArrow(poly);`

It even seems to work with rotated and transformed shapes.

@+

Marc

Likes

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Enthusiast ,
Jun 20, 2017 Jun 20, 2017

Copied

Hi Marc and Uwe,

I arrived at a result that quickly climbed the limits, for the test I created the polygons manually and it is there, but I am difficult ...

Here is the code (but I am repaired from scratch, to test the segment lengths, I am devoted, thanks Marc).

/---------------------

Je suis parvenus Ć  un rĆ©sulta qui a vite montre ces limites, pour test j'ai crĆ©e manuellement des polygones et c'est lĆ ,  qu'un difficultĆ© supplĆ©mentaire est apparu ...

voici le code (mais je suis repartie de zĆ©ro, pour test les longueurs de segment, je suis devancĆ©, merci Marc).

`function modificationBloc (leBloc) {               \$.writeln("modificationBloc () : " + leBloc.constructor.name +' ā geometricBounds : ' + leBloc.geometricBounds);               var sel_path = leBloc.paths[0].entirePath;          var iTopLeft = topLeftIndex(sel_path);                      \$.writeln('iTopLeft : '+ iTopLeft );        // contrĆ“l 1        if (sel_path.length == 7) { // if 01             \$.writeln('sel_path.length : '+ sel_path.length );                if (sel_path[iTopLeft + 1][0].toFixed(2) == sel_path[iTopLeft][0].toFixed(2)  && sel_path[iTopLeft +1][1].toFixed(2) < sel_path[iTopLeft + 2][1].toFixed(2)) { // cĆ“tĆ© gauche  // if 02                       \$.writeln('Gauche');                       sel_path.splice(iTopLeft+1, 3);                                  } else if  (sel_path[iTopLeft+1][1].toFixed(2) == sel_path[iTopLeft+2][1].toFixed(2) && sel_path[iTopLeft+2][0].toFixed(2) < sel_path[(iTopLeft == 4 ? 0 : iTopLeft+3)][0].toFixed(2)) { // cĆ“tĆ© bat // if 02                                             \$.writeln('Bat');                         sel_path.splice(iTopLeft+2, 3);                                  } else if  (sel_path[iTopLeft + 2][0].toFixed(2) == sel_path[(iTopLeft == 4 ? 0 : iTopLeft + 3)][0].toFixed(2) && sel_path[(iTopLeft == 4 ? 0 : iTopLeft+3)][1].toFixed(2) > sel_path[iTopLeft][1].toFixed(2) ) { // cĆ“tĆ© droit // if 02                                                \$.writeln('Droit');                         sel_path.splice(iTopLeft+3, 3);//                    } else if (sel_path[0][1].toFixed(2) == sel_path[sel_path.length-1][1].toFixed(2) && sel_path[sel_path.length-1][0].toFixed(2) < sel_path[2][0].toFixed(2) &&  sel_path[sel_path.length-1][0].toFixed(2) > sel_path[0][0].toFixed(2)) { // cĆ“tĆ© haut                                   } else if (sel_path[iTopLeft][1].toFixed(2) == sel_path[(iTopLeft != 0 ? iTopLeft-1: sel_path.length-1)][1].toFixed(2)                                 && sel_path[(iTopLeft != 0 ? iTopLeft-1: sel_path.length-1)][0].toFixed(2) < sel_path[iTopLeft + 2][0].toFixed(2)                                 /*&& sel_path[(iTopLeft != 0 ? iTopLeft-1: sel_path.length-1)][0].toFixed(2) > sel_path[iTopLeft][0].toFixed(2)*/) { // cĆ“tĆ© haut                                                  \$.writeln('haut');                         sel_path.splice(iTopLeft+4, 3);                                 } else {                            \$.writeln('Sortie');                            \$.writeln(sel_path.length + ' ā Test 1 : '+ (sel_path[iTopLeft][1].toFixed(2) == sel_path[(iTopLeft != 0 ? iTopLeft-1: sel_path.length-1)][1].toFixed(2))                             + ' ā Test 2 : '+ (sel_path[(iTopLeft != 0 ? iTopLeft-1: sel_path.length-1)][0].toFixed(2) < sel_path[iTopLeft + 2][0].toFixed(2))                            + ' ā Test 3 : '+ (sel_path[(iTopLeft != 0 ? iTopLeft-1: sel_path.length-1)][0].toFixed(2) > sel_path[iTopLeft][0].toFixed(2)));                                     }// fin du if 02              leBloc.paths[0].entirePath = sel_path;          } // fin du if 01    }//`

Voici l'image des cas de figure :

As I made the findings that the first point can be by all, I change my approach more my code becomes illegible.
Thank you Marc, I tested your code (I still apply to understand it!)
It worked in Figures 1, 3 and 4. The zero point in Figure 2 positioned at this right also caused problems ... it could not delete point 6

/------------------------------------

Comme j'ai fait la constations que le premier point peut ĆŖtre par tout, je change dāapproche de plus mon code devient illisible.

Merci Marc, j'ai donc testĆ© votre code (je m'applique encore Ć  le comprendre! )

Il a fonctionne sur les figure 1, 3 et 4. Le point zĆ©ro dans la figure 2 positionnĆ© Ć  cette en droit ma aussi posĆ© des problĆØme ... il n'a pas pu supprimĆ© le point 6

Voici le fichier Indisegn CC2017   : Dropbox - Exemple2.zip

A+

Philippe

Likes

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Enthusiast ,
Jun 20, 2017 Jun 20, 2017

Copied

Hi Marc and Uwe,

Looking at the code for Mark for understanding, I made a small change to the following level:

En regardent le code de Marc pour la comprĆ©hension, j'ai fait une petit modification au niveau suivent :

`  // Remove points r-1, r-2... (modulo n.)    // Supprimer les points r-1, r-2 ... (modulo n.)  // ---  // Backup ligne original : for( t=n-4 ; t-- ; pp[r = -1 + (r || n--)].remove() );  // Backup Ligne de Marc        for( t=n-4 ; t-- ;  n--) {                  pp[r = -1 + r ].remove();                \$.writeln("pp[ " +r + "] ā " );                  }`

The values of "r" changes to -1 and deletes point 6. ... YES !!!

La valeurs de "r"  passe Ć  -1 et supprime le point 6. ... YES !!!

A+

Philippe

Likes

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Enthusiast ,
Jun 20, 2017 Jun 20, 2017

Copied

Likes

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Guide ,
Jun 20, 2017 Jun 20, 2017

Copied

Have you tried my fixed code with your example #18?

Works for me.

@+

Marc

Likes

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Enthusiast ,
Jun 20, 2017 Jun 20, 2017

Copied

LATEST

Our messages cross yes this function! GREAT.
thank you

/------

Nos messages se croise oui cela fonction ! SUPER.

Merci Ć  vous

Likes

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Guide ,
Jun 20, 2017 Jun 20, 2017

Copied

Indeed, there is a bug in my snippet.

We need to decrement n at each step whatever r:

Here is the fix (line #31 of my code):

for( t=n-4 ; t-- ; pp[r=-1+(r||n)].remove(), --n );

@+

Marc

Likes

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
Resources
Learn and Support
Resources
Crash and Slow Performance