Example #1
0
bool nuiSpline::Tessellate(nuiPath& rVertices, float Quality) const
{
  if (mCacheValid && mLastQuality == Quality)
  {
    uint32 count = mTessCache.GetCount();
    for (uint32 i = 0; i < count; i++)
      rVertices.AddVertex(mTessCache[i]);
  }
  else
  {
    std::vector<nuiSplinePoint> Points;

    Evaluate(Points, (uint)(GetSize() * (20.0f * Quality)));

    std::vector<nuiSplinePoint>::iterator it;
    std::vector<nuiSplinePoint>::iterator end = Points.end();
    for (it = Points.begin(); it != end; ++it)
    {
      rVertices.AddVertex(*it);
      mTessCache.AddVertex(*it);
    }
    mLastQuality = Quality;
    mCacheValid = true;
  }
  return true;
}
Example #2
0
void nuiOutliner::AddCap(const nuiPoint& rFirstPoint, const nuiPoint& rLastPoint, nuiPath& rPoints) const
{
  switch (mLineCap)
  {
  case nuiLineCapBut:
    // Nothing special to do
    rPoints.AddVertexOptim(rFirstPoint);
    rPoints.AddVertexOptim(rLastPoint);
    break;
  case nuiLineCapRound:
    {
      nuiArc arc(rFirstPoint, rLastPoint,  mRealLineWidth, mRealLineWidth, 0, true, true);
      arc.Tessellate(rPoints, 0.5f);
      //rPoints.AddVertexOptim(rFirstPoint);
    }
    break;
  case nuiLineCapSquare:
    {
      nuiVector vec = rLastPoint - rFirstPoint;
      vec.Normalize();
      float tmp = vec[0];
      vec[0] = vec[1];
      vec[1] = -tmp;
      vec *= mLineWidth * 0.5f;
      rPoints.AddVertexOptim(nuiPoint(rFirstPoint+vec));
      rPoints.AddVertexOptim(nuiPoint(rLastPoint+vec));
    }
    break;
  }
}
Example #3
0
void nuiOutliner::AddJoin(const nuiPoint& Point0, const nuiPoint& Point1, const nuiPoint& Point2, const nuiPoint& Point3, nuiPath& rPoints) const
{
  const double x1 = Point0[0];
  const double y1 = Point0[1];

  const double x2 = Point1[0];
  const double y2 = Point1[1];

  const double x3 = Point2[0];
  const double y3 = Point2[1];

  const double x4 = Point3[0];
  const double y4 = Point3[1];

  const double x43 = x4 - x3;
  const double y43 = y4 - y3;
  const double x21 = x2 - x1;
  const double y21 = y2 - y1;

  const double denom = y43 * x21 - x43 * y21;

  if (denom == 0.0f)
  {
    // The segments are parallel.
    rPoints.AddVertexOptim(Point3);
  }
  else
  {
    const double y13 = y1 - y3;
    const double x13 = x1 - x3;
    const double denom_inv = 1.0f/denom;
    const double ua = (x43 * y13 - y43 * x13) * denom_inv;
    const double ub = (x21 * y13 - y21 * x13) * denom_inv;

    if (mLineJoin == nuiLineJoinMiter || (ua >= 0.0f && ua <= 1.0f) && (ub >= 0.0f && ub <= 1.0f))
    {
      nuiPoint mitter((float)(x1 + ua*(x2-x1)), (float)(y1 + ua*(y2-y1)));
      rPoints.AddVertexOptim(mitter);
    }
    else if (mLineJoin == nuiLineJoinRound)
    {
      nuiArc arc(Point1, Point2,  mRealLineWidth, mRealLineWidth, 0, false, true);
      arc.Tessellate(rPoints, 0.5f);
    }
    else // Bevel
    {
      rPoints.AddVertexOptim(Point1);
      rPoints.AddVertexOptim(Point2);
    }
  }
}
Example #4
0
bool nuiOutliner::Tessellate(nuiPath& rPoints, float Quality) const
{
  nuiPath Vertices;
  bool res = mpPath->Tessellate(Vertices, Quality);

  rPoints.Clear();

  if (!res)
    return false;

  uint total = Vertices.GetCount();

  uint offset = 0;
  uint count = total;

  //Find sub path:
  for (uint i = offset; i < total; i++)
  {
    uint ii = i+1;
    if (Vertices[i].GetType() == nuiPointTypeStop || ii == total)
    {
      count = ii - offset;
      if (Vertices[i].GetType() == nuiPointTypeStop)
        count--;
      Tessellate(rPoints, Vertices, offset, count, Quality);

      offset = ii;
    }
  }

  return res;
}
Example #5
0
bool nuiArc::Tessellate(nuiPath& rVertices, float Quality) const
{
  // I shamelessly stole this code from svgl
  double x1, y1, x2, y2;
  x1 = mStartVertex.Elt[0];
  y1 = mStartVertex.Elt[1];
  x2 = mStopVertex.Elt[0];
  y2 = mStopVertex.Elt[1];
  double angle = mAngle;
  double xr, yr;
  xr = mXRadius;
  yr = mYRadius;

  rVertices.AddVertexOptim(nuiPoint((float)x1, (float)y1));

  if ((x1 == x2) && (y1 == y2) && !mLargeArc)
  {
    return true;
  }

  // be sure mXRadius or mYRadius are non-zero
  if( mXRadius == 0 || mYRadius == 0) 
  {
    rVertices.AddVertexOptim(nuiPoint((float)x2, (float)y2));
    return true;
  }

  // make sure mXRadius and mYRadius are positive
  if(xr < 0)
    xr = -xr;
  if(yr < 0)
    yr = -yr;

  const double cosa = cos(angle * M_PI / 180.0);
  const double sina = sin(angle * M_PI / 180.0);


  // compute the center (see svg.pdf)
  const double xp1 = cosa * (x1 - x2) / 2.0 + sina * (y1 - y2) / 2.f;
  const double yp1 = -sina * (x1 - x2) / 2.0 + cosa * (y1 - y2) / 2.f;

  double rx2 = xr * xr, ry2 = yr * yr, xp12 = xp1 * xp1, yp12 = yp1 * yp1;

  // make sure xr and yr are large enough
  {
    double tmp = xp12 / rx2 + yp12 / ry2;
    if (tmp > 1)
    {
      rx2 *= tmp;
      ry2 *= tmp;
      tmp = sqrt(tmp);
      xr *= tmp;
      yr *= tmp;
    }
  }

  double fact = ( rx2 * ry2 / (rx2 * yp12 + ry2 * xp12)) - 1;
  if (fact < 0) 
  {
    fact = 0;
  }

  fact = sqrt(fact);
  if (mLargeArc == mSweep)
    fact = -fact;

  double xpc = xr * yp1 / yr;
  double ypc =  - yr * xp1 / xr;

  xpc *= fact;
  ypc *= fact;

  double xc = xpc * cosa - ypc * sina + (x1 + x2) / 2.f;
  double yc = xpc * sina + ypc * cosa + (y1 + y2) / 2.f;

  // determine t1 and t2, limits given by (x1, y1) (x2, y2)

  double t1;
  double deltat;
  //    double t2;
  {
    double xv1 = (xp1 - xpc) / xr;
    double yv1 = (yp1 - ypc) / yr;
    double norm1 = xv1 * xv1 + yv1 * yv1;

    double cosangle1 = xv1 / sqrt(norm1);
    if (cosangle1 < -1.0f)
      cosangle1 = -1.0f;
    if (cosangle1 > 1.0f)
      cosangle1 = 1.0f;
    t1 = acos(cosangle1);
    if (yv1 < 0)
      t1 = -t1;

    double xv2 = (-xp1 - xpc) / xr;
    double yv2 = (-yp1 - ypc) / yr;
    double norm2 = xv2 * xv2 + yv2 * yv2;
    deltat = xv1 * xv2 + yv1 * yv2;
    deltat = deltat / sqrt(norm1 * norm2);
    if (deltat < -1.0)
      deltat = -1.0;
    if (deltat > 1.0)
      deltat = 1.0;
    deltat = acos(deltat);
    if ( (xv1 * yv2 - yv1 * xv2) < 0)
      deltat = -deltat;

    if (!mSweep && (deltat > 0))
      deltat -= 2.0 * M_PI;

    if (mSweep && (deltat < 0))
      deltat += 2.0 * M_PI;
  }


  // compute vertices
  /*
  fast incremental cos and sin generation

  cos(a+dt) = cos(a) cos(dt) - sin(a)  sin(dt);
  sin(a+dt) = cos(a) sin(dt) + cos(dt) sin(a);

  <=>
  cos(a+2*dt) = cos(a + dt) cos(dt) - sin(a + dt) sin(dt)
  sin(a+2*dt) = cos(a + dt) sin(dt) + cos(a + dt) sin(a)
  */

  const int nb = ToBelow(M_PI * (xr + yr) * Quality);
  const double dt = deltat / nb;
  const double cosdt = cos(dt);
  const double sindt = sin(dt);
  double cost1_plus_ndt = cos(t1 + dt);
  double sint1_plus_ndt = sin(t1 + dt);

  for (int i = 0; i < nb; ++i) 
  {
    /*
      ellipsoid:
      x(t) = xr.cos(t)
      y(t) = yr.cos(t)
    */


    double x = xr * cost1_plus_ndt;
    double y = yr * sint1_plus_ndt;

    {
      // compute cos and sin
      double tmp = cost1_plus_ndt * cosdt - sint1_plus_ndt * sindt;
      sint1_plus_ndt = cost1_plus_ndt * sindt + sint1_plus_ndt * cosdt; 
      cost1_plus_ndt = tmp;
    }

    // rotate
    // angle = -angle, I don't know why...
    {
      double tmp = x * cosa - y * sina;
      y = x * sina + y * cosa;
      x = tmp;
    }

    // translate
    x += xc;
    y += yc;

    rVertices.AddVertexOptim(nuiPoint((float)x, (float)y));
  }
  return true;
}
Example #6
0
void nuiOutliner::Tessellate(nuiPath& rPoints, const nuiPath& rVertices, uint offset, int count, float Quality) const
{
  nuiPath Left;
  nuiPath Right;

  NGL_ASSERT(count);

  const nuiPoint& rstart = rVertices[offset];
  const nuiPoint& rstop = rVertices[offset + count - 1];
  bool closed = rstart == rstop;

  int segments = count;
  if (!closed)
    segments--;

  int i;
  // Create four outlined vertex per segment:
  for (i = 0; i < segments; i++)
  {
    int p1 = i;
    int p2 = (p1+1);
    p1 += offset;
    p2 += offset;

    const nuiPoint& rPoint = rVertices[p1];
    const nuiPoint& rNextPoint = rVertices[p2];

    if (!(rPoint == rNextPoint))
    {
      nuiVector vec(rNextPoint - rPoint);
      vec.Normalize();
      vec *= mRealLineWidth;
      float tmp = vec[0];
      vec[0] = vec[1];
      vec[1] = -tmp;

      Left.AddVertexOptim(nuiPoint(rPoint + vec));
      Left.AddVertexOptim(nuiPoint(rNextPoint + vec));
      Right.AddVertexOptim(nuiPoint(rPoint - vec));
      Right.AddVertexOptim(nuiPoint(rNextPoint - vec));
    }
  }

  Right.Reverse();

  if (!Left.GetCount() || !Right.GetCount()) // Case of a path where all points have the same coordinates
  {
    switch (mLineCap)
    {
      case nuiLineCapBut:
        // The result is empty.
        break;
      case nuiLineCapRound:
        {
          const double CIRCLE_FACTOR = (1.0/3.5);
          const double X = rstart[0];
          const double Y = rstart[1];

          uint count = ToAbove((double)(2.0 * M_PI * (double)mRealLineWidth * (double)CIRCLE_FACTOR));

          float step = 2.0f * (float)M_PI / (float)count;
          for (uint i = 0; i <= count; i++)
          {
            float angle = step * (float) i;
            float x = (float)(X + sin(angle) * mRealLineWidth);
            float y = (float)(Y + cos(angle) * mRealLineWidth);
            
            rPoints.AddVertexOptim(nuiPoint(x, y, 0));
          }
        }
        break;
      case nuiLineCapSquare:
        {
          const float x = rstart[0];
          const float y = rstart[1];
          rPoints.AddVertexOptim(nuiPoint(x - mRealLineWidth, y - mRealLineWidth));
          rPoints.AddVertexOptim(nuiPoint(x + mRealLineWidth, y - mRealLineWidth));
          rPoints.AddVertexOptim(nuiPoint(x + mRealLineWidth, y + mRealLineWidth));
          rPoints.AddVertexOptim(nuiPoint(x - mRealLineWidth, y + mRealLineWidth));
          rPoints.AddVertexOptim(nuiPoint(x - mRealLineWidth, y - mRealLineWidth));
        }
        break;
    }  
  }
  else if (closed && Left.GetCount() >= 2 && Right.GetCount() >= 2) // Case of a closed path (make sure that is at least a segment).
  {
    // Left:
    int ndx1 = 0;
    int ndx2 = 0;
    for (i = 0; i < segments-1; i++)
    {
      ndx1 = i * 2;
      ndx2 = ndx1 + 2;
      AddJoin(Left[ndx1], Left[ndx1+1], Left[ndx2], Left[ndx2+1], rPoints);
    }
    if (mLineJoin == nuiLineJoinBevel)
      rPoints.AddVertexOptim(rPoints.Front());
    else
      rPoints.Back() = rPoints.Front();
    rPoints.StopPath();

    // Right:
    for (i = 0; i < segments; i++)
    {
      ndx1 = i * 2;
      ndx2 = ndx1 + 2;
      AddJoin(Right[ndx1], Right[ndx1+1], Right[ndx2], Right[ndx2+1], rPoints);
    }
    rPoints.StopPath();
  }
  else
  {
    NGL_ASSERT(!Left.IsEmpty());
    NGL_ASSERT(!Right.IsEmpty());
    int cnt = segments - 1;
    // Left:
    rPoints.AddVertexOptim(Left.Front());
    int ndx1 = 0;
    int ndx2 = 0;
    for (i = 0; i < cnt; i++)
    {
      ndx1 = i * 2;
      ndx2 = ndx1 + 2;
      AddJoin(Left[ndx1], Left[ndx1+1], Left[ndx2], Left[ndx2+1], rPoints);
    }
    AddCap(Left.Back(), Right.Front(), rPoints);

    // Right:
    for (i = 0; i < cnt; i++)
    {
      ndx1 = i * 2;
      ndx2 = ndx1 + 2;
      AddJoin(Right[ndx1], Right[ndx1+1], Right[ndx2], Right[ndx2+1], rPoints);
    }
    AddCap(Right.Back(), Left.Front(), rPoints);
    rPoints.Front() = rPoints.Back();

    rPoints.StopPath();
  }
}
Example #7
0
void nuiPath::AddPathOptim(const nuiPath& rPath)
{
  uint toadd = rPath.GetCount();
  for (uint i = 0; i < toadd; i++)
    AddVertexOptim(rPath[i]);
}