Easily Replicating segment of PCB layout?
1257 9
MadOverlord 2 years ago
I'm an EasyEDA newbie so please forgive me if there's an obvious answer to this that I've missed. I am designing a board that has 8 identical submodules which are then wired together to form the final layout. I've come up with a nice layout for the submodule (and figured out how to use test pins in the design so that the module has nicely defined entry points). So far, so good. The problem is: what is the easiest way to replicate the nice layout for the other 7 submodules? I have tried: 1) Creating modules. Does not work, because importing a schematic module does not automatically use the associated PCB module (but does rename the parts and nets in the schematic), and importing a PCB module does NOT rename the parts and nets, so it's useless for multiple copies of the same module. And with no documentation that I can find, it's unclear to me exactly what the point of importing PCB modules is. 2) Selecting everything, deselect the components, copy-paste to create a set of empty tracks, move the proper components and then rename all the nets in the tracks. This works, but its tedious. If there is a simple solution, I'd much appreciate a pointer to it. One thing that I did notice is that you can select all the tracks and then clear their nets all at once. Unfortunately, there doesn't seem to be a "Rebuild Nets" feature. The algorithm would seem to be straightforward:   While progress is being made, for each track in the selection, if the net is blank, then if it touches something that is in a named net, set it to that net. This would effectively flood-fill the tracks with the proper net connections. It would allow you to do this workflow: 1) Copy a group of tracks and paste them. 2) Clear their net labels. 3) Drag in the correct components (which have net labels). 4) Link all the tracks to their new components. Is there perhaps a script that does this? Thanks in advance for any help you can provide!
Komentáře
UserSupport 2 years ago
Hi There is no good to do this noe, but we will try to support it in the feature. Thanks
Odpovědět
MadOverlord 2 years ago
I had a little time this evening so I played around with the API and got a basic script working that relinks PCB items that have a blank NetID. Feel free to use it as you see fit. Limitations: \* Only does one pass of relinking per run\, so script may need to be executed several times to relink complicated layouts\. I need to understand how to update the state between passes\. \* Can relink tracks\, pads and vias\. Cannot relink footprints because I can't figure out how to get changes to internal footprint objects to stick\. However\, for the major use case described above\, it works fine\. I am sure there are bugs and glitches, your mileage may vary, use at your own risk! `// Relink objects with blank NET by finding a net they touch``//` `// 2020-01-01 by MadOverlord, `[`[email protected]`](mailto:[email protected]) `//` `// TRACK[gId, layerid, net, pointarr[].x,y]]` `// PAD[gId, layerid, net, x, y]` `// VIA[gId, layerid, net, x, y]` `// FOOTPRINT(TRACK, PAD, VIA)` `// layerId 11 = all` `//` `// json documentation: `[`https://gist.github.com/dillonHe/071d4680dcdbf6bf9dd6`](https://gist.github.com/dillonHe/071d4680dcdbf6bf9dd6) `//` `// This could be a lot faster, but I am prioritizing simplicity here` `// because I don't program in Javascript regularly, and I want it to` `// be very clear what the script is doing.``function relink(json, obj, owner) {``    var id, item, point, new_net, count=0;``function netAt(obj, x, y, layer) {``        var id, item, point, net;``for (id in obj.TRACK) {` `item = obj.TRACK[id];` `if (item.net != "" && (item.layerid == layer || item.layerid == 11 || layer == 11)) {` `for (point of item.pointArr) {` `if (point.x == x && point.y == y) {` `return item.net;` `}` `}` `}` `}``for (id in obj.VIA) {` `item = obj.VIA[id];` `if (item.net != "" && (item.layerid == layer || item.layerid == 11 || layer == 11)) {` `if (item.x == x && item.y == y) {` `return item.net;` `}` `}` `}``for (id in obj.PAD) {` `item = obj.PAD[id];` `if (item.net != "" && (item.layerid == layer || item.layerid == 11 || layer == 11)) {` `if (item.x == x && item.y == y) {` `return item.net;` `}` `}` `}``// Footprint contains subelements, so we recurse``for (id in obj.FOOTPRINT) {` `net = netAt(obj.FOOTPRINT[id], x, y, layer);` `if (net != "") {` `return net;` `}` `}``// Fail``return ""``}``console.log("Tracks");``for (id in obj.TRACK) {` `if(json.TRACK.hasOwnProperty(id)) {` `            item = obj.TRACK[id];` `    if (item.net == "") {` `                console.log("Attempting", item);` `    for (point of item.pointArr) {` `    new_net = netAt(json, point.x, point.y, item.layerid);` `    if (new_net != "") {` `                        api('updateShape', {` `                             "shapeType": "TRACK",` `                            "jsonCache": {` `                            "gId": item.gId,` `                            "net": new_net` `                            }` `                            });` `                        console.log("Netted", new_net, item);` `                        count += 1;` `    break;` `    }` `    }` `    }` `        }` `}``console.log("Vias");``for (id in obj.VIA) {` `item = obj.VIA[id];` `if (item.net == "") {` `            console.log("Attempting", item);` `            new_net = netAt(json, item.x, item.y, item.layerid);` `            if (new_net != "") {` `                api('updateShape', {` `                        "shapeType": "VIA",` `                        "jsonCache": {` `                        "gId": item.gId,` `                        "net": new_net` `                    }` `                    });` `                console.log("Netted", new_net, item);` `                count += 1;` `                break;` `            }` `}` `}``console.log("Pads");``for (id in obj.PAD) {` `item = obj.PAD[id];` `if (item.net == "") {` `            console.log("Attempting", item);` `            new_net = netAt(json, item.x, item.y, item.layerid);` `            if (new_net != "") {` `                api('updateShape', {` `                        "shapeType": "PAD",` `                        "shape": item.shape,` `                        "type": item.type,` `                        "jsonCache": {` `                        "gId": item.gId,` `                        "net": new_net` `                    }` `                    });` `                console.log("Netted", new_net, item);` `                count += 1;` `                break;` `            }` `}` `}``// Footprint contains subelements, so we recurse - disabled for now` `    // because I don't know how to update subelements!``// console.log("Footprints");` `    //` `// for (id in obj.FOOTPRINT) {` `// count += relink(json, obj.FOOTPRINT[id], id);` `// }``    return count;``}``var json, count=0, i;``// Do a single pass of relinking. I tried multiple passes but can't figure out` `// how to update the json state after each pass. So for now, you just have to` `// run the script a few times.``json = api('getSource', {type: "json"});` `count += relink(json, json, null);``alert("Relink: " + count + " nets were updated.")`
Odpovědět
MadOverlord 2 years ago
Whoops, pasted it wrong, let's try that again... ``` // Relink objects with blank NET by finding a net they touch // // 2020-01-01 by MadOverlord, [[email protected]](mailto:[email protected]) // // TRACK[gId, layerid, net, pointarr[].x,y]] // PAD[gId, layerid, net, x, y] // VIA[gId, layerid, net, x, y] // FOOTPRINT(TRACK, PAD, VIA) // layerId 11 = all // // json documentation: [https://gist.github.com/dillonHe/071d4680dcdbf6bf9dd6](https://gist.github.com/dillonHe/071d4680dcdbf6bf9dd6) // // This could be a lot faster, but I am prioritizing simplicity here // because I don't program in Javascript regularly, and I want it to // be very clear what the script is doing. function relink(json, obj, owner) {     var id, item, point, new_net, count=0; function netAt(obj, x, y, layer) {         var id, item, point, net; for (id in obj.TRACK) { item = obj.TRACK[id]; if (item.net != "" && (item.layerid == layer || item.layerid == 11 || layer == 11)) { for (point of item.pointArr) { if (point.x == x && point.y == y) { return item.net; } } } } for (id in obj.VIA) { item = obj.VIA[id]; if (item.net != "" && (item.layerid == layer || item.layerid == 11 || layer == 11)) { if (item.x == x && item.y == y) { return item.net; } } } for (id in obj.PAD) { item = obj.PAD[id]; if (item.net != "" && (item.layerid == layer || item.layerid == 11 || layer == 11)) { if (item.x == x && item.y == y) { return item.net; } } } // Footprint contains subelements, so we recurse for (id in obj.FOOTPRINT) { net = netAt(obj.FOOTPRINT[id], x, y, layer); if (net != "") { return net; } } // Fail return "" } console.log("Tracks"); for (id in obj.TRACK) { if(json.TRACK.hasOwnProperty(id)) {             item = obj.TRACK[id];     if (item.net == "") {                 console.log("Attempting", item);     for (point of item.pointArr) {     new_net = netAt(json, point.x, point.y, item.layerid);     if (new_net != "") {                         api('updateShape', {                              "shapeType": "TRACK",                             "jsonCache": {                             "gId": item.gId,                             "net": new_net                             }                             });                         console.log("Netted", new_net, item);                         count += 1;     break;     }     }     }         } } console.log("Vias"); for (id in obj.VIA) { item = obj.VIA[id]; if (item.net == "") {             console.log("Attempting", item);             new_net = netAt(json, item.x, item.y, item.layerid);             if (new_net != "") {                 api('updateShape', {                         "shapeType": "VIA",                         "jsonCache": {                         "gId": item.gId,                         "net": new_net                     }                     });                 console.log("Netted", new_net, item);                 count += 1;                 break;             } } } console.log("Pads"); for (id in obj.PAD) { item = obj.PAD[id]; if (item.net == "") {             console.log("Attempting", item);             new_net = netAt(json, item.x, item.y, item.layerid);             if (new_net != "") {                 api('updateShape', {                         "shapeType": "PAD",                         "shape": item.shape,                         "type": item.type,                         "jsonCache": {                         "gId": item.gId,                         "net": new_net                     }                     });                 console.log("Netted", new_net, item);                 count += 1;                 break;             } } } // Footprint contains subelements, so we recurse - disabled for now     // because I don't know how to update subelements! // console.log("Footprints");     // // for (id in obj.FOOTPRINT) { // count += relink(json, obj.FOOTPRINT[id], id); // }     return count; } var json, count=0, i; // Do a single pass of relinking. I tried multiple passes but can't figure out // how to update the json state after each pass. So for now, you just have to // run the script a few times. json = api('getSource', {type: "json"}); count += relink(json, json, null); alert("Relink: " + count + " nets were updated.") ```
Odpovědět
MadOverlord 2 years ago
(and the eternal war of tabs vs. spaces rages on).. Happy New Year!
Odpovědět
MadOverlord 2 years ago
Bugfix: forgot to remove some test break statements; this meant that only one pad/via was getting relinked per pass. ``` // Relink objects with blank NET by finding a net they touch // // 2020-01-01 by MadOverlord, [email protected]meigo.com // // TRACK[gId, layerid, net, pointarr[].x,y]] // PAD[gId, layerid, net, x, y] // VIA[gId, layerid, net, x, y] // FOOTPRINT(TRACK, PAD, VIA) // layerId 11 = all // // json documentation: https://gist.github.com/dillonHe/071d4680dcdbf6bf9dd6 // // This could be a lot faster, but I am prioritizing simplicity here // because I don't program in Javascript regularly, and I want it to // be very clear what the script is doing. function relink(json, obj, owner) {     var id, item, point, new_net, count=0;     function netAt(obj, x, y, layer) {         var id, item, point, net;     for (id in obj.TRACK) {     item = obj.TRACK[id];     if (item.net != "" && (item.layerid == layer || item.layerid == 11 || layer == 11)) {     for (point of item.pointArr) {     if (point.x == x && point.y == y) {     return item.net;     }     }     }     }     for (id in obj.VIA) {     item = obj.VIA[id];     if (item.net != "" && (item.layerid == layer || item.layerid == 11 || layer == 11)) {     if (item.x == x && item.y == y) {     return item.net;     }     }     }     for (id in obj.PAD) {     item = obj.PAD[id];     if (item.net != "" && (item.layerid == layer || item.layerid == 11 || layer == 11)) {     if (item.x == x && item.y == y) {     return item.net;     }     }     }     // Footprint contains subelements, so we recurse     for (id in obj.FOOTPRINT) {     net = netAt(obj.FOOTPRINT[id], x, y, layer);     if (net != "") {     return net;     }     }     // Fail     return ""     }     console.log("Tracks");     for (id in obj.TRACK) {     if(json.TRACK.hasOwnProperty(id)) {             item = obj.TRACK[id];             if (item.net == "") {                 console.log("Attempting", item);                 for (point of item.pointArr) {                     new_net = netAt(json, point.x, point.y, item.layerid);                     if (new_net != "") {                         api('updateShape', {                                 "shapeType": "TRACK",                                 "jsonCache": {                                 "gId": item.gId,                                 "net": new_net                             }                             });                         console.log("Netted", new_net, item);                         count += 1;                         break;                     }                 }             }         }     }     console.log("Vias");     for (id in obj.VIA) {         item = obj.VIA[id];         if (item.net == "") {             console.log("Attempting", item);             new_net = netAt(json, item.x, item.y, item.layerid);             if (new_net != "") {                 api('updateShape', {                         "shapeType": "VIA",                         "jsonCache": {                         "gId": item.gId,                         "net": new_net                     }                     });                 console.log("Netted", new_net, item);                 count += 1;             }         }     }     console.log("Pads");     for (id in obj.PAD) {     item = obj.PAD[id];     if (item.net == "") {             console.log("Attempting", item);             new_net = netAt(json, item.x, item.y, item.layerid);             if (new_net != "") {                 api('updateShape', {                         "shapeType": "PAD",                         "shape": item.shape,                         "type": item.type,                         "jsonCache": {                         "gId": item.gId,                         "net": new_net                     }                     });                 console.log("Netted", new_net, item);                 count += 1;             }     }     }     // Footprint contains subelements, so we recurse - disabled for now     // because I don't know how to update subelements!     // console.log("Footprints");     //     // for (id in obj.FOOTPRINT) {     //  count += relink(json, obj.FOOTPRINT[id], id);     // }     return count; } var json, count=0, i; // Do a single pass of relinking. I tried multiple passes but can't figure out // how to update the json state after each pass. So for now, you just have to // run the script a few times. json = api('getSource', {type: "json"}); count += relink(json, json, null); alert("Relink: " + count + " nets were updated.") ```
Odpovědět
andyfierman 2 years ago
Thanks for posting your efforts! Much appreciated.
Odpovědět
tobalt 2 years ago
Dear MadOverlord, it is commendable that you tackle the shortcomings of EasyEDA with your own coding efforts. I have never used js at all, but your script is clearly written so i might even get into it Your script seems to do essentially the same as the 4th one of duritskiys sccripts here: [https://easyeda.com/forum/topic/Copy-Paste-Dublicating-9185827a952e4312854e808ed38df228](https://easyeda.com/forum/topic/Copy-Paste-Dublicating-9185827a952e4312854e808ed38df228) Refer to one of the last posts 4SmartReconnectTracks.js Both scripts don't update copper areas
Odpovědět
MadOverlord 2 years ago
Slightly updated script, added an adjustable closeness tolerance because sometime component links are a fraction of a mil misadjusted. ``` // Relink objects with blank NET by finding a net they touch // // 2020-01-04 by MadOverlord, [email protected] // // TRACK[gId, layerid, net, pointarr[].x,y]] // PAD[gId, layerid, net, x, y] // VIA[gId, layerid, net, x, y] // FOOTPRINT(TRACK, PAD, VIA) // layerId 11 = all // // json documentation: https://gist.github.com/dillonHe/071d4680dcdbf6bf9dd6 // // This could be a lot faster, but I am prioritizing simplicity here // because I don't program in Javascript regularly, and I want it to // be very clear what the script is doing. // // Typical Use case: // // Copy/Paste the wiring for a module you want to duplicate. // Select all the wires, holes and vias (turning off unneeded layers helps) // Set net to blank. // Move new components into position. // Run script multiple times until it doesn't find any nets to update. // Profit! function relink(json, obj, owner) {     var id, item, point, new_net, count=0;     const TOLERANCE = 1;    // how close to dead center match we require; footprints often have tiny offsets     function netAt(obj, x, y, layer) {         var id, item, point, net, temp;         for (id in obj.TRACK) {             item = obj.TRACK[id];             if (item.net != "" && (item.layerid == layer || item.layerid == 11 || layer == 11)) {                 for (point of item.pointArr) {                     if (Math.abs(point.x-x) < TOLERANCE && Math.abs(point.y-y) < TOLERANCE) {                         return item.net;                     }                 }             }         }         for (id in obj.VIA) {             item = obj.VIA[id];             if (item.net != "" && (item.layerid == layer || item.layerid == 11 || layer == 11)) {                 if (Math.abs(item.x-x) < TOLERANCE && Math.abs(item.y-y) < TOLERANCE) {                     return item.net;                 }             }         }         for (id in obj.PAD) {             item = obj.PAD[id];             if (item.net != "" && (item.layerid == layer || item.layerid == 11 || layer == 11)) {                 if (Math.abs(item.x-x) < TOLERANCE && Math.abs(item.y-y) < TOLERANCE) {                     return item.net;                 }             }         }         // Footprint contains subelements, so we recurse         for (id in obj.FOOTPRINT) {             net = netAt(obj.FOOTPRINT[id], x, y, layer);             if (net != "") {                 return net;             }         }         // Fail         return ""     }     console.log("Tracks");     for (id in obj.TRACK) {         if(json.TRACK.hasOwnProperty(id)) {             item = obj.TRACK[id];             if (item.net == "") {                 console.log("Attempting", id, item);                 for (point of item.pointArr) {                     new_net = netAt(json, point.x, point.y, item.layerid);                     if (new_net != "") {                         api('updateShape', {                                 "shapeType": "TRACK",                                 "jsonCache": {                                 "gId": item.gId,                                 "net": new_net                             }                             });                         console.log("Netted", new_net, item);                         count += 1;                         break;                     }                 }             }         }     }     console.log("Vias");     for (id in obj.VIA) {         item = obj.VIA[id];         if (item.net == "") {             console.log("Attempting", id, item);             new_net = netAt(json, item.x, item.y, item.layerid);             if (new_net != "") {                 api('updateShape', {                         "shapeType": "VIA",                         "jsonCache": {                         "gId": item.gId,                         "net": new_net                     }                     });                 console.log("Netted", new_net, item);                 count += 1;             }         }     }     console.log("Pads");     for (id in obj.PAD) {     item = obj.PAD[id];     if (item.net == "") {             console.log("Attempting", id, item);             new_net = netAt(json, item.x, item.y, item.layerid);             if (new_net != "") {                 api('updateShape', {                         "shapeType": "PAD",                         "shape": item.shape,                         "type": item.type,                         "jsonCache": {                         "gId": item.gId,                         "net": new_net                     }                     });                 console.log("Netted", new_net, item);                 count += 1;             }     }     }     // Footprint contains subelements, so we recurse - disabled for now     // because I don't know how to update subelements!     // console.log("Footprints");     //     // for (id in obj.FOOTPRINT) {     //  count += relink(json, obj.FOOTPRINT[id], id);     // }     return count; } var json, count=0, i; // Do a single pass of relinking. I tried multiple passes but can't figure out // how to update the json state after each pass. So for now, you just have to // run the script a few times. json = api('getSource', {type: "json"}); count += relink(json, json, null); alert("Relink: " + count + " nets were updated.") ```
Odpovědět
Kajetan321 4 weeks ago
@UserSupport I am very much looking forward to having this implemented in the upcoming version of EasyEDA.  Multiple instances of the same module would be great and a huge time saver! Thank you,
Odpovědět
Pro přidání komentáře se musíte Přihlásit nebo Registrovat
goToTop
你现在访问的是EasyEDA海外版,使用建立访问速度更快的国内版 https://lceda.cn(需要重新注册)
如果需要转移工程请在个人中心 - 工程 - 工程高级设置 - 下载工程,下载后在https://lceda.cn/editor 打开保存即可。
有问题联系QQ 3001956291 不再提醒
svg-battery svg-battery-wifi svg-books svg-more svg-paste svg-pencil svg-plant svg-ruler svg-share svg-user svg-logo-cn svg-double-arrow
We use cookies to offer you a better experience. Detailed information on the use of cookies on this website is provided in our Privacy Policy. By using this site, you consent to the use of our cookies.