Copy link to clipboard
Copied
Hello gurus,
I need to select the most top/left object in a page.
The Y is the tiebreaker. Any suggestion?
I tried sorting by geometricBounds[0] and geometricBounds[1] but can not accomplish what I need.
Thanks in advance.
I have no idea why, but I got it.
Tired of playing with this sort function, I put this absurd and it works.
If anyone understand the logic behind this function, I'd love to know.
var doc = app.activeDocument;
var pg = app.activeWindow.activePage;
getFirstImg(pg);
function getFirstImg(pg) {
var gbs = [];
for (var i=0; i<pg.rectangles.length; i++) {
if (pg.rectangles[i].itemLayer == img && pg.rectangles[i].graphics.length) {
var recgb = pg.rectangles[i].geometricBounds;
gbs.push([recgb[0]
...
For anyone wondering, here's the solution I came up with for Luis on a Facebook thread. The yThresh accounted for objects not perfectly aligned on the top (in mm), but could be set to whatever threshold you felt appropriate.
var apis = app.activeDocument.pages[0].pageItems.everyItem().getElements();
apis.sort(function (a,b) {
var agb = a.geometricBounds;
var bgb = b.geometricBounds;
var yThresh = Math.abs(agb[0] - bgb[0]);
if (yThresh > 5) {
if (agb[0] > bgb[0]) return 1;
else if (bgb[0] > agb[0])
Copy link to clipboard
Copied
I have no idea why, but I got it.
Tired of playing with this sort function, I put this absurd and it works.
If anyone understand the logic behind this function, I'd love to know.
var doc = app.activeDocument;
var pg = app.activeWindow.activePage;
getFirstImg(pg);
function getFirstImg(pg) {
var gbs = [];
for (var i=0; i<pg.rectangles.length; i++) {
if (pg.rectangles[i].itemLayer == img && pg.rectangles[i].graphics.length) {
var recgb = pg.rectangles[i].geometricBounds;
gbs.push([recgb[0] , recgb[1] , pg.rectangles[i].graphics[0].itemLink.name , pg.rectangles[i]]);
}
}
gbs.sort(function(a, b) { return (a[0] - b[0]) + (a[1] - b[1]); });
app.select(gbs[0][3]);
}
Copy link to clipboard
Copied
You create an array of subarrays, sort the array by top and left coordinates, then take the first item, which is gbs[0]. This array item is an array itself with the rectangle as the fourth element, which you address by gbs[0][3].
Copy link to clipboard
Copied
Hi @lfcorullon
In fact the elements are sorted by comparing their (top+left) sum. Just note that the sort key (a[0]–b[0])+(a[1]–b[1]) is nothing but (a[0]+a[1])–(b[0]+b[1]), that is, (top+left)₀ – (top+left)₁. This is on average a good approximation when the X and Y axes have the same priority. In the below example you can see that the winner is the rectangle that reaches the minimal sum (Σ=340.)
However, using the sort method for this purpose is clearly useless and expensive, since the minimum value can always be found in linear time O(N)—while sort relies on a loglinear algorithm, i.e. O(N×log(N)). I think you could just do as follows:
function selectFirstImage(/*?Layer|str*/ly,/*?Document*/doc,/*?Page*/pg, t,a,b,c,i,iBest,xyMin)
//----------------------------------
// Select and return the (top+left)most image container on a page.
// `ly` : Target layer or layer name (opt.)
// `doc` : Target document (default=active.)
// `pg` : Target page (default=active.)
// ---
// => SplineItems [OK] | false [KO]
{
// Checkpoint -> doc, pg
// ---
doc || (doc=app.properties.activeDocument||0);
if( !doc.isValid || 'Document' != doc.constructor.name ) return false;
pg || ((pg=app.properties.activeWindow)&&(pg=pg.properties.activePage)) || (pg=doc.pages[0]);
if( !pg.isValid || 'Page' != pg.constructor.name ) return false;
// Layer filter (optional.)
// ---
'string'==typeof ly && ly.length && (ly=doc.layers.itemByName(ly));
( ly && 'Layer'==ly.constructor.name && ly.isValid ) || (ly=void 0);
// Browse the SplineItems collection.
// ---
t = pg.splineItems.everyItem();
if( !t.isValid ) return false;
a = t.getElements();
b = ly ? t.itemLayer : [];
// Identify the object having the minimal (x+y) sum.
// ---
for
(
i=a.length, iBest=false, xyMin=1/0 ;
i-- ;
ly===b[i] && (t=a[i]).graphics.length && (t=t.geometricBounds)
&& xyMin > (t=t[0]+t[1]) && (xyMin=t, iBest=i)
);
return false !== iBest && (app.select(t=a[iBest]), t);
}
// Example:
selectFirstImage('Layer 1');
Copy link to clipboard
Copied
Wow, thank you @Marc Autret!!!
Your knowledge makes em feel illiterate.
I tried your code in two different documents and nothing is being selected.
I just typed the layer name in the function call...
Copy link to clipboard
Copied
Now I'm having the same difficult to select elements in row order.
Any help?
Copy link to clipboard
Copied
For anyone wondering, here's the solution I came up with for Luis on a Facebook thread. The yThresh accounted for objects not perfectly aligned on the top (in mm), but could be set to whatever threshold you felt appropriate.
var apis = app.activeDocument.pages[0].pageItems.everyItem().getElements();
apis.sort(function (a,b) {
var agb = a.geometricBounds;
var bgb = b.geometricBounds;
var yThresh = Math.abs(agb[0] - bgb[0]);
if (yThresh > 5) {
if (agb[0] > bgb[0]) return 1;
else if (bgb[0] > agb[0]) return -1;
}
return agb[1] > bgb[1];
});