int CalligraphicShader::shade(Stroke &ioStroke) const { Interface0DIterator v; Functions0D::VertexOrientation2DF0D fun; StrokeVertex *sv; for (v = ioStroke.verticesBegin(); !v.isEnd(); ++v) { real thickness; if (fun(v) < 0) return -1; Vec2f vertexOri(fun.result); Vec2r ori2d(-vertexOri[1], vertexOri[0]); ori2d.normalizeSafe(); real scal = ori2d * _orientation; sv = dynamic_cast<StrokeVertex *>(&(*v)); if (_clamp && (scal < 0)) { scal = 0.0; sv->attribute().setColor(1, 1, 1); } else { scal = fabs(scal); sv->attribute().setColor(0, 0, 0); } thickness = _minThickness + scal * (_maxThickness - _minThickness); if (thickness < 0.0) thickness = 0.0; sv->attribute().setThickness(thickness / 2.0, thickness / 2.0); } return 0; }
int SpatialNoiseShader::shade(Stroke &ioStroke) const { Interface0DIterator v, v2; v = ioStroke.verticesBegin(); Vec2r p(v->getProjectedX(), v->getProjectedY()); v2 = v; ++v2; Vec2r p0(v2->getProjectedX(), v2->getProjectedY()); p0 = p + 2 * (p - p0); StrokeVertex *sv; sv = dynamic_cast<StrokeVertex *>(&(*v)); real initU = sv->strokeLength() * real(NB_VALUE_NOISE); if (_pureRandom) initU += RandGen::drand48() * real(NB_VALUE_NOISE); Functions0D::VertexOrientation2DF0D fun; while (!v.isEnd()) { sv = dynamic_cast<StrokeVertex *>(&(*v)); Vec2r p(sv->getPoint()); if (fun(v) < 0) return -1; Vec2r vertexOri(fun.result); Vec2r ori2d(vertexOri[0], vertexOri[1]); ori2d = Vec2r(p - p0); ori2d.normalizeSafe(); PseudoNoise mynoise; real bruit; if (_smooth) bruit = mynoise.turbulenceSmooth(_xScale * sv->curvilinearAbscissa() + initU, _nbOctave); else bruit = mynoise.turbulenceLinear(_xScale * sv->curvilinearAbscissa() + initU, _nbOctave); Vec2r noise(-ori2d[1] * _amount * bruit, ori2d[0] * _amount * bruit); sv->setPoint(p[0] + noise[0], p[1] + noise[1]); p0 = p; ++v; } ioStroke.UpdateLength(); return 0; }
static Stroke *createStroke(Interface1D& inter) { Stroke *stroke = new Stroke; stroke->setId(inter.getId()); float currentCurvilignAbscissa = 0.0f; Interface0DIterator it = inter.verticesBegin(), itend = inter.verticesEnd(); Interface0DIterator itfirst = it; Vec2r current(it->getPoint2D()); Vec2r previous = current; SVertex *sv; CurvePoint *cp; StrokeVertex *stroke_vertex = NULL; bool hasSingularity = false; do { cp = dynamic_cast<CurvePoint*>(&(*it)); if (!cp) { sv = dynamic_cast<SVertex*>(&(*it)); if (!sv) { cerr << "Warning: unexpected Vertex type" << endl; continue; } stroke_vertex = new StrokeVertex(sv); } else { stroke_vertex = new StrokeVertex(cp); } current = stroke_vertex->getPoint2D(); Vec2r vec_tmp(current - previous); real dist = vec_tmp.norm(); if (dist < 1.0e-6) hasSingularity = true; currentCurvilignAbscissa += dist; stroke_vertex->setCurvilinearAbscissa(currentCurvilignAbscissa); stroke->push_back(stroke_vertex); previous = current; ++it; } while ((it != itend) && (it != itfirst)); if (it == itfirst) { // Add last vertex: cp = dynamic_cast<CurvePoint*>(&(*it)); if (!cp) { sv = dynamic_cast<SVertex*>(&(*it)); if (!sv) cerr << "Warning: unexpected Vertex type" << endl; else stroke_vertex = new StrokeVertex(sv); } else { stroke_vertex = new StrokeVertex(cp); } current = stroke_vertex->getPoint2D(); Vec2r vec_tmp(current - previous); real dist = vec_tmp.norm(); if (dist < 1.0e-6) hasSingularity = true; currentCurvilignAbscissa += dist; stroke_vertex->setCurvilinearAbscissa(currentCurvilignAbscissa); stroke->push_back(stroke_vertex); } // Discard the stroke if the number of stroke vertices is less than two if (stroke->strokeVerticesSize() < 2) { delete stroke; return NULL; } stroke->setLength(currentCurvilignAbscissa); if (hasSingularity) { // Try to address singular points such that the distance between two subsequent vertices // are smaller than epsilon. StrokeInternal::StrokeVertexIterator v = stroke->strokeVerticesBegin(); StrokeInternal::StrokeVertexIterator vnext = v; ++vnext; Vec2r next((*v).getPoint()); while (!vnext.isEnd()) { current = next; next = (*vnext).getPoint(); if ((next - current).norm() < 1.0e-6) { StrokeInternal::StrokeVertexIterator vprevious = v; if (!vprevious.isBegin()) --vprevious; // collect a set of overlapping vertices std::vector<StrokeVertex *> overlapping_vertices; overlapping_vertices.push_back(&(*v)); do { overlapping_vertices.push_back(&(*vnext)); current = next; ++v; ++vnext; if (vnext.isEnd()) break; next = (*vnext).getPoint(); } while ((next - current).norm() < 1.0e-6); Vec2r target; bool reverse; if (!vnext.isEnd()) { target = (*vnext).getPoint(); reverse = false; } else if (!vprevious.isBegin()) { target = (*vprevious).getPoint(); reverse = true; } else { // Discard the stroke because all stroke vertices are overlapping delete stroke; return NULL; } current = overlapping_vertices.front()->getPoint(); Vec2r dir(target - current); real dist = dir.norm(); real len = 1.0e-3; // default offset length int nvert = overlapping_vertices.size(); if (dist < len * nvert) { len = dist / nvert; } dir.normalize(); Vec2r offset(dir * len); // add the offset to the overlapping vertices StrokeVertex *sv; std::vector<StrokeVertex *>::iterator it = overlapping_vertices.begin(); if (!reverse) { for (int n = 0; n < nvert; n++) { sv = (*it); sv->setPoint(sv->getPoint() + offset * (n + 1)); ++it; } } else { for (int n = 0; n < nvert; n++) { sv = (*it); sv->setPoint(sv->getPoint() + offset * (nvert - n)); ++it; } } if (vnext.isEnd()) break; } ++v; ++vnext; } } { // Check if the stroke no longer contains singular points Interface0DIterator v = stroke->verticesBegin(); Interface0DIterator vnext = v; ++vnext; Vec2r next((*v).getPoint2D()); bool warning = false; while (!vnext.isEnd()) { current = next; next = (*vnext).getPoint2D(); if ((next - current).norm() < 1.0e-6) { warning = true; break; } ++v; ++vnext; } if (warning && G.debug & G_DEBUG_FREESTYLE) { printf("Warning: stroke contains singular points.\n"); } } return stroke; }