static void cubicQuadIntersection(skiatest::Reporter* reporter, int index) { int iIndex = static_cast<int>(index); const SkDCubic& cubic = quadCubicTests[index].cubic; SkASSERT(ValidCubic(cubic)); const SkDQuad& quad = quadCubicTests[index].quad; SkASSERT(ValidQuad(quad)); SkReduceOrder reduce1; SkReduceOrder reduce2; int order1 = reduce1.reduce(cubic, SkReduceOrder::kNo_Quadratics); int order2 = reduce2.reduce(quad); if (order1 != 4) { SkDebugf("[%d] cubic order=%d\n", iIndex, order1); REPORTER_ASSERT(reporter, 0); } if (order2 != 3) { SkDebugf("[%d] quad order=%d\n", iIndex, order2); REPORTER_ASSERT(reporter, 0); } SkIntersections i; int roots = i.intersect(cubic, quad); for (int pt = 0; pt < roots; ++pt) { double tt1 = i[0][pt]; SkDPoint xy1 = cubic.ptAtT(tt1); double tt2 = i[1][pt]; SkDPoint xy2 = quad.ptAtT(tt2); if (!xy1.approximatelyEqual(xy2)) { SkDebugf("%s [%d,%d] x!= t1=%g (%g,%g) t2=%g (%g,%g)\n", __FUNCTION__, iIndex, pt, tt1, xy1.fX, xy1.fY, tt2, xy2.fX, xy2.fY); } REPORTER_ASSERT(reporter, xy1.approximatelyEqual(xy2)); } reporter->bumpTestCount(); }
static void coincidentTestOne(skiatest::Reporter* reporter, int test1, int test2) { const SkDQuad& quad1 = coincidentTestSet[test1]; SkASSERT(ValidQuad(quad1)); const SkDQuad& quad2 = coincidentTestSet[test2]; SkASSERT(ValidQuad(quad2)); SkIntersections intersections2; intersections2.intersect(quad1, quad2); REPORTER_ASSERT(reporter, intersections2.coincidentUsed() == 2); REPORTER_ASSERT(reporter, intersections2.used() == 2); for (int pt = 0; pt < intersections2.coincidentUsed(); ++pt) { double tt1 = intersections2[0][pt]; double tt2 = intersections2[1][pt]; SkDPoint pt1 = quad1.ptAtT(tt1); SkDPoint pt2 = quad2.ptAtT(tt2); REPORTER_ASSERT(reporter, pt1.approximatelyEqual(pt2)); } }
static void standardTestCases(skiatest::Reporter* reporter) { bool showSkipped = false; for (size_t index = 0; index < quadraticTests_count; ++index) { const SkDQuad& quad1 = quadraticTests[index][0]; SkASSERT(ValidQuad(quad1)); const SkDQuad& quad2 = quadraticTests[index][1]; SkASSERT(ValidQuad(quad2)); SkReduceOrder reduce1, reduce2; int order1 = reduce1.reduce(quad1); int order2 = reduce2.reduce(quad2); if (order1 < 3) { if (showSkipped) { SkDebugf("[%d] quad1 order=%d\n", static_cast<int>(index), order1); } } if (order2 < 3) { if (showSkipped) { SkDebugf("[%d] quad2 order=%d\n", static_cast<int>(index), order2); } } if (order1 == 3 && order2 == 3) { SkIntersections intersections; intersections.intersect(quad1, quad2); if (intersections.used() > 0) { for (int pt = 0; pt < intersections.used(); ++pt) { double tt1 = intersections[0][pt]; SkDPoint xy1 = quad1.ptAtT(tt1); double tt2 = intersections[1][pt]; SkDPoint xy2 = quad2.ptAtT(tt2); if (!xy1.approximatelyEqual(xy2)) { SkDebugf("%s [%d,%d] x!= t1=%g (%g,%g) t2=%g (%g,%g)\n", __FUNCTION__, static_cast<int>(index), pt, tt1, xy1.fX, xy1.fY, tt2, xy2.fX, xy2.fY); REPORTER_ASSERT(reporter, 0); } } } } } }
static void oneOffTest1(skiatest::Reporter* reporter, size_t outer, size_t inner) { const SkDQuad& quad1 = testSet[outer]; SkASSERT(ValidQuad(quad1)); const SkDQuad& quad2 = testSet[inner]; SkASSERT(ValidQuad(quad2)); SkIntersections intersections2; intersections2.intersect(quad1, quad2); for (int pt = 0; pt < intersections2.used(); ++pt) { double tt1 = intersections2[0][pt]; SkDPoint xy1 = quad1.ptAtT(tt1); double tt2 = intersections2[1][pt]; SkDPoint xy2 = quad2.ptAtT(tt2); if (!xy1.approximatelyEqual(xy2)) { SkDebugf("%s [%d,%d] x!= t1=%g (%g,%g) t2=%g (%g,%g)\n", __FUNCTION__, static_cast<int>(outer), static_cast<int>(inner), tt1, xy1.fX, xy1.fY, tt2, xy2.fX, xy2.fY); REPORTER_ASSERT(reporter, 0); } #if ONE_OFF_DEBUG SkDebugf("%s [%d][%d] t1=%1.9g (%1.9g, %1.9g) t2=%1.9g\n", __FUNCTION__, outer, inner, tt1, xy1.fX, xy1.fY, tt2); #endif } }
Error _dxf_quadsToQmesh (xfieldT *xf, void *globals) { DEFGLOBALDATA(globals) ; Quadruple *neighbors ; /* neighbors array gives a quad's neighbors */ Qstrip *stripArray = 0 ; /* temp array of strips */ int point[MaxQstripSize] ; /* array into which to build point list */ char *usedArray = 0 ; /* marks quads already used */ int nStrips = 0 ; /* number of strips generated */ int nStrippedPts = 0 ; /* number of points stripped */ int nPtsInStrip ; /* number of points in current strip */ int start_quad ; /* first quad of the strip */ int quad ; /* the current quad */ int dir, i0, i1, i2, i3 ; /* the 4 indexes into quads[quad].p[?] */ int prev_quad, prev_i0, /* used to determine the same current info */ prev_i1,prev_i2,prev_i3 ; Quadruple *quads ; /* array of original quad connections */ int nquads ; /* number of original quad connections */ int i, j, k ; /* misc. indices */ QMesh qmesh = NULL; dxObject qmesho = NULL; ENTRY(("_dxf_quadsToQmesh(0x%x)", xf)); qmesho = _dxf_QueryObject(MESHHASH, (dxObject)xf->field); if (qmesho) { xf->meshObject = DXReference(qmesho); qmesh = (QMesh)DXGetPrivateData((Private)qmesho); _installQMeshInfo(xf, qmesh); return OK; } if (xf->connectionType != ct_quads) { EXIT(("xf->connectionType not ct_quads")); return OK ; } PRINT(("invalid connections: %d", xf->invCntns? DXGetInvalidCount(xf->invCntns): 0)) ; neighbors = getNeighbors(xf); /* get quad connection info; quad connections are replaced by strips */ quads = DXGetArrayData(xf->connections_array) ; nquads = xf->nconnections ; /*npoints = xf->npositions ;*/ xf->origNConnections = nquads; xf->origConnections_array = xf->connections_array; xf->connections_array = NULL; /* allocate temporary array to hold maximum possible number of strips */ if (!(stripArray = (Qstrip *) tdmAllocate(sizeof(Qstrip) * nquads))) { PRINT(("out of memory")); DXErrorGoto (ERROR_NO_MEMORY, "#13000") ; } if (neighbors) { /* quad connections expressed explicitly, we need usedArray */ if (!(usedArray = tdmAllocateZero(sizeof(char) * Bytes(nquads)))) { PRINT(("out of memory")); DXErrorGoto (ERROR_NO_MEMORY, "#13000") ; } /* strip the field, placing strip info into temporary arrays */ for (start_quad = 0; start_quad < nquads; start_quad++) { if (GoodQuad(start_quad)) { nPtsInStrip = 0 ; quad = start_quad ; InitFirstQuad(i0,i1,i2,i3) ; /* pick 1st quad initial vertices */ AddPoint(quad,i1) ; /* add the 1st two... */ AddPoint(quad,i0) ; /* ...points to the mesh */ while (quad >= 0) /* while there's a valid quad... */ { AddPoint(quad,i3) ; /* add another quad to the strip */ AddPoint(quad,i2) ; MarkQuad(quad) ; /* mark it as used */ NextQuad(quad) ; /* move on to next quad */ } /* save strip points */ AllocateAndCopyQstripPointArray() ; } } tdmFree((Pointer)usedArray) ; usedArray = NULL; } else { /* quad connections expressed in compact mesh array form */ int n, counts[100] ; if (!DXQueryGridConnections (xf->origConnections_array, &n, counts) || n != 2) DXErrorGoto (ERROR_INTERNAL, "#13140") ; PRINT(("counts[0] = %d", counts[0])); PRINT(("counts[1] = %d", counts[1])); for (n = 0, i = 0 ; i < counts[0]-1 ; i++) { j = 0 ; while (j < counts[1]-1) { for ( ; j < counts[1]-1 && !ValidQuad(xf->invCntns, n) ; j++, n++) /* skip invalid quads up to end of row/column */ ; if (j == counts[1]-1) break ; /* start triangle strip */ nPtsInStrip = 0 ; point[nPtsInStrip++] = n + i ; point[nPtsInStrip++] = n + i + counts[1] ; while (j < counts[1]-1 && nPtsInStrip < MaxQstripSize && ValidQuad(xf->invCntns, n)) { /* add valid quads up to end of row/column or strip limit */ point[nPtsInStrip++] = n + i + 1 ; point[nPtsInStrip++] = n + i + 1 + counts[1] ; j++ ; n++ ; } /* save strip points */ AllocateAndCopyQstripPointArray() ; } } } PRINT(("stripped %d quadrangles", (nStrippedPts - 2*nStrips)/2)); PRINT(("generated %d triangle strips", nStrips)); PRINT(("average number of triangles per strip: %f", nStrips? (nStrippedPts - 2*nStrips)/(float)nStrips: 0)); if (! _newQMesh(nStrips, nStrippedPts, &qmesh, &qmesho)) goto error; for (i=j=k=0 ; i<nStrips ; i++) { qmesh->meshes[j++] = k; qmesh->meshes[j++] = stripArray[i].points; memcpy(qmesh->connections+k, stripArray[i].point, stripArray[i].points*sizeof(int)); k += stripArray[i].points; } _dxf_InsertObject(MESHHASH, (dxObject)(xf->field), (dxObject)qmesho); xf->meshObject = DXReference(qmesho); _installQMeshInfo(xf, qmesh); /* free temporary array of strips */ if (usedArray) tdmFree((Pointer)usedArray); if (stripArray) FreeTempStrips() ; EXIT(("OK")); return OK ; error: if (usedArray) tdmFree((Pointer)usedArray); if (stripArray) FreeTempStrips() ; EXIT(("ERROR")); return 0 ; }
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)); } }
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); }