// ================================================================================= // BuildMachineCoordinateData_m(): private bool BuildMachineCoordinateData_m() { double X_nom = 0; double Y_nom = 0; if (Properties.Settings.Default.Placement_SkipMeasurements) { foreach (DataGridViewRow Row in CadData_GridView.Rows) { // Cad data is validated. double.TryParse(Row.Cells["X_nominal"].Value.ToString(), out X_nom); double.TryParse(Row.Cells["Y_nominal"].Value.ToString(), out Y_nom); X_nom += Properties.Settings.Default.General_JigOffsetX; Y_nom += Properties.Settings.Default.General_JigOffsetY; Row.Cells["X_machine"].Value = X_nom.ToString("0.000", CultureInfo.InvariantCulture); Row.Cells["Y_machine"].Value = Y_nom.ToString("0.000", CultureInfo.InvariantCulture); Row.Cells["Rotation_machine"].Value = Row.Cells["Rotation"].Value; } // Refresh UI: Update_GridView(CadData_GridView); return true; }; if (ValidMeasurement_checkBox.Checked) { return true; } // Check, that our data is good: if (!ValidateCADdata_m()) return false; // Find the fiducials form CAD data: int FiducialsRow = 0; if (!FindFiducials_m(out FiducialsRow)) { return false; } // OriginalFiducials are at JobData_GridView.Rows[FiducialsRow] string[] FiducialDesignators = JobData_GridView.Rows[FiducialsRow].Cells["ComponentList"].Value.ToString().Split(','); // Are there at least two? if (FiducialDesignators.Length < 2) { ShowMessageBox( "Only one fiducial found.", "Too few fiducials", MessageBoxButtons.OK); return false; } // Get ready for position measurements DisplayText("SetFiducialsMeasurement"); SetFiducialsMeasurement(); // Move them to our array, checking the data: PhysicalComponent[] Fiducials = new PhysicalComponent[FiducialDesignators.Length]; // store the data here // double X_nom = 0; // double Y_nom = 0; for (int i = 0; i < FiducialDesignators.Length; i++) // for each fiducial in our OriginalFiducials array, { Fiducials[i] = new PhysicalComponent(); Fiducials[i].Designator = FiducialDesignators[i]; // find the fiducial in CAD data. foreach (DataGridViewRow Row in CadData_GridView.Rows) { if (Row.Cells["Component"].Value.ToString() == FiducialDesignators[i]) // If this is the fiducial we want, { // Get its nominal position (value already checked). double.TryParse(Row.Cells["X_nominal"].Value.ToString(), out X_nom); double.TryParse(Row.Cells["Y_nominal"].Value.ToString(), out Y_nom); break; } } Fiducials[i].X_nominal = X_nom; Fiducials[i].Y_nominal = Y_nom; // And measure it's true location: if (!MeasureFiducial_m(ref Fiducials[i])) { return false; } // We could put the machine data in place at this point. However, // we don't, as if the algorithms below are correct, the data will not change more than measurement error. // During development, that is a good checkpoint. } // Find the homographic tranformation from CAD data (fiducials.nominal) to measured machine coordinates // (fiducials.machine): Transform transform = new Transform(); HomographyEstimation.Point[] nominals = new HomographyEstimation.Point[Fiducials.Length]; HomographyEstimation.Point[] measured = new HomographyEstimation.Point[Fiducials.Length]; // build point data arrays: for (int i = 0; i < Fiducials.Length; i++) { nominals[i].X = Fiducials[i].X_nominal; nominals[i].Y = Fiducials[i].Y_nominal; nominals[i].W = 1.0; measured[i].X = Fiducials[i].X_machine; measured[i].Y = Fiducials[i].Y_machine; measured[i].W = 1.0; } // find the tranformation bool res = transform.Estimate(nominals, measured, ErrorMetric.Transfer, 450, 450); // the PCBs are smaller than 450mm if (!res) { ShowMessageBox( "Transform estimation failed.", "Data error", MessageBoxButtons.OK); return false; } // Analyze the transform: Displacement is for debug. We could also calculate X & Y stretch and shear, but why bother. // Find out the displacement in the transform (where nominal origin ends up): HomographyEstimation.Point Loc, Loc2; Loc.X = 0.0; Loc.Y = 0.0; Loc.W = 1.0; Loc = transform.TransformPoint(Loc); Loc = Loc.NormalizeHomogeneous(); DisplayText("Transform:"); DisplayText("dX= " + (Loc.X).ToString()); DisplayText("dY= " + Loc.Y.ToString()); // We do need rotation. Find out by rotatíng a unit vector: Loc2.X = 1.0; Loc2.Y = 0.0; Loc2.W = 1.0; Loc2 = transform.TransformPoint(Loc2); Loc2 = Loc2.NormalizeHomogeneous(); DisplayText("dX= " + Loc2.X.ToString()); DisplayText("dY= " + Loc2.Y.ToString()); double angle = Math.Asin(Loc2.Y - Loc.Y) * 180.0 / Math.PI; // in degrees DisplayText("angle= " + angle.ToString()); // Calculate machine coordinates of all components: foreach (DataGridViewRow Row in CadData_GridView.Rows) { // build a point from CAD data values double.TryParse(Row.Cells["X_nominal"].Value.ToString(), out Loc.X); double.TryParse(Row.Cells["Y_nominal"].Value.ToString(), out Loc.Y); Loc.W = 1; // transform it Loc = transform.TransformPoint(Loc); Loc = Loc.NormalizeHomogeneous(); // store calculated location values Row.Cells["X_machine"].Value = Loc.X.ToString("0.000", CultureInfo.InvariantCulture); Row.Cells["Y_machine"].Value = Loc.Y.ToString("0.000", CultureInfo.InvariantCulture); // handle rotation double rot; double.TryParse(Row.Cells["Rotation"].Value.ToString(), out rot); rot += angle; while (rot > 360.0) { rot -= 360.0; } while (rot < 0.0) { rot += 360.0; } Row.Cells["Rotation_machine"].Value = rot.ToString("0.0000", CultureInfo.InvariantCulture); } // Refresh UI: Update_GridView(CadData_GridView); // For debug, compare fiducials true measured locations and the locations. // Also, if a fiducials moves more than 0.5mm, something is off (maybe there // was a via too close to a fid, and we picked that for a measurement). Warn the user! bool DataOk = true; double dx, dy; for (int i = 0; i < Fiducials.Length; i++) { Loc.X = Fiducials[i].X_nominal; Loc.Y = Fiducials[i].Y_nominal; Loc.W = 1.0; Loc = transform.TransformPoint(Loc); Loc = Loc.NormalizeHomogeneous(); dx = Math.Abs(Loc.X - Fiducials[i].X_machine); dy = Math.Abs(Loc.Y - Fiducials[i].Y_machine); DisplayText(Fiducials[i].Designator + ": x_meas= " + Fiducials[i].X_machine.ToString("0.000", CultureInfo.InvariantCulture) + ", x_calc= " + Loc.X.ToString("0.000", CultureInfo.InvariantCulture) + ", dx= " + dx.ToString("0.000", CultureInfo.InvariantCulture) + ": y_meas= " + Fiducials[i].Y_machine.ToString("0.000", CultureInfo.InvariantCulture) + ", y_calc= " + Loc.Y.ToString("0.000", CultureInfo.InvariantCulture) + ", dy= " + dy.ToString("0.000", CultureInfo.InvariantCulture)); if ((Math.Abs(dx) > 0.4) || (Math.Abs(dy) > 0.4)) { DataOk = false; } }; if (!DataOk) { DisplayText(" ** A fiducial moved more than 0.4mm from its measured location"); DisplayText(" ** when applied the same calculations than regular componets."); DisplayText(" ** (Maybe the camera picked a via instead of a fiducial?)"); DisplayText(" ** Placement data is likely not good."); DialogResult dialogResult = ShowMessageBox( "Nominal to machine trasnformation seems to be off. (See log window)", "Cancel operation?", MessageBoxButtons.OKCancel ); if (dialogResult == DialogResult.Cancel) { return false; } } // Done! ValidMeasurement_checkBox.Checked = true; return true; }// end BuildMachineCoordinateData_m