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

Illustrator Scripting: transfer real life longitude & latitude on Illustrator Map - help needed(!)

Community Expert ,
Jul 03, 2024 Jul 03, 2024

Copy link to clipboard

Copied

Hi community,

 

this one is a really hard one!

Going back and forth for a couple of days now my brain got completely stucked... so please give me some input or maybe someone can work out a functional script in this case:

 

A bunch of coordinates (longitude & latitude values) must be transfered onto an Illustrator map to set a dot for each location... I'm stuggeling with creating the right formular to set them right... I'm pretty sure it's just a mathematical logical issue thing...

 

 

// the locations in latitude & longitude as vars:
    var lat1 = 48.7491239657; //city_1
    var lon1 = 9.17012929916; //city_1

    var lat2 = 47.6264900005; //city_2
    var lon2 = 7.65646999127; //city_2

    var lat3 = 49.4682342; //city_3
    var lon3 = 8.5611973; //city_3


// the locations manually set on the Illustrator-Map as vars:
    var my_x1 = mm(116.60); //city_1
    var my_y1 = mm(82.97); //city_1

    var my_x2 = mm(39.83); //city_2
    var my_y2 = mm(168.54); //city_2

    var my_x3 = mm(83.67); //city_3
    var my_y3 = mm(29.33); //city_3

//mm to point converter
function mm(n) {
    return n * 2.83464567;
}

 

 

PS. and as always – only scripting solutions appreceated! 😉

 

 

TOPICS
Scripting

Views

763

Translate

Translate

Report

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 3 Correct answers

Community Expert , Jul 04, 2024 Jul 04, 2024

Hallo Nils,

sofern du die entsprechenden Start und Endkoordinaten passend zu deiner Dokumentengröße verfügbar hast, ist es "simpler Dreisatz".

Screenshot 2024-07-05 024310.png

gegeben ist:

ein Dokument in der Größe 200 mm × 297 mm

ein Kartenausschnitt von 9,0° Ost bis 10,0° Ost und 49,0° Nord bis 48,0° Nord

die X-Koordinate von Stuttgart Bad Cannstatt ist fast exakt 9,2° Ost

Berechnung:

also pos X = (X-Koordinate Stuttgart Bad Cannstatt - KarteGeoCoorLinks) * Dokument Rechts / (KarteGeoCoorRechts - KarteGeoCoorLinks)

in mm
pos

...

Votes

Translate

Translate
Community Expert , Jul 08, 2024 Jul 08, 2024

@m1b Hi Mark,

thank you so much for this brillant script!

It worked out quite well in the smaller map but not for a larger section as the geometrical distortion will lead to inaccurate results in the outer areas...

never the less this answer is correct as well 🙂

Votes

Translate

Translate
Community Expert , Jul 12, 2024 Jul 12, 2024

It took a while to figure it out but this is the best aswer as it leaded to a solution for my issue!

Best tip ever was that something might be wrong with my Illustrator file as the coords were almost 30mm off – so I created a new file and there we go!

Next issue were multiple distortions within the scan of the original map so I had to fix it in two ways:

1.) I started by using the solution pixxxelschubser pointed out

2.) I added a factor to multiply the distortions for left to right and top to b

...

Votes

Translate

Translate
Adobe
Community Expert ,
Jul 03, 2024 Jul 03, 2024

Copy link to clipboard

Copied

Hi @Nils M. Barner, Edit: I have updated my code below (and thanks to the solveMatrix function from ChatGPT!) and I hope it will work this time! 🙂

 

The idea is you call the "getTransform" function, giving it your example transformation pairs [ [lat,long], [x, y] ] and it returns a function that you can use thereafter for transforming your coordinates. Let me know if it works in practice!

- Mark

 

 

/**
 * @file Transform Latitude Longitude.js
 * Demo of transforming lat,long coordinates
 * into Illustrator coordinates.
 *
 * Notes:
 * - This is a quick, simple method and hardly tested,
 *   so be careful to check the results.
 * - It knows nothing about actual cartography or
 *   map projections!
 * - It works using the supplied example transformations.
 *
 * @author m1b, chatGPT
 * @discussion https://community.adobe.com/t5/illustrator-discussions/illustrator-scripting-transfer-real-life-longitude-amp-latitude-on-illustrator-map-help-needed/m-p/14716499
 */
(function () {

    const mm = 2.834645;

    // these examples are necessary to calibrate the transformer
    var city1 = [48.7491239657, 9.17012929916],
        city2 = [47.6264900005, 7.65646999127],
        city3 = [49.4682342, 8.5611973];

    var city1_pts = [116.60 * mm, 82.97 * mm],
        city2_pts = [39.83 * mm, 168.54 * mm],
        city3_pts = [83.67 * mm, 29.33 * mm];

    // generate a transform function using some examples
    var transform = getTransform([
        [city1, city1_pts],
        [city2, city2_pts],
        [city3, city3_pts],
    ]);

    // calculate position of a new city
    var city4 = [48.123456, 8.654321],
        city4_pts = transform(city4);

    $.writeln('city4_pts = ' + city4_pts);

})();

/**
 * Returns a transform function that transforms
 * [latitude, longitude] into Illustrator [x, y],
 * given an array of example `pairs`.
 * @author m1b and chatGPT
 * @version 2024-07-03
 * @param {Array<Array>} pairs - array of [lat_lon, pts] pairs.
 * @returns {Function}
 */
function getTransform(pairs) {

    var A = [],
        B = [];

    for (var i = 0; i < pairs.length; i++) {
        A.push([pairs[i][0][0], pairs[i][0][1], 1, 0, 0, 0]);
        A.push([0, 0, 0, pairs[i][0][0], pairs[i][0][1], 1]);
        B.push(pairs[i][1][0], pairs[i][1][1]);
    }

    // Solve for the affine transformation matrix using matrix algebra (A * X = B)
    var X = solveMatrix(A, B);

    var m = [
        [X[0], X[1], X[2]],
        [X[3], X[4], X[5]],
    ];

    // Transform function to apply the affine transformation
    return (

        function transform(latLon) {
            return [
                m[0][0] * latLon[0] + m[0][1] * latLon[1] + m[0][2],
                m[1][0] * latLon[0] + m[1][1] * latLon[1] + m[1][2],
            ];
        }

    );


};

/**
 * Solves a system of linear equations using Gaussian elimination.
 * 
 * This function solves the system of equations represented by the augmented matrix [A|B],
 * where A is an n x n matrix and B is an n x 1 vector.
 * 
 * @author chatGPT
 * @version 2024-07-03
 * @param {Array<Array<Number>>} A - The coefficient an n x n matrix of the system of equations.
 * @param {Array<Number>} B - The constant terms vector of the system of equations.
 * @returns {Array<Number>} - The solution vector X such that A * X = B.
 */
function solveMatrix(A, B) {

    var n = A.length;

    for (var i = 0; i < n; i++)
        A[i].push(B[i]);

    for (var i = 0; i < n; i++) {

        var maxRow = i;

        for (var k = i + 1; k < n; k++)
            if (Math.abs(A[k][i]) > Math.abs(A[maxRow][i]))
                maxRow = k;

        var tmp = A[maxRow];
        A[maxRow] = A[i];
        A[i] = tmp;

        for (var k = i + 1, c; k < n; k++) {

            c = -A[k][i] / A[i][i];

            for (var j = i; j < n + 1; j++) {
                if (i === j)
                    A[k][j] = 0;
                else
                    A[k][j] += c * A[i][j];
            }

        }

    }

    var X = new Array(n);

    for (var i = n - 1; i >= 0; i--) {

        X[i] = A[i][n] / A[i][i];

        for (var k = i - 1; k >= 0; k--)
            A[k][n] -= A[k][i] * X[i];
    }

    return X;

};

 

Votes

Translate

Translate

Report

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 ,
Jul 03, 2024 Jul 03, 2024

Copy link to clipboard

Copied

@mark: is this the fixed version now? or should I still ignore?

 

Votes

Translate

Translate

Report

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 ,
Jul 03, 2024 Jul 03, 2024

Copy link to clipboard

Copied

Please take it for a test drive!

Votes

Translate

Translate

Report

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 ,
Jul 03, 2024 Jul 03, 2024

Copy link to clipboard

Copied

Sorry about posting my faulty code before. I've updated it now, thanks to some help from ChatGPT!, and tested a bit more and it gives the expected results now. - Mark

Votes

Translate

Translate

Report

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 ,
Jul 04, 2024 Jul 04, 2024

Copy link to clipboard

Copied

@m1b: Hi Mark,

I tried your Script but coords are still far off...

Just tried to figure out why but I got even more confused now...

Please find a simplified demo .ai file attached (please rename the .pdf > .ai) so you can try on your own...

My thoughts on the case:

Something might be twisted (lang/long, x/y, ...) so values get mixed up... 

Here's my script so far (just added some more functions and vars to it):

 

/**
 * @File Transform Latitude Longitude.js
 * Demo of transforming lat,long coordinates
 * into Illustrator coordinates.
 *
 * Notes:
 * - This is a quick, simple method and hardly tested,
 *   so be careful to check the results.
 * - It knows nothing about actual cartography or
 *   map projections!
 * - It works using the supplied example transformations.
 *
 * @author m1b, chatGPT
 * @discussion https://community.adobe.com/t5/illustrator-discussions/illustrator-scripting-transfer-real-life-longitude-amp-latitude-on-illustrator-map-help-needed/m-p/14716499
 */

#target illustrator

////// first things first and basic checks

    var docRef = app.activeDocument;
    var artboardRef = docRef.artboards;
    var scriptRef = new File($.fileName).path;
    var separator = '\\';
    var lineBreak = '\r';
    var CSVref = '';
    var GoodToGo = false;

    var thisX;
    var thisY;
    var xStartPos = 0; //// just in case to move
    var yStartPos = 0; //// just in case to move

    var hsdDiameter = mm(1.65); //// size of hotspot dot
    var hsdStrokeWidth = 0.5;  //// stroke weight of hotspot dot
    var hsdColor = makeCMYKColor(10,100,90,0);
    var hsdStrokeColor = makeCMYKColor(100,0,0,0);

(function () {

    const mm = 2.834645;

    // these examples are necessary to calibrate the transformer
    var city1 = [48.7491239657, 9.17012929916], //// this ist Stuttgart //_latitude (north/south > Y) then _longitude (west/east > X)
        city2 = [47.6264900005, 7.65646999127], //// this is Lörrach
        city3 = [49.4682342, 8.5611973]; //// this is Mannheim
//     var city4 = [48.7493055, 8.2197765], //// this is Baden-Baden
//     var city5 = [48.984742, 8.403163], //// this is Karlsruhe
//     var city6 = [48.2315269, 9.8833368], //// this is Ulm (might be a bit off)
//     var city7 = [49.5985400069, 9.69389004153], //// this is Tauberbischofsheim


    var city1_pts = [152,887 * mm, 99,701 * mm], //// this is Stuttgart //_x then _y
        city2_pts = [76,123 * mm, 185,265 * mm], //// this is Lörrach
        city3_pts = [119,954 * mm, 46,053 * mm]; //// this is Mannheim

    // generate a transform function using some examples
    var transform = getTransform([
        [city1, city1_pts],
        [city2, city2_pts],
        [city3, city3_pts],
    ]);

    // calculate position of a new city
    var city4 = [48.7491239657, 9.17012929916], // this is Baden-Baden
        city4_pts = transform(city4);
    var city5 = [48.984742, 8.403163], //// this is Karlsruhe
        city5_pts = transform(city5);
     var city7 = [49.5985400069, 9.69389004153], //// this is Tauberbischofsheim
         city7_pts = transform(city7);

    $.writeln('city4_pts = ' + city4_pts);
alert(city4_pts);
    var thisX = city4_pts[0] + xStartPos;
    var thisY = city4_pts[1] + yStartPos;
    createHotSpot(thisX,thisY,hsdDiameter);
    
alert(city5_pts);
    var thisX = city5_pts[0] + xStartPos;
    var thisY = city5_pts[1] + yStartPos;
    createHotSpot(thisX,thisY,hsdDiameter);
        
alert(city7_pts);
    var thisX = city7_pts[0] + xStartPos;
    var thisY = city7_pts[1] + yStartPos;
    createHotSpot(thisX,thisY,hsdDiameter);

})();


// create hotspot
function createHotSpot(xHS, yHS, diaHS) {

    var myX = xHS + diaHS/2; //for center point
    var myY = yHS - diaHS/2; //for center point
    
    var thisHotSpot = docRef.activeLayer.pathItems.ellipse(myX, myY, diaHS, diaHS);

    thisHotSpot.fillColor = hsdColor;
    thisHotSpot.stroked = true;
    thisHotSpot.strokeWidth = hsdStrokeWidth;
    thisHotSpot.strokeColor = hsdStrokeColor;

    return thisHotSpot; // Return the created thisHotSpot
}


/**
 * Returns a transform function that transforms
 * [latitude, longitude] into Illustrator [x, y],
 * given an array of example `pairs`.
 * @author m1b and chatGPT
 * @version 2024-07-03
 * @Param {Array<Array>} pairs - array of [lat_lon, pts] pairs.
 * @Returns {Function}
 */
function getTransform(pairs) {

    var A = [],
        B = [];

    for (var i = 0; i < pairs.length; i++) {
        A.push([pairs[i][0][0], pairs[i][0][1], 1, 0, 0, 0]);
        A.push([0, 0, 0, pairs[i][0][0], pairs[i][0][1], 1]);
        B.push(pairs[i][1][0], pairs[i][1][1]);
    }

    // Solve for the affine transformation matrix using matrix algebra (A * X = B)
    var X = solveMatrix(A, B);

    var m = [
        [X[0], X[1], X[2]],
        [X[3], X[4], X[5]],
    ];

    // Transform function to apply the affine transformation
    return (

        function transform(latLon) {
            return [
                m[0][0] * latLon[0] + m[0][1] * latLon[1] + m[0][2],
                m[1][0] * latLon[0] + m[1][1] * latLon[1] + m[1][2],
            ];
        }

    );


};

/**
 * Solves a system of linear equations using Gaussian elimination.
 * 
 * This function solves the system of equations represented by the augmented matrix [A|B],
 * where A is an n x n matrix and B is an n x 1 vector.
 * 
 * @author chatGPT
 * @version 2024-07-03
 * @Param {Array<Array<Number>>} A - The coefficient an n x n matrix of the system of equations.
 * @Param {Array<Number>} B - The constant terms vector of the system of equations.
 * @Returns {Array<Number>} - The solution vector X such that A * X = B.
 */
function solveMatrix(A, B) {

    var n = A.length;

    for (var i = 0; i < n; i++)
        A[i].push(B[i]);

    for (var i = 0; i < n; i++) {

        var maxRow = i;

        for (var k = i + 1; k < n; k++)
            if (Math.abs(A[k][i]) > Math.abs(A[maxRow][i]))
                maxRow = k;

        var tmp = A[maxRow];
        A[maxRow] = A[i];
        A[i] = tmp;

        for (var k = i + 1, c; k < n; k++) {

            c = -A[k][i] / A[i][i];

            for (var j = i; j < n + 1; j++) {
                if (i === j)
                    A[k][j] = 0;
                else
                    A[k][j] += c * A[i][j];
            }

        }

    }

    var X = new Array(n);

    for (var i = n - 1; i >= 0; i--) {

        X[i] = A[i][n] / A[i][i];

        for (var k = i - 1; k >= 0; k--)
            A[k][n] -= A[k][i] * X[i];
    }

    return X;

};

function mm(n) {
    return n * 2.83464567;
}

function makeCMYKColor(c,m,y,k){
    var ink = new CMYKColor();
    ink.cyan   = c;
    ink.magenta = m;
    ink.yellow  = y;
    ink.black  = k;
    return ink;
}

 

  Thanks

Nils

Votes

Translate

Translate

Report

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 ,
Jul 04, 2024 Jul 04, 2024

Copy link to clipboard

Copied

Hi @Nils M. Barner, thanks for the map—that helped. Actually, my script seemed to work fine. This is what I did...

 

First, I entered three cities from your map: Lörrach, Mannheim and Ulm, both lat/long and map coordinates (taken as the centre of the circle on your map. These are to calibrate the transform function. Here is the data I added to the script (replacing all the city1, city2, ... stuff):

// these examples are necessary to calibrate the transformer
const lörrach = [47.6168, 7.6691],
    mannheim = [49.4875, 8.4660],
    ulm = [48.4011, 9.9876];

const lörrach_pts = [76.123 * mm, 185.265 * mm],
    mannheim_pts = [119.954 * mm, 46.053 * mm],
    ulm_pts = [191.809 * mm, 127.151 * mm];

// generate a transform function using some examples
var transform = getTransform([
    [lörrach, lörrach_pts],
    [mannheim, mannheim_pts],
    [ulm, ulm_pts],
]);

// calculate position of a new city
var stuttgart = [48.7758, 9.1829],
    heilbronn = [49.1427, 9.2109];

// now transform into map coordinates
var stuttgart_pts = transform(stuttgart),
    heilbronn_pts = transform(heilbronn);

$.writeln('stuttgart_pts = ' + stuttgart_pts);
$.writeln('heilbronn_pts = ' + heilbronn_pts);

 

Then I entered two new cities—Stuttgart and Heilbronn—lat/long and used the transform function to give me the coordinates in pts. Console output:

stuttgart_pts = 434.552869517851,281.040327929184
heilbronn_pts = 441.087488743414,203.598201369798

 

Then I just positioned a green circle at those two points on your map. This is what I got:

Screenshot 2024-07-05 at 00.42.48.png

 

So not too bad at all. Does it work for you?

- Mark

Votes

Translate

Translate

Report

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 ,
Jul 08, 2024 Jul 08, 2024

Copy link to clipboard

Copied

@m1b Hi Mark,

thank you so much for this brillant script!

It worked out quite well in the smaller map but not for a larger section as the geometrical distortion will lead to inaccurate results in the outer areas...

never the less this answer is correct as well 🙂

Votes

Translate

Translate

Report

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 ,
Jul 12, 2024 Jul 12, 2024

Copy link to clipboard

Copied

LATEST

Hi @Nils M. Barner, did you try just putting in 4 points at extreme points? Eg the corners only? Similar to @pixxxelschubser's idea? I wonder if that would be more accurate?

 

Or maybe we could calibrate the transform each time, using only the three "mapped" cities closest to the unknown city? Perhaps this would adequately minimize the inaccuracies?

 

You can tell I am only guessing here because I am very ignorant about this domain.

- Mark

Votes

Translate

Translate

Report

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 ,
Jul 03, 2024 Jul 03, 2024

Copy link to clipboard

Copied

Hallo Nils, 

hast du eventuell auch die deinen Dokumentengrenzen entsprechenden Geo-Koordinaten? Denn dann könnte man doch normalerweise die City-Koordinaten durch Dreisatz-Berechnung ermitteln.

 

Oder habe ich die Aufgabenstellung nicht richtig verstanden?

Votes

Translate

Translate

Report

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 ,
Jul 03, 2024 Jul 03, 2024

Copy link to clipboard

Copied

Hi pixxxelschubser 😉

I was thinking of setting up a x/y start coordinate to give all points a fixed reference...

 

Wie meinst du genau mit der Dreisatzberechnung?

 

Votes

Translate

Translate

Report

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 ,
Jul 04, 2024 Jul 04, 2024

Copy link to clipboard

Copied

Hallo Nils,

sofern du die entsprechenden Start und Endkoordinaten passend zu deiner Dokumentengröße verfügbar hast, ist es "simpler Dreisatz".

Screenshot 2024-07-05 024310.png

gegeben ist:

ein Dokument in der Größe 200 mm × 297 mm

ein Kartenausschnitt von 9,0° Ost bis 10,0° Ost und 49,0° Nord bis 48,0° Nord

die X-Koordinate von Stuttgart Bad Cannstatt ist fast exakt 9,2° Ost

Berechnung:

also pos X = (X-Koordinate Stuttgart Bad Cannstatt - KarteGeoCoorLinks) * Dokument Rechts / (KarteGeoCoorRechts - KarteGeoCoorLinks)

in mm
pos X = (9,2 - 9) * 200 / (10 - 9)

pos X = (0,2) * 200 / (1)

pos X = 40

 

bzw in pt

pos X = (9,2 - 9) * 566.929 / (10 - 9)

pos X = (0,2) * 566.929 / (1)

pos X = 113.385826771653

 

Votes

Translate

Translate

Report

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 ,
Jul 08, 2024 Jul 08, 2024

Copy link to clipboard

Copied

Hallo Nils, 

die Variante mit den Start- und Endkoordinaten kommt für dich nicht in Frage?

Votes

Translate

Translate

Report

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 ,
Jul 12, 2024 Jul 12, 2024

Copy link to clipboard

Copied

It took a while to figure it out but this is the best aswer as it leaded to a solution for my issue!

Best tip ever was that something might be wrong with my Illustrator file as the coords were almost 30mm off – so I created a new file and there we go!

Next issue were multiple distortions within the scan of the original map so I had to fix it in two ways:

1.) I started by using the solution pixxxelschubser pointed out

2.) I added a factor to multiply the distortions for left to right and top to button

3.) after fixing this there was still a lot of distortion going on in the corners so additionally I devided the whole map into 4 areas and scaled each of these sections individually based on the distance from the center of the artboard + some additional factors for each direction...

 

This finally produced the desired, precise result!

 

I will not post a finished script here, as the result is too special and only works smoothly for this one map. Hope the way to get there will help anyone seeking for a similar solution.

 

Nils

 

Votes

Translate

Translate

Report

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