Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

[SCRIPT] How to select most top/left object

Enthusiast ,
Jun 15, 2021 Jun 15, 2021

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.

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

correct answers 2 Correct answers

Enthusiast , Jun 15, 2021 Jun 15, 2021

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]
...
Translate
Community Expert , Aug 10, 2021 Aug 10, 2021

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

...
Translate
Enthusiast ,
Jun 15, 2021 Jun 15, 2021

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]);
	}
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Jun 16, 2021 Jun 16, 2021

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].

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

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

TopLeftImage.png

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');
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Jun 18, 2021 Jun 18, 2021

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...

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

Now I'm having the same difficult to select elements in row order.

Any help?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Aug 10, 2021 Aug 10, 2021
LATEST

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

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