The Higher Education and Research forge

Home My Page Projects Code Snippets Project Openings Complex Surface Machining Optimization
Summary Activity SCM

SCM Repository

authorJean-Max Redonnet <jean-max.redonnet@unniv-tlse3.fr>
Fri, 22 May 2020 16:46:34 +0000 (18:46 +0200)
committerJean-Max Redonnet <jean-max.redonnet@unniv-tlse3.fr>
Fri, 22 May 2020 16:46:34 +0000 (18:46 +0200)
Still WIP

src/org/ica/cosmo/experiments/MachiningIsoScallopTest.java [new file with mode: 0644]
src/org/ica/cosmo/machining/ZoneMilling_IsoScallop3A.java [new file with mode: 0644]

diff --git a/src/org/ica/cosmo/experiments/MachiningIsoScallopTest.java b/src/org/ica/cosmo/experiments/MachiningIsoScallopTest.java
new file mode 100644 (file)
index 0000000..4eddfc6
--- /dev/null
@@ -0,0 +1,122 @@
+package org.ica.cosmo.experiments;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.ArrayList;
+
+import org.ica.cosmo.clustering.ALGO_TYPE;
+import org.ica.cosmo.clustering.Clustering;
+import org.ica.cosmo.clustering.METRIC;
+import org.ica.cosmo.demos.SurfaceBuilder;
+import org.ica.cosmo.machining.MillingContext;
+import org.ica.cosmo.machining.ZoneMilling_IsoScallop3A;
+import org.ica.cosmo.zoning.SurfaceMap;
+import org.ica.cosmo.zoning.Zone;
+import org.ica.vtkviewer.VtkViewer;
+import org.ica.vtkviewer.model.Color4d;
+import org.ica.vtkviewer.model.VtkModel;
+import org.ica.vtkviewer.model.VtkSurfaceMap;
+import org.ica.vtkviewer.model.VtkToolpath;
+import org.lgmt.dgl.surfaces.Surface;
+import org.lgmt.dgl.surfaces.SurfacePoint;
+import org.lgmt.dgl.vecmath.Point3d;
+import org.lgmt.jcam.cutter.Cutter;
+import org.lgmt.jcam.toolpath.Toolpath;
+
+import vtk.vtkNativeLibrary;
+
+public class MachiningIsoScallopTest implements PropertyChangeListener {
+       static {
+               if (!vtkNativeLibrary.LoadAllNativeLibraries()) {
+                       for (vtkNativeLibrary lib : vtkNativeLibrary.values()) {
+                               if (!lib.IsLoaded()) {
+                                       System.out.println(lib.GetLibraryName() + " not loaded");
+                               }
+                       }
+               }
+               vtkNativeLibrary.DisableOutputWindow(null);
+       }
+
+       /** méthode de clustering à utiliser */
+       private ALGO_TYPE algo_type = ALGO_TYPE.KMEANS;
+
+       /** métrique */
+       private METRIC metric = METRIC.SLOPE;
+
+       /** surface */
+       private Surface surface;
+
+       /** tessellation */
+       private int tessU = 80;
+       private int tessV = 80;
+
+       /** nombre de zones */
+       private int k = 3;
+
+       VtkModel model;
+       
+       /** main program */
+       public static void main(String[] args) {
+               new MachiningIsoScallopTest();
+       }
+
+       public MachiningIsoScallopTest() {
+               super();
+               MillingContext.getInstance().setCutter(new Cutter(5.0, 2.0, 100.0));
+               MillingContext.getInstance().setScallopHeight(0.1);
+               MillingContext.getInstance().setPasLongitudinal(1.0);
+               this.surface = SurfaceBuilder.getTile();
+               
+
+               SurfaceMap map = new SurfaceMap(surface, tessU, tessV);
+               Clustering c = new Clustering(k, map, algo_type, metric, true);
+               c.run();
+               try {
+                       map = c.call();
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+               k = c.getCentroids().length;
+               
+               model = new VtkModel();
+               model.add(new VtkSurfaceMap(map));
+               VtkViewer viewer = new VtkViewer(model, "Machining Demo");
+               viewer.run();
+
+               ArrayList<ZoneMilling_IsoScallop3A> zma = new ArrayList<ZoneMilling_IsoScallop3A>(k);
+//             double totalLength = 0.0;
+//             double totalTime = 0.0;
+//             long start_time = System.currentTimeMillis();
+               for (int zj = 0; zj < k; zj++) {
+                       System.out.println("Milling zone " + zj);
+                       Zone z = map.getZone(zj);
+                       SurfacePoint center = z.getCenter(); 
+                       ZoneMilling_IsoScallop3A zMilling = new ZoneMilling_IsoScallop3A(z, center, true);
+                       zMilling.addPropertyChangeListener(this);
+                       zma.add(zMilling);
+                       zMilling.run();
+
+//                     totalTime = totalTime + zMilling.getMillingTimeApprox();
+//                     totalLength = totalLength + zMilling.getToolPathApproxLength();
+//                     System.out.println("longueur d'usinage de la zone = " + zMilling.getToolPathApproxLength());
+//                     System.out.println("durée d'usinage de la zone = " + zMilling.getMillingTimeApprox() + " s");
+
+               }
+//             long end_time = System.currentTimeMillis();
+//             long sim_duration = end_time - start_time;
+//
+//             System.out.println("durée de simulation de l'usinage = " + sim_duration + " ms");
+//             System.out.println("longueur de trajectoire d'usinage = " + totalLength);
+//             System.out.println("durée de l'usinage = " + totalTime + " s");
+
+       }
+
+       @Override
+       public void propertyChange(PropertyChangeEvent event) {
+               if (event.getPropertyName() == "NewToolpath") {
+                       Toolpath<? extends Point3d> traj = (Toolpath<?>)event.getNewValue();
+                       model.add(new VtkToolpath(traj, 4.0, new Color4d(1.0, 1.0, 0.0)));
+               }
+       }
+
+}
diff --git a/src/org/ica/cosmo/machining/ZoneMilling_IsoScallop3A.java b/src/org/ica/cosmo/machining/ZoneMilling_IsoScallop3A.java
new file mode 100644 (file)
index 0000000..ff74577
--- /dev/null
@@ -0,0 +1,446 @@
+package org.ica.cosmo.machining;
+
+import static java.lang.Math.abs;
+import static java.lang.Math.atan;
+import static java.lang.Math.cos;
+import static java.lang.Math.pow;
+import static java.lang.Math.sqrt;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+
+import org.ica.cosmo.zoning.UVMeshUnit;
+import org.ica.cosmo.zoning.Zone;
+import org.lgmt.dgl.commons.Util;
+import org.lgmt.dgl.functions.BivarFunction;
+import org.lgmt.dgl.functions.MultivarEvaluable;
+import org.lgmt.dgl.functions.MultivarFunction;
+import org.lgmt.dgl.optimization.NewtonSolver;
+import org.lgmt.dgl.optimization.Status;
+import org.lgmt.dgl.surfaces.Surface;
+import org.lgmt.dgl.surfaces.SurfacePoint;
+import org.lgmt.dgl.vecmath.GVector;
+import org.lgmt.dgl.vecmath.Point3d;
+import org.lgmt.dgl.vecmath.Vector2d;
+import org.lgmt.dgl.vecmath.Vector3d;
+import org.lgmt.dgl.vecmath.Vectors;
+import org.lgmt.jcam.part.CLSurface;
+import org.lgmt.jcam.toolpath.Toolpath;
+
+public class ZoneMilling_IsoScallop3A extends AbstractZoneMilling {
+       private enum DIR {
+               FW(1.0), BW(-1.0);
+
+               private final double value;
+
+               private DIR(double value) {
+                       this.value = value;
+               }
+       };
+
+       private enum SIDE {
+               LEFT(1.0), RIGHT(-1.0);
+
+               private final double value;
+
+               private SIDE(double value) {
+                       this.value = value;
+               }
+       };
+
+       /** The first point of the first toolpath */
+       private SurfacePoint startP;
+
+       /** The first point of the last computed toolpath */
+       private SurfacePoint initP;
+       /** The first vector of the last computed toolpath */
+       private Vector3d initV;
+
+       /** le gestionnaire de listeners pour cette opération d'usinage */
+       protected final PropertyChangeSupport support = new PropertyChangeSupport(this);
+
+       /** liste des mailles de la zone */
+       private ArrayList<UVMeshUnit> meshList = new ArrayList<UVMeshUnit>();
+
+       /** surface centre-outil dans le repère global */
+       private Surface CLSurf;
+
+       public ZoneMilling_IsoScallop3A(Zone zone, SurfacePoint start, boolean clSurf) {
+               super(zone);
+               this.startP = start;
+
+               if (clSurf) {
+                       this.CLSurf = this.surface;
+               } else {
+                       this.CLSurf = new CLSurface(surface, cutter);
+               }
+
+               for (UVMeshUnit m : zone.getMeshmap().values()) {
+                       meshList.add(new UVMeshUnit(CLSurf, m.getIndex(), m.getUmin(), m.getUmax(), m.getVmin(), m.getVmax()));
+               }
+       }
+
+       @Override
+       public void run() {
+               Toolpath<SurfacePoint> lastToolpath = null;
+               Toolpath<SurfacePoint> nextToolpath = null;
+
+               Toolpath<SurfacePoint> firstTraj = calc1stPath();
+               if (firstTraj != null) {
+//                     System.out.println(firstTraj.toString());
+                       finalizeToolpath(firstTraj);
+                       lastToolpath = firstTraj;
+                       nextToolpath = firstTraj; // to be sure entering the while
+               } else {
+                       System.err.println("Cannot compute first traj. Aborting...");
+                       return;
+               }
+
+               for (SIDE side : SIDE.values()) {
+                       while (nextToolpath != null) {
+                               double sod = calcSOD(initP, initV);
+                               Vector3d sideV = Vectors.cross(new Vector3d(0.0, 0.0, 1.0), initV);
+                               sideV.normalize();
+                               sideV.scale(side.value * sod);
+                               Point3d ptmp = new Point3d(initP);
+                               ptmp.add(sideV);
+                               SurfacePoint p = CLSurf.getNormalPointProjection(ptmp, initP.u, initP.v);
+                               if (p != null)
+                                       nextToolpath = calcToolpath(p, lastToolpath, side);
+                               else
+                                       nextToolpath = null;
+                               if (nextToolpath != null) {
+                                       finalizeToolpath(nextToolpath);
+                                       lastToolpath = nextToolpath;
+                               }
+                       }
+                       // preparing the side change
+                       lastToolpath = firstTraj;
+                       nextToolpath = firstTraj; // to be sure entering the while
+                       initP = firstTraj.get(firstTraj.getNbPoints() / 2);
+                       initV = new Vector3d(initP, firstTraj.get(firstTraj.getNbPoints() / 2 + 1));
+               }
+       }
+
+       private Toolpath<SurfacePoint> initToolpath(SurfacePoint start, SurfacePoint end) {
+               Toolpath<SurfacePoint> tp = new Toolpath<SurfacePoint>(start, end);
+               support.firePropertyChange("NewToolpath", null, tp);
+               for (PropertyChangeListener pcl : support.getPropertyChangeListeners()) {
+                       tp.addPropertyChangeListener(pcl);
+               }
+               return tp;
+       }
+
+       private void finalizeToolpath(Toolpath<SurfacePoint> tp) {
+               toolPathSet.add(tp);
+               initP = tp.get(tp.getNbPoints() / 2);
+               initV = new Vector3d(initP, tp.get(tp.getNbPoints() / 2 + 1));
+       }
+
+       private Toolpath<SurfacePoint> calc1stPath() {
+               Toolpath<SurfacePoint> tp = null;
+               SurfacePoint nextP = null;
+
+               DIR initDir = DIR.FW;
+               nextP = this.calcNextPointSSD(initDir, startP);
+               if (nextP == null) {
+                       initDir = DIR.BW;
+                       nextP = this.calcNextPointSSD(initDir, startP);
+               }
+               if (nextP == null) {
+                       System.err.println("Toolpath calculation cannot start: no point found");
+                       return null;
+               }
+
+               if (initDir == DIR.FW)
+                       tp = initToolpath(startP, nextP);
+               if (initDir == DIR.BW)
+                       tp = initToolpath(nextP, startP);
+
+               propagatePath(DIR.FW, tp, null);
+               propagatePath(DIR.BW, tp, null);
+
+               return tp;
+       }
+
+       private Toolpath<SurfacePoint> calcToolpath(SurfacePoint p, Toolpath<SurfacePoint> lastToolPath, SIDE side) {
+               Toolpath<SurfacePoint> tp = null;
+               SurfacePoint nextP = null;
+               SurfacePoint p0 = p; // this toolpath starting point
+               SurfacePoint lastP = new SurfacePoint(p0);
+
+               DIR initDir = DIR.FW;
+               nextP = this.calcNextPointSH(initDir, lastP, lastToolPath);
+               if (nextP == null) {
+                       initDir = DIR.BW;
+                       nextP = this.calcNextPointSH(initDir, lastP, lastToolPath);
+               }
+               if (nextP == null) {
+                       System.err.println("Toolpath calculation cannot start: no point found");
+                       return null;
+               }
+
+               if (initDir == DIR.FW)
+                       tp = initToolpath(p0, nextP);
+               if (initDir == DIR.BW)
+                       tp = initToolpath(nextP, p0);
+
+               propagatePath(DIR.FW, tp, lastToolPath);
+               propagatePath(DIR.BW, tp, lastToolPath);
+
+               return tp;
+       }
+
+       private void propagatePath(DIR dir, Toolpath<SurfacePoint> tp, Toolpath<SurfacePoint> sidePath) {
+               SurfacePoint lastP = null;
+               if (dir == DIR.FW)
+                       lastP = new SurfacePoint(tp.getLast());
+               if (dir == DIR.BW)
+                       lastP = new SurfacePoint(tp.getFirst());
+               SurfacePoint nextP = new SurfacePoint();
+               while (nextP != null) {
+                       nextP = calcNextPoint(dir, lastP, sidePath);
+                       if (nextP != null) {
+                               if (dir == DIR.FW)
+                                       tp.append(new SurfacePoint(nextP));
+                               if (dir == DIR.BW)
+                                       tp.prepend(new SurfacePoint(nextP));
+                               lastP = nextP;
+                       }
+               }
+       }
+
+       private SurfacePoint calcNextPoint(DIR dir, SurfacePoint lastP, Toolpath<SurfacePoint> lastToolPath) {
+               SurfacePoint nextP = null;
+
+               if (lastToolPath == null) {
+                       nextP = calcNextPointSSD(dir, lastP);
+                       return nextP;
+               }
+
+               nextP = calcNextPointSH(dir, lastP, lastToolPath);
+               if (nextP == null)
+                       nextP = calcNextPointSSD(dir, lastP);
+
+               return nextP;
+       }
+
+       /**
+        * Calcule le point suivant dans la direction de plus grande pente
+        * 
+        * @param dir
+        * @param point
+        * @return
+        */
+       private SurfacePoint calcNextPointSSD(DIR dir, SurfacePoint point) {
+               double u = point.u;
+               double v = point.v;
+               double sfd = MillingContext.getInstance().getPasLongitudinal();
+
+               Vector3d n = CLSurf.normal(u, v);
+               Vector3d slopeDir = new Vector3d(n.x, n.y, 0.0); // direction de plus grande pente
+               slopeDir.scale(dir.value);
+
+               Vector3d vdir = Vectors.cross(n, Vectors.cross(n, slopeDir));
+               vdir.normalize();
+               vdir.scale(sfd);
+
+               Point3d p = new Point3d(point);
+               p.add(vdir);
+
+               SurfacePoint nextP = CLSurf.getNormalPointProjection(p, u, v);
+
+               if (nextP != null)
+                       if (zone.includes(nextP.u, nextP.v))
+                               return nextP;
+               return null;
+       }
+
+       private SurfacePoint calcNextPointSH(DIR dir, SurfacePoint lastP, Toolpath<SurfacePoint> lastToolPath) {
+               int i = 1;
+               double dotprod = -1.0;
+               Toolpath<SurfacePoint> ltp = lastToolPath;
+               while (dotprod < 0.0 && i < ltp.getNbPoints()) {
+                       dotprod = Vectors.dot(new Vector3d(ltp.get(i - 1), ltp.get(i)), new Vector3d(lastP, ltp.get(i)));
+                       i++;
+               }
+               if (dotprod < 0.0)
+                       return null;
+
+               int startIndex = i - 1;
+               SurfacePoint pi0 = ltp.get(startIndex); // p(i)
+               SurfacePoint pi1 = null;
+               Vector3d vref = null;
+               if (dir == DIR.FW) {
+                       if (startIndex + 1 >= ltp.getNbPoints())
+                               return null;
+                       pi1 = ltp.get(startIndex + 1); // p(i+1)
+                       vref = new Vector3d(pi0, pi1);
+               }
+               if (dir == DIR.BW) {
+                       if (startIndex - 1 <= 0)
+                               return null;
+                       pi1 = ltp.get(startIndex - 1); // p(i-1)
+                       vref = new Vector3d(pi1, pi0);
+               }
+
+               double u0 = lastP.u + (pi1.u - pi0.u);
+               double v0 = lastP.v + (pi1.v - pi0.v);
+
+               SurfacePoint nextP = null;
+               nextP = solveIsoScallop(pi0, lastP, vref, u0, v0);
+
+               if (nextP != null && zone.includes(nextP.u, nextP.v))
+                       return nextP;
+               return null;
+
+       }
+
+       /**
+        * 
+        * @param p    le point de référence sur la traj adjacente
+        * @param q    le point extrême (premier ou dernier) de la traj en cours
+        * @param vref le vecteur de référence sur la traj adjacente
+        * @param u0   point de départ
+        * @param v0   point de départ
+        * @return un point appratenant à la surface ou null
+        */
+       private SurfacePoint solveIsoScallop(SurfacePoint p, SurfacePoint q, Vector3d vref, double u0, double v0) {
+               double sfd = MillingContext.getInstance().getPasLongitudinal();
+               double sod = calcSOD(q, vref);
+
+               // Var vector : [u, v, k]
+               final BivarFunction fx = CLSurf.getV3f().getFx();
+               final BivarFunction fy = CLSurf.getV3f().getFy();
+               final BivarFunction fz = CLSurf.getV3f().getFz();
+               MultivarFunction f1 = new MultivarFunction(3, new MultivarEvaluable() {
+                       @Override
+                       public double eval(GVector v) {
+                               return pow(fx.eval(v.get(0), v.get(1)) - q.x, 2) + pow(fy.eval(v.get(0), v.get(1)) - q.y, 2)
+                                               + pow(fz.eval(v.get(0), v.get(1)) - q.z, 2) - pow(sfd, 2);
+                       }
+               });
+               MultivarFunction f2 = new MultivarFunction(3, new MultivarEvaluable() {
+                       @Override
+                       public double eval(GVector v) {
+                               return vref.x * (fx.eval(v.get(0), v.get(1)) - v.get(2) * vref.x - p.x)
+                                               + vref.y * (fy.eval(v.get(0), v.get(1)) - v.get(2) * vref.y - p.y)
+                                               + vref.z * (fz.eval(v.get(0), v.get(1)) - v.get(2) * vref.z - p.z);
+                       }
+               });
+               MultivarFunction f3 = new MultivarFunction(3, new MultivarEvaluable() {
+                       @Override
+                       public double eval(GVector v) {
+                               return pow(fx.eval(v.get(0), v.get(1)) - v.get(2) * vref.x - p.x, 2)
+                                               + pow(fy.eval(v.get(0), v.get(1)) - v.get(2) * vref.y - p.y, 2)
+                                               + pow(fz.eval(v.get(0), v.get(1)) - v.get(2) * vref.z - p.z, 2) - pow(sod, 2);
+                       }
+               });
+               List<MultivarFunction> functions = new ArrayList<MultivarFunction>();
+               functions.add(f1);
+               functions.add(f2);
+               functions.add(f3);
+               NewtonSolver solver = new NewtonSolver(functions, 10);
+               solver.setLogging(true);
+               solver.setLogLevel(Level.FINE);
+               solver.init(new GVector(new double[] { u0, v0, 0.5 }));
+
+               SurfacePoint nextP = null;
+               if (solver.run() == Status.TOL_REACHED && CLSurf.isDefinedFor(solver.getVar().get(0), solver.getVar().get(1))) {
+                       if (solver.getVar().get(2) < 0 || solver.getVar().get(2) > 1)
+                               System.err.println("Warning k outside [0;1]");
+                       nextP = new SurfacePoint(CLSurf, solver.getVar().get(0), solver.getVar().get(1));
+               }
+               return nextP;
+       }
+
+       /**
+        * Calcule le pas transversal en un point donné.
+        * 
+        * Le pas transversale est calculé en p dans la direction perpendiculaire au
+        * vecteur v et du côté défini par side.
+        * 
+        * @param p
+        * @param v
+        * @param side
+        * 
+        * @return la valeur du pas transversal
+        */
+       private double calcSOD(SurfacePoint p, Vector3d vf) {
+               double sod = cutter.getRadius(); // le pas transversal à calculer, initialisé au max
+               double reff; // le rayon effectif
+               double d; // la distance entre les centreReff
+
+               double gamma;
+               reff = calcReffAt(p, vf);
+               // dans un premier temps, on néglige la courbure de la surface
+               // pour calculer la distance entre les deux centres Reff
+               d = 2 * sqrt(2 * reff * sh - sh * sh);
+               double u = p.u;
+               double v = p.v;
+               Vector3d n = CLSurf.normal(u, v);
+               gamma = atan(sqrt(n.x * n.x + n.y * n.y) / n.z);
+
+               // atan impaire => gamma peut être > 0 ou < 0, ce n'est pas grave puisqu'on
+               // n'utilise que le cosinus
+               sod = d * cos(gamma);
+
+               return sod;
+       }
+
+       private double calcReffAt(SurfacePoint p, Vector3d vf) {
+               double u = p.u;
+               double v = p.v;
+
+               Vector3d n = CLSurf.normal(u, v);
+
+               // Pente maxi
+               double S = abs(Util.angle0(n, new Vector3d(0.0, 0.0, 1.0)));
+
+               double R = cutter.getRadius();
+               double r = cutter.getTipRadius();
+
+               // Direction de plus grande pente
+               Vector2d maxSlopeDirection = new Vector2d(n.x, n.y);
+               if (n.y < 0) // TODO: check me!
+                       maxSlopeDirection.scale(-1.0);
+
+               // Direction d'usinage
+               Vector2d vfDirection = new Vector2d(vf.x, vf.y); // TODO: check my sign!
+
+               // alpha est l'angle entre la direction de plus grande pente et la
+               // direction d'usinage.
+               double alpha = maxSlopeDirection.angle(vfDirection);
+
+               double reff = ((R - r) * Math.pow(Math.cos(alpha), 2))
+                               / (Math.sin(S) * (1 - Math.pow(Math.sin(S), 2) * Math.pow(Math.sin(alpha), 2))) + r;
+
+               return reff;
+       }
+
+       /**
+        * Observer design pattern implementation.
+        * 
+        * Add a listener
+        * 
+        * @param listener
+        */
+       public void addPropertyChangeListener(PropertyChangeListener listener) {
+               this.support.addPropertyChangeListener(listener);
+       }
+
+       /**
+        * Observer design pattern implementation.
+        * 
+        * Remove a listener
+        * 
+        * @param listener
+        */
+       public void removePropertyChangeListener(PropertyChangeListener listener) {
+               this.support.removePropertyChangeListener(listener);
+       }
+
+}