Point getClosestOnLine(Point from, Point p0, Point p1) { Point direction = p1 - p0; Point toFrom = from-p0; int64_t projected_x = dot(toFrom, direction) ; int64_t x_p0 = 0; int64_t x_p1 = vSize2(direction); if (projected_x <= x_p0) { return p0; } if (projected_x >= x_p1) { return p1; } else { if (vSize2(direction) == 0) { std::cout << "warning! too small segment" << std::endl; return p0; } Point ret = p0 + projected_x / vSize(direction) * direction / vSize(direction); return ret ; } }
void SparseGridTest::getNearestAssert( const std::vector<Point>& registered_points, Point target, const coord_t grid_size, Point* expected, const std::function<bool(const typename SparsePointGridInclusive<Point>::Elem& elem)> &precondition) { SparsePointGridInclusive<Point> grid(grid_size); for (Point point : registered_points) { grid.insert(point, point); } typename SparsePointGridInclusive<Point>::Elem result; //The actual call to test. const bool success = grid.getNearest(target, grid_size, result, precondition); { std::stringstream ss; ss << "getNearest returned " << success << " but should've returned " << (expected != nullptr) << "."; CPPUNIT_ASSERT_MESSAGE(ss.str(), success == (expected != nullptr)); } if (expected) { std::stringstream ss; ss << "getNearest reported the nearest point to be " << result.val << " (distance " << vSize(target - result.val) << "), but it was " << *expected << " (distance " << vSize(*expected - target) << ")."; CPPUNIT_ASSERT_MESSAGE(ss.str(), result.val == *expected); } }
bool MergeInfillLines::isConvertible(unsigned int path_idx_first_move, Point& first_middle, Point& second_middle, int64_t& line_width, bool use_second_middle_as_first) { int64_t max_line_width = nozzle_size * 3 / 2; unsigned int idx = path_idx_first_move; if (idx + 3 > paths.size()-1) return false; if (paths[idx+0].config != &travelConfig) return false; if (paths[idx+1].points.size() > 1) return false; if (paths[idx+1].config == &travelConfig) return false; // if (paths[idx+2].points.size() > 1) return false; if (paths[idx+2].config != &travelConfig) return false; if (paths[idx+3].points.size() > 1) return false; if (paths[idx+3].config == &travelConfig) return false; Point& a = paths[idx+0].points.back(); // first extruded line from Point& b = paths[idx+1].points.back(); // first extruded line to Point& c = paths[idx+2].points.back(); // second extruded line from Point& d = paths[idx+3].points.back(); // second extruded line to Point ab = b - a; Point cd = d - c; int64_t prod = dot(ab,cd); if (std::abs(prod) + 400 < vSize(ab) * vSize(cd)) // 400 = 20*20, where 20 micron is the allowed inaccuracy in the dot product, introduced by the inaccurate point locations of a,b,c,d return false; // extrusion moves not in the same or opposite diraction if (prod < 0) { ab = ab * -1; } Point infill_vector = (cd + ab) / 2; if (!shorterThen(infill_vector, 5 * nozzle_size)) return false; // infill lines too far apart first_middle = (use_second_middle_as_first)? second_middle : (a + b) / 2; second_middle = (c + d) / 2; Point dir_vector_perp = crossZ(second_middle - first_middle); int64_t dir_vector_perp_length = vSize(dir_vector_perp); // == dir_vector_length if (dir_vector_perp_length == 0) return false; if (dir_vector_perp_length > 5 * nozzle_size) return false; // infill lines too far apart line_width = std::abs( dot(dir_vector_perp, infill_vector) / dir_vector_perp_length ); if (line_width > max_line_width) return false; // combined lines would be too wide if (line_width == 0) return false; // dot is zero, so lines are in each others extension, not next to eachother { // check whether the two lines are adjacent Point ca = first_middle - c; double ca_size = vSizeMM(ca); double cd_size = vSizeMM(cd); double prod = INT2MM(dot(ca, cd)); double fraction = prod / ( ca_size * cd_size ); int64_t line2line_dist = MM2INT(cd_size * std::sqrt(1.0 - fraction * fraction)); if (line2line_dist + 20 > paths[idx+1].config->getLineWidth()) return false; // there is a gap between the two lines } return true; };
std::shared_ptr<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>> Comb::findBestCrossing(PolygonRef from, Point estimated_start, Point estimated_end) { ClosestPolygonPoint* best_in = nullptr; ClosestPolygonPoint* best_out = nullptr; int64_t best_detour_dist = std::numeric_limits<int64_t>::max(); std::vector<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>> crossing_out_candidates = PolygonUtils::findClose(from, getBoundaryOutside(), getOutsideLocToLine()); for (std::pair<ClosestPolygonPoint, ClosestPolygonPoint>& crossing_candidate : crossing_out_candidates) { int64_t crossing_dist2 = vSize2(crossing_candidate.first.location - crossing_candidate.second.location); if (crossing_dist2 > max_crossing_dist2) { continue; } int64_t dist_to_start = vSize(crossing_candidate.second.location - estimated_start); // use outside location, so that the crossing direction is taken into account int64_t dist_to_end = vSize(crossing_candidate.second.location - estimated_end); int64_t detour_dist = dist_to_start + dist_to_end; if (detour_dist < best_detour_dist) { best_in = &crossing_candidate.first; best_out = &crossing_candidate.second; best_detour_dist = detour_dist; } } if (best_detour_dist == std::numeric_limits<int64_t>::max()) { return std::shared_ptr<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>>(); } return std::make_shared<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>>(*best_in, *best_out); }
void WallOverlapComputation::debugCheck() { for (std::pair<WallOverlapPointLink, bool> pair : overlap_point_links) { if (std::abs(vSize( pair.first.a.p() - pair.first.b.p()) - pair.first.dist) > 10) DEBUG_PRINTLN(vSize( pair.first.a.p() - pair.first.b.p())<<" != " << pair.first.dist); } }
void WallOverlapComputation::addOverlapEndings() { // for (WallOverlapPointLink& link : end_points) // { // // assume positive direction for a, negative for b // Loc2ListPolyIndex::iterator a_it_f = loc_to_list_poly_idx.find(link.a); // if (a_it_f == loc_to_list_poly_idx.end()) { DEBUG_PRINTLN(" ERROR: cannot find point a!! "); } // ListPolygon::iterator a_it = a_it_f->second; // // Loc2ListPolyIndex::iterator b_it_f = loc_to_list_poly_idx.find(link.b); // if (b_it_f == loc_to_list_poly_idx.end()) { DEBUG_PRINTLN(" ERROR: cannot find point b!! "); } // ListPolygon::iterator b_it = b_it_f->second; // // ListPolygon::iterator a_it_next = a_it; // a_it_next++; // if (a_it_next == // } // for (ListPolygon& poly : list_polygons) // { // for (ListPolygon::iterator it = poly.begin(); it != poly.end(); ++it) // { // Point& p = *it; // // } // } for (std::pair<WallOverlapPointLink, bool> link_pair : overlap_point_links) { WallOverlapPointLink& link = link_pair.first; ListPolyIt a_next = link.a; ++a_next; ListPolyIt b_next = link.b; --b_next; Point& a1 = link.a.p(); Point& a2 = a_next.p(); Point& b1 = link.b.p(); Point& b2 = b_next.p(); Point a = a2-a1; Point b = b2-b1; if (point_to_link.find(a_next.p()) == point_to_link.end() || point_to_link.find(b_next.p()) == point_to_link.end()) { int64_t dist = overlapEndingDistance(a1, a2, b1, b2, link.dist); if (dist > 0) { Point a_p = a1 + a * dist / vSize(a); ListPolygon::iterator new_a = link.a.poly.insert(a_next.it, a_p); Point b_p = b1 + b * dist / vSize(b); ListPolygon::iterator new_b = link.a.poly.insert(link.b.it, b_p); addOverlapPoint(ListPolyIt(link.a.poly, new_a), ListPolyIt(link.b.poly, new_b), lineWidth); } } } }
std::shared_ptr<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>> Comb::Crossing::findBestCrossing(const Polygons& outside, const PolygonRef from, const Point estimated_start, const Point estimated_end, Comb& comber) { ClosestPolygonPoint* best_in = nullptr; ClosestPolygonPoint* best_out = nullptr; int64_t best_detour_score = std::numeric_limits<int64_t>::max(); int64_t best_crossing_dist2; std::vector<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>> crossing_out_candidates = PolygonUtils::findClose(from, outside, comber.getOutsideLocToLine()); bool seen_close_enough_connection = false; for (std::pair<ClosestPolygonPoint, ClosestPolygonPoint>& crossing_candidate : crossing_out_candidates) { int64_t crossing_dist2 = vSize2(crossing_candidate.first.location - crossing_candidate.second.location); if (crossing_dist2 > comber.max_crossing_dist2 * 2) { // preliminary filtering continue; } int64_t dist_to_start = vSize(crossing_candidate.second.location - estimated_start); // use outside location, so that the crossing direction is taken into account int64_t dist_to_end = vSize(crossing_candidate.second.location - estimated_end); int64_t detour_dist = dist_to_start + dist_to_end; int64_t detour_score = crossing_dist2 + detour_dist * detour_dist / 1000; // prefer a closest connection over a detour // The detour distance is generally large compared to the crossing distance. // While the crossing is generally about 1mm across, // the distance between an arbitrary point and the boundary may well be a couple of centimetres. // So the crossing_dist2 is about 1.000.000 while the detour_dist_2 is in the order of 400.000.000 // In the end we just want to choose between two points which have the _same_ crossing distance, modulo rounding error. if ((!seen_close_enough_connection && detour_score < best_detour_score) // keep the best as long as we havent seen one close enough (so that we may walk along the polygon to find a closer connection from it in the code below) || (!seen_close_enough_connection && crossing_dist2 <= comber.max_crossing_dist2) // make the one which is close enough the best as soon as we see one close enough || (seen_close_enough_connection && crossing_dist2 <= comber.max_crossing_dist2 && detour_score < best_detour_score)) // update to keep the best crossing which is close enough already { if (!seen_close_enough_connection && crossing_dist2 <= comber.max_crossing_dist2) { seen_close_enough_connection = true; } best_in = &crossing_candidate.first; best_out = &crossing_candidate.second; best_detour_score = detour_score; best_crossing_dist2 = crossing_dist2; } } if (best_detour_score == std::numeric_limits<int64_t>::max()) { // i.e. if best_in == nullptr or if best_out == nullptr return std::shared_ptr<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>>(); } if (best_crossing_dist2 > comber.max_crossing_dist2) { // find closer point on line segments, rather than moving between vertices of the polygons only PolygonUtils::walkToNearestSmallestConnection(*best_in, *best_out); best_crossing_dist2 = vSize2(best_in->location - best_out->location); if (best_crossing_dist2 > comber.max_crossing_dist2) { return std::shared_ptr<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>>(); } } return std::make_shared<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>>(*best_in, *best_out); }
void SparseGridTest::getNearbyAssert( const std::vector<Point>& registered_points, Point target, const coord_t grid_size, const std::unordered_set<Point>& expected_near, const std::unordered_set<Point>& expected_far) { SparsePointGridInclusive<Point> grid(grid_size); for(Point point : registered_points) { grid.insert(point, point); } //The actual call to test. const std::vector<typename SparsePointGridInclusive<Point>::Elem> result = grid.getNearby(target, grid_size); //Are all near points reported as near? for (const Point point : expected_near) { std::stringstream ss; ss << "Point " << point << " is near " << target << " (distance " << vSize(point - target) << "), but getNearby didn't report it as such. Grid size: " << grid_size; //Must be in result. CPPUNIT_ASSERT_MESSAGE( ss.str(), std::find_if(result.begin(), result.end(), [&point](const typename SparsePointGridInclusive<Point>::Elem &elem) { return elem.val == point; }) != result.end()); } //Are all far points NOT reported as near? for (const Point point : expected_far) { std::stringstream ss; ss << "Point " << point << " is far from " << target << " (distance " << vSize(point - target) << "), but getNearby thought it was near. Grid size: " << grid_size; //Must not be in result. CPPUNIT_ASSERT_MESSAGE( ss.str(), std::find_if(result.begin(), result.end(), [&point](const typename SparsePointGridInclusive<Point>::Elem &elem) { return elem.val == point; }) == result.end()); } }
void SparseGridTest::getNearbyLineTest() { std::vector<Point> input; for (coord_t x = 0; x < 200; x++) { input.emplace_back(x, 95); } const Point target(100, 100); const coord_t grid_size = 10; std::unordered_set<Point> near; std::unordered_set<Point> far; for (const Point point : input) { coord_t distance = vSize(point - target); if (distance < grid_size) { near.insert(point); } else if (distance > grid_size * 2) //Grid size * 2 are guaranteed to be considered "far". { far.insert(point); } } getNearbyAssert(input, target, grid_size, near, far); }
void BucketGrid2DTest::findNearbyObjectsLineTest() { std::vector<Point> input; for (long long x = 0; x < 200; x++) { input.emplace_back(x, 95); } const Point target(100, 100); const unsigned long long grid_size = 10; std::unordered_set<Point> near; std::unordered_set<Point> far; for (const Point point : input) { unsigned long long distance = vSize(point - target); if (distance < grid_size) { near.insert(point); } else if (distance > grid_size * 2) //Grid size * 2 are guaranteed to be considered "far". { far.insert(point); } } findNearbyObjectsAssert(input, target, grid_size, near, far); }
void PrimeTower::addPurgeMove(LayerPlan& gcode_layer, int extruder_nr, const ExtruderTrain *train, const Point& start_pos, const Point& end_pos, double purge_volume) const { // Find out how much purging needs to be done. const GCodePathConfig& current_gcode_path_config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr]; const coord_t purge_move_length = vSize(start_pos - end_pos); const unsigned int line_width = current_gcode_path_config.getLineWidth(); const double layer_height_mm = (gcode_layer.getLayerNr() == 0) ? train->getSettingInMillimeters("layer_height_0") : train->getSettingInMillimeters("layer_height"); const double normal_volume = INT2MM(INT2MM(purge_move_length * line_width)) * layer_height_mm; // Volume extruded on the "normal" move float purge_flow = purge_volume / normal_volume; const double purge_move_length_mm = INT2MM(purge_move_length); const double purge_move_time = purge_move_length_mm / current_gcode_path_config.getSpeed(); const double purge_extrusion_speed_mm3_per_sec = purge_volume / purge_move_time; const double max_possible_extursion_speed_mm3_per_sec = 3.0; const double speed = current_gcode_path_config.getSpeed(); double speed_factor = 1.0; if (purge_extrusion_speed_mm3_per_sec > max_possible_extursion_speed_mm3_per_sec) { // compensate the travel speed for the large extrusion amount const double min_time_needed_for_extrusion = purge_volume / max_possible_extursion_speed_mm3_per_sec; const double compensated_speed = purge_move_length_mm / min_time_needed_for_extrusion; speed_factor = compensated_speed / speed; } // As we need a plan, which can't have a stationary extrusion, we use an extrusion move to prime. // This has the added benefit that it will evenly spread the primed material inside the tower. gcode_layer.addExtrusionMove(end_pos, current_gcode_path_config, SpaceFillType::None, purge_flow, false, speed_factor); }
void LinearAlg2DTest::getPointOnLineWithDistAssert(const Point p, const Point a, const Point b, int64_t dist, Point actual_result, bool actual_returned) { Point supposed_result; bool supposed_returned = LinearAlg2D::getPointOnLineWithDist(p, a, b, dist, supposed_result); int64_t returned_dist = vSize(supposed_result - p); std::stringstream ss; if (actual_returned) { if (supposed_returned) { ss << "Point " << p << " was projected on (" << a << "-" << b << ") to " << supposed_result << " instead of " << actual_result << "."; } else { ss << "Point " << p << " wasn't projected on (" << a << "-" << b << ") instead of projecting to " << actual_result << "."; } } else { if (supposed_returned) { ss << "Point " << p << " was projected on (" << a << "-" << b << ") to " << supposed_result << ", but it wasn't supposed to project."; } else { ss << "This is no error! This should never show!"; } } ss << " \t Requested dist was " << dist << " result dist is " << returned_dist << "."; CPPUNIT_ASSERT_MESSAGE(ss.str(), (!actual_returned && !supposed_returned) || (actual_returned && vSize2(actual_result - supposed_result) < 10 * 10 && std::abs(returned_dist - dist) < 10)); }
void FffPolygonGenerator::processFuzzyWalls(SliceMeshStorage& mesh) { if (mesh.getSettingAsCount("wall_line_count") == 0) { return; } int64_t fuzziness = mesh.getSettingInMicrons("magic_fuzzy_skin_thickness"); int64_t avg_dist_between_points = mesh.getSettingInMicrons("magic_fuzzy_skin_point_dist"); int64_t min_dist_between_points = avg_dist_between_points * 3 / 4; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value int64_t range_random_point_dist = avg_dist_between_points / 2; for (unsigned int layer_nr = 0; layer_nr < mesh.layers.size(); layer_nr++) { SliceLayer& layer = mesh.layers[layer_nr]; for (SliceLayerPart& part : layer.parts) { Polygons results; Polygons& skin = (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") == ESurfaceMode::SURFACE)? part.outline : part.insets[0]; for (PolygonRef poly : skin) { // generate points in between p0 and p1 PolygonRef result = results.newPoly(); int64_t dist_left_over = rand() % (min_dist_between_points / 2); // the distance to be traversed on the line before making the first new point Point* p0 = &poly.back(); for (Point& p1 : poly) { // 'a' is the (next) new point between p0 and p1 Point p0p1 = p1 - *p0; int64_t p0p1_size = vSize(p0p1); int64_t dist_last_point = dist_left_over + p0p1_size * 2; // so that p0p1_size - dist_last_point evaulates to dist_left_over - p0p1_size for (int64_t p0pa_dist = dist_left_over; p0pa_dist < p0p1_size; p0pa_dist += min_dist_between_points + rand() % range_random_point_dist) { int r = rand() % (fuzziness * 2) - fuzziness; Point perp_to_p0p1 = turn90CCW(p0p1); Point fuzz = normal(perp_to_p0p1, r); Point pa = *p0 + normal(p0p1, p0pa_dist) + fuzz; result.add(pa); dist_last_point = p0pa_dist; } dist_left_over = p0p1_size - dist_last_point; p0 = &p1; } while (result.size() < 3 ) { unsigned int point_idx = poly.size() - 2; result.add(poly[point_idx]); if (point_idx == 0) { break; } point_idx--; } if (result.size() < 3) { result.clear(); for (Point& p : poly) result.add(p); } } skin = results; } } }
bool wxStaticBox::Create( wxWindow* pParent, wxWindowID vId, const wxString& rsLabel, const wxPoint& rPos, const wxSize& rSize, long lStyle, const wxString& rsName ) { if(!CreateControl( pParent ,vId ,rPos ,rSize ,lStyle ,wxDefaultValidator ,rsName )) { return false; } wxPoint vPos(0,0); wxSize vSize(0,0); if (!OS2CreateControl( wxT("STATIC") ,SS_GROUPBOX ,vPos ,vSize ,rsLabel )) { return false; } // // To be transparent we should have the same colour as the parent as well // SetBackgroundColour(GetParent()->GetBackgroundColour()); LONG lColor = (LONG)wxBLACK->GetPixel(); ::WinSetPresParam( m_hWnd ,PP_FOREGROUNDCOLOR ,sizeof(LONG) ,(PVOID)&lColor ); lColor = (LONG)m_backgroundColour.GetPixel(); ::WinSetPresParam( m_hWnd ,PP_BACKGROUNDCOLOR ,sizeof(LONG) ,(PVOID)&lColor ); SetSize( rPos.x ,rPos.y ,rSize.x ,rSize.y ); return true; } // end of wxStaticBox::Create
coord_t MergeInfillLines::calcPathLength(const Point path_start, GCodePath& path) const { Point previous_point = path_start; coord_t result = 0; for (const Point point : path.points) { result += vSize(point - previous_point); previous_point = point; } return result; }
/* * @brief * Create FBO */ bool SurfaceTextureBuffer::CreateFBO() { // Get renderer Renderer &cRenderer = static_cast<Renderer&>(GetRenderer()); // Get the depending of the texture buffer type PLRenderer::TextureBuffer *pTextureBuffer = static_cast<PLRenderer::TextureBuffer*>(m_cTextureBufferHandler.GetResource()); if (pTextureBuffer) { // Get size Vector2i vSize(-1, -1); switch (pTextureBuffer->GetType()) { case PLRenderer::Resource::TypeTextureBuffer2D: { PLRenderer::TextureBuffer2D *pTextureBuffer2D = static_cast<PLRenderer::TextureBuffer2D*>(pTextureBuffer); vSize = pTextureBuffer2D->GetSize(); break; } case PLRenderer::Resource::TypeTextureBufferCube: { PLRenderer::TextureBufferCube *pTextureBufferCube = static_cast<PLRenderer::TextureBufferCube*>(pTextureBuffer); const uint32 nSize = pTextureBufferCube->GetSize(); vSize.x = vSize.y = nSize; break; } } if (vSize.x > 0 && vSize.y > 0) { // Initialize frame buffer m_pFrameBufferObject = new FrameBufferObject(); uint32 nFormat = 0; // Depth buffer requested? if (m_nFlags & Depth) nFormat |= FrameBufferObject::Depth24; // Depth buffer only? (for instance for depth shadow mapping) if (pTextureBuffer->GetFormat() != PLRenderer::TextureBuffer::D16 && pTextureBuffer->GetFormat() != PLRenderer::TextureBuffer::D24 && pTextureBuffer->GetFormat() != PLRenderer::TextureBuffer::D32) nFormat |= FrameBufferObject::Color; // Stencil buffer requested? if (m_nFlags & Stencil) nFormat |= FrameBufferObject::Stencil; if (m_pFrameBufferObject->Initialize(cRenderer, vSize, nFormat, pTextureBuffer->GetFormat(), (m_nFlags & NoMultisampleAntialiasing) != 0)) { // Jipi, all went fine and we are still here! :) return true; } else { // D'OH!! delete m_pFrameBufferObject; m_pFrameBufferObject = nullptr; } } } // Error! return false; }
// ----------------------------------------------------------------------------- // CTestPlatAlfVisual::TestAlfLayoutSetAndGetL // ----------------------------------------------------------------------------- // TInt CTestPlatAlfVisual::TestAlfLayoutSetAndGetL( CStifItemParser& /*aItem*/ ) { _LIT( KTestPlatAlfVisual, "TestPlatAlfVisual" ); _LIT( KTestAlfLayoutSetAndGetL, "TestAlfLayoutSetAndGetL" ); TestModuleIf().Printf( 0, KTestPlatAlfVisual, KTestAlfLayoutSetAndGetL ); // Print to log file iLog->Log( KTestAlfLayoutSetAndGetL ); CAlfLayout* vLayout = CAlfLayout::AddNewL( *iAlfCtl ); CAlfImageVisual* vVisualOne = CAlfImageVisual::AddNewL( *iAlfCtl ); TUid vUid = { 0x00000000 }; TAlfImage vFirstImage( vUid, EAknsAppIconTypeList, TSize( 1, 1), EAspectRatioPreserved, 0, 0, 0, 0 ); vVisualOne->SetImage( vFirstImage ); CAlfImageVisual* vVisualTwo = CAlfImageVisual::AddNewL( *iAlfCtl ); TUid vSecUid = { 0x00000001 }; TAlfImage vSecImage( vSecUid, EAknsAppIconTypeList, TSize( 1, 1), EAspectRatioPreserved, 0, 0, 0, 0 ); vVisualTwo->SetImage( vSecImage ); vLayout->Append( vVisualOne ); vLayout->Append( vVisualTwo ); vLayout->EnableScrollingL(); vLayout->Scrolling(); TAlfTimedPoint vPoint( 0, 0 ); vLayout->SetScrollOffset( vPoint ); vLayout->ScrollOffset(); TPoint vPos( 0, 1); TSize vSize( 1, 1 ); vLayout->ChildOrdinal( 1 ); vLayout->ChildPos( 0, vPos ); vLayout->ChildSize( 0, vSize ); TAlfXYMetric vXYMetric; vLayout->SetInnerPadding( vXYMetric ); vLayout->InnerPaddingAsMetric(); const TPoint vConstPos( 1, 1); vLayout->SetInnerPadding( vConstPos ); vLayout->InnerPadding(); vLayout->SetTransitionTime( 1 ); vLayout->TransitionTime(); vLayout->HorizontalInnerPadding(); vLayout->VerticalInnerPadding(); vLayout->InnerPaddingInBaseUnits(); vLayout->EffectiveLayoutOrdinal( *vVisualTwo ); return KErrNone; }
int addInvisibleBlockade(lua_State *l) { Ogre::Vector3 vPos(Ogre::StringConverter::parseVector3(lua_tostring(l, 1))); Ogre::Vector3 vSize(Ogre::StringConverter::parseVector3(lua_tostring(l, 2))); btRigidBody::btRigidBodyConstructionInfo rbConstruction(0, new btDefaultMotionState(), new btBoxShape(BtOgre::Convert::toBullet(vSize))); btRigidBody *pRB = new btRigidBody(rbConstruction); pRB->setWorldTransform(btTransform(btQuaternion::getIdentity(), BtOgre::Convert::toBullet(vPos))); GameScriptParser::getSingleton().getMap()->getPhysicsManager()->getWorld()->addRigidBody(pRB, COL_WALL, MASK_BLOCKADE_COLLIDES_WITH); lua_pushinteger(l, GameScriptParser::getSingleton().addPointerToMap(pRB, GameScriptParser::UserPointerData::RIGID_BODY)); return 1; }
void SparseGridTest::getNearestEqualTest() { std::vector<Point> registered_points; registered_points.emplace_back(95, 100); registered_points.emplace_back(105, 100); Point target = Point(100, 100); const coord_t grid_size = 10; const Point expected1 = Point(95, 100); const Point expected2 = Point(105, 100); SparsePointGridInclusive<Point> grid(grid_size); for (Point point : registered_points) { grid.insert(point, point); } typename SparsePointGridInclusive<Point>::Elem result; //The actual call to test. const bool success = grid.getNearest(target, grid_size, result, SparsePointGridInclusive<Point>::no_precondition); { std::stringstream ss; ss << "getNearest returned " << success << " but should've returned true."; CPPUNIT_ASSERT_MESSAGE(ss.str(), success); } { std::stringstream ss; ss << "getNearest reported the nearest point to be " << result.val << " (distance " << vSize(target - result.val) << "), but it should've been " << expected1 << " (distance " << vSize(expected1 - target) << ") or " << expected2 << " (distance " << vSize(expected2 - target) << ")."; CPPUNIT_ASSERT_MESSAGE(ss.str(), result.val == expected1 || result.val == expected2); } }
void BucketGrid2DTest::findNearbyObjectsAssert(const std::vector<Point>& registered_points, Point target, const unsigned long long grid_size, const std::unordered_set<Point>& expected_near, const std::unordered_set<Point>& expected_far) { BucketGrid2D<Point> grid(grid_size); for(Point point : registered_points) { grid.insert(point, point); } const std::vector<Point> result = grid.findNearbyObjects(target); //The actual call to test. //Note that the result may contain the same point more than once. This test is robust against that. for (const Point point : expected_near) //Are all near points reported as near? { std::stringstream ss; ss << "Point " << point << " is near " << target << " (distance " << vSize(point - target) << "), but findNearbyObjects didn't report it as such. Grid size: " << grid_size; CPPUNIT_ASSERT_MESSAGE(ss.str(), std::find(result.begin(), result.end(), point) != result.end()); //Must be in result. } for (const Point point : expected_far) //Are all far points NOT reported as near? { std::stringstream ss; ss << "Point " << point << " is far from " << target << " (distance " << vSize(point - target) << "), but findNearbyObjects thought it was near. Grid size: " << grid_size; CPPUNIT_ASSERT_MESSAGE(ss.str(), std::find(result.begin(), result.end(), point) == result.end()); //Must not be in result. } }
/* converting a CellMatrix of interpolation types to a sid::vector<int> */ vector<int> FromCellMatrixToInterpolVector(const CellMatrix& aCM) { if (aCM.Size() > maxInterpoltypesNb) { ostringstream vOs; vOs << "Maximum number of interpolations is " << maxInterpoltypesNb << ", please advise."; MG_THROW(vOs.str()); } vector<string> vInterpolTypesStr = FromCellMatrixToVectorStr(aCM); size_t vSize(vInterpolTypesStr.size()); vector<int> vInterpolTypesInt(vSize); for(size_t i=0; i<vSize; ++i) vInterpolTypesInt[i] = InterpolMethodConvertor[vInterpolTypesStr[i]]; return vInterpolTypesInt; }
vector<ProgramBinary> Program::get_Binaries() { vector<ProgramBinary> r; vector<Device> devs = Devices; if (cl_uint n = devs.size()) { vector<size_t> vSize(n); ClCheck(::clGetProgramInfo(Handle(), CL_PROGRAM_BINARY_SIZES, sizeof(size_t)*n, &vSize[0], 0)); r.resize(n); vector<void*> vp(n); for (int i=0; i<n; ++i) { r[i].Device = devs[i]; r[i].Binary.Size = vSize[i]; vp[i] = r[i].Binary.data(); } ClCheck(::clGetProgramInfo(Handle(), CL_PROGRAM_BINARIES, sizeof(void*)*n, &vp[0], 0)); } return r; }
bool Comb::moveInside(Point* p, int distance) { Point ret = *p; int64_t bestDist = MM2INT(2.0) * MM2INT(2.0); for(unsigned int n=0; n<boundery.size(); n++) { if (boundery[n].size() < 1) continue; Point p0 = boundery[n][boundery[n].size()-1]; for(unsigned int i=0; i<boundery[n].size(); i++) { Point p1 = boundery[n][i]; //Q = A + Normal( B - A ) * ((( B - A ) dot ( P - A )) / VSize( A - B )); Point pDiff = p1 - p0; int64_t lineLength = vSize(pDiff); int64_t distOnLine = dot(pDiff, *p - p0) / lineLength; if (distOnLine < 10) distOnLine = 10; if (distOnLine > lineLength - 10) distOnLine = lineLength - 10; Point q = p0 + pDiff * distOnLine / lineLength; int64_t dist = vSize2(q - *p); if (dist < bestDist) { bestDist = dist; ret = q + crossZ(normal(p1 - p0, distance)); } p0 = p1; } } if (bestDist < MM2INT(2.0) * MM2INT(2.0)) { *p = ret; return true; } return false; }
void Selene::CDefaultApplication::Render(float fDeltaTime) { Vector2 vSize(200.0f, 200.0f); Vector2 vPos(400.0f, 300.0f); float afCoords[8] = { -vSize.x * 0.5f, -vSize.y * 0.5f, vSize.x * 0.5f, -vSize.y * 0.5f, vSize.x * 0.5f, vSize.y * 0.5f, -vSize.x * 0.5f, vSize.y * 0.5f, }; // elfQuads_begin(); // // format - argb // elfQuads_setColour(0xffff4080); //// elfQuads_setTextureRectangle(0.0f, 0.0f, 1.0f, 1.0f); //// elfQuads_drawRectangleCentered(m_fPosX, m_fPosY, m_fSizeWidth, m_fSizeHeight); // //elfQuads_drawRectangle(fStartX, fStartY, fEndX, fEndY); // elfQuads_drawShapeOffset(vPos.x, vPos.y, afCoords); // elfQuads_end(); }
float WallOverlapComputation::getFlow(const Point& from, const Point& to) { using Point2LinkIt = PolygonProximityLinker::Point2Link::iterator; if (!overlap_linker.isLinked(from)) { // [from] is not linked return 1; } const std::pair<Point2LinkIt, Point2LinkIt> to_links = overlap_linker.getLinks(to); if (to_links.first == to_links.second) { // [to] is not linked return 1; } int64_t overlap_area = 0; // note that we don't need to loop over all from_links, because they are handled in the previous getFlow(.) call (or in the very last) for (Point2LinkIt to_link_it = to_links.first; to_link_it != to_links.second; ++to_link_it) { const ProximityPointLink& to_link = to_link_it->second; ListPolyIt to_it = to_link.a; ListPolyIt to_other_it = to_link.b; if (to_link.a.p() != to) { assert(to_link.b.p() == to && "Either part of the link should be the point in the link!"); std::swap(to_it, to_other_it); } ListPolyIt from_it = to_it.prev(); if (from_it.p() != from) { logWarning("Polygon has multiple verts at the same place: (%lli, %lli); PolygonProximityLinker fails in such a case!\n", from.X, from.Y); } ListPolyIt to_other_next_it = to_other_it.next(); // move towards [from]; the lines on the other side move in the other direction // to from // o<--o<--T<--F // | : : // v : : // o-->o-->o-->o // , , // ; to_other_next // to other bool are_in_same_general_direction = dot(from - to, to_other_it.p() - to_other_next_it.p()) > 0; // handle multiple points linked to [to] // o<<<T<<<F // / | // / | // o>>>o>>>o // , , // ; to other next // to other if (!are_in_same_general_direction) { overlap_area = std::max(overlap_area, handlePotentialOverlap(to_it, to_it, to_link, to_other_next_it, to_other_it)); } // handle multiple points linked to [to_other] // o<<<T<<<F // | / // | / // o>>>o>>>o bool all_are_in_same_general_direction = are_in_same_general_direction && dot(from - to, to_other_it.prev().p() - to_other_it.p()) > 0; if (!all_are_in_same_general_direction) { overlap_area = std::max(overlap_area, handlePotentialOverlap(from_it, to_it, to_link, to_other_it, to_other_it)); } // handle normal case where the segment from-to overlaps with another segment // o<<<T<<<F // | | // | | // o>>>o>>>o // , , // ; to other next // to other if (!are_in_same_general_direction) { overlap_area = std::max(overlap_area, handlePotentialOverlap(from_it, to_it, to_link, to_other_next_it, to_other_it)); } } int64_t normal_area = vSize(from - to) * line_width; float ratio = float(normal_area - overlap_area) / normal_area; // clamp the ratio because overlap compensation might be faulty because // WallOverlapComputation::getApproxOverlapArea only gives roughly accurate results return std::min(1.0f, std::max(0.0f, ratio)); }
int64_t WallOverlapComputation::getApproxOverlapArea(const Point from, const Point to, const int64_t to_dist, const Point other_from, const Point other_to, const int64_t from_dist) { const int64_t overlap_width_2 = line_width * 2 - from_dist - to_dist; //Twice the width of the overlap area, perpendicular to the lines. // check whether the line segment overlaps with the point if one of the line segments is just a point if (from == to) { if (LinearAlg2D::pointIsProjectedBeyondLine(from, other_from, other_to) != 0) { return 0; } const int64_t overlap_length_2 = vSize(other_to - other_from); //Twice the length of the overlap area, alongside the lines. return overlap_length_2 * overlap_width_2 / 4; //Area = width * height. } if (other_from == other_to) { if (LinearAlg2D::pointIsProjectedBeyondLine(other_from, from, to) != 0) { return 0; } const int64_t overlap_length_2 = vSize(from - to); //Twice the length of the overlap area, alongside the lines. return overlap_length_2 * overlap_width_2 / 4; //Area = width * height. } short from_rel = LinearAlg2D::pointIsProjectedBeyondLine(from, other_from, other_to); short to_rel = LinearAlg2D::pointIsProjectedBeyondLine(to, other_from, other_to); short other_from_rel = LinearAlg2D::pointIsProjectedBeyondLine(other_from, from, to); short other_to_rel = LinearAlg2D::pointIsProjectedBeyondLine(other_to, from, to); if (from_rel != 0 && to_rel == from_rel && other_from_rel != 0 && other_to_rel == other_from_rel) { // both segments project fully beyond or before each other // for example: or: // O<------O . O------>O // : : \_ // ' O------->O O------>O return 0; } if (from_rel != 0 && from_rel == other_from_rel && to_rel == 0 && other_to_rel == 0) { // only ends of line segments overlap // // to_proj // ^^^^^ // O<--+----O // : : // O-----+-->O // ,,,,, // other_to_proj const Point other_vec = other_from - other_to; const int64_t to_proj = dot(to - other_to, other_vec) / vSize(other_vec); const Point vec = from - to; const int64_t other_to_proj = dot(other_to - to, vec) / vSize(vec); const int64_t overlap_length_2 = to_proj + other_to_proj; //Twice the length of the overlap area, alongside the lines. return overlap_length_2 * overlap_width_2 / 4; //Area = width * height. } if (to_rel != 0 && to_rel == other_to_rel && from_rel == 0 && other_from_rel == 0) { // only beginnings of line segments overlap // // from_proj // ^^^^^ // O<---+---O // : : // O---+---->O // ,,,,, // other_from_proj const Point other_vec = other_to - other_from; const int64_t from_proj = dot(from - other_from, other_vec) / vSize(other_vec); const Point vec = to - from; const int64_t other_from_proj = dot(other_from - from, vec) / vSize(vec); const int64_t overlap_length_2 = from_proj + other_from_proj; //Twice the length of the overlap area, alongside the lines. return overlap_length_2 * overlap_width_2 / 4; //Area = width * height. } //More complex case. const Point from_middle = other_to + from; // don't divide by two just yet const Point to_middle = other_from + to; // don't divide by two just yet const int64_t overlap_length_2 = vSize(from_middle - to_middle); //(An approximation of) twice the length of the overlap area, alongside the lines. return overlap_length_2 * overlap_width_2 / 4; //Area = width * height. }
bool MergeInfillLines::isConvertible(const Point& a, const Point& b, const Point& c, const Point& d, int64_t line_width, Point& first_middle, Point& second_middle, int64_t& resulting_line_width, bool use_second_middle_as_first) { use_second_middle_as_first = false; int64_t nozzle_size = line_width; // TODO int64_t max_line_width = nozzle_size * 3 / 2; Point ab = b - a; Point cd = d - c; if (b == c) { return false; // the line segments are connected! } int64_t ab_size = vSize(ab); int64_t cd_size = vSize(cd); if (ab_size > nozzle_size * 5 || cd_size > nozzle_size * 5) { return false; // infill lines are too long; otherwise infill lines might be merged when the next infill line is coincidentally shorter like |, would become \ ... } // if the lines are in the same direction then abs( dot(ab,cd) / |ab| / |cd| ) == 1 int64_t prod = dot(ab,cd); if (std::abs(prod) + 400 < ab_size * cd_size) // 400 = 20*20, where 20 micron is the allowed inaccuracy in the dot product, introduced by the inaccurate point locations of a,b,c,d return false; // extrusion moves not in the same or opposite diraction // make lines in the same direction by flipping one if (prod < 0) { ab = ab * -1; } else if (prod == 0) { return false; // lines are orthogonal! } else if (b == d || a == c) { return false; // the line segments are connected! } first_middle = (use_second_middle_as_first)? second_middle : (a + b) / 2; second_middle = (c + d) / 2; Point dir_vector_perp = crossZ(second_middle - first_middle); int64_t dir_vector_perp_length = vSize(dir_vector_perp); // == dir_vector_length if (dir_vector_perp_length == 0) return false; if (dir_vector_perp_length > 5 * nozzle_size) return false; // infill lines too far apart Point infill_vector = (cd + ab) / 2; // (similar to) average line / direction of the infill // compute the resulting line width resulting_line_width = std::abs( dot(dir_vector_perp, infill_vector) / dir_vector_perp_length ); if (resulting_line_width > max_line_width) return false; // combined lines would be too wide if (resulting_line_width == 0) return false; // dot is zero, so lines are in each others extension, not next to eachother // check whether two lines are adjacent (note: not 'line segments' but 'lines') Point ac = c - first_middle; Point infill_vector_perp = crossZ(infill_vector); int64_t perp_proj = dot(ac, infill_vector_perp); int64_t infill_vector_perp_length = vSize(infill_vector_perp); if (std::abs(std::abs(perp_proj) / infill_vector_perp_length - line_width) > 20) // it should be the case that dot(ac, infill_vector_perp) / |infill_vector_perp| == line_width { return false; // lines are too far apart or too close together } // check whether the two line segments are adjacent. // full infill in a narrow area might result in line segments with arbitrary distance between them // the more the narrow passage in the area gets aligned with the infill direction, the further apart the line segments will be // however, distant line segments might also be due to different narrow passages, so we limit the distance between merged line segments. if (!LinearAlg2D::lineSegmentsAreCloserThan(a, b, c, d, line_width * 2)) { return false; } return true; };
void SlicerLayer::makePolygons(OptimizedVolume* ov, bool keepNoneClosed, bool extensiveStitching) { for(unsigned int startSegment=0; startSegment < segmentList.size(); startSegment++) { if (segmentList[startSegment].addedToPolygon) continue; ClipperLib::Polygon poly; poly.push_back(segmentList[startSegment].start); unsigned int segmentIndex = startSegment; bool canClose; while(true) { canClose = false; segmentList[segmentIndex].addedToPolygon = true; Point p0 = segmentList[segmentIndex].end; poly.push_back(p0); int nextIndex = -1; OptimizedFace* face = &ov->faces[segmentList[segmentIndex].faceIndex]; for(unsigned int i=0;i<3;i++) { if (face->touching[i] > -1 && faceToSegmentIndex.find(face->touching[i]) != faceToSegmentIndex.end()) { Point p1 = segmentList[faceToSegmentIndex[face->touching[i]]].start; Point diff = p0 - p1; if (shorterThen(diff, 10)) { if (faceToSegmentIndex[face->touching[i]] == (int)startSegment) canClose = true; if (segmentList[faceToSegmentIndex[face->touching[i]]].addedToPolygon) continue; nextIndex = faceToSegmentIndex[face->touching[i]]; } } } if (nextIndex == -1) break; segmentIndex = nextIndex; } if (canClose) polygonList.add(poly); else openPolygonList.add(poly); } //Clear the segmentList to save memory, it is no longer needed after this point. segmentList.clear(); //Connecting polygons that are not closed yet, as models are not always perfect manifold we need to join some stuff up to get proper polygons //First link up polygon ends that are within 2 microns. for(unsigned int i=0;i<openPolygonList.size();i++) { if (openPolygonList[i].size() < 1) continue; for(unsigned int j=0;j<openPolygonList.size();j++) { if (openPolygonList[j].size() < 1) continue; Point diff = openPolygonList[i][openPolygonList[i].size()-1] - openPolygonList[j][0]; int64_t distSquared = vSize2(diff); if (distSquared < 2 * 2) { if (i == j) { polygonList.add(openPolygonList[i]); openPolygonList[i].clear(); break; }else{ for(unsigned int n=0; n<openPolygonList[j].size(); n++) openPolygonList[i].push_back(openPolygonList[j][n]); openPolygonList[j].clear(); } } } } //Next link up all the missing ends, closing up the smallest gaps first. This is an inefficient implementation which can run in O(n*n*n) time. while(1) { int64_t bestScore = 10000 * 10000; unsigned int bestA = -1; unsigned int bestB = -1; bool reversed = false; for(unsigned int i=0;i<openPolygonList.size();i++) { if (openPolygonList[i].size() < 1) continue; for(unsigned int j=0;j<openPolygonList.size();j++) { if (openPolygonList[j].size() < 1) continue; Point diff = openPolygonList[i][openPolygonList[i].size()-1] - openPolygonList[j][0]; int64_t distSquared = vSize2(diff); if (distSquared < bestScore) { bestScore = distSquared; bestA = i; bestB = j; reversed = false; } if (i != j) { Point diff = openPolygonList[i][openPolygonList[i].size()-1] - openPolygonList[j][openPolygonList[j].size()-1]; int64_t distSquared = vSize2(diff); if (distSquared < bestScore) { bestScore = distSquared; bestA = i; bestB = j; reversed = true; } } } } if (bestScore >= 10000 * 10000) break; if (bestA == bestB) { polygonList.add(openPolygonList[bestA]); openPolygonList[bestA].clear(); }else{ if (reversed) { for(unsigned int n=openPolygonList[bestB].size()-1; int(n)>=0; n--) openPolygonList[bestA].push_back(openPolygonList[bestB][n]); }else{ for(unsigned int n=0; n<openPolygonList[bestB].size(); n++) openPolygonList[bestA].push_back(openPolygonList[bestB][n]); } openPolygonList[bestB].clear(); } } if (extensiveStitching) { //For extensive stitching find 2 open polygons that are touching 2 closed polygons. // Then find the sortest path over this polygon that can be used to connect the open polygons, // And generate a path over this shortest bit to link up the 2 open polygons. // (If these 2 open polygons are the same polygon, then the final result is a closed polyon) while(1) { unsigned int bestA = -1; unsigned int bestB = -1; gapCloserResult bestResult; bestResult.len = LLONG_MAX; bestResult.polygonIdx = -1; bestResult.pointIdxA = -1; bestResult.pointIdxB = -1; for(unsigned int i=0; i<openPolygonList.size(); i++) { if (openPolygonList[i].size() < 1) continue; { gapCloserResult res = findPolygonGapCloser(openPolygonList[i][0], openPolygonList[i][openPolygonList[i].size()-1]); if (res.len > 0 && res.len < bestResult.len) { bestA = i; bestB = i; bestResult = res; } } for(unsigned int j=0; j<openPolygonList.size(); j++) { if (openPolygonList[j].size() < 1 || i == j) continue; gapCloserResult res = findPolygonGapCloser(openPolygonList[i][0], openPolygonList[j][openPolygonList[j].size()-1]); if (res.len > 0 && res.len < bestResult.len) { bestA = i; bestB = j; bestResult = res; } } } if (bestResult.len < LLONG_MAX) { if (bestA == bestB) { if (bestResult.pointIdxA == bestResult.pointIdxB) { polygonList.add(openPolygonList[bestA]); openPolygonList[bestA].clear(); } else if (bestResult.AtoB) { unsigned int n = polygonList.size(); polygonList.add(ClipperLib::Polygon()); for(unsigned int j = bestResult.pointIdxA; j != bestResult.pointIdxB; j = (j + 1) % polygonList[bestResult.polygonIdx].size()) polygonList[n].push_back(polygonList[bestResult.polygonIdx][j]); for(unsigned int j = openPolygonList[bestA].size() - 1; int(j) >= 0; j--) polygonList[n].push_back(openPolygonList[bestA][j]); openPolygonList[bestA].clear(); } else { unsigned int n = polygonList.size(); polygonList.add(openPolygonList[bestA]); for(unsigned int j = bestResult.pointIdxB; j != bestResult.pointIdxA; j = (j + 1) % polygonList[bestResult.polygonIdx].size()) polygonList[n].push_back(polygonList[bestResult.polygonIdx][j]); openPolygonList[bestA].clear(); } } else { if (bestResult.pointIdxA == bestResult.pointIdxB) { for(unsigned int n=0; n<openPolygonList[bestA].size(); n++) openPolygonList[bestB].push_back(openPolygonList[bestA][n]); openPolygonList[bestA].clear(); } else if (bestResult.AtoB) { ClipperLib::Polygon poly; for(unsigned int n = bestResult.pointIdxA; n != bestResult.pointIdxB; n = (n + 1) % polygonList[bestResult.polygonIdx].size()) poly.push_back(polygonList[bestResult.polygonIdx][n]); for(unsigned int n=poly.size()-1;int(n) >= 0; n--) openPolygonList[bestB].push_back(poly[n]); for(unsigned int n=0; n<openPolygonList[bestA].size(); n++) openPolygonList[bestB].push_back(openPolygonList[bestA][n]); openPolygonList[bestA].clear(); } else { for(unsigned int n = bestResult.pointIdxB; n != bestResult.pointIdxA; n = (n + 1) % polygonList[bestResult.polygonIdx].size()) openPolygonList[bestB].push_back(polygonList[bestResult.polygonIdx][n]); for(unsigned int n = openPolygonList[bestA].size() - 1; int(n) >= 0; n--) openPolygonList[bestB].push_back(openPolygonList[bestA][n]); openPolygonList[bestA].clear(); } } } else { break; } } } /* int q=0; for(unsigned int i=0;i<openPolygonList.size();i++) { if (openPolygonList[i].size() < 2) continue; if (!q) printf("***\n"); printf("S: %f %f\n", float(openPolygonList[i][0].X), float(openPolygonList[i][0].Y)); printf("E: %f %f\n", float(openPolygonList[i][openPolygonList[i].size()-1].X), float(openPolygonList[i][openPolygonList[i].size()-1].Y)); q = 1; } */ //if (q) exit(1); if (keepNoneClosed) { for(unsigned int n=0; n<openPolygonList.size(); n++) { if (openPolygonList[n].size() > 0) polygonList.add(openPolygonList[n]); } } //Clear the openPolygonList to save memory, the only reason to keep it after this is for debugging. //openPolygonList.clear(); //Remove all the tiny polygons, or polygons that are not closed. As they do not contribute to the actual print. int snapDistance = 1000; for(unsigned int i=0;i<polygonList.size();i++) { int length = 0; for(unsigned int n=1; n<polygonList[i].size(); n++) { length += vSize(polygonList[i][n] - polygonList[i][n-1]); if (length > snapDistance) break; } if (length < snapDistance) { polygonList.remove(i); i--; } } //Finally optimize all the polygons. Every point removed saves time in the long run. optimizePolygons(polygonList); }
bool Comb::moveInside(Point* from, int distance) { Point ret = *from; int64_t maxDist2 = MM2INT(2.0) * MM2INT(2.0); int64_t bestDist2 = maxDist2; for(PolygonRef poly : boundary) { if (poly.size() < 2) continue; Point p0 = poly[poly.size()-2]; Point p1 = poly.back(); bool projected_p_beyond_prev_segment = dot(p1 - p0, *from - p0) > vSize2(p1 - p0); for(Point& p2 : poly) { // X = A + Normal( B - A ) * ((( B - A ) dot ( P - A )) / VSize( A - B )); // X = P projected on AB Point& a = p1; Point& b = p2; Point& p = *from; Point ab = b - a; Point ap = p - a; int64_t ab_length = vSize(ab); int64_t ax_length = dot(ab, ap) / ab_length; if (ax_length < 0) // x is projected to before ab { if (projected_p_beyond_prev_segment) { // case which looks like: > . projected_p_beyond_prev_segment = false; Point& x = p1; int64_t dist2 = vSize2(x - p); if (dist2 < bestDist2) { bestDist2 = dist2; ret = x + normal(crossZ(normal(a, distance*4) + normal(p1 - p0, distance*4)), distance); // *4 to retain more precision for the eventual normalization } } else { projected_p_beyond_prev_segment = false; p0 = p1; p1 = p2; continue; } } else if (ax_length > ab_length) // x is projected to beyond ab { projected_p_beyond_prev_segment = true; p0 = p1; p1 = p2; continue; } else { projected_p_beyond_prev_segment = false; Point x = a + ab * ax_length / ab_length; int64_t dist2 = vSize2(x - *from); if (dist2 < bestDist2) { bestDist2 = dist2; ret = x + crossZ(normal(ab, distance)); } } p0 = p1; p1 = p2; } } if (bestDist2 < maxDist2) { *from = ret; return true; } return false; }
bool Comb::calc(Point startPoint, Point endPoint, CombPaths& combPaths, bool startInside, bool endInside, int64_t max_comb_distance_ignored) { if (shorterThen(endPoint - startPoint, max_comb_distance_ignored)) { return true; } //Move start and end point inside the comb boundary unsigned int start_inside_poly = NO_INDEX; if (startInside) { start_inside_poly = PolygonUtils::moveInside(boundary_inside, startPoint, offset_extra_start_end, max_moveInside_distance2); if (!boundary_inside.inside(start_inside_poly) || start_inside_poly == NO_INDEX) { if (start_inside_poly != NO_INDEX) { // if not yet inside because of overshoot, try again start_inside_poly = PolygonUtils::moveInside(boundary_inside, startPoint, offset_extra_start_end, max_moveInside_distance2); } if (start_inside_poly == NO_INDEX) //If we fail to move the point inside the comb boundary we need to retract. { startInside = false; } } } unsigned int end_inside_poly = NO_INDEX; if (endInside) { end_inside_poly = PolygonUtils::moveInside(boundary_inside, endPoint, offset_extra_start_end, max_moveInside_distance2); if (!boundary_inside.inside(endPoint) || end_inside_poly == NO_INDEX) { if (end_inside_poly != NO_INDEX) { // if not yet inside because of overshoot, try again end_inside_poly = PolygonUtils::moveInside(boundary_inside, endPoint, offset_extra_start_end, max_moveInside_distance2); } if (end_inside_poly == NO_INDEX) //If we fail to move the point inside the comb boundary we need to retract. { endInside = false; } } } unsigned int start_part_boundary_poly_idx; unsigned int end_part_boundary_poly_idx; unsigned int start_part_idx = (start_inside_poly == NO_INDEX)? NO_INDEX : partsView_inside.getPartContaining(start_inside_poly, &start_part_boundary_poly_idx); unsigned int end_part_idx = (end_inside_poly == NO_INDEX)? NO_INDEX : partsView_inside.getPartContaining(end_inside_poly, &end_part_boundary_poly_idx); if (startInside && endInside && start_part_idx == end_part_idx) { // normal combing within part PolygonsPart part = partsView_inside.assemblePart(start_part_idx); combPaths.emplace_back(); LinePolygonsCrossings::comb(part, startPoint, endPoint, combPaths.back(), -offset_dist_to_get_from_on_the_polygon_to_outside, max_comb_distance_ignored); return true; } else { // comb inside part to edge (if needed) >> move through air avoiding other parts >> comb inside end part upto the endpoint (if needed) // INSIDE | in_between | OUTSIDE | in_between | INSIDE // ^crossing_1_in ^crossing_1_mid ^crossing_1_out ^crossing_2_out ^crossing_2_mid ^crossing_2_in // // when startPoint is inside crossing_1_in is of interest // when it is in between inside and outside it is equal to crossing_1_mid Point crossing_1_in_or_mid; // the point inside the starting polygon if startPoint is inside or the startPoint itself if it is not inside Point crossing_1_out; Point crossing_2_in_or_mid; // the point inside the ending polygon if endPoint is inside or the endPoint itself if it is not inside Point crossing_2_out; { // find crossing over the in-between area between inside and outside if (startInside) { ClosestPolygonPoint crossing_1_in_cp = PolygonUtils::findClosest(endPoint, boundary_inside[start_part_boundary_poly_idx]); crossing_1_in_or_mid = PolygonUtils::moveInside(crossing_1_in_cp, offset_dist_to_get_from_on_the_polygon_to_outside); // in-case } else { crossing_1_in_or_mid = startPoint; // mid-case } if (endInside) { ClosestPolygonPoint crossing_2_in_cp = PolygonUtils::findClosest(crossing_1_in_or_mid, boundary_inside[end_part_boundary_poly_idx]); crossing_2_in_or_mid = PolygonUtils::moveInside(crossing_2_in_cp, offset_dist_to_get_from_on_the_polygon_to_outside); // in-case } else { crossing_2_in_or_mid = endPoint; // mid-case } } bool avoid_other_parts_now = avoid_other_parts; if (avoid_other_parts_now && vSize2(crossing_1_in_or_mid - crossing_2_in_or_mid) < offset_from_outlines_outside * offset_from_outlines_outside * 4) { // parts are next to eachother, i.e. the direct crossing will always be smaller than two crossings via outside avoid_other_parts_now = false; } if (avoid_other_parts_now) { // compute the crossing points when moving through air Polygons& outside = getBoundaryOutside(); // comb through all air, since generally the outside consists of a single part crossing_1_out = crossing_1_in_or_mid; if (startInside || outside.inside(crossing_1_in_or_mid, true)) // start in_between { // move outside ClosestPolygonPoint* crossing_1_out_cpp = PolygonUtils::findClose(crossing_1_in_or_mid, outside, getOutsideLocToLine()); if (crossing_1_out_cpp) { crossing_1_out = PolygonUtils::moveOutside(*crossing_1_out_cpp, offset_dist_to_get_from_on_the_polygon_to_outside); } else { PolygonUtils::moveOutside(outside, crossing_1_out, offset_dist_to_get_from_on_the_polygon_to_outside); } } int64_t in_out_dist2_1 = vSize2(crossing_1_out - crossing_1_in_or_mid); if (startInside && in_out_dist2_1 > max_crossing_dist2) // moveInside moved too far { // if move is to far over in_between // find crossing closer by std::shared_ptr<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>> best = findBestCrossing(boundary_inside[start_part_boundary_poly_idx], startPoint, endPoint); if (best) { crossing_1_in_or_mid = PolygonUtils::moveInside(best->first, offset_dist_to_get_from_on_the_polygon_to_outside); crossing_1_out = PolygonUtils::moveOutside(best->second, offset_dist_to_get_from_on_the_polygon_to_outside); } } crossing_2_out = crossing_2_in_or_mid; if (endInside || outside.inside(crossing_2_in_or_mid, true)) { // move outside ClosestPolygonPoint* crossing_2_out_cpp = PolygonUtils::findClose(crossing_2_in_or_mid, outside, getOutsideLocToLine()); if (crossing_2_out_cpp) { crossing_2_out = PolygonUtils::moveOutside(*crossing_2_out_cpp, offset_dist_to_get_from_on_the_polygon_to_outside); } else { PolygonUtils::moveOutside(outside, crossing_2_out, offset_dist_to_get_from_on_the_polygon_to_outside); } } int64_t in_out_dist2_2 = vSize2(crossing_2_out - crossing_2_in_or_mid); if (endInside && in_out_dist2_2 > max_crossing_dist2) // moveInside moved too far { // if move is to far over in_between // find crossing closer by std::shared_ptr<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>> best = findBestCrossing(boundary_inside[end_part_boundary_poly_idx], endPoint, crossing_1_out); if (best) { crossing_2_in_or_mid = PolygonUtils::moveInside(best->first, offset_dist_to_get_from_on_the_polygon_to_outside); crossing_2_out = PolygonUtils::moveOutside(best->second, offset_dist_to_get_from_on_the_polygon_to_outside); } } } if (startInside) { // start to boundary PolygonsPart part_begin = partsView_inside.assemblePart(start_part_idx); // comb through the starting part only combPaths.emplace_back(); LinePolygonsCrossings::comb(part_begin, startPoint, crossing_1_in_or_mid, combPaths.back(), -offset_dist_to_get_from_on_the_polygon_to_outside, max_comb_distance_ignored); } // throught air from boundary to boundary if (avoid_other_parts_now) { combPaths.emplace_back(); combPaths.throughAir = true; if ( vSize(crossing_1_in_or_mid - crossing_2_in_or_mid) < vSize(crossing_1_in_or_mid - crossing_1_out) + vSize(crossing_2_in_or_mid - crossing_2_out) ) { // via outside is moving more over the in-between zone combPaths.back().push_back(crossing_1_in_or_mid); combPaths.back().push_back(crossing_2_in_or_mid); } else { LinePolygonsCrossings::comb(getBoundaryOutside(), crossing_1_out, crossing_2_out, combPaths.back(), offset_dist_to_get_from_on_the_polygon_to_outside, max_comb_distance_ignored); } } else { // directly through air (not avoiding other parts) combPaths.emplace_back(); combPaths.throughAir = true; combPaths.back().cross_boundary = true; // TODO: calculate whether we cross a boundary! combPaths.back().push_back(crossing_1_in_or_mid); combPaths.back().push_back(crossing_2_in_or_mid); } if (endInside) { // boundary to end PolygonsPart part_end = partsView_inside.assemblePart(end_part_idx); // comb through end part only combPaths.emplace_back(); LinePolygonsCrossings::comb(part_end, crossing_2_in_or_mid, endPoint, combPaths.back(), -offset_dist_to_get_from_on_the_polygon_to_outside, max_comb_distance_ignored); } return true; } }