Issue 563: Support non-rectangular Data Matrix
[zxing.git] / core / src / com / google / zxing / datamatrix / detector / Detector.java
index 59ffbad..6c43ef7 100644 (file)
@@ -141,35 +141,118 @@ public final class Detector {
     // The top right point is actually the corner of a module, which is one of the two black modules
     // adjacent to the white module at the top right. Tracing to that corner from either the top left
     // or bottom right should work here.
-    int dimension = Math.min(transitionsBetween(topLeft, topRight).getTransitions(),
-                             transitionsBetween(bottomRight, topRight).getTransitions());
-    if ((dimension & 0x01) == 1) {
+    
+    
+    int dimensionTop = transitionsBetween(topLeft, topRight).getTransitions();
+    int dimensionRight = transitionsBetween(bottomRight, topRight).getTransitions();
+    
+    if ((dimensionTop & 0x01) == 1) {
       // it can't be odd, so, round... up?
-      dimension++;
+      dimensionTop++;
     }
-    dimension += 2;
+    dimensionTop += 2;
+    
+    if ((dimensionRight & 0x01) == 1) {
+        // it can't be odd, so, round... up?
+        dimensionRight++;
+      }
+      dimensionRight += 2;
+
+    BitMatrix bits = null;
+    ResultPoint correctedTopRight = null;
+      
+    if (dimensionTop >= dimensionRight * 2 || dimensionRight >= dimensionTop * 2){
+       //The matrix is rectangular
+       
+        correctedTopRight = correctTopRightRectangular(bottomLeft, bottomRight, topLeft, topRight, dimensionTop, dimensionRight);
+        if (correctedTopRight == null){
+               correctedTopRight = topRight;
+        }
+        
+        dimensionTop = transitionsBetween(topLeft, correctedTopRight).getTransitions();
+        dimensionRight = transitionsBetween(bottomRight, correctedTopRight).getTransitions();
+        
+        if ((dimensionTop & 0x01) == 1) {
+          // it can't be odd, so, round... up?
+          dimensionTop++;
+        }
+        
+        if ((dimensionRight & 0x01) == 1) {
+            // it can't be odd, so, round... up?
+            dimensionRight++;
+          }
+        
+          bits = sampleGrid(image, topLeft, bottomLeft, bottomRight, correctedTopRight, dimensionTop, dimensionRight);
+          
+    } else {
+       //The matrix is square
+        
+       int dimension = Math.min(dimensionRight, dimensionTop);
+        //correct top right point to match the white module
+        correctedTopRight = correctTopRight(bottomLeft, bottomRight, topLeft, topRight, dimension);
+        if (correctedTopRight == null){
+               correctedTopRight = topRight;
+        }
 
-    //correct top right point to match the white module
-    ResultPoint correctedTopRight = correctTopRight(bottomLeft, bottomRight, topLeft, topRight, dimension);
-    if (correctedTopRight == null){
-       correctedTopRight = topRight;
-    }
+        //We redetermine the dimension using the corrected top right point
+        int dimensionCorrected = Math.max(transitionsBetween(topLeft, correctedTopRight).getTransitions(),
+                                  transitionsBetween(bottomRight, correctedTopRight).getTransitions());
+        dimensionCorrected++;
+        if ((dimensionCorrected & 0x01) == 1) {
+          dimensionCorrected++;
+        }
 
-    //We redetermine the dimension using the corrected top right point
-    int dimension2 = Math.max(transitionsBetween(topLeft, correctedTopRight).getTransitions(),
-                              transitionsBetween(bottomRight, correctedTopRight).getTransitions());
-    dimension2++;
-    if ((dimension2 & 0x01) == 1) {
-      dimension2++;
+        bits = sampleGrid(image, topLeft, bottomLeft, bottomRight, correctedTopRight, dimensionCorrected, dimensionCorrected);
     }
 
-    BitMatrix bits = sampleGrid(image, topLeft, bottomLeft, bottomRight, correctedTopRight, dimension2);
 
     return new DetectorResult(bits, new ResultPoint[]{topLeft, bottomLeft, bottomRight, correctedTopRight});
   }
 
   /**
-   * Calculates the position of the white top right module using the output of the rectangle detector
+   * Calculates the position of the white top right module using the output of the rectangle detector for a rectangular matrix
+   */
+  private ResultPoint correctTopRightRectangular(ResultPoint bottomLeft,
+               ResultPoint bottomRight, ResultPoint topLeft, ResultPoint topRight,
+               int dimensionTop, int dimensionRight) {
+         
+               float corr = distance(bottomLeft, bottomRight) / (float)dimensionTop;
+               int norm = distance(topLeft, topRight);
+               float cos = (topRight.getX() - topLeft.getX()) / norm;
+               float sin = (topRight.getY() - topLeft.getY()) / norm;
+               
+               ResultPoint c1 = new ResultPoint(topRight.getX()+corr*cos, topRight.getY()+corr*sin);
+       
+               corr = distance(bottomLeft, topLeft) / (float)dimensionRight;
+               norm = distance(bottomRight, topRight);
+               cos = (topRight.getX() - bottomRight.getX()) / norm;
+               sin = (topRight.getY() - bottomRight.getY()) / norm;
+               
+               ResultPoint c2 = new ResultPoint(topRight.getX()+corr*cos, topRight.getY()+corr*sin);
+
+               if (!isValid(c1)){
+                       if (isValid(c2)){
+                               return c2;
+                       }
+                       return null;
+               } else if (!isValid(c2)){
+                       return c1;
+               }
+               
+               int l1 = Math.abs(dimensionTop - transitionsBetween(topLeft, c1).getTransitions()) + 
+                                       Math.abs(dimensionRight - transitionsBetween(bottomRight, c1).getTransitions());
+               int l2 = Math.abs(dimensionTop - transitionsBetween(topLeft, c2).getTransitions()) + 
+               Math.abs(dimensionRight - transitionsBetween(bottomRight, c2).getTransitions());
+               
+               if (l1 <= l2){
+                       return c1;
+               }
+               
+               return c2;
+}
+
+/**
+   * Calculates the position of the white top right module using the output of the rectangle detector for a square matrix
    */
   private ResultPoint correctTopRight(ResultPoint bottomLeft,
                                       ResultPoint bottomRight,
@@ -242,20 +325,22 @@ public final class Detector {
                                       ResultPoint bottomLeft,
                                       ResultPoint bottomRight,
                                       ResultPoint topRight,
-                                      int dimension) throws NotFoundException {
+                                      int dimensionX,
+                                      int dimensionY) throws NotFoundException {
 
     GridSampler sampler = GridSampler.getInstance();
 
     return sampler.sampleGrid(image,
-                              dimension,
+                              dimensionX,
+                              dimensionY,
                               0.5f,
                               0.5f,
-                              dimension - 0.5f,
+                              dimensionX - 0.5f,
                               0.5f,
-                              dimension - 0.5f,
-                              dimension - 0.5f,
+                              dimensionX - 0.5f,
+                              dimensionY - 0.5f,
                               0.5f,
-                              dimension - 0.5f,
+                              dimensionY - 0.5f,
                               topLeft.getX(),
                               topLeft.getY(),
                               topRight.getX(),