static void testOneCoincident(skiatest::Reporter* reporter, const SkDLine& line1,
                              const SkDLine& line2) {
    SkASSERT(ValidLine(line1));
    SkASSERT(ValidLine(line2));
    SkIntersections ts2;
    int pts2 = ts2.intersect(line1, line2);
    REPORTER_ASSERT(reporter, pts2 == 2);
    REPORTER_ASSERT(reporter, pts2 == ts2.used());
    check_results(reporter, line1, line2, ts2);
#if 0
    SkIntersections ts;
    int pts = ts.intersect(line1, line2);
    REPORTER_ASSERT(reporter, pts == pts2);
    REPORTER_ASSERT(reporter, pts == 2);
    REPORTER_ASSERT(reporter, pts == ts.used());
    check_results(reporter, line1, line2, ts);
#endif
}
static void testOne(skiatest::Reporter* reporter, const SkDLine& line1, const SkDLine& line2) {
    SkASSERT(ValidLine(line1));
    SkASSERT(ValidLine(line2));
    SkIntersections i;
    int pts = i.intersect(line1, line2);
    REPORTER_ASSERT(reporter, pts);
    REPORTER_ASSERT(reporter, pts == i.used());
    check_results(reporter, line1, line2, i);
    if (line1[0] == line1[1] || line2[0] == line2[1]) {
        return;
    }
    if (line1[0].fY == line1[1].fY) {
        double left = SkTMin(line1[0].fX, line1[1].fX);
        double right = SkTMax(line1[0].fX, line1[1].fX);
        SkIntersections ts;
        ts.horizontal(line2, left, right, line1[0].fY, line1[0].fX != left);
        check_results(reporter, line2, line1, ts);
    }
    if (line2[0].fY == line2[1].fY) {
        double left = SkTMin(line2[0].fX, line2[1].fX);
        double right = SkTMax(line2[0].fX, line2[1].fX);
        SkIntersections ts;
        ts.horizontal(line1, left, right, line2[0].fY, line2[0].fX != left);
        check_results(reporter, line1, line2, ts);
    }
    if (line1[0].fX == line1[1].fX) {
        double top = SkTMin(line1[0].fY, line1[1].fY);
        double bottom = SkTMax(line1[0].fY, line1[1].fY);
        SkIntersections ts;
        ts.vertical(line2, top, bottom, line1[0].fX, line1[0].fY != top);
        check_results(reporter, line2, line1, ts);
    }
    if (line2[0].fX == line2[1].fX) {
        double top = SkTMin(line2[0].fY, line2[1].fY);
        double bottom = SkTMax(line2[0].fY, line2[1].fY);
        SkIntersections ts;
        ts.vertical(line1, top, bottom, line2[0].fX, line2[0].fY != top);
        check_results(reporter, line1, line2, ts);
    }
}
DEF_TEST(PathOpsConicLineIntersection, reporter) {
    for (size_t index = 0; index < lineConicTests_count; ++index) {
        int iIndex = static_cast<int>(index);
        const SkDConic& conic = lineConicTests[index].conic;
        SkASSERT(ValidConic(conic));
        const SkDLine& line = lineConicTests[index].line;
        SkASSERT(ValidLine(line));
        SkReduceOrder reducer;
        SkPoint pts[3] = { conic.fPts.fPts[0].asSkPoint(), conic.fPts.fPts[1].asSkPoint(),
            conic.fPts.fPts[2].asSkPoint() };
        SkPoint reduced[3];
        SkPath::Verb order1 = SkReduceOrder::Conic(pts, conic.fWeight, reduced);
        if (order1 != SkPath::kConic_Verb) {
            SkDebugf("%s [%d] conic verb=%d\n", __FUNCTION__, iIndex, order1);
            REPORTER_ASSERT(reporter, 0);
        }
        int order2 = reducer.reduce(line);
        if (order2 < 2) {
            SkDebugf("%s [%d] line order=%d\n", __FUNCTION__, iIndex, order2);
            REPORTER_ASSERT(reporter, 0);
        }
        SkIntersections intersections;
        bool flipped = false;
        int result = doIntersect(intersections, conic, line, flipped);
        REPORTER_ASSERT(reporter, result == lineConicTests[index].result);
        if (intersections.used() <= 0) {
            continue;
        }
        for (int pt = 0; pt < result; ++pt) {
            double tt1 = intersections[0][pt];
            REPORTER_ASSERT(reporter, tt1 >= 0 && tt1 <= 1);
            SkDPoint t1 = conic.ptAtT(tt1);
            double tt2 = intersections[1][pt];
            REPORTER_ASSERT(reporter, tt2 >= 0 && tt2 <= 1);
            SkDPoint t2 = line.ptAtT(tt2);
            if (!t1.approximatelyEqual(t2)) {
                SkDebugf("%s [%d,%d] x!= t1=%1.9g (%1.9g,%1.9g) t2=%1.9g (%1.9g,%1.9g)\n",
                    __FUNCTION__, iIndex, pt, tt1, t1.fX, t1.fY, tt2, t2.fX, t2.fY);
                REPORTER_ASSERT(reporter, 0);
            }
            if (!t1.approximatelyEqual(lineConicTests[index].expected[0])
                    && (lineConicTests[index].result == 1
                    || !t1.approximatelyEqual(lineConicTests[index].expected[1]))) {
                SkDebugf("%s t1=(%1.9g,%1.9g)\n", __FUNCTION__, t1.fX, t1.fY);
                REPORTER_ASSERT(reporter, 0);
            }
        }
    }
}
static void testOneOffs(skiatest::Reporter* reporter) {
    bool flipped = false;
    for (size_t index = 0; index < oneOffs_count; ++index) {
        const SkDConic& conic = oneOffs[index].conic;
        SkASSERT(ValidConic(conic));
        const SkDLine& line = oneOffs[index].line;
        SkASSERT(ValidLine(line));
        SkIntersections intersections;
        int result = doIntersect(intersections, conic, line, flipped);
        for (int inner = 0; inner < result; ++inner) {
            double conicT = intersections[0][inner];
            SkDPoint conicXY = conic.ptAtT(conicT);
            double lineT = intersections[1][inner];
            SkDPoint lineXY = line.ptAtT(lineT);
            if (!conicXY.approximatelyEqual(lineXY)) {
                conicXY.approximatelyEqual(lineXY);
                SkDebugf("");
            }
            REPORTER_ASSERT(reporter, conicXY.approximatelyEqual(lineXY));
        }
    }
}
static void PathOpsDRectTest(skiatest::Reporter* reporter) {
    size_t index;
    SkDRect rect, rect2;
    for (index = 0; index < lineTests_count; ++index) {
        const SkDLine& line = lineTests[index];
        SkASSERT(ValidLine(line));
        rect.setBounds(line);
        REPORTER_ASSERT(reporter, rect.fLeft == SkTMin(line[0].fX, line[1].fX));
        REPORTER_ASSERT(reporter, rect.fTop == SkTMin(line[0].fY, line[1].fY));
        REPORTER_ASSERT(reporter, rect.fRight == SkTMax(line[0].fX, line[1].fX));
        REPORTER_ASSERT(reporter, rect.fBottom == SkTMax(line[0].fY, line[1].fY));
        rect2.set(line[0]);
        rect2.add(line[1]);
        REPORTER_ASSERT(reporter, rect2.fLeft == SkTMin(line[0].fX, line[1].fX));
        REPORTER_ASSERT(reporter, rect2.fTop == SkTMin(line[0].fY, line[1].fY));
        REPORTER_ASSERT(reporter, rect2.fRight == SkTMax(line[0].fX, line[1].fX));
        REPORTER_ASSERT(reporter, rect2.fBottom == SkTMax(line[0].fY, line[1].fY));
        REPORTER_ASSERT(reporter, rect.contains(line[0]));
        REPORTER_ASSERT(reporter, rect.intersects(&rect2));
    }
    for (index = 0; index < quadTests_count; ++index) {
        const SkDQuad& quad = quadTests[index];
        SkASSERT(ValidQuad(quad));
        rect.setRawBounds(quad);
        REPORTER_ASSERT(reporter, rect.fLeft == SkTMin(quad[0].fX,
                SkTMin(quad[1].fX, quad[2].fX)));
        REPORTER_ASSERT(reporter, rect.fTop == SkTMin(quad[0].fY,
                SkTMin(quad[1].fY, quad[2].fY)));
        REPORTER_ASSERT(reporter, rect.fRight == SkTMax(quad[0].fX,
                SkTMax(quad[1].fX, quad[2].fX)));
        REPORTER_ASSERT(reporter, rect.fBottom == SkTMax(quad[0].fY,
                SkTMax(quad[1].fY, quad[2].fY)));
        rect2.setBounds(quad);
        REPORTER_ASSERT(reporter, rect.intersects(&rect2));
        // FIXME: add a recursive box subdivision method to verify that tight bounds is correct
        SkDPoint leftTop = {rect2.fLeft, rect2.fTop};
        REPORTER_ASSERT(reporter, rect.contains(leftTop));
        SkDPoint rightBottom = {rect2.fRight, rect2.fBottom};
        REPORTER_ASSERT(reporter, rect.contains(rightBottom));
    }
    for (index = 0; index < cubicTests_count; ++index) {
        const SkDCubic& cubic = cubicTests[index];
        SkASSERT(ValidCubic(cubic));
        rect.setRawBounds(cubic);
        REPORTER_ASSERT(reporter, rect.fLeft == SkTMin(cubic[0].fX,
                SkTMin(cubic[1].fX, SkTMin(cubic[2].fX, cubic[3].fX))));
        REPORTER_ASSERT(reporter, rect.fTop == SkTMin(cubic[0].fY,
                SkTMin(cubic[1].fY, SkTMin(cubic[2].fY, cubic[3].fY))));
        REPORTER_ASSERT(reporter, rect.fRight == SkTMax(cubic[0].fX,
                SkTMax(cubic[1].fX, SkTMax(cubic[2].fX, cubic[3].fX))));
        REPORTER_ASSERT(reporter, rect.fBottom == SkTMax(cubic[0].fY,
                SkTMax(cubic[1].fY, SkTMax(cubic[2].fY, cubic[3].fY))));
        rect2.setBounds(cubic);
        REPORTER_ASSERT(reporter, rect.intersects(&rect2));
        // FIXME: add a recursive box subdivision method to verify that tight bounds is correct
        SkDPoint leftTop = {rect2.fLeft, rect2.fTop};
        REPORTER_ASSERT(reporter, rect.contains(leftTop));
        SkDPoint rightBottom = {rect2.fRight, rect2.fBottom};
        REPORTER_ASSERT(reporter, rect.contains(rightBottom));
    }
}
Ejemplo n.º 6
0
// Creates new set of lines from the computed columns
bool CubeLineSegmenter::AddLines(Pixa *lines) {
  // create an array that will hold the bounding boxes
  // of the concomps belonging to each line
  Boxaa *lines_con_comps = boxaaCreate(lines->n);
  if (lines_con_comps == NULL) {
    return false;
  }

  for (int line = 0; line < lines->n; line++) {
    // if the line is not valid
    if (ValidLine(lines->pix[line], lines->boxa->box[line]) == false) {
      // split it
      Pixa *split_lines = SplitLine(lines->pix[line],
          lines->boxa->box[line]);

      // remove the old line
      if (pixaRemovePix(lines, line) != 0) {
        return false;
      }

      line--;

      if (split_lines == NULL) {
        continue;
      }

      // add the split lines instead and move the pointer
      for (int s_line = 0; s_line < split_lines->n; s_line++) {
        Pix *sp_line = pixaGetPix(split_lines, s_line, L_CLONE);
        Box *sp_box = boxaGetBox(split_lines->boxa, s_line, L_CLONE);

        if (sp_line == NULL || sp_box == NULL) {
          return false;
        }

        // insert the new line
        if (pixaInsertPix(lines, ++line, sp_line, sp_box) != 0) {
          return false;
        }
      }

      // remove the split lines
      pixaDestroy(&split_lines);
    }
  }

  // compute the concomps bboxes of each line
  for (int line = 0; line < lines->n; line++) {
    Boxa *line_con_comps = ComputeLineConComps(lines->pix[line],
        lines->boxa->box[line], NULL);

    if (line_con_comps == NULL) {
      return false;
    }

    // insert it into the boxaa array
    if (boxaaAddBoxa(lines_con_comps, line_con_comps, L_INSERT) != 0) {
      return false;
    }
  }

  // post process the lines:
  // merge the contents of "small" lines info legitimate lines
  for (int line = 0; line < lines->n; line++) {
    // a small line detected
    if (SmallLine(lines->boxa->box[line]) == true) {
      // merge its components to one of the valid lines
      if (MergeLine(lines->pix[line], lines->boxa->box[line],
          lines, lines_con_comps) == true) {
        // remove the small line
        if (pixaRemovePix(lines, line) != 0) {
          return false;
        }

        if (boxaaRemoveBoxa(lines_con_comps, line) != 0) {
          return false;
        }

        line--;
      }
    }
  }

  boxaaDestroy(&lines_con_comps);

  // add the pix masks
  if (pixaaAddPixa(columns_, lines, L_INSERT) != 0) {
    return false;
  }

  return true;
}
Ejemplo n.º 7
0
// split a line continously until valid or fail
Pixa *CubeLineSegmenter::SplitLine(Pix *line_mask_pix, Box *line_box) {
  // clone the line mask
  Pix *line_pix = pixClone(line_mask_pix);

  if (line_pix == NULL) {
    return NULL;
  }

  // AND with the image to get the actual line
  pixRasterop(line_pix, 0, 0, line_pix->w, line_pix->h,
    PIX_SRC & PIX_DST, img_, line_box->x, line_box->y);

  // continue to do rasterop morphology on the line until
  // it splits to valid lines or we fail
  int morph_hgt = kLineSepMorphMinHgt - 1,
    best_threshold = kLineSepMorphMinHgt - 1,
    max_valid_portion = 0;

  Boxa *boxa;
  Pixa *pixac;

  do {
    pixac = VerticalClosing(line_pix, morph_hgt, &boxa);

    // add the box offset to all the lines
    // and check for the validity of each
    int line,
      valid_line_cnt = 0,
      valid_portion = 0;

    for (line = 0; line < pixac->n; line++) {
      boxa->box[line]->x += line_box->x;
      boxa->box[line]->y += line_box->y;

      if (ValidLine(pixac->pix[line], boxa->box[line]) == true) {
        // count valid lines
        valid_line_cnt++;

        // and the valid portions
        valid_portion += boxa->box[line]->h;
      }
    }

    // all the lines are valid
    if (valid_line_cnt == pixac->n) {
      boxaDestroy(&boxa);
      pixDestroy(&line_pix);
      return pixac;
    }

    // a larger valid portion
    if (valid_portion > max_valid_portion) {
      max_valid_portion = valid_portion;
      best_threshold = morph_hgt;
    }

    boxaDestroy(&boxa);
    pixaDestroy(&pixac);

    morph_hgt--;
  }
  while (morph_hgt > 0);

  // failed to break into valid lines
  // attempt to crack the line
  pixac = CrackLine(line_pix, line_box);
  if (pixac != NULL) {
    pixDestroy(&line_pix);
    return pixac;
  }

  // try to leverage any of the lines
  // did the best threshold yield a non zero valid portion
  if (max_valid_portion > 0) {
    // use this threshold to break lines
    pixac = VerticalClosing(line_pix, best_threshold, &boxa);

    // add the box offset to all the lines
    // and check for the validity of each
    for (int line = 0; line < pixac->n; line++) {
      boxa->box[line]->x += line_box->x;
      boxa->box[line]->y += line_box->y;

      // remove invalid lines from the pixa
      if (ValidLine(pixac->pix[line], boxa->box[line]) == false) {
        pixaRemovePix(pixac, line);
        line--;
      }
    }

    boxaDestroy(&boxa);
    pixDestroy(&line_pix);
    return pixac;
  }

  // last resort: attempt to crack the line
  pixDestroy(&line_pix);

  return NULL;
}
Ejemplo n.º 8
0
// do a desperate attempt at cracking lines
Pixa *CubeLineSegmenter::CrackLine(Pix *cracked_line_pix,
                                   Box *cracked_line_box, int line_cnt) {
  // create lines pixa array
  Pixa **lines_pixa = new Pixa*[line_cnt];
  if (lines_pixa == NULL) {
    return NULL;
  }

  memset(lines_pixa, 0, line_cnt * sizeof(*lines_pixa));

  // compute line conn comps
  Pixa *line_con_comps_pix;
  Boxa *line_con_comps = ComputeLineConComps(cracked_line_pix,
    cracked_line_box, &line_con_comps_pix);

  if (line_con_comps == NULL) {
    delete []lines_pixa;
    return NULL;
  }

  // assign each conn comp to the a line based on its centroid
  for (int con = 0; con < line_con_comps->n; con++) {
    Box *con_box = line_con_comps->box[con];
    Pix *con_pix = line_con_comps_pix->pix[con];
    int mid_y = (con_box->y - cracked_line_box->y) + (con_box->h / 2),
      line_idx = MIN(line_cnt - 1,
                     (mid_y * line_cnt / cracked_line_box->h));

    // create the line if it has not been created?
    if (lines_pixa[line_idx] == NULL) {
      lines_pixa[line_idx] = pixaCreate(line_con_comps->n);
      if (lines_pixa[line_idx] == NULL) {
        delete []lines_pixa;
        boxaDestroy(&line_con_comps);
        pixaDestroy(&line_con_comps_pix);
        return NULL;
      }
    }

    // add the concomp to the line
    if (pixaAddPix(lines_pixa[line_idx], con_pix, L_CLONE) != 0 ||
        pixaAddBox(lines_pixa[line_idx], con_box, L_CLONE)) {
      delete []lines_pixa;
      boxaDestroy(&line_con_comps);
      pixaDestroy(&line_con_comps_pix);
    }
  }

  // create the lines pixa
  Pixa *lines = pixaCreate(line_cnt);
  bool success = true;

  // create and check the validity of the lines
  for (int line = 0; line < line_cnt; line++) {
    Pixa *line_pixa = lines_pixa[line];

    // skip invalid lines
    if (line_pixa == NULL) {
      continue;
    }

    // merge the pix, check the validity of the line
    // and add it to the lines pixa
    Box *line_box;
    Pix *line_pix = Pixa2Pix(line_pixa, &line_box);
    if (line_pix == NULL ||
        line_box == NULL ||
        ValidLine(line_pix, line_box) == false ||
        pixaAddPix(lines, line_pix, L_INSERT) != 0 ||
        pixaAddBox(lines, line_box, L_INSERT) != 0) {
      if (line_pix != NULL) {
        pixDestroy(&line_pix);
      }

      if (line_box != NULL) {
        boxDestroy(&line_box);
      }

      success = false;

      break;
    }
  }

  // cleanup
  for (int line = 0; line < line_cnt; line++) {
    if (lines_pixa[line] != NULL) {
      pixaDestroy(&lines_pixa[line]);
    }
  }

  delete []lines_pixa;
  boxaDestroy(&line_con_comps);
  pixaDestroy(&line_con_comps_pix);

  if (success == false) {
    pixaDestroy(&lines);
    lines = NULL;
  }

  return lines;
}
Ejemplo n.º 9
0
static void setup(const SortSet* set, const size_t idx,
        SkOpSegment* seg, int* ts, const SkPoint& startPt) {
    SkPoint start, end;
    const SkPoint* data = set[idx].ptData;
    bool useIntersectPt = startPt.fX != 0 || startPt.fY != 0;
    if (useIntersectPt) {
        start = startPt;
        end = set[idx].endPt;
    }
    switch(set[idx].ptCount) {
        case 2: {
            SkASSERT(ValidPoints(data, 2));
            seg->addLine(data, false, false);
            SkDLine dLine;
            dLine.set(set[idx].ptData);
            SkASSERT(ValidLine(dLine));
            if (useIntersectPt) {
                break;
            }
            start = dLine.ptAtT(set[idx].tStart).asSkPoint();
            end = dLine.ptAtT(set[idx].tEnd).asSkPoint();
            } break;
        case 3: {
            SkASSERT(ValidPoints(data, 3));
            seg->addQuad(data, false, false);
            SkDQuad dQuad;
            dQuad.set(set[idx].ptData);
            SkASSERT(ValidQuad(dQuad));
             if (useIntersectPt) {
                break;
            }
            start = dQuad.ptAtT(set[idx].tStart).asSkPoint();
            end = dQuad.ptAtT(set[idx].tEnd).asSkPoint();
            } break;
        case 4: {
            SkASSERT(ValidPoints(data, 4));
            seg->addCubic(data, false, false);
            SkDCubic dCubic;
            dCubic.set(set[idx].ptData);
            SkASSERT(ValidCubic(dCubic));
            if (useIntersectPt) {
                break;
            }
            start = dCubic.ptAtT(set[idx].tStart).asSkPoint();
            end = dCubic.ptAtT(set[idx].tEnd).asSkPoint();
            } break;
    }
    double tStart = set[idx].tStart;
    double tEnd = set[idx].tEnd;
    seg->addT(NULL, start, tStart);
    seg->addT(NULL, end, tEnd);
    if (tStart != 0 && tEnd != 0) {
        seg->addT(NULL, set[idx].ptData[0], 0);
    }
    if (tStart != 1 && tEnd != 1) {
        seg->addT(NULL, set[idx].ptData[set[idx].ptCount - 1], 1);
    }
    int tIndex = 0;
    ts[0] = 0;
    ts[1] = 1;
    do {
        if (seg->t(tIndex) == set[idx].tStart) {
            ts[0] = tIndex;
        }
        if (seg->t(tIndex) == set[idx].tEnd) {
            ts[1] = tIndex;
        }
        if (seg->t(tIndex) >= 1) {
            break;
        }
    } while (++tIndex);
}