diff --git a/Marlin/UBL.h b/Marlin/UBL.h
index ffb96a9f6fbfcbead2a8a7aba1a22906fe869401..51f58e235d1362040332a55fea0782cfb69b021a 100644
--- a/Marlin/UBL.h
+++ b/Marlin/UBL.h
@@ -42,13 +42,13 @@
     bool axis_unhomed_error(bool, bool, bool);
     void dump(char * const str, const float &f);
     bool ubl_lcd_clicked();
-    void probe_entire_mesh(const float&, const float&, const bool, const bool);
+    void probe_entire_mesh(const float&, const float&, const bool, const bool, const bool);
     void debug_current_and_destination(char *title);
     void ubl_line_to_destination(const float&, const float&, const float&, const float&, const float&, uint8_t);
     void manually_probe_remaining_mesh(const float&, const float&, const float&, const float&, const bool);
     vector_3 tilt_mesh_based_on_3pts(const float&, const float&, const float&);
     float measure_business_card_thickness(const float&);
-    mesh_index_pair find_closest_mesh_point_of_type(const MeshPointType, const float&, const float&, const bool, unsigned int[16]);
+    mesh_index_pair find_closest_mesh_point_of_type(const MeshPointType, const float&, const float&, const bool, unsigned int[16], bool);
     void find_mean_mesh_height();
     void shift_mesh_height();
     bool g29_parameter_parsing();
diff --git a/Marlin/UBL_Bed_Leveling.cpp b/Marlin/UBL_Bed_Leveling.cpp
index 55f7a6d43bf86b37ae62e0988c70d722a5815061..83a0b2e47eaa17e9078986671413fa2f35d4e10e 100644
--- a/Marlin/UBL_Bed_Leveling.cpp
+++ b/Marlin/UBL_Bed_Leveling.cpp
@@ -166,32 +166,34 @@
     int8_t i, j;
     UNUSED(map_type);
 
-    SERIAL_PROTOCOLLNPGM("\nBed Topography Report:\n");
+    if (map_type==0) {
+      SERIAL_PROTOCOLLNPGM("\nBed Topography Report:\n");
 
-    SERIAL_ECHOPAIR("(", 0);
-    SERIAL_ECHOPAIR(", ", UBL_MESH_NUM_Y_POINTS - 1);
-    SERIAL_ECHOPGM(")    ");
+      SERIAL_ECHOPAIR("(", 0);
+      SERIAL_ECHOPAIR(", ", UBL_MESH_NUM_Y_POINTS - 1);
+      SERIAL_ECHOPGM(")    ");
+    }
 
     current_xi = ubl.get_cell_index_x(current_position[X_AXIS] + (MESH_X_DIST) / 2.0);
     current_yi = ubl.get_cell_index_y(current_position[Y_AXIS] + (MESH_Y_DIST) / 2.0);
 
-    for (i = 0; i < UBL_MESH_NUM_X_POINTS - 1; i++) {
-      SERIAL_ECHOPGM("            ");
-      #if TX_BUFFER_SIZE>0
-        MYSERIAL.flushTX();
-      #endif
-      delay(15);
-    }
-
-    SERIAL_ECHOPAIR("(", UBL_MESH_NUM_X_POINTS - 1);
-    SERIAL_ECHOPAIR(",", UBL_MESH_NUM_Y_POINTS - 1);
-    SERIAL_ECHOLNPGM(")");
-
-    //  if (map_type || 1) {
+    if (map_type==0) {
+      for (i = 0; i < UBL_MESH_NUM_X_POINTS - 1; i++) {
+        SERIAL_ECHOPGM("            ");
+        #if TX_BUFFER_SIZE>0
+          MYSERIAL.flushTX();
+        #endif
+        delay(15);
+      }
+      
+      SERIAL_ECHOPAIR("(", UBL_MESH_NUM_X_POINTS - 1);
+      SERIAL_ECHOPAIR(",", UBL_MESH_NUM_Y_POINTS - 1);
+      SERIAL_ECHOLNPGM(")");
 
       SERIAL_ECHOPAIR("(", UBL_MESH_MIN_X);
       SERIAL_ECHOPAIR(",", UBL_MESH_MAX_Y);
       SERIAL_CHAR(')');
+      delay(15);
 
       for (i = 0; i < UBL_MESH_NUM_X_POINTS - 1; i++) {
         SERIAL_ECHOPGM("            ");
@@ -204,75 +206,82 @@
       SERIAL_ECHOPAIR("(", UBL_MESH_MAX_X);
       SERIAL_ECHOPAIR(",", UBL_MESH_MAX_Y);
       SERIAL_ECHOLNPGM(")");
-
-    //  }
+      delay(15);
+    }
 
     for (j = UBL_MESH_NUM_Y_POINTS - 1; j >= 0; j--) {
       for (i = 0; i < UBL_MESH_NUM_X_POINTS; i++) {
         f = z_values[i][j];
 
         // is the nozzle here?  if so, mark the number
-        SERIAL_CHAR(i == current_xi && j == current_yi ? '[' : ' ');
+        if (map_type==0) 
+          SERIAL_CHAR(i == current_xi && j == current_yi ? '[' : ' ');
 
         if (isnan(f))
-          SERIAL_PROTOCOLPGM("    .    ");
+          if (map_type==0) {
+            SERIAL_PROTOCOLPGM("    .    ");
+          } else 
+            SERIAL_PROTOCOLPGM("NAN");
         else {
           // if we don't do this, the columns won't line up nicely
-          if (f >= 0.0) SERIAL_CHAR(' ');
+          if (f>=0.0 && map_type==0) SERIAL_CHAR(' ');
           SERIAL_PROTOCOL_F(f, 3);
           idle();
         }
+        if (map_type!=0 && i<UBL_MESH_NUM_X_POINTS-1) 
+         SERIAL_PROTOCOLPGM(",");
+
         #if TX_BUFFER_SIZE>0
           MYSERIAL.flushTX();
         #endif
         delay(15);
-        if (i == current_xi && j == current_yi) // is the nozzle here? if so, finish marking the number
-          SERIAL_CHAR(']');
-        else
-          SERIAL_PROTOCOL("  ");
-
-        SERIAL_CHAR(' ');
+        if (map_type==0) {
+          if (i == current_xi && j == current_yi) // is the nozzle here? if so, finish marking the number
+            SERIAL_CHAR(']');
+          else
+            SERIAL_PROTOCOL("  ");
+          SERIAL_CHAR(' ');
+        }
       }
       SERIAL_EOL;
-      if (j) { // we want the (0,0) up tight against the block of numbers
+      if (j && map_type==0) { // we want the (0,0) up tight against the block of numbers
         SERIAL_CHAR(' ');
         SERIAL_EOL;
       }
     }
 
-    //  if (map_type) {
-    SERIAL_ECHOPAIR("(", int(UBL_MESH_MIN_X));
-    SERIAL_ECHOPAIR(",", int(UBL_MESH_MIN_Y));
-    SERIAL_ECHOPGM(")    ");
+    if (map_type==0) {
+      SERIAL_ECHOPAIR("(", int(UBL_MESH_MIN_X));
+      SERIAL_ECHOPAIR(",", int(UBL_MESH_MIN_Y));
+      SERIAL_ECHOPGM(")    ");
 
-    for (i = 0; i < UBL_MESH_NUM_X_POINTS - 1; i++)  {
-      SERIAL_ECHOPGM("            ");
-      #if TX_BUFFER_SIZE>0
-        MYSERIAL.flushTX();
-      #endif
-      delay(15);
-    }
-
-    SERIAL_ECHOPAIR("(", int(UBL_MESH_MAX_X));
-    SERIAL_ECHOPAIR(",", int(UBL_MESH_MIN_Y));
-    SERIAL_CHAR(')');
-    SERIAL_EOL;
+      for (i = 0; i < UBL_MESH_NUM_X_POINTS - 1; i++)  {
+        SERIAL_ECHOPGM("            ");
+        #if TX_BUFFER_SIZE>0
+          MYSERIAL.flushTX();
+        #endif
+        delay(15);
+      }
+      SERIAL_ECHOPAIR("(", int(UBL_MESH_MAX_X));
+      SERIAL_ECHOPAIR(",", int(UBL_MESH_MIN_Y));
+      SERIAL_CHAR(')');
+      SERIAL_EOL;
 
-    SERIAL_ECHOPAIR("(", 0);
-    SERIAL_ECHOPAIR(",", 0);
-    SERIAL_ECHOPGM(")       ");
+      SERIAL_ECHOPAIR("(", 0);
+      SERIAL_ECHOPAIR(",", 0);
+      SERIAL_ECHOPGM(")       ");
 
-    for (i = 0; i < UBL_MESH_NUM_X_POINTS - 1; i++) {
-      SERIAL_ECHOPGM("            ");
-      #if TX_BUFFER_SIZE>0
-        MYSERIAL.flushTX();
-      #endif
-      delay(15);
+      for (i = 0; i < UBL_MESH_NUM_X_POINTS - 1; i++) {
+        SERIAL_ECHOPGM("            ");
+        #if TX_BUFFER_SIZE>0
+          MYSERIAL.flushTX();
+        #endif
+        delay(15);
+      }
+      SERIAL_ECHOPAIR("(", UBL_MESH_NUM_X_POINTS-1);
+      SERIAL_ECHOPAIR(",", 0);
+      SERIAL_ECHOLNPGM(")");
     }
-
-    SERIAL_ECHOPAIR("(", UBL_MESH_NUM_X_POINTS-1);
-    SERIAL_ECHOPAIR(",", 0);
-    SERIAL_ECHOLNPGM(")");
   }
 
   bool unified_bed_leveling::sanity_check() {
diff --git a/Marlin/UBL_G29.cpp b/Marlin/UBL_G29.cpp
index 026045a7bc260052331b57aaec3c2fbf54296e6e..f582bc408d971dcc0a16cc424a64cef5b6e5144d 100644
--- a/Marlin/UBL_G29.cpp
+++ b/Marlin/UBL_G29.cpp
@@ -125,7 +125,10 @@
    *   O     Map   *    Display the Mesh Map Topology.
    *                    The parameter can be specified alone (ie. G29 O) or in combination with many of the
    *                    other commands. The Mesh Map option works with all of the Phase
-   *                    commands (ie. G29 P4 R 5 X 50 Y100 C -.1 O)
+   *                    commands (ie. G29 P4 R 5 X 50 Y100 C -.1 O)  The Map parameter can also of a Map Type
+   *                    specified.  A map type of 0 is the default is user readable.   A map type of 1 can
+   *                    be specified and is suitable to Cut & Paste into Excel to allow graphing of the user's
+   *                    mesh.
    *
    *   N    No Home     G29 normally insists that a G28 has been performed. You can over rule this with an
    *                    N option. In general, you should not do this. This can only be done safely with
@@ -250,6 +253,10 @@
    *
    *   T     3-Point    Perform a 3 Point Bed Leveling on the current Mesh
    *
+   *   U     Unlevel    Perform a probe of the outer perimeter to assist in physically leveling unlevel beds.
+   *                    Only used for G29 P1 O U   It will speed up the probing of the edge of the bed.  This
+   *                    is useful when the entire bed does not need to be probed because it will be adjusted.
+   *
    *   W     What?      Display valuable data the Unified Bed Leveling System knows.
    *
    *   X #   *      *   X Location for this line of commands
@@ -297,7 +304,7 @@
 
   // The simple parameter flags and values are 'static' so parameter parsing can be in a support routine.
   static int g29_verbose_level = 0, phase_value = -1, repetition_cnt = 1,
-             storage_slot = 0, test_pattern = 0;
+             storage_slot = 0, map_type = 0, test_pattern = 0, unlevel_value = -1;
   static bool repeat_flag = UBL_OK, c_flag = false, x_flag = UBL_OK, y_flag = UBL_OK, statistics_flag = UBL_OK, business_card_mode = false;
   static float x_pos = 0.0, y_pos = 0.0, height_value = 5.0, measured_z, card_thickness = 0.0, constant = 0.0;
 
@@ -331,7 +338,7 @@
     if (code_seen('I')) {
       repetition_cnt = code_has_value() ? code_value_int() : 1;
       while (repetition_cnt--) {
-        const mesh_index_pair location = find_closest_mesh_point_of_type(REAL, x_pos, y_pos, 0, NULL);  // The '0' says we want to use the nozzle's position
+        const mesh_index_pair location = find_closest_mesh_point_of_type(REAL, x_pos, y_pos, 0, NULL, false);  // The '0' says we want to use the nozzle's position
         if (location.x_index < 0) {
           SERIAL_PROTOCOLLNPGM("Entire Mesh invalidated.\n");
           break;            // No more invalid Mesh Points to populate
@@ -381,6 +388,16 @@
       }
     }
 
+/*
+    if (code_seen('U')) {
+      unlevel_value = code_value_int();
+//    if (unlevel_value < 0 || unlevel_value > 7) {
+//      SERIAL_PROTOCOLLNPGM("Invalid Unlevel value. (0-4)\n");
+//      return;
+//    }
+    }
+*/
+
     if (code_seen('P')) {
       phase_value = code_value_int();
       if (phase_value < 0 || phase_value > 7) {
@@ -410,7 +427,7 @@
             SERIAL_PROTOCOLLNPGM(")\n");
           }
           probe_entire_mesh(x_pos + X_PROBE_OFFSET_FROM_EXTRUDER, y_pos + Y_PROBE_OFFSET_FROM_EXTRUDER,
-                            code_seen('O') || code_seen('M'), code_seen('E'));
+                            code_seen('O') || code_seen('M'), code_seen('E'), code_seen('U'));
           break;
         //
         // Manually Probe Mesh in areas that can not be reached by the probe
@@ -455,7 +472,7 @@
           // If no repetition is specified, do the whole Mesh
           if (!repeat_flag) repetition_cnt = 9999;
           while (repetition_cnt--) {
-            const mesh_index_pair location = find_closest_mesh_point_of_type(INVALID, x_pos, y_pos, 0, NULL); // The '0' says we want to use the nozzle's position
+            const mesh_index_pair location = find_closest_mesh_point_of_type(INVALID, x_pos, y_pos, 0, NULL, false); // The '0' says we want to use the nozzle's position
             if (location.x_index < 0) break; // No more invalid Mesh Points to populate
             z_values[location.x_index][location.y_index] = height_value;
           }
@@ -700,7 +717,7 @@
    * Probe all invalidated locations of the mesh that can be reached by the probe.
    * This attempts to fill in locations closest to the nozzle's start location first.
    */
-  void probe_entire_mesh(const float &lx, const float &ly, const bool do_ubl_mesh_map, const bool stow_probe) {
+  void probe_entire_mesh(const float &lx, const float &ly, const bool do_ubl_mesh_map, const bool stow_probe, bool do_furthest) {
     mesh_index_pair location;
 
     ubl_has_control_of_lcd_panel++;
@@ -721,7 +738,7 @@
         return;
       }
 
-      location = find_closest_mesh_point_of_type(INVALID, lx, ly, 1, NULL);  // the '1' says we want the location to be relative to the probe
+      location = find_closest_mesh_point_of_type(INVALID, lx, ly, 1, NULL, do_furthest );  // the '1' says we want the location to be relative to the probe
       if (location.x_index >= 0 && location.y_index >= 0) {
         const float xProbe = ubl.map_x_index_to_bed_location(location.x_index),
                     yProbe = ubl.map_y_index_to_bed_location(location.y_index);
@@ -734,7 +751,7 @@
         z_values[location.x_index][location.y_index] = measured_z + Z_PROBE_OFFSET_FROM_EXTRUDER;
       }
 
-      if (do_ubl_mesh_map) ubl.display_map(1);
+      if (do_ubl_mesh_map) ubl.display_map(map_type);
 
     } while (location.x_index >= 0 && location.y_index >= 0);
 
@@ -862,9 +879,9 @@
     float last_x = -9999.99, last_y = -9999.99;
     mesh_index_pair location;
     do {
-      if (do_ubl_mesh_map) ubl.display_map(1);
+      if (do_ubl_mesh_map) ubl.display_map(map_type);
 
-      location = find_closest_mesh_point_of_type(INVALID, lx, ly, 0, NULL); // The '0' says we want to use the nozzle's position
+      location = find_closest_mesh_point_of_type(INVALID, lx, ly, 0, NULL, false); // The '0' says we want to use the nozzle's position
       // It doesn't matter if the probe can not reach the
       // NAN location. This is a manual probe.
       if (location.x_index < 0 && location.y_index < 0) continue;
@@ -923,7 +940,7 @@
       }
     } while (location.x_index >= 0 && location.y_index >= 0);
 
-    if (do_ubl_mesh_map) ubl.display_map(1);
+    if (do_ubl_mesh_map) ubl.display_map(map_type);
 
     LEAVE:
     restore_ubl_active_state_and_leave();
@@ -941,6 +958,7 @@
     x_pos = current_position[X_AXIS];
     y_pos = current_position[Y_AXIS];
     x_flag = y_flag = repeat_flag = false;
+    map_type = 0;
     constant = 0.0;
     repetition_cnt = 1;
 
@@ -1008,6 +1026,23 @@
         return UBL_ERR;
       }
     }
+
+    if (code_seen('O')) {     // Check if a map type was specified
+      map_type = code_value_int() ? code_has_value() : 0; 
+      if ( map_type<0 || map_type>1) {
+        SERIAL_PROTOCOLLNPGM("Invalid map type.\n");
+        return UBL_ERR;
+      }
+    }
+
+    if (code_seen('M')) {     // Check if a map type was specified
+      map_type = code_value_int() ? code_has_value() : 0; 
+      if ( map_type<0 || map_type>1) {
+        SERIAL_PROTOCOLLNPGM("Invalid map type.\n");
+        return UBL_ERR;
+      }
+    }
+
     return UBL_OK;
   }
 
@@ -1217,9 +1252,9 @@
         z_values[x][y] = z_values[x][y] - tmp_z_values[x][y];
   }
 
-  mesh_index_pair find_closest_mesh_point_of_type(const MeshPointType type, const float &lx, const float &ly, const bool probe_as_reference, unsigned int bits[16]) {
-    int i, j;
-    float closest = 99999.99;
+  mesh_index_pair find_closest_mesh_point_of_type(const MeshPointType type, const float &lx, const float &ly, const bool probe_as_reference, unsigned int bits[16], bool far_flag) {
+    int i, j, k, l;
+    float distance, closest = far_flag ? -99999.99 : 99999.99;
     mesh_index_pair return_val;
 
     return_val.x_index = return_val.y_index = -1;
@@ -1254,9 +1289,21 @@
 
           // We can get to it. Let's see if it is the closest location to the nozzle.
           // Add in a weighting factor that considers the current location of the nozzle.
-          const float distance = HYPOT(px - mx, py - my) + HYPOT(current_x - mx, current_y - my) * 0.01;
 
-          if (distance < closest) {
+          distance = HYPOT(px - mx, py - my) + HYPOT(current_x - mx, current_y - my) * 0.1;
+
+	  if (far_flag) {                                    // If doing the far_flag action, we want to be as far as possible
+            for (k = 0; k < UBL_MESH_NUM_X_POINTS; k++) {    // from the starting point and from any other probed points.  We
+              for (l = 0; j < UBL_MESH_NUM_Y_POINTS; l++) {  // want the next point spread out and filling in any blank spaces
+                if ( !isnan(z_values[k][l])) {               // in the mesh.   So we add in some of the distance to every probed 
+                  distance += (i-k)*(i-k)*MESH_X_DIST*.05;   // point we can find.
+                  distance += (j-l)*(j-l)*MESH_Y_DIST*.05;
+		}
+              }
+	    }
+	  }
+
+          if ( (!far_flag&&(distance < closest)) || (far_flag&&(distance > closest)) ) {  // if far_flag, look for furthest away point
             closest = distance;       // We found a closer location with
             return_val.x_index = i;   // the specified type of mesh value.
             return_val.y_index = j;
@@ -1283,9 +1330,9 @@
     do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE);
     do_blocking_move_to_xy(lx, ly);
     do {
-      if (do_ubl_mesh_map) ubl.display_map(1);
+      if (do_ubl_mesh_map) ubl.display_map(map_type);
 
-      location = find_closest_mesh_point_of_type( SET_IN_BITMAP, lx,  ly, 0, not_done); // The '0' says we want to use the nozzle's position
+      location = find_closest_mesh_point_of_type( SET_IN_BITMAP, lx,  ly, 0, not_done, false); // The '0' says we want to use the nozzle's position
                                                                                               // It doesn't matter if the probe can not reach this
                                                                                               // location. This is a manual edit of the Mesh Point.
       if (location.x_index < 0 && location.y_index < 0) continue; // abort if we can't find any more points.
@@ -1356,7 +1403,7 @@
 
     ubl_has_control_of_lcd_panel = false;
 
-    if (do_ubl_mesh_map) ubl.display_map(1);
+    if (do_ubl_mesh_map) ubl.display_map(map_type);
     restore_ubl_active_state_and_leave();
     do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE);