blend2d icon indicating copy to clipboard operation
blend2d copied to clipboard

a simple cubic going crazy

Open abu-irrational opened this issue 4 years ago • 3 comments

it's a just a simple cubic, but for some degenerate cases it takes seconds and gigabytes of memory !

// a simple cubic,
 // it is a degenerate curve for beta 0, PI/2, PI, ...
 // it works for beta = 0.0
 //  BUT for beta = 2*PI    (same curve as for beta = 0)
 //  it uses GigaBYTES !
BLPath mycurve(double R, double beta) {

  BLPath path;
  double x = R*cos(beta);
  double y = R*sin(beta);

  path.moveTo(x,y);
  path.cubicTo(0.0,2*y,  0.0,-2*y,  x,-2*y);

  return path;
}


BLImage render(const BLContextCreateInfo& cci) {
  BLImage img(512, 512, BL_FORMAT_PRGB32);
  BLContext ctx(img, cci);

  ctx.clearAll();

  BLPoint P;
  double R = 200.0;

  // build a path p0  with beta 0.0
  BLPath path0 = mycurve(R, 0.0);

   // for beta=360,  mycurve(R,2*PI)   should be  equal to mycurve(R,0) 
   //  but ...
   //  we have an approx PI ... 

  double PI =3.141592653589793; 
  BLPath path360 = mycurve(R, 2*PI);


  // TEST !!!   repeat 50 times  ... Strace gives <Execution timed out>

  ctx.setStrokeStyle(BLRgba32(0xFFFFFFFF));

  for (int i=0; i< 50; ++i) {
      ctx.strokePath(path0);

    ctx.strokePath(path360);
  }
  return img;
}

abu-irrational avatar Sep 05 '21 23:09 abu-irrational

Should be fixed by 2f79eb23ab0b00c5a00535c4f2477c15e626dfa4

kobalicek avatar Dec 18 '21 19:12 kobalicek

Tested your fix: I should say that it's only partially fixed. The worst cases causing huge processing times are fixed, but there are still simple (degenerate cubics) that are not drawn.

Consider this cubic {0,0} ,{200,0}, {200,0}, {0, 0} it should be rendered as a straight line from (0,0) to (150,0) (and then back to (0,0)) but this curve is not drawn at all.

----- here is a fiddle for testing ----

BLPath mycubic(BLPoint P0, BLPoint P1, BLPoint P2, BLPoint P3) { BLPath path;

path.moveTo(P0); path.cubicTo(P1,P2,P3); return path; }

BLImage render(const BLContextCreateInfo& cci) { BLImage img(512, 512, BL_FORMAT_PRGB32); BLContext ctx(img, cci);

ctx.clearAll();

double width = ctx.targetWidth(); double height = ctx.targetHeight();

// translate origin at center of the screen ctx.translate(width/2.0,height/2.0);

// draw XY axis 

ctx.setFillStyle(BLRgba32(0xFF808080)); ctx.setStrokeStyle(BLRgba32(0xFF404040)); ctx.strokeLine(0.0,height,0.0,-height); ctx.strokeLine(-width, 0.0,width,0.0);

// set color for the next cubics .. ctx.setStrokeStyle(BLRgba32(0xFFFFFFFF));

ctx.strokePath(mycubic( {0,0},{200,0},{200,0},{0, 0} )); // nothing is drawn !!  

// translate the same cubic vertically 
//  then apply a minimal variation to a coord
ctx.translate(0,50);
ctx.strokePath(mycubic( {0,0},{200.001,0},{200,0},{0, 0} ));   // OK

return img; }

abu-irrational avatar Dec 19 '21 16:12 abu-irrational

I'm not sure what I've found regarding degenerate cubics not rendered such as (0,0) (0,100) (0,100) (0,0)
or more generally cubics like {pA pB pB pA} but I've found some strange suspicious things in "pathstroke.cpp"

The first thing I noted is at line 288 BLPoint p[7] // ? why 7 ? 4 is enough ! this could be not important (just some unused space on the stack), but then I noted that isCubicFlat(..) (at line 299) on curves like the ones above returns "true". Is it correct ? I agree that {pA pB pB pA} are 4 aligned points, but this is not a flat curve, it's a 'folded' curve starting from pA, going straight to pB, and then going back to pA .. Anyway, after this isCubicFlat test, this curve is treated as a Line from p0 to the last point p3, but this is a null segment and so it's skipped.

I could be wrong, I didn't debug the code, just read it, and honestly, I didn't understand the used algorithm, but this "isCubicFlat()" looks strange to me.

abu-irrational avatar Dec 22 '21 00:12 abu-irrational