The UCAM got possibility to expand its functionality by programming any function in JAVA code. This means that every function the CAM department can imagine is possible to develop. It is only up to the programmer how advanced the functions will be and what they can do. The use of UCAM API is quite simple, and the description is almost perfect.

The rout calculator

The code snippet shows a function, which goes through all appertures on the layer and returns the size of every block as a BlockInfo class-variable. The picked code is just an example for UCAM programming, to show the UCAM-API included into the software.

yxedoywdwafms898acr5hokhy06dbehf_BlockInfo

public class BlockInfo {


   private int level;

   private int cPnlpPnl;               // number of cust. panels in prod. panel

   private int pcbcPnl;               // number of PCBs in customer panel

   private double sizepcbx;

   private double sizepcby;

   private double sizepnlx;

   private double sizepnly;

   private int stepprodpnlx;            // step x in production panel

   private int stepprodpnly;            // step y in production panel

   private int stepcustpnlx;            // step x in customer panel

   private int stepcustpnly;            // step y in customer panel


   private double ppxrepeat;            // repeat x in production panel

   private double ppyrepeat;            // repeat y in production panel

   private double cpxrepeat;            // repeat x in customer panel

   private double cpyrepeat;            // repeat y in customer panel


   // konstruktor

   public BlockInfo() {

       level = 0;

       cPnlpPnl = 0;

       pcbcPnl = 0;

       sizepcbx = 0;

       sizepcby = 0;

       sizepnlx = 0;

       sizepnly = 0;

       stepprodpnlx = 0;

       stepprodpnly = 0;

       stepcustpnlx = 0;

       stepcustpnly = 0;

       ppxrepeat = 0;

       ppyrepeat = 0;

       cpxrepeat = 0;

       cpyrepeat = 0;

   }


   public BlockInfo dispOutlineApe(Uape uape, int ile_ape) {

       double xSize2 = 0, ySize2 = 0;

       Upoint[] upointTab = new Upoint[32];


       for (int j = 0; j < ile_ape; j++) {

           if ((uape.is_it("blo")) && (level == 0)) {

               cPnlpPnl = uape.numobj();

               sizepnlx = Math.round((uape.dimension().xsize()) * 100) / 100.00;

               sizepnly = Math.round((uape.dimension().ysize()) * 100) / 100.00;


           } else if ((uape.is_it("blo")) && (level == 1)) {

               pcbcPnl = uape.numobj();

               sizepcbx = Math.round((uape.dimension().xsize()) * 100) / 100.00;

               sizepcby = Math.round((uape.dimension().ysize()) * 100) / 100.00;

               Uapeobj uapeobj = uape.firstobj();

               int k, m;

               for (k = 0; k < uape.numobj(); k++) {

                   Dpfobj dpfobj = uapeobj.obj();        

                   if (dpfobj.is_it("fla")) {

                       upointTab[k] = dpfobj.fp();        

                   }

                   uapeobj = uapeobj.next();

               }


               for (m = 0; m < k; m++) {

                   xSize2 = Math.round((upointTab[0].x - upointTab[m].x) * 100) / 100.00;

                   if (xSize2 == 0) {

                       stepcustpnly++;                    

                   }

                   ySize2 = Math.round((upointTab[m].y - upointTab[0].y) * 100) / 100.00;

                   if (ySize2 == 0) {

                       stepcustpnlx++;                    

                   }

               }


               System.out.println("xSize2: " + xSize2);

               System.out.println("ySize2: " + ySize2);


           } else if ((uape.is_it("blo")) && (level == 2)) {

               System.out.println(uape.toString());


           } else if ((uape.is_it("blo")) && (level == 3)) {

               System.out.println(uape.toString());

           }


           if (uape.is_it("blo")) {

               Ubloape ublape = (Ubloape) uape;                            

               Ulayer ubllayer = ublape.lay();                            

               level++;                                                    

               dispOutlineApe(ubllayer.firstape(), ubllayer.numapes());    // recursion

           }

           uape = uape.next();

       }

       return null;

   }

New functionality for UCAM

The code below demonstrates how to attach a custom function to be executed by the UCAM. The desired function appears in the hypertool menu.
Its code is loaded when UCAM starts, so if a run-time error occurs then UCAM crashes immediately! The solution for this issue could be to delete the UcamActions.class from the UCAM-root directory and debug the code.

ucam_actions

import com.barco.ets.ucam.hypertool.Ucamapp;

import com.barco.ets.ucam.dtl.Ucamaction;

import com.company.ucam.silk.MainHTConsole;

import com.company.ucam.silk.MainOptimize;

import com.company.ucam.silk.MainSilk3;

import com.company.ucam.silk.MainHoles;


/**

* Class loaded by Ucam. Only its static block is executed.

*/

public class UcamActions {

   // Static block executed when the class is loaded.

   static {

       Ucamaction act = new Ucamaction() {

           public void action() {

               new MainSilk3().main();

           }

       };

       Ucamapp.cO.add_pb("silk_export", "Silk export", null, act,

               "hypertool_menu", true);


       act = new Ucamaction() {

           public void action() {

               new MainHTConsole().HTConsole();

           }

       };

       Ucamapp.cO.add_pb("hyper_tool_console", "Hyper Tool Console", null,

               act, "hypertool_menu", true);


       act = new Ucamaction() {

           public void action() {

               new MainOptimize().main();

           }

       };

       Ucamapp.cO.add_pb("drill_time", "Drill Time", null, act,

               "hypertool_menu", true);


       act = new Ucamaction() {

           public void action() {

               new MainHoles().main();

           }

       };

       Ucamapp.cO.add_pb("sort_holes", "Sort Holes", null, act,

               "hypertool_menu", true);

   }

As I have programming experience in both UCAM and Genesis, so the UCAM is more intuitiv and user friendly to program than the Genesis. Period.

The Silk output

silk_output

This project is considered to make the daily work easier in the CAM department. This program is usefull while outputing the gerber data for a silk screen machine.

The silk printer needs two data layers to print the silk legend. These layers need to be exported to 274x format. One is the legend layer and the other is the outline. Both layers need some modyfications before export. The frame should be removed from the silk data, and fiducials have to be copied to the outline. Finally both layers are rotated and exported. The same steps happen for the bottom silk layer. Additional the layers for bottom side must be mirrored.

By using this script we save about 10-15min (or even 30min when outputing 2 silk layers) for every job process.

prepareTopSilk

private void prepareTopSilk() {

   int iApe = 0;

   String nApe = "";

   String nFrameApe = "";


   // remove the block 2001 from the outline layer

   if (outline_p != null && (ktcomp_p != null)) {

       outline_p.setactive(true);

       int cAppeNum = 0;

       Uape olape = outline_p.firstape();

       for (int i = 1; i <= outline_p.numapes(); ++i) {

           nApe = olape.name();

           if (nApe.equals("frame") || olape.num() == 2001) {

               nFrameApe = nApe;

               num = olape.num();

               olape.select_curape();

               cAppeNum += olape.select_count();

               olape.erase();

           }

           olape = olape.next();

       }

       outline_p.ape_clean();

       outline_p.select_all("-");

       outline_p.block_expand(); // expand the layer


       // remove redundant elements except BLOCK(2001) and TXT(101)

       ktcomp_p.setactive(true);

       cAppeNum = 0;

       Uape ktape = ktcomp_p.firstape();

       for (int i = 1; i <= ktcomp_p.numapes(); ++i) {

           iApe = ktape.num();

           if (iApe == 2001) {

               boolean isBLOCK = ktape.is_it("block");

               if (isBLOCK != true) {

                   com.barco.ets.ucam.log4ucam.LogViewerGUI.getDialog()

                           .addMessage(

                                   "MSGERR:" + "Error: Layer "

                                           + ktcomp_p.name()

                                           + " was expanded before.\n");

               }

           } else if (iApe == 101) {

               boolean isTXT = ktape.is_it("txt");

               if (isTXT != true) {

                   ktape.select_curape();

                   cAppeNum += ktape.select_count();

                   ktape.erase();

               }


           } else {

               nFrameApe = Integer.toString(iApe);

               // num = ktape.num(); // Gets the aperture number

               ktape.select_curape();

               cAppeNum += ktape.select_count();

               ktape.erase();

           }

           ktape = ktape.next();

       }

       ktcomp_p.ape_clean();

       ktcomp_p.select_all("-");

       ktcomp_p.block_expand(); // expand the layer


       // find the uk-frame and copy it to the outline layer

       cAppeNum = 0;

       int counter = 0;

       boolean isCirApe;

       ktape = ktcomp_p.firstape();

       for (int i = 1; i <= ktcomp_p.numapes(); ++i) {

           iApe = ktape.num();

           nApe = ktape.name();


           if (nApe.equals("ktframe")) {

               nFrameApe = nApe;

               num = ktape.num();

               ktape.select_curape();

               outline_p.copy(ktcomp_p, "sel");

               ktape.erase();

               counter++;

           }

           else if (iApe == 104) {

               isCirApe = ktape.is_it("cir");


               Urectangle dim = ktape.dimension();

               if (isCirApe == true && dim.xsize() > 0.298

                       && dim.xsize() < 0.302) {

                   // change the app size to 0.25mm

                   Uape newApe = Ucirape.cO.create(iApe, 0.25);

                   if (newApe == null)

                       System.out

                               .println("Error: Ucirape.cO.create() was failed.");

                   ktape.select_curape();

                   int res = ktcomp_p.replace_aperture(newApe, "sel");

                   outline_p.copy(ktcomp_p, "sel");

                   counter++;

               }

               ktape.erase();

           } else {

               String aName = ktape.name();

               int aNum = ktape.num();

           }

           ktape = ktape.next();

       }

       if (counter == 0) {

           com.barco.ets.ucam.log4ucam.LogViewerGUI.getDialog()

                   .addMessage(

                           "MSGERR:"

                                   + "'ktframe' was not found on layer: "

                                   + ktcomp_p.name() + "\n");

       }

       ktcomp_p.ape_clean();

       ktcomp_p.select_all("-");

       outline_p.select_all("-");

   }

}

The Drill Time calculator

drilcalc

In the drill department of the factory the manager whishes to predict the time a drill machine needs to execute one drill task. This is how the drill calculating tool was born.

The drill calculator counts all holes on the panel circuit board. It optimizes the drill path as it would be the case for the real drill process. The optimized path is considered for calculating the time used on the drill machine. But no only the drill size is considered for calculation but also the size of the drill bit, the feed and the RPMs, the height position and the time for changining of a drill bit.

calculateDrillTime

   public void calculateDrillTime(String cust, String custno) {

       Uextlayer udro = findDroLayer(ujob);

       if (udro != null) {

           textArea.append("Info: udro exists and will be deleted now. \n");

           ujob.deletelayer(udro);

       }

       Ulayer dr_p = ujob.getlayerbyname("dr_p");

       if (dr_p == null) {

           textArea.append("Error: layer does not exists? \n");

           return;

       }

       ujob.setactive("all", 0);

       dr_p.setactive(true);

       dr_p.load();

       dr_p.block_expand();

       ujob.drill_optimise(1, 4, "all");

       dr_p.setactive(false); 

       udro = findDroLayer(ujob);

       udro.load();


       float[] tool = new float[120];

       int[] path = new int[120];

       int[] pads = new int[120];

       int pos = 0;


       Uape myApe;

       Float myFloat;

       int napes = udro.numapes();


       for (int n = 1; n <= napes; n++) {

           myApe = udro.getape(n);

           if (myApe.is_it("TXT")) {

               Utxtape myUtxtape = (Utxtape) udro.getape(n);

               String myString = myUtxtape.string();

               if (myString.endsWith("MM")) {

                   textArea.append(myString + "\n");


                   // new path

                   int elif = myString.lastIndexOf(" MM");

                   int blif = myString.lastIndexOf(" ", elif - 1);

                   String myValue = myString.substring(blif + 1, elif);

                   Integer myInt = Integer.valueOf(myValue);

                   path[pos] = myInt;


                   // old path

                   elif = myString.lastIndexOf(" MM", blif);

                   blif = myString.lastIndexOf(" ", elif - 1);

                   myValue = myString.substring(blif + 1, elif);

                   myInt = Integer.valueOf(myValue);


                   // pads

                   elif = myString.lastIndexOf(" MM", blif);

                   if (elif != -1) {

                       elif = elif + 11;

                       blif = myString.lastIndexOf(" ", elif - 1);

                       myValue = myString.substring(blif + 1, elif);

                       myInt = Integer.valueOf(myValue);

                       pads[pos] = myInt;

                   }


                   // tool

                   elif = myString.lastIndexOf(" MM", blif);

                   blif = myString.lastIndexOf(" ", elif - 1);

                   if (blif != -1 || elif != -1) {

                       myValue = myString.substring(blif + 1, elif);

                       myFloat = Float.valueOf(myValue);

                   } else {

                       myFloat = (float) 0.0;

                   }

                   tool[pos] = myFloat;

                   pos++; // pointer to next element

               }

           }

           actionLabel.setText("Done.");

       }


       IniFile mif = new IniFile("config.ini");

       HashMap<String, Double> myHashMap = mif.readIniFile();


       try {

           IN = myHashMap.get("IN");

           PANELS = myHashMap.get("PANELS");

           PANEL_THICKNESS = myHashMap.get("PANEL_THICKNESS");

           ALU_PLATE = myHashMap.get("ALU_PLATE");

           OUT = myHashMap.get("OUT");

           POSITION_SPEED = myHashMap.get("POSITION_SPEED");

           BACKFEED = myHashMap.get("BACKFEED");

           TIME_TOOL_CHANGE = myHashMap.get("TIME_TOOL_CHANGE");

           TIME_LASER_CHECK = myHashMap.get("TIME_LASER_CHECK");

       }


       catch (NullPointerException npe) {

           textArea.append("The file config.ini was not found. \n" +

                   "Standard parameters will be used for calculation. \n");

       }


       // prepare the tool table from the TOOLSGP.TDB

       float[] aTools = getTools("TOOLSGP.TDB");

       for (int n = 0; n < pos; n++) {

           drill_hight = IN + ALU_PLATE + (PANELS * PANEL_THICKNESS) + OUT;

           SpindleFeed = (findSpindleFeed(aTools, tool[n]) * 1000) / 60; // [mm/sec]

           drill_time += ((drill_hight / SpindleFeed) + (drill_hight / BACKFEED) * 0.01);

           numberOfHoles = pads[n];

           oneToolDrillTime = drill_time * numberOfHoles;

           oneToolPositionTime = path[n] / POSITION_SPEED;

           oneToolPositionTime = oneToolPositionTime + (oneToolPositionTime * 0.01);

           time_all = oneToolPositionTime + oneToolDrillTime;


           // tool replacement

           if (numberOfHoles > 2) {

               time_all = TIME_TOOL_CHANGE + TIME_LASER_CHECK + time_all;

           }

           time = time + time_all;

       }

       long total = Math.round(time);

       int hours = (int) (total / 60 / 60);

       int minutes = (int) (total - (hours * 60 * 60)) / 60;

       int seconds = (int) (total - ((hours * 60 * 60) + (minutes * 60)));


       textArea.append("drill time: " + total + " [sec] \n");

       textArea.append("drill time: " + hours + ":"

           + minutes + ":" + seconds + " [hh:mm:ss] \n");

       actionLabel.setText(hours + ":" + minutes + ":" + seconds);

   }