// Tests the version of the constructor that takes a vector of points // with a small sample of points TEST_F(SplineTest, constructor_from_points_small_case) { std::vector<Point2D> points = {{1, 1}, {3, 3}, {2, 4}, {5, 1}}; Spline spline(points); // Check the start and end points of the spline // (ie. check that the spline passes through the start and end points) EXPECT_EQ(Point2D(1, 1), spline(0)); EXPECT_EQ(Point2D(5, 1), spline(1)); // Check the values at the interpolation points // (ie. check that the spline passes through the interpolation points) EXPECT_EQ(Point2D(3, 3), spline.getPointAtZeroToNIndex(1)); EXPECT_EQ(Point2D(2, 4), spline.getPointAtZeroToNIndex(2)); EXPECT_EQ(Point2D(5, 1), spline.getPointAtZeroToNIndex(3)); // Check a couple points in between interpolation points Point2D p; // Point between the (1,1) and (3,3) interpolation points p = spline.getPointAtZeroToNIndex(0.5); EXPECT_GE(p.x(), 1); EXPECT_LE(p.x(), 3); EXPECT_GE(p.y(), 1); EXPECT_LE(p.y(), 3); // Point between the (2,4) and (5,1) interpolation points p = spline.getPointAtZeroToNIndex(2.5); EXPECT_GE(p.x(), 2); EXPECT_LE(p.x(), 5); EXPECT_GE(p.y(), 1); EXPECT_LE(p.y(), 4); }
void Viewer::DrawBox(const Point2D &x1, const Point2D &x2) { glBegin(GL_LINE_LOOP); glVertex2f(x1.x(), x1.y()); glVertex2f(x1.x(), x2.y()); glVertex2f(x2.x(), x2.y()); glVertex2f(x2.x(), x1.y()); glEnd(); }
void Viewer::DrawQuad(const Point2D &x1, const Point2D &x2) { glBegin(GL_QUADS); glVertex2f(x1.x(), x1.y()); glVertex2f(x1.x(), x2.y()); glVertex2f(x2.x(), x2.y()); glVertex2f(x2.x(), x1.y()); glEnd(); }
void Viewer::DrawCross(const Point2D &x, const LA::Vector2f &size) { glBegin(GL_LINES); glVertex2f(x.x() - size.x(), x.y()); glVertex2f(x.x() + size.x(), x.y()); glVertex2f(x.x(), x.y() - size.y()); glVertex2f(x.x(), x.y() + size.y()); glEnd(); }
TEST_F(TerrainBlockTest, data) { Point2D<int> southWestPixel(position.x() * 256, (position.y() + 1) * 256); Point2D<int> northEastPixel((position.x() + 1) * 256, position.y() * 256); Point2D<double> southWest = GeoPoint::fromPixel(southWestPixel, zoomLevel, 256).toWebMercator(); Point2D<double> northEast = GeoPoint::fromPixel(northEastPixel, zoomLevel, 256).toWebMercator(); double referenceArea = (float(northEast.x()) - float(southWest.x())) * (float(northEast.y()) - float(southWest.y())); const std::vector<float>& vertexBuffer = terrainBlock->vertexBuffer(); const auto& indexBuffer = TerrainBlock::indexBuffer(); ASSERT_EQ(75, vertexBuffer.size()); ASSERT_EQ(96, indexBuffer.size()); auto readPolygon = [&](int startPosition) -> std::tuple<Point3D<float>, Point3D<float>, Point3D<float>> { return std::make_tuple(Point3D<float>(vertexBuffer[indexBuffer[startPosition] * 3], vertexBuffer[indexBuffer[startPosition] * 3 + 1], vertexBuffer[indexBuffer[startPosition] * 3 + 2]), Point3D<float>(vertexBuffer[indexBuffer[startPosition + 1] * 3], vertexBuffer[indexBuffer[startPosition + 1] * 3 + 1], vertexBuffer[indexBuffer[startPosition + 1] * 3 + 2]), Point3D<float>(vertexBuffer[indexBuffer[startPosition + 2] * 3], vertexBuffer[indexBuffer[startPosition + 2] * 3 + 1], vertexBuffer[indexBuffer[startPosition + 2] * 3 + 2])); }; double terrainBlockArea = 0; std::unordered_set<long> heights; for (int i = 0; i < indexBuffer.size(); i += 3) { auto polygon = readPolygon(i); const Point3D<float>& p1 = std::get<0>(polygon); const Point3D<float>& p2 = std::get<1>(polygon); const Point3D<float>& p3 = std::get<2>(polygon); EXPECT_FALSE(p1 == p2); EXPECT_FALSE(p1 == p3); EXPECT_FALSE(p2 == p3); terrainBlockArea += triangleArea(p1, p2, p3); long h1 = lround(p1.z()); long h2 = lround(p2.z()); long h3 = lround(p3.z()); EXPECT_NE(0, h1); EXPECT_NE(0, h2); EXPECT_NE(0, h3); heights.insert(h1); heights.insert(h2); heights.insert(h3); } EXPECT_FLOAT_EQ(referenceArea, terrainBlockArea); EXPECT_EQ(62 - 55 + 1, heights.size()); }
// ********************* SQUARE ********************** Square::Square(Point2D origin, double length, double angle){ this->isconvex=true; this->vertexes.reserve(4); vertexes.push_back(origin); double c(std::cos(angle)); double s(std::sin(angle)); vertexes.push_back(Point2D(origin.x()+length*c, origin.y()+length*s)); vertexes.push_back(Point2D(origin.x()+length*(c-s), origin.y()+length*(c+s))); vertexes.push_back(Point2D(origin.x()-length*s, origin.y()+length*c)); }
void ViewportPainter::drawPoint(Point2D & point) { if(point.getTime() != "-1") { QString text("t = " + point.getTime()); QRect rect(point.x()+TEXT_OFFSET_X, point.y()-TEXT_OFFSET_Y,10*text.length()+2*TEXT_MARGIN,15+2*TEXT_MARGIN); this->setBrush(QColor(255, 255, 255, 255)); this->drawRect(rect); this->drawText(rect,Qt::AlignHCenter|Qt::AlignVCenter,text); } if(point.selected()) this->setBrush(QColor(255, 0, 0, 255)); else this->setBrush(QColor(255, 248, 133, 255)); this->drawEllipse(point.x()-POINT_SIZE/2,point.y()-POINT_SIZE/2,POINT_SIZE,POINT_SIZE); }
double Point2D::distance(Point2D another) { double dx = x() - another.x(); double dy = y() - another.y(); return sqrt( dx*dx + dy*dy); };
Point2D Point2D::moveby(Point2D shift_pt) { double new_x = x() + shift_pt.x(); double new_y = y() + shift_pt.y(); return Point2D(new_x, new_y); };
bool Rectangle::add_point(const Point2D& p){ if(is_point_within(p)){ Point2D currPnt; bool newPnt = true; for(int x = 0; x <m_points_contained.size(); x++){ currPnt = m_points_contained[x]; if(currPnt.x() == p.x() && currPnt.y() == p.y()) newPnt = false; } if(newPnt){ m_points_contained.push_back(p); return true; } else return false; } else return false; }
void TerrainBlockTest::SetUp() { srtmFactory = std::make_unique<TempSRTMFileFactory>(); srtmFactory->createFile(southWestPoint, [&](TempSRTMFileFactory::WriteValueCallback writeValue) { Point2D<int> southWestPixel(position.x() * 256, (position.y() + 1) * 256); Point2D<int> northEastPixel((position.x() + 1) * 256, position.y() * 256); Point2D<double> southWest = GeoPoint::fromPixel(southWestPixel, zoomLevel, 256); Point2D<double> northEast = GeoPoint::fromPixel(northEastPixel, zoomLevel, 256); short counter = 10; for (int y = (southWest.y() - southWestPoint.y()) * HeightMap::POINTS_IN_DEGREE; y <= ceil((northEast.y() - southWestPoint.y()) * HeightMap::POINTS_IN_DEGREE); y++) { for (int x = (southWest.x() - southWestPoint.x()) * HeightMap::POINTS_IN_DEGREE; x <= ceil((northEast.x() - southWestPoint.x()) * HeightMap::POINTS_IN_DEGREE); x++) { writeValue(y, x, counter += 10); } } writeValue(0, HeightMap::POINTS_IN_DEGREE, 0); }); heightGrid = std::make_unique<HeightGrid>(srtmFactory->tmpDirectory(), [](int latitude, int longitude){}); terrainBlock = std::make_unique<TerrainBlock>(Point3D<int>(position.x(), position.y(), zoomLevel), *heightGrid); }
void Point2D::rotate(double const& radiant, Point2D const& center, bool filled) /* Bool Filled = true führt zu ausgeülltem Kreis. sollte viellcht in Klasse Kreis überladen werden? Oder eine adapter Klasse shape eingeführt werden. Diese benötigt diese Art der Drehung für die Darstellung. Derzeit. Ansonsten wird nur die Kontur gemalt. */ { double x,y = 0; if ( !filled ) { x = -center.x()+x_; y = -center.y()+y_; } else { x = center.x()-x_; y = center.y()-y_; } Point2D r{x,y}; r.rotate(radiant); x_ = r.x() + center.x(); y_ = r.y() + center.y(); }
Point3D::Point3D(Point2D pt2d, double z, bool valid = true) { _valid = valid; _x = pt2d.x(); _y = pt2d.y(); _z = z; };
void ViewportPainter::drawBezierCurve(BezierCurve & curve) { Point2D * beginPoint = curve.getBeginPoint(); Point2D * endPoint = curve.getEndPoint(); Point2D * controlPoint = curve.getControlPoint(); // Plus tard dessin de la courbe : // this->drawArc(beginPoint->x(),beginPoint->y(),endPoint->x()-beginPoint->x(),endPoint->y()-beginPoint->y(),0*16,360*16); this->drawLine(beginPoint->x(),beginPoint->y(),endPoint->x(),endPoint->y()); // Dessin du vecteur /*this->setPen(QColor(255, 120, 0, 255)); this->drawPoint(*controlPoint); this->drawLine(beginPoint->x(),beginPoint->y(),controlPoint->x(),controlPoint->y()); // Dessiner la fleche du vecteur //this->drawLine(controlPoint->x(),controlPoint->y()); //this->drawLine(controlPoint->x(),controlPoint->y()); this->setPen(QColor(0, 0, 0, 255));*/ }
void LaserLauncher::draw(void) const { using namespace ImageHandle; const auto count{get_count()}; const auto angle{this->angle()}; const Point2D P{d->d * Point2D(-sin(angle), cos(angle))}; gp::DrawRotaGraphF(gp::level(11), pos().x(), pos().y(), 0.08, angle, shaft, true); gp::DrawRotaGraphF(gp::level(11), pos().x() - P.x(), pos().y() - P.y(), 0.08, angle, right_shell, true); gp::DrawRotaGraphF(gp::level(11), pos().x() + P.x(), pos().y() + P.y(), 0.08, angle, left_shell, true); }
void Viewer::DrawWireCircle(const Point2D &x, const float r) { PrepareCircle(); float dx, dy; glBegin(GL_LINE_LOOP); const int N = int(g_xsCircle.size()); for (int i = 0; i < N; ++i) { dx = r * g_xsCircle[i].v0(); dy = r * g_xsCircle[i].v1(); glVertex2f(dx + x.x(), dy + x.y()); } glEnd(); }
void Viewer::DrawSolidCircle(const Point2D &x, const float r) { PrepareCircle(); float dx, dy; glBegin(GL_TRIANGLE_FAN); glVertex2fv(x); const int N = int(g_xsCircle.size()); //for(int i = 0; i < N; ++i) for (int i = N - 1; i >= 0; --i) { dx = r * g_xsCircle[i].v0(); dy = r * g_xsCircle[i].v1(); glVertex2f(dx + x.x(), dy + x.y()); } glEnd(); }
bool Rectangle::add_point(const Point2D& p) { const std::vector<Point2D> & contained_points = points_contained(); if(is_point_within(p)) { for(unsigned int i=0; i<contained_points.size(); i++) { if(p.x()==contained_points[i].x() && p.y()==contained_points[i].y()) { return false; } if(p.x()!=contained_points[i].x() && p.y()!=contained_points[i].y() && i==contained_points.size()-1) { setMPoints(p); return true; } } return false; } else { return false; } }
void AbstractPolygon::checkConvexity() { Vertices const & myV(this->vertexes); auto mysize=this->size(); // We consider segments and triangles as convex if (mysize <= 3) { this->isconvex=true; return; } //! Since we are dealing with floating points it is better to have // a small number so that |a| < smallNumber means for us a==0 double smallNumber(1000*std::numeric_limits<double>::min()); Point2D p; Point2D v; Point2D u; double res(0.0); double newres(0.0); //! C++11 sintax. decltype(expr) returns the type of the expression for ( decltype(mysize) i=0; i < mysize; ++i) { p = myV[i]; // ! next point Point2D tmp = myV[(i+1) % myV.size()]; v = tmp - p; //! next next point u = myV[(i+2) % myV.size()]; if (i == 0) // in first loop direction is unknown, so save it in res res = u.x() * v.y() - u.y() * v.x() + v.x() * p.y() - v.y() * p.x(); else{ newres = u.x() * v.y() - u.y() * v.x() + v.x() * p.y() - v.y() * p.x(); if (std::abs(res)<smallNumber){ // The two edges are aligned, skip test and update res res=newres; } else if ( std::abs(newres)>= smallNumber && (newres > 0 && res < 0) || (newres < 0 && res > 0) ){ this->isconvex=false; return; } } }// end for this->isconvex=true; return; }
void Viewer::DrawCovariance(const Point2D &x, const Point2DCovariance &S, const float X2) { PrepareCircle(); LA::AlignedMatrix2x2f U; LA::Vector2f l; S.EigenDecompose(U, l, 0.0f); l.x() = sqrtf(l.x() * X2); l.y() = sqrtf(l.y() * X2); xp128f tmp; tmp.vset_all_lane(l.x(), l.y(), l.x(), l.y()); U.m_00_01_10_11() = tmp * U.m_00_01_10_11(); glBegin(GL_LINE_LOOP); const int N = int(g_xsCircle.size()); for (int i = 0; i < N; ++i) { const LA::Vector2f dx = U * g_xsCircle[i]; glVertex2f(dx.x() + x.x(), dx.y() + x.y()); } glEnd(); }
std::string TempSRTMFileFactory::createFile(Point2D<int> southWestPoint, InitFileCallback callback) { std::string path = tmpDirectory_ + '/' + HeightGrid::getSRTMFileName(southWestPoint.y(), southWestPoint.x()); FILE* file = fopen(path.c_str(), "wb"); if (!file) throw std::runtime_error("Can't create file"); WriteValueCallback writeValue = [&](int row, int col, short val) { long offset = ((HeightMap::POINTS_IN_DEGREE - row) * (HeightMap::POINTS_IN_DEGREE + 1) + col) * sizeof(short); if(fseek(file, offset, SEEK_SET)) throw std::runtime_error("fseek failed"); val = htons(val); if(fwrite(&val, sizeof(short), 1, file) != 1) throw std::runtime_error("fwrite returned unexpected result"); }; callback(writeValue); (void) fclose(file); return path; }
void operator()(const Point2D& p) { GNode n = g.createNode(0); g.addNode(n); nodes[p.x() * height + p.y()] = n; }
bool Rectangle::is_point_within(const Point2D& p) const { return (p.x() <= m_upper_right.x() && p.y() <= m_upper_right.y()) || (p.x() >= m_lower_left.x() && p.y() >= m_lower_left.y()); }
bool Rectangle::is_point_within(const Point2D& p) const { return (p.x() <= m_upper_right.x() && p.y() <= m_upper_right.y()) || (p.x() >= m_lower_left.x() && p.y() >= m_lower_left.y()); //error here, both cases must be true to prove point is within bounds }
bool Circle::is_inside(Point2D const& point) const { return (sqrt(pow(center_.x()-point.x(),2) + pow(center_.y()-point.y(),2)) <= radius_); }
bool Intrinsic::Undistort(const Point2D &xd, Point2D *xn, LA::AlignedMatrix2x2f *JT, UndistortionMap *UM, const bool initialized) const { #ifdef CFG_DEBUG if (FishEye()) { UT::Error("TODO (haomin)\n"); } #endif if (!NeedUndistortion()) { *xn = xd; JT->MakeIdentity(); return true; } float dr, j, dx2; LA::AlignedMatrix2x2f J; LA::SymmetricMatrix2x2f A; LA::AlignedMatrix2x2f AI; LA::Vector2f e, dx; #ifdef FTR_UNDIST_DOG_LEG float dx2GN, dx2GD, delta2, beta; LA::Vector2f dxGN, dxGD; bool update, converge; #endif if (UM) { if (UM->Empty()) { UM->Set(*this); } *xn = UM->Get(xd); //#ifdef CFG_DEBUG #if 0 *xn = xd * xn->x(); #endif } else if (!initialized) { *xn = xd; } #if defined FTR_UNDIST_VERBOSE && FTR_UNDIST_VERBOSE == 1 const Point2D _xd = m_k.GetNormalizedToImage(xd); UT::Print("x = %03d %03d", int(_xd.x() + 0.5f), int(_xd.y() + 0.5f)); UT::Print(" e = %f", sqrtf((GetDistorted(*xn) - xd).SquaredLength() * m_k.m_fx * m_k.m_fy)); #endif const float *ds = m_k.m_ds, *jds = m_k.m_jds; const float dx2Conv = FTR_UNDIST_CONVERGE * fxyI(); //const float dx2Conv = FTR_UNDIST_CONVERGE * m_k.m_fxyI; #ifdef FTR_UNDIST_DOG_LEG delta2 = FTR_UNDIST_DL_RADIUS_INITIAL; #endif for (int iIter = 0; iIter < FTR_UNDIST_MAX_ITERATIONS; ++iIter) { #if 0 //#if 1 if (UT::Debugging()) { UT::Print("%d %e %e\n", iIter, xn->x(), xn->y()); } #endif const float x = xn->x(), x2 = x * x, y = xn->y(), y2 = y * y, xy = x * y; const float r2 = x2 + y2, r4 = r2 * r2, r6 = r2 * r4; dr = ds[4] * r6 + ds[1] * r4 + ds[0] * r2 + 1.0f; j = jds[4] * r4 + jds[1] * r2 + ds[0]; if (m_radial6) { const float dr2I = 1.0f / (ds[7] * r6 + ds[6] * r4 + ds[5] * r2 + 1.0f); dr *= dr2I; j = (j - (jds[7] * r4 + jds[6] * r2 + ds[5]) * dr) * dr2I; } e.x() = dr * x; e.y() = dr * y; J.m00() = j * (x2 + x2) + dr; J.m01() = j * (xy + xy); J.m11() = j * (y2 + y2) + dr; //#ifdef CFG_DEBUG #if 0 J.m00() = 1 - 3 * x2 - y2; J.m01() = -2 * xy; J.m11() = 1 - x2 - 3 * y2; #endif if (m_tangential) { const float dx = jds[2] * xy + ds[3] * (r2 + x2 + x2); const float dy = jds[3] * xy + ds[2] * (r2 + y2 + y2); e.x() = dx + e.x(); e.y() = dy + e.y(); const float d2x = jds[2] * x, d2y = jds[2] * y; const float d3x = jds[3] * x, d3y = jds[3] * y; J.m00() = d3x + d3x + d3x + d2y + J.m00(); J.m01() = d2x + d3y + J.m01(); J.m11() = d3x + d2y + d2y + d2y + J.m11(); } J.m10() = J.m01(); e -= xd; LA::SymmetricMatrix2x2f::AAT(J, A); //#ifdef CFG_DEBUG #if 0 A.Set(J.m00(), J.m01(), J.m11()); #endif const LA::Vector2f b = J * e; if (!A.GetInverse(AI)) { //return false; break; } LA::AlignedMatrix2x2f::Ab(AI, b, dx); dx.MakeMinus(); dx2 = dx.SquaredLength(); #ifdef FTR_UNDIST_DOG_LEG if (!UM) { dxGN = dx; dx2GN = dx2; dx2GD = 0.0f; const float F = e.SquaredLength(); const Point2D xnBkp = *xn; update = true; converge = false; for (int iIterDL = 0; iIterDL < FTR_UNDIST_DL_MAX_ITERATIONS; ++iIterDL) { if (dx2GN > delta2 && dx2GD == 0.0f) { const float bl = sqrtf(b.SquaredLength()); const LA::Vector2f g = b * (1.0f / bl); const LA::Vector2f Ag = A * g; const float xl = bl / g.Dot(Ag); g.GetScaled(-xl, dxGD); dx2GD = xl * xl; #ifdef CFG_DEBUG UT::AssertEqual(dxGD.SquaredLength(), dx2GD); #endif } if (dx2GN <= delta2) { dx = dxGN; dx2 = dx2GN; beta = 1.0f; } else if (dx2GD >= delta2) { if (delta2 == 0.0f) { dx = dxGD; dx2 = dx2GD; } else { dxGD.GetScaled(sqrtf(delta2 / dx2GD), dx); dx2 = delta2; } beta = 0.0f; } else { const LA::Vector2f v = dxGN - dxGD; const float d = dxGD.Dot(v), v2 = v.SquaredLength(); //beta = float((-d + sqrt(double(d) * d + (delta2 - dx2GD) * double(v2))) / v2); beta = (-d + sqrtf(d * d + (delta2 - dx2GD) * v2)) / v2; dx = dxGD; dx += v * beta; dx2 = delta2; } *xn += dx; const float dFa = F - (GetDistorted(*xn) - xd).SquaredLength(); const float dFp = F - (e + J * dx).SquaredLength(); const float rho = dFa > 0.0f && dFp > 0.0f ? dFa / dFp : -1.0f; if (rho < FTR_UNDIST_DL_GAIN_RATIO_MIN) { delta2 *= FTR_UNDIST_DL_RADIUS_FACTOR_DECREASE; if (delta2 < FTR_UNDIST_DL_RADIUS_MIN) { delta2 = FTR_UNDIST_DL_RADIUS_MIN; } *xn = xnBkp; update = false; converge = false; continue; } else if (rho > FTR_UNDIST_DL_GAIN_RATIO_MAX) { delta2 = std::max(delta2, FTR_UNDIST_DL_RADIUS_FACTOR_INCREASE * dx2); if (delta2 > FTR_UNDIST_DL_RADIUS_MAX) { delta2 = FTR_UNDIST_DL_RADIUS_MAX; } } update = true; converge = dx2 < dx2Conv; break; } if (!update || converge) { break; } } else #endif { *xn += dx; if (dx2 < dx2Conv) { break; } } #if defined FTR_UNDIST_VERBOSE && FTR_UNDIST_VERBOSE == 2 const std::string str = UT::String("%02d ", iIter); if (iIter == 0) { UT::PrintSeparator(); m_k.GetNormalizedToImage(xd).Print(std::string(str.size(), ' ') + "x = ", false, true); } GetNormalizedToImage(xnBkp).Print(str + "x = ", false, false); UT::Print(" e = %f dx = %f beta = %f\n", sqrtf(F * fxy()), sqrtf(dx2 * fxy()), beta); #endif } if (JT) { J.GetTranspose(*JT); } #if defined FTR_UNDIST_VERBOSE && FTR_UNDIST_VERBOSE == 1 UT::Print(" --> %f\n", sqrtf((GetDistorted(*xn) - xd).SquaredLength() * m_k.m_fx * m_k.m_fy)); #endif return true; }
int KdTree::Node::comparebyX(const Point2D& p) { if (p.x() < p_.x()) return -1; if (p.x() > p_.x()) return 1; return 0; }
Point2D Point2D::operator=(Point2D p2) { return Point2D(p2.x(), p2.y()); };
inline void translate(const Point2D& point) { glTranslated(point.x(), point.y(), 0.0); }
TEST_F(SceneAssemblerTest, terrain) { srtmFactory->createFile(Point2D<int>(0, 0), [&](TempSRTMFileFactory::WriteValueCallback writeValue) { writeValue(0, HeightMap::POINTS_IN_DEGREE, 0); }); constexpr int pixelsInTile = 256; auto textureTileAt = [&](double latitude, double longitude, int zoomLevel) -> Point2D<int> { Point2D<int> pixel = GeoPoint(latitude, longitude).toPixel(zoomLevel, pixelsInTile); return Point2D<int>(pixel.x() / pixelsInTile, pixel.y() / pixelsInTile); }; int expectedSyncCounter = 0; auto terrain = sceneAssembler->terrain(); Point2D<int> center = textureTileAt(0.5, 0.5, 22); sceneAssembler->updateLocation(center, 22); terrain = waitForNewValue<decltype(terrain)>(terrain, [&]() { return sceneAssembler->terrain(); }); EXPECT_EQ(++expectedSyncCounter, syncCounter); auto blocks1 = collect(terrain); for (auto&& block : blocks1) EXPECT_EQ(2, block.use_count()); center = advance(center, 1, 0); sceneAssembler->updateLocation(center, 22); terrain = waitForNewValue<decltype(terrain)>(terrain, [&]() { return sceneAssembler->terrain(); }); EXPECT_EQ(++expectedSyncCounter, syncCounter); auto blocks2 = collect(terrain); { std::vector<std::shared_ptr<PlatformTerrainBlock>> diff; std::set_difference(blocks2.begin(), blocks2.end(), blocks1.begin(), blocks1.end(), std::back_inserter(diff)); EXPECT_EQ(SceneAssembler::TERRAIN_GRID_SIZE, diff.size()); } center = advance(center, 0, 1); sceneAssembler->updateLocation(center, 22); terrain = waitForNewValue<decltype(terrain)>(terrain, [&]() { return sceneAssembler->terrain(); }); EXPECT_EQ(++expectedSyncCounter, syncCounter); auto blocks3 = collect(terrain); { std::vector<std::shared_ptr<PlatformTerrainBlock>> diff1; std::set_difference(blocks3.begin(), blocks3.end(), blocks2.begin(), blocks2.end(), std::back_inserter(diff1)); EXPECT_EQ(SceneAssembler::TERRAIN_GRID_SIZE, diff1.size()); std::vector<std::shared_ptr<PlatformTerrainBlock>> diff2; std::set_difference(blocks3.begin(), blocks3.end(), blocks1.begin(), blocks1.end(), std::back_inserter(diff2)); EXPECT_EQ(2 * SceneAssembler::TERRAIN_GRID_SIZE - 1, diff2.size()); } center = textureTileAt(0.5, 0.5, 21); sceneAssembler->updateLocation(center, 21); terrain = waitForNewValue<decltype(terrain)>(terrain, [&]() { return sceneAssembler->terrain(); }); EXPECT_EQ(++expectedSyncCounter, syncCounter); auto terrain0 = terrain; auto blocks4 = collect(terrain); { std::vector<std::shared_ptr<PlatformTerrainBlock>> diff; std::set_difference(blocks4.begin(), blocks4.end(), blocks1.begin(), blocks1.end(), std::back_inserter(diff)); EXPECT_EQ(SceneAssembler::TERRAIN_GRID_SIZE * SceneAssembler::TERRAIN_GRID_SIZE, diff.size()); } center = advance(center, 1, 2); sceneAssembler->updateLocation(center, 21); terrain = waitForNewValue<decltype(terrain)>(terrain, [&]() { return sceneAssembler->terrain(); }); EXPECT_EQ(++expectedSyncCounter, syncCounter); EXPECT_TRUE((*terrain0)[2][1] == (*terrain)[0][0]); center = advance(center, 0, -15); sceneAssembler->updateLocation(center, 21); terrain = waitForNewValue<decltype(terrain)>(terrain, [&]() { return sceneAssembler->terrain(); }); }