Exporting DXF is mirrored - CMM Arm

I am working on building a CMM Arm with the end goal of exporting a 3D .DXF file of the object measured as well as a point cloud file (simple Tab Delimited Text file). I am having trouble with exporting the DXF as its saving as a mirrored image to the original (see processing screen shot and Solidworks import below). Where I believe I am falling into trouble is the scale and translate functions I call early on in the draw() function.

scale(1, -1); //Reverses the Y coordinate system
translate(0, -height); //Reverses the Y coordinate system

The reason I used this was to flip the Y axis so that it matches machine coordinates and not programming coordinates. If I need to I can change the hardware but that’s a bit of a nightmare at this point.

How can I export the dxf file in the correct orientation?


//============================================================
//  3D Digitizer
//  Used with 3D digitizer:
//  Program based off original concept by: http://fablab.ruc.dk/diy-digitizer/
//  4 Axis digitizing arm. Point Cloud export and surface shape
//============================================================

import processing.serial.*;
import peasy.*;
import processing.dxf.*;
PrintWriter output;

boolean record = false;
RawDXF dxf;

//============================================================
//-3D navigation
//============================================================
PeasyCam cam;

//============================================================
//-Digitizer
//============================================================
pointer digitizer = new pointer(this, 0);

//============================================================
//  GUI controls
//============================================================
ArrayList<control> controls = new ArrayList<control>();

control ctl_clear = new control(10, 10, 'q', "Clear", "Clear all");
control ctl_point = new control(10, 10+1*40, 'p', "Point", "Mark a point");
control ctl_circle = new control(10, 10+2*40, 'c', "Circle", "Mark a hole");
control ctl_feature = new control(10, 10+3*40, 'f', "Feature", "Start a feature. Use \"Modify\" to add points");
control ctl_modify = new control(10, 10+4*40, 'm', "Modify", "Modify last figure");
control ctl_pdf = new control(10, 10+5*40, 'z', ".pdf", "Export as flat PDF file");
control ctl_dxf = new control(10, 10+6*40, 'd', ".dxf", "Export as 3D .DFX file");

//============================================================
//  Objects
//============================================================
ArrayList<object> objects = new ArrayList<object>();

//============================================================
//  Setup
//============================================================
void setup()
{
  size(1200, 800, P3D);
  output = createWriter("positions.txt");
  //Set up visualizer
  cam = new PeasyCam(this, 300);
  cam.setMinimumDistance(50);
  cam.setMaximumDistance(1000);
  //Add GUI controls to display list
  controls.add(ctl_clear);
  controls.add(ctl_point); 
  ctl_point.typematic=true;
  controls.add(ctl_circle); 
  ctl_circle.typematic=true;
  controls.add(ctl_feature);
  controls.add(ctl_modify);
  ctl_modify.typematic=true;
  controls.add(ctl_pdf);
  controls.add(ctl_dxf);

  background(50);
}

//============================================================
//  Handy globals
//============================================================
float penX=0;
float penY=0;
float penZ=0;
float penA=0;
//PVector pen;

object currentObject=null; //-Last created object

//============================================================
//  Draw
//======================================================proce======

void draw()
{

  //-Get coordinated from digitizer
  digitizer.update();      //-Update globals

  scale(1, -1);            //Reverses the Y coordinate system
  translate(0, -height);   //Reverses the Y coordinate system

  translate(-135, 650);    // Moves the background

  PVector pd=new PVector(digitizer.tip.x, digitizer.tip.y);
  penA=digitizer.rotation;

  pd.rotate(-penA);

  penX=pd.x;   
  penY=pd.y;
  penZ=digitizer.tip.z;
  //  pen=digitizer.tip;


  background(0);

  //-Draw pad
  stroke(250);
  //  fill(10,10,10,128);
  noFill();
  rect(-45, -10, 305, 235);

  rotateZ(penA);

  // Draw Tool Home Location
  stroke(100, 500, 0);
  line(248, 277, -52, 258, 277, -52);  // Horizontal Line
  line(248, 287, -52, 248, 277, -52);  // Vertical Line

  //-Draw Orign Triad
  stroke(255, 0, 0);  // X Axis Line
  line(0, 0, 20, 0);
  stroke(0, 255, 0);  // Y Axis Line
  line(0, 0, 0, 20);
  stroke(0, 0, 255);  // Z Axis Line
  line(0, 0, 0, 0, 0, 20);

  /*
  //-Draw all objects flat projection
   for (object obj : objects)
   {
   obj.project();
   }
   */

  if (record == true) {
    beginRaw(DXF, "output.dxf"); // Start recording to the file
  }

  //-Draw all objects
  for (object obj : objects)
  {
    obj.draw();
  }

  if (record == true) {
    endRaw();
    record = false; // Stop recording to the file
  }


  //-Draw cursor
  pushMatrix();
  rotateZ(-penA);
  translate(digitizer.tip.x, digitizer.tip.y, digitizer.tip.z);
  stroke(0, 255, 0);
  noFill();
  box(5);
  popMatrix();


  //-Draw Heads Up Display
  cam.beginHUD();  
  color faceColor=color(98, 206, 198);
  color textColor=color(75, 42, 0);
  stroke(50);
  fill(98, 206, 198);
  rect(width-115, 10, 105, 90);
  fill(75, 42, 0);
  textSize(15);
  //-Coordinates
  text("X: "+penX, width-110, 30);
  text("Y: "+penY, width-110, 50);
  text("Z: "+penZ, width-110, 70);
  text("R: "+penA, width-110, 90);
  pushStyle();
  //-Update GUI controls 
  if (ctl_clear.update())
  {
    objects.clear();
  }
  if (ctl_point.update())
  {
    currentObject=new gpoint(penX, penY, penZ);
    objects.add(currentObject);
    point(penX, penY, penZ);
    output.println(penX + "\t" + penY + "\t" + penZ);
  }
  if (ctl_circle.update())
  {
    currentObject=new gcircle(penX, penY, penZ);
    objects.add(currentObject);
  }
  if (ctl_feature.update())
  {
    currentObject=new gfeature(penX, penY, penZ);
    objects.add(currentObject);
  }
  if (ctl_modify.update())
  {
    if (currentObject!=null)
    {
      currentObject.modify(new PVector(penX, penY, penZ));
    }
  }
  // XXX PDF File Save
  if (ctl_pdf.update())
  {
    
    record = true; // DXF record switch

    output.flush(); // Writes the remaining data to the file
    output.close(); // Finishes the file
    //exit(); // Stops the program



    /*
    beginRaw(DXF, "output.dxf"); 
     background(255);
     translate(width/2, height/2);
     //    scale(2.84832);
     for (object obj : objects)
     {
     obj.export();
     }
     endRaw();
     
    /*
     String s="3D_"+Integer.toString(year())+"_"+Integer.toString(day())+"_"+Integer.toString(hour())+"_"+Integer.toString(minute())+"_"+Integer.toString(second())+".pdf";
     beginRecord(PDF, s); 
     background(255);
     translate(width/2, height/2);
     scale(2.84832);
     for (object obj : objects)
     {
     obj.export();
     }
     endRecord();
     */
  }

  //-Draw GUI controls
  for (control ctl : controls)
  {
    if (ctl.change)
      ctl.draw();
    if (ctl.mouseOver)
      ctl.drawHelp();
  }
  popStyle();
  cam.endHUD();
}

2 Likes

For reference here is the CMM Arm (Faro Arm) that I made. It reads rotary encoders via an Arduino and spits out coordinates via Serial to Processing.

2 Likes

It is a bit hard for me to understand what your requirements are. You are intentionally flipping your coordinates with scale/translate, but you don’t want them flipped. Can you explain this part more? Why not just… stop flipping them?

Machine Coordinates and Processing coordinates are not the same. A move in Y+ is inverse in
machine coordinates. As such I inverted the Y coordinate in processing and this allows for the movement in the arm to read correctly in processing. Sense what I am using this for is based around machine coordinates I was hoping to keep using this system. But as I have posted its saving the 3D model backwards. Hope this makes a bit more sense?

To be clear in the programming, 98% of it is not my code. Standing on the shoulders of giants and all.

This is the way processing uses coordinates:

Machine coordinates:

1 Like

Here is an image with the physical coordinates of the Faro arm I am using, look at the bottom right corner I drew the Triad on the surface plate.

1 Like

Think I got it figured out. It was all to do with where I placed my beginRaw statement in the draw() function. I did not realize that when you call beginRaw it cancels out any scale/translate function. So, I had to re-initialize them both right after I began recording.

  if (record == true) {
    beginRaw(DXF, "output.dxf"); // Start recording to the file
    scale(1, -1);
    translate(-100, -100);
  }

Its not pretty, but I am learning…

2 Likes

Not exactly it cancels out, but rather that both beginRaw() & beginRecord() internally creates a temp PGraphics which is initialized w/ default styles & transforms, just like the sketch’s main canvas. :nerd_face:

I recall a long time ago I had created a separate initCanvas() invoked both from setup() and right after each beginRecord(), so both the main canvas & temporary PGraphics would have the same styles: :bulb:

2 Likes

Amazing!!. im about to build something similar atm.
For now I just scaled up a arm project I found but the updgrade I had in my mind the whole time looks about like yours do.

Right now im just trying to get a .pdf out to see how the tolerance is.The scale is super off and im kind of stuck.

So glad I found this post!. Great work!

My arm:

1 Like