bool TRegion::Imp::isSubRegionOf(const TRegion::Imp &r) const { if (!r.getBBox().contains(getBBox())) return false; for (UINT i = 0; i < m_edge.size(); i++) { for (UINT j = 0; j < r.m_edge.size(); j++) { TEdge *e = r.m_edge[j]; TEdge *subE = m_edge[i]; if (subE->m_index == e->m_index && (subE->m_w0 < m_edge[i]->m_w1) == (e->m_w0 < e->m_w1)) { bool forward = (e->m_w0 < e->m_w1); if (forward && (subE->m_w0 >= e->m_w0 || areAlmostEqual(subE->m_w0, e->m_w0, 1e-3)) && (subE->m_w1 <= e->m_w1 || areAlmostEqual(subE->m_w1, e->m_w1, 1e-3))) return true; if (!forward && (subE->m_w0 <= e->m_w0 || areAlmostEqual(subE->m_w0, e->m_w0, 1e-3)) && (subE->m_w1 >= e->m_w1 || areAlmostEqual(subE->m_w1, e->m_w1, 1e-3))) return true; } } } return false; }
void checkPolyline(const vector<T3DPointD> &p) { int ret; if (p.size() < 3) return; TPointD p1; TPointD p2; int pointSize = (int)p.size() - 1; for (int i = 0; i < pointSize; i++) { for (int j = i + 1; j < pointSize; j++) { vector<DoublePair> res; p1 = TPointD(p[i].x, p[i].y); p2 = TPointD(p[i + 1].x, p[i + 1].y); TSegment s0(p1, p2); p1 = TPointD(p[j].x, p[j].y); p2 = TPointD(p[j + 1].x, p[j + 1].y); TSegment s1(p1, p2); ret = intersect(s0, s1, res); if (ret) assert( (ret == 1) && (areAlmostEqual(res[0].first, 1) || areAlmostEqual(res[0].first, 0)) && (areAlmostEqual(res[0].second, 1) || areAlmostEqual(res[0].second, 0))); } } p1 = TPointD(p.back().x, p.back().y); p2 = TPointD(p[0].x, p[0].y); TSegment s0(p1, p2); for (int j = 0; j < pointSize; j++) { vector<DoublePair> res; p1 = TPointD(p[j].x, p[j].y); p2 = TPointD(p[j + 1].x, p[j + 1].y); TSegment s1(p1, p2); ret = intersect(s0, s1, res); if (ret) assert( (ret == 1) && (areAlmostEqual(res[0].first, 1) || areAlmostEqual(res[0].first, 0)) && (areAlmostEqual(res[0].second, 1) || areAlmostEqual(res[0].second, 0))); } }
void CameraTestTool::drawClosestFieldCamera(double pixelSize) { CleanupParameters *cp = CleanupSettingsModel::instance()->getCurrentParameters(); double zoom = cp->m_closestField / cp->m_camera.getSize().lx; if (areAlmostEqual(zoom, 1.0, 1e-2)) return; TRectD rect(cp->m_camera.getStageRect()); rect = rect.enlarge((zoom - 1) * (rect.x1 - rect.x0 + 1) / 2.0, (zoom - 1) * (rect.y1 - rect.y0 + 1) / 2.0); glColor3d(0.0, 0.0, 1.0); glLineStipple(1, 0xFFFF); glEnable(GL_LINE_STIPPLE); // box glBegin(GL_LINE_STRIP); glVertex2d(rect.x0, rect.y0); glVertex2d(rect.x0, rect.y1 - pixelSize); glVertex2d(rect.x1 - pixelSize, rect.y1 - pixelSize); glVertex2d(rect.x1 - pixelSize, rect.y0); glVertex2d(rect.x0, rect.y0); glEnd(); glDisable(GL_LINE_STIPPLE); // camera name TPointD pos = rect.getP01() + TPointD(0, 4); glPushMatrix(); glTranslated(pos.x, pos.y, 0); glScaled(2, 2, 2); tglDrawText(TPointD(), "Closest Field"); glPopMatrix(); }
void ForecastDisplay::display() { std::cout << "Forecast: "; if (current_pressure_ > last_pressure_) std::cout << "Improving weather on the way!\n"; else if (areAlmostEqual(current_pressure_, last_pressure_, 1e-20f)) std::cout << "More of the same\n"; else if (current_pressure_ < last_pressure_) std::cout << "Watch out for cooler, rainy weather\n"; }
std::string TGeometryFx::getAlias(double frame, const TRenderSettings &info) const { TGeometryFx *tthis = const_cast<TGeometryFx *>(this); TAffine affine = tthis->getPlacement(frame); std::string alias = getFxType(); alias += "["; // alias degli effetti connessi alle porte di input separati da virgole // una porta non connessa da luogo a un alias vuoto (stringa vuota) for (int i = 0; i < getInputPortCount(); ++i) { TFxPort *port = getInputPort(i); if (port->isConnected()) { TRasterFxP ifx = port->getFx(); assert(ifx); alias += ifx->getAlias(frame, info); } alias += ","; } return alias + (areAlmostEqual(affine.a11, 0) ? "0" : ::to_string(affine.a11, 5)) + "," + (areAlmostEqual(affine.a12, 0) ? "0" : ::to_string(affine.a12, 5)) + "," + (areAlmostEqual(affine.a13, 0) ? "0" : ::to_string(affine.a13, 5)) + "," + (areAlmostEqual(affine.a21, 0) ? "0" : ::to_string(affine.a21, 5)) + "," + (areAlmostEqual(affine.a22, 0) ? "0" : ::to_string(affine.a22, 5)) + "," + (areAlmostEqual(affine.a23, 0) ? "0" : ::to_string(affine.a23, 5)) + "]"; }
void expectAlmostEqual(ValueType actual, ValueType expected, const double& precision=0.0001, String failureMessage = String()) { const bool result = areAlmostEqual(actual, expected, precision); if (!result) { if (failureMessage.isNotEmpty()) failureMessage << " -- "; failureMessage << "Expected value: " << expected << ", Actual value: " << actual; } expect(result, failureMessage); }
void TRegion::addEdge(TEdge *e, bool minimizeEdges) { if (minimizeEdges && e->m_s->getMaxThickness() > 0.0 && //outline strokes ignore this !m_imp->m_edge.empty() && m_imp->m_edge.back()->m_index == e->m_index && areAlmostEqual(m_imp->m_edge.back()->m_w1, e->m_w0, 1e-5)) m_imp->m_edge.back()->m_w1 = e->m_w1; else m_imp->m_edge.push_back(e); m_imp->m_isValidBBox = false; //if (e->m_s->isSelfLoop()) // assert(m_imp->m_edge.size()==1); }
TRegion *TRegion::findRegion(const TRegion &r) const { if (areAlmostEqual(r.getBBox(), getBBox(), 1e-3)) return (TRegion *)this; if (!getBBox().contains(r.getBBox())) return 0; TRegion *ret; for (UINT i = 0; i < m_imp->m_includedRegionArray.size(); i++) if ((ret = m_imp->m_includedRegionArray[i]->findRegion(r)) != 0) return ret; return 0; }
bool TRegion::Imp::getInternalPoint(TPointD &p, double left, double right, double y) { assert(left < right); if (areAlmostEqual(left, right, 1e-2)) return false; double mid = 0.5 * (left + right); p = TPointD(mid, y); if (noSubregionContains(p)) return true; if (!getInternalPoint(p, left, mid, y)) return getInternalPoint(p, mid, right, y); else return true; }
void makeOutline(const TStroke *stroke, int startQuad, int endQuad, outlineBoundary &ob, double error2) { //std::ofstream cout("c:\\temp\\outline.txt"); assert(stroke); assert(startQuad >= 0); assert(endQuad < stroke->getChunkCount()); assert(startQuad <= endQuad); TThickQuadratic *tq; std::vector<TQuadratic *> arrayUp, arrayDown; TQuadratic arc; if (!stroke->getChunkCount()) return; //if (startQuad==0) { const TThickQuadratic *tq = stroke->getChunk(startQuad); // trova i punti sul cerchio che corrispondono // a due fette di 90 gradi. // Ritorna una quadratica invece di tre singoli punti solo per compattezza. TQuadratic arc = getCircleQuarter(tq, QUARTER_BEGIN); // estrae le quadratiche che corrispondono ad i due archi... splitCircularArcIntoQuadraticCurves(tq->getP0(), arc.getP0(), arc.getP1(), arrayUp); // e le ordina in modo che l'outline sia composta sempre da // una curva superiore ed una inferiore corrispondente changeDirection(arrayUp); splitCircularArcIntoQuadraticCurves(tq->getP0(), arc.getP1(), arc.getP2(), arrayDown); changeDirection(arrayDown, true); // copia le curve nell'outline; se gli array non hanno la stessa dimensione // quello con meno curve viene riempito con curve improprie // che hanno i punti di controllo coincidente con l'ultimo estremo valido //cout<<"quads del semicerchio left:"<<std::endl; copy(/*cout, */ arrayUp, arrayDown, ob); } for (int i = startQuad; i <= endQuad; ++i) { tq = (TThickQuadratic *)stroke->getChunk(i); TThickPoint p0 = tq->getThickP0(); TThickPoint p1 = tq->getThickP1(); TThickPoint p2 = tq->getThickP2(); if (p0.x == p1.x) { if (p1.x == p2.x && ((p1.y > p0.y && p1.y > p2.y) || (p1.y < p0.y && p1.y < p2.y))) tq = new TThickQuadratic(p0, 0.5 * (p0 + p1), p1); } else if (p0.y == p1.y) { if (p0.y == p2.y && ((p1.x > p0.x && p1.x > p2.x) || (p1.x < p0.x && p1.x < p2.x))) tq = new TThickQuadratic(p0, 0.5 * (p0 + p1), p1); } else { double fac1 = 1.0 / (p0.x - p1.x); double fac2 = 1.0 / (p0.y - p1.y); double aux1 = fac1 * (p2.x - p1.x); double aux2 = fac2 * (p2.y - p1.y); double aux3 = fac1 * (p0.x - p2.x); double aux4 = fac2 * (p0.y - p2.y); if ((areAlmostEqual(aux1, aux2) && aux1 >= 0) || (areAlmostEqual(aux3, aux4) && aux3 >= 0 && aux3 <= 1)) tq = new TThickQuadratic(p0, 0.5 * (p0 + p1), p1); } //cout<<"quad# "<<i<<":" <<*tq<<std::endl; makeOutline(/*cout, */ ob, *tq, error2); if (tq != stroke->getChunk(i)) delete tq; } arrayUp.clear(); arrayDown.clear(); // come sopra ultimo pezzo di arco // if (endQuad==stroke->getChunkCount()-1) { arc = getCircleQuarter(tq, QUARTER_END); splitCircularArcIntoQuadraticCurves(tq->getP2(), arc.getP1(), arc.getP0(), arrayUp); changeDirection(arrayUp); splitCircularArcIntoQuadraticCurves(tq->getP2(), arc.getP2(), arc.getP1(), arrayDown); changeDirection(arrayDown, true); //cout<<"quads del semicerchio right:"<<std::endl; copy(/*cout,*/ arrayUp, arrayDown, ob); } }
int intersect(const TQuadratic &q, const TSegment &s, std::vector<DoublePair> &intersections, bool firstIsQuad) { int solutionNumber = 0; // Note the line `a*x+b*y+c = 0` we search for solutions // di a*x(t)+b*y(t)+c=0 in [0,1] double a = s.getP0().y - s.getP1().y, b = s.getP1().x - s.getP0().x, c = -(a * s.getP0().x + b * s.getP0().y); // se il segmento e' un punto if (0.0 == a && 0.0 == b) { double outParForQuad = q.getT(s.getP0()); if (areAlmostEqual(q.getPoint(outParForQuad), s.getP0())) { if (firstIsQuad) intersections.push_back(DoublePair(outParForQuad, 0)); else intersections.push_back(DoublePair(0, outParForQuad)); return 1; } return 0; } if (q.getP2() - q.getP1() == q.getP1() - q.getP0()) { // the second is a segment.... if (firstIsQuad) return intersect(TSegment(q.getP0(), q.getP2()), s, intersections); else return intersect(s, TSegment(q.getP0(), q.getP2()), intersections); } std::vector<TPointD> bez, pol; bez.push_back(q.getP0()); bez.push_back(q.getP1()); bez.push_back(q.getP2()); bezier2poly(bez, pol); std::vector<double> poly_1(3, 0), sol; poly_1[0] = a * pol[0].x + b * pol[0].y + c; poly_1[1] = a * pol[1].x + b * pol[1].y; poly_1[2] = a * pol[2].x + b * pol[2].y; if (!(rootFinding(poly_1, sol))) return 0; double segmentPar, solution; TPointD v10(s.getP1() - s.getP0()); for (UINT i = 0; i < sol.size(); ++i) { solution = sol[i]; if ((0.0 <= solution && solution <= 1.0) || areAlmostEqual(solution, 0.0, 1e-6) || areAlmostEqual(solution, 1.0, 1e-6)) { segmentPar = (q.getPoint(solution) - s.getP0()) * v10 / (v10 * v10); if ((0.0 <= segmentPar && segmentPar <= 1.0) || areAlmostEqual(segmentPar, 0.0, 1e-6) || areAlmostEqual(segmentPar, 1.0, 1e-6)) { TPointD p1 = q.getPoint(solution); TPointD p2 = s.getPoint(segmentPar); assert(areAlmostEqual(p1, p2, 1e-1)); if (firstIsQuad) intersections.push_back(DoublePair(solution, segmentPar)); else intersections.push_back(DoublePair(segmentPar, solution)); solutionNumber++; } } } return solutionNumber; }
int intersect(const TPointD &p1, const TPointD &p2, const TPointD &p3, const TPointD &p4, std::vector<DoublePair> &intersections) { // This algorithm is presented in Graphics Geems III pag 199 static double Ax, Bx, Ay, By, Cx, Cy, d, f, e; static double x1lo, x1hi, y1lo, y1hi; Ax = p2.x - p1.x; Bx = p3.x - p4.x; // test delle BBox if (Ax < 0.0) { x1lo = p2.x; x1hi = p1.x; } else { x1lo = p1.x; x1hi = p2.x; } if (Bx > 0.0) { if (x1hi < p4.x || x1lo > p3.x) return 0; } else if (x1hi < p3.x || x1lo > p4.x) return 0; Ay = p2.y - p1.y; By = p3.y - p4.y; if (Ay < 0) { y1lo = p2.y; y1hi = p1.y; } else { y1lo = p1.y; y1hi = p2.y; } if (By > 0) { if (y1hi < p4.y || y1lo > p3.y) return 0; } else if (y1hi < p3.y || y1lo > p4.y) return 0; Cx = p1.x - p3.x; Cy = p1.y - p3.y; d = By * Cx - Bx * Cy; f = Ay * Bx - Ax * By; e = Ax * Cy - Ay * Cx; if (f > 0) { if (d < 0) return 0; if (!areAlmostEqual(d, f)) if (d > f) return 0; if (e < 0) return 0; if (!areAlmostEqual(e, f)) if (e > f) return 0; } else if (f < 0) { if (d > 0) return 0; if (!areAlmostEqual(d, f)) if (d < f) return 0; if (e > 0) return 0; if (!areAlmostEqual(e, f)) if (e < f) return 0; } else { if (d < 0 || d > 1 || e < 0 || e > 1) return 0; if (p1 == p2 && p3 == p4) { intersections.push_back(DoublePair(0, 0)); return 1; } // Check that the segments are not on the same line. if (!cross(p2 - p1, p4 - p1)) { // Calculation of Barycentric combinations. double distp2p1 = norm2(p2 - p1); double distp3p4 = norm2(p3 - p4); double dist2_p3p1 = norm2(p3 - p1); double dist2_p4p1 = norm2(p4 - p1); double dist2_p3p2 = norm2(p3 - p2); double dist2_p4p2 = norm2(p4 - p2); int intersection = 0; // Calculation of the first two solutions. double vol1; if (distp3p4) { distp3p4 = sqrt(distp3p4); vol1 = (p1 - p3) * normalize(p4 - p3); if (vol1 >= 0 && vol1 <= distp3p4) // Barycentric combinations valid { intersections.push_back(DoublePair(0.0, vol1 / distp3p4)); ++intersection; } vol1 = (p2 - p3) * normalize(p4 - p3); if (vol1 >= 0 && vol1 <= distp3p4) { intersections.push_back(DoublePair(1.0, vol1 / distp3p4)); ++intersection; } } if (distp2p1) { distp2p1 = sqrt(distp2p1); vol1 = (p3 - p1) * normalize(p2 - p1); if (dist2_p3p2 && dist2_p3p1) if (vol1 >= 0 && vol1 <= distp2p1) { intersections.push_back(DoublePair(vol1 / distp2p1, 0.0)); ++intersection; } vol1 = (p4 - p1) * normalize(p2 - p1); if (dist2_p4p2 && dist2_p4p1) if (vol1 >= 0 && vol1 <= distp2p1) { intersections.push_back(DoublePair(vol1 / distp2p1, 1.0)); ++intersection; } } return intersection; } return -1; } double par_s = d / f; double par_t = e / f; intersections.push_back(DoublePair(par_s, par_t)); return 1; }
int intersect(const TQuadratic &c0, const TQuadratic &c1, std::vector<DoublePair> &intersections, bool checksegments) { int ret; // Works baddly, sometimes patch intersections... if (checksegments) { ret = intersectCloseControlPoints(c0, c1, intersections); if (ret != -2) return ret; } double a = c0.getP0().x - 2 * c0.getP1().x + c0.getP2().x; double b = 2 * (c0.getP1().x - c0.getP0().x); double d = c0.getP0().y - 2 * c0.getP1().y + c0.getP2().y; double e = 2 * (c0.getP1().y - c0.getP0().y); double coeff = b * d - a * e; int i = 0; if (areAlmostEqual(coeff, 0.0)) // c0 is a Segment, or a single point!!! { TSegment s = TSegment(c0.getP0(), c0.getP2()); ret = intersect(s, c1, intersections); if (a == 0 && d == 0) // values of t in s coincide with values of t in c0 return ret; for (i = intersections.size() - ret; i < (int)intersections.size(); i++) { intersections[i].first = c0.getT(s.getPoint(intersections[i].first)); } return ret; } double c = c0.getP0().x; double f = c0.getP0().y; double g = c1.getP0().x - 2 * c1.getP1().x + c1.getP2().x; double h = 2 * (c1.getP1().x - c1.getP0().x); double k = c1.getP0().x; double m = c1.getP0().y - 2 * c1.getP1().y + c1.getP2().y; double p = 2 * (c1.getP1().y - c1.getP0().y); double q = c1.getP0().y; if (areAlmostEqual(h * m - g * p, 0.0)) // c1 is a Segment, or a single point!!! { TSegment s = TSegment(c1.getP0(), c1.getP2()); ret = intersect(c0, s, intersections); if (g == 0 && m == 0) // values of t in s coincide with values of t in c0 return ret; for (i = intersections.size() - ret; i < (int)intersections.size(); i++) { intersections[i].second = c1.getT(s.getPoint(intersections[i].second)); } return ret; } double a2 = (g * d - a * m); double b2 = (h * d - a * p); double c2 = ((k - c) * d + (f - q) * a); coeff = 1.0 / coeff; double A = (a * a + d * d) * coeff * coeff; double aux = A * c2 + (a * b + d * e) * coeff; std::vector<double> t; std::vector<double> solutions; t.push_back(aux * c2 + a * c + d * f - k * a - d * q); aux += A * c2; t.push_back(aux * b2 - h * a - d * p); t.push_back(aux * a2 + A * b2 * b2 - g * a - d * m); t.push_back(2 * A * a2 * b2); t.push_back(A * a2 * a2); rootFinding(t, solutions); // solutions.push_back(0.0); //per convenzione; un valore vale l'altro.... for (i = 0; i < (int)solutions.size(); i++) { if (solutions[i] < 0) { if (areAlmostEqual(solutions[i], 0, 1e-6)) solutions[i] = 0; else continue; } else if (solutions[i] > 1) { if (areAlmostEqual(solutions[i], 1, 1e-6)) solutions[i] = 1; else continue; } DoublePair tt; tt.second = solutions[i]; tt.first = coeff * (tt.second * (a2 * tt.second + b2) + c2); if (tt.first < 0) { if (areAlmostEqual(tt.first, 0, 1e-6)) tt.first = 0; else continue; } else if (tt.first > 1) { if (areAlmostEqual(tt.first, 1, 1e-6)) tt.first = 1; else continue; } intersections.push_back(tt); assert(areAlmostEqual(c0.getPoint(tt.first), c1.getPoint(tt.second), 1e-1)); } return intersections.size(); }
//----------------------------------------------------------------------------- bool TRegion::Imp::contains(const TPointD &p) const { bool leftAreOdd = false; if (!getBBox().contains(p)) return false; //printContains(p); UINT i; int side = 0; for (i = 0; i < m_edge.size() * 2; i++) //i pari, esplora gli edge, //i dispari esplora i segmenti di autoclose tra un edge e il successivo { if (i & 0x1) { TPointD p0 = m_edge[i / 2]->m_s->getPoint(m_edge[i / 2]->m_w1); TPointD p1; if (i / 2 < m_edge.size() - 1) p1 = m_edge[i / 2 + 1]->m_s->getPoint(m_edge[i / 2 + 1]->m_w0); else p1 = m_edge[0]->m_s->getPoint(m_edge[0]->m_w0); if (tmin(p0.y, p1.y) > p.y || tmax(p0.y, p1.y) < p.y) continue; if (!areAlmostEqual(p0, p1, 1e-2)) side = findSides(p, TQuadratic(p0, 0.5 * (p0 + p1), p1), 0.0, 1.0, leftAreOdd, side); continue; } TEdge *e = m_edge[i / 2]; TStroke *s = e->m_s; if (s->getBBox().y0 > p.y || s->getBBox().y1 < p.y) continue; double t0, t1; int chunkIndex0, chunkIndex1; const TThickQuadratic *q0, *q1; s->getChunkAndT(e->m_w0, chunkIndex0, t0); s->getChunkAndT(e->m_w1, chunkIndex1, t1); q0 = s->getChunk(chunkIndex0); q1 = s->getChunk(chunkIndex1); if (i == 0 && areAlmostEqual(q0->getPoint(t0).y, p.y)) { double tEnd; int chunkIndexEnd; TEdge *edgeEnd = m_edge.back(); edgeEnd->m_s->getChunkAndT(edgeEnd->m_w1, chunkIndexEnd, tEnd); assert(areAlmostEqual(edgeEnd->m_s->getChunk(chunkIndexEnd)->getPoint(tEnd).y, p.y)); side = edgeEnd->m_s->getChunk(chunkIndexEnd)->getSpeed(tEnd).y > 0 ? 1 : -1; } if (chunkIndex0 != chunkIndex1) { /*if (chunkIndex0>chunkIndex1) { tswap(chunkIndex0, chunkIndex1); tswap(t0, t1); }*/ if (chunkIndex0 > chunkIndex1) { side = findSides(p, *q0, t0, 0, leftAreOdd, side); for (int j = chunkIndex0 - 1; j > chunkIndex1; j--) side = findSides(p, *s->getChunk(j), 1, 0, leftAreOdd, side); side = findSides(p, *q1, 1, t1, leftAreOdd, side); } else { side = findSides(p, *q0, t0, 1, leftAreOdd, side); for (int j = chunkIndex0 + 1; j < chunkIndex1; j++) side = findSides(p, *s->getChunk(j), 0, 1, leftAreOdd, side); side = findSides(p, *q1, 0, t1, leftAreOdd, side); } } else side = findSides(p, *q0, t0, t1, leftAreOdd, side); if (i & 0x1) delete q0; } return leftAreOdd; }