diff --git a/course-generator/center.lua b/course-generator/center.lua index d0b4c1051..14a65baa9 100644 --- a/course-generator/center.lua +++ b/course-generator/center.lua @@ -193,6 +193,28 @@ function findBestTrackAngle( polygon, islands, width, distanceFromBoundary, cent return b.angle, b.nTracks, b.nBlocks, b.smallBlockScore == 0 or centerSettings.useBestAngle end +local function addWaypointsToBlocks(blocks, width, extendTracks) + -- using a while loop as we'll remove blocks if they have no tracks + local nTotalTracks = 0 + local i = 1 + while blocks[i] do + local block = blocks[i] + nTotalTracks = nTotalTracks + #block + courseGenerator.debug( "Block %d has %d tracks", i, #block ) + block.tracksWithWaypoints = addWaypointsToTracks( block, width, extendTracks ) + block.covered = false + -- we may end up with blocks without tracks in case we did not find a single track + -- with at least two waypoints. Now remove those blocks + if #blocks[i].tracksWithWaypoints == 0 then + courseGenerator.debug( "Block %d removed as it has no tracks with waypoints", i) + table.remove(blocks, i) + else + i = i + 1 + end + end + return nTotalTracks +end + --- Count the blocks with just a few tracks function countSmallBlockScore( blocks ) local nResult = 0 @@ -210,14 +232,15 @@ end --- Generate up/down tracks covering a polygon at the optimum angle -- -function generateTracks( headlands, islands, width, extendTracks, nHeadlandPasses, centerSettings ) - local distanceFromBoundary +function generateTracks( headlands, islands, width, nHeadlandPasses, centerSettings ) + local distanceFromBoundary, extendTracks if nHeadlandPasses == 0 then -- ugly hack: if there are no headlands, our tracks go right up to the field boundary. So extend tracks -- exactly width / 2 - extendTracks = extendTracks + width / 2 + extendTracks = width / 2 distanceFromBoundary = width / 2 else + extendTracks = 0 distanceFromBoundary = width end @@ -262,24 +285,7 @@ function generateTracks( headlands, islands, width, extendTracks, nHeadlandPasse local blocks = splitCenterIntoBlocks( parallelTracks, width ) - -- using a while loop as we'll remove blocks if they have no tracks - local nTotalTracks = 0 - local i = 1 - while blocks[i] do - local block = blocks[i] - nTotalTracks = nTotalTracks + #block - courseGenerator.debug( "Block %d has %d tracks", i, #block ) - block.tracksWithWaypoints = addWaypointsToTracks( block, width, extendTracks ) - block.covered = false - -- we may end up with blocks without tracks in case we did not find a single track - -- with at least two waypoints. Now remove those blocks - if #blocks[i].tracksWithWaypoints == 0 then - courseGenerator.debug( "Block %d removed as it has no tracks with waypoints", i) - table.remove(blocks, i) - else - i = i + 1 - end - end + local nTotalTracks = addWaypointsToBlocks(blocks, width, extendTracks) if #blocks > 30 or ( #blocks > 1 and ( nTotalTracks / #blocks ) < 2 ) then -- don't waste time on unrealistic problems @@ -315,14 +321,14 @@ function generateTracks( headlands, islands, width, extendTracks, nHeadlandPasse end end courseGenerator.debug( '%d. block %d, entry corner %d, direction to next = %d, on the bottom = %s, on the left = %s', i, block.id, block.entryCorner, - block.directionToNextBlock or 0, tostring( isCornerOnTheBottom( block.entryCorner )), tostring( isCornerOnTheLeft( block.entryCorner ))) + block.directionToNextBlock or 0, tostring( isCornerOnTheBottom( block.entryCorner )), tostring( isCornerOnTheLeft( block.entryCorner ))) local continueWithTurn = not block.trackToThisBlock if continueWithTurn then track[ #track ].turnStart = true end local linkedTracks = linkParallelTracks(block.tracksWithWaypoints, - isCornerOnTheBottom( block.entryCorner ), isCornerOnTheLeft( block.entryCorner ), centerSettings, continueWithTurn, - transformedHeadlands, rotatedIslands, width) + isCornerOnTheBottom( block.entryCorner ), isCornerOnTheLeft( block.entryCorner ), centerSettings, continueWithTurn, + transformedHeadlands, rotatedIslands, width) -- remember where the up/down rows start (transition from headland to up/down rows) if i == 1 then linkedTracks[1].upDownRowStart = #track @@ -1141,8 +1147,9 @@ function findBlockSequence( blocks, headland, circleStart, circleStep, nHeadland if nHeadlandPasses > 0 then distance, dir = getDistanceBetweenPointsOnHeadland( headland, circleStart, currentBlockEntryPoint.index, { circleStep } ) else - -- if ther's no headland, look for the closest point no matter what direction (as we can ignore the clockwise/ccw settings) + -- if there is no headland, look for the closest point no matter what direction (as we can ignore the clockwise/ccw settings) distance, dir = getDistanceBetweenPointsOnHeadland( headland, circleStart, currentBlockEntryPoint.index, { -1, 1 } ) + --print(currentBlockIx, chromosome.entryCorner[currentBlockIx], distance, dir, circleStart, currentBlockEntryPoint.index) end chromosome.distance, chromosome.directionToNextBlock[ currentBlockIx ] = chromosome.distance + distance, dir else diff --git a/course-generator/cp.lua b/course-generator/cp.lua index fc3ce9ee4..10837b592 100644 --- a/course-generator/cp.lua +++ b/course-generator/cp.lua @@ -113,7 +113,6 @@ function courseGenerator.generate( vehicle ) vehicle.cp.oldCourseGeneratorSettings.startingLocationWorldPos.z) end - local extendTracks = 0 local minDistanceBetweenPoints = 0.5 local doSmooth = true local roundCorners = false @@ -173,7 +172,7 @@ function courseGenerator.generate( vehicle ) end local status, ok = xpcall( generateCourseForField, function(err) printCallstack(); return err end, field, workWidth, headlandSettings, - extendTracks, minDistanceBetweenPoints, + minDistanceBetweenPoints, minSmoothAngle, maxSmoothAngle, doSmooth, roundCorners, turnRadiusAdjustedForMultiTool, courseGenerator.pointsToXy( islandNodes ), diff --git a/course-generator/geo.lua b/course-generator/geo.lua index 448f2ef07..bdd6a30ce 100644 --- a/course-generator/geo.lua +++ b/course-generator/geo.lua @@ -1166,8 +1166,8 @@ end -- This will do a full circle, that is, roll over from -- #polygon to 1 or 1 to #polygon if step < 0 function Polygon:iterator( from, to, step ) - local i = from or 1 - local n = to or #self + local i = from and self:getIndex(from) or 1 + local n = to and self:getIndex(to) or #self local s = step or 1 local lastOne = false return function() diff --git a/course-generator/headland.lua b/course-generator/headland.lua index fc44cfddc..f56bd826b 100644 --- a/course-generator/headland.lua +++ b/course-generator/headland.lua @@ -453,7 +453,7 @@ function calculateOneSide(boundary, innerBoundary, startIx, endIx, step, rightSi return headlands end -function generateTwoSideHeadlands( polygon, islands, implementWidth, extendTracks, headlandSettings, centerSettings, +function generateTwoSideHeadlands( polygon, islands, implementWidth, headlandSettings, centerSettings, minDistanceBetweenPoints, minSmoothAngle, maxSmoothAngle ) -- translate polygon so we can rotate it around its center. This way all points -- will be approximately the same distance from the origin and the rotation calculation diff --git a/course-generator/track.lua b/course-generator/track.lua index 6940cd580..36234e3fe 100644 --- a/course-generator/track.lua +++ b/course-generator/track.lua @@ -54,11 +54,7 @@ -- center tracks to skip. When 0, normal alternating tracks are generated -- when > 0, intermediate tracks are skipped to allow for wider turns -- --- extendTracks --- extend center tracks into the headland (meters) to prevent unworked --- triangles with long plows. --- --- minDistanceBetweenPoints +-- minDistanceBetweenPoints -- minimum distance allowed between vertices. Keeps the number of generated -- vertices for headland passes low. For fine tuning only -- @@ -103,7 +99,7 @@ -- instead of trying to find the optimal angle. -- -function generateCourseForField( field, implementWidth, headlandSettings, extendTracks, +function generateCourseForField( field, implementWidth, headlandSettings, minDistanceBetweenPoints, minSmoothAngle, maxSmoothAngle, doSmooth, fromInside, turnRadius, islandNodes, islandBypassMode, centerSettings ) @@ -136,7 +132,7 @@ function generateCourseForField( field, implementWidth, headlandSettings, extend linkHeadlandTracks( field, implementWidth, headlandSettings.isClockwise, headlandSettings.startLocation, doSmooth, minSmoothAngle, maxSmoothAngle ) field.track, field.bestAngle, field.nTracks, field.blocks, resultIsOk = generateTracks( field.headlandTracks, field.bigIslands, - implementWidth, extendTracks, headlandSettings.nPasses, centerSettings ) + implementWidth, headlandSettings.nPasses, centerSettings ) elseif headlandSettings.nPasses == 0 or -- TODO: use the mode only, not nPasses, this is only for backwards compatibility headlandSettings.mode == courseGenerator.HEADLAND_MODE_NONE then -- no headland pass wanted, still generate a dummy one on the field boundary so @@ -144,16 +140,16 @@ function generateCourseForField( field, implementWidth, headlandSettings, extend field.headlandTracks[ 1 ] = calculateHeadlandTrack( field.boundary, courseGenerator.HEADLAND_MODE_NORMAL, field.boundary.isClockwise, 0, minDistanceBetweenPoints, minSmoothAngle, maxSmoothAngle, 0, doSmooth, not fromInside, nil, nil ) linkHeadlandTracks( field, implementWidth, headlandSettings.isClockwise, headlandSettings.startLocation, doSmooth, minSmoothAngle, maxSmoothAngle ) field.track, field.bestAngle, field.nTracks, field.blocks, resultIsOk = generateTracks( field.headlandTracks, field.bigIslands, - implementWidth, extendTracks, headlandSettings.nPasses, centerSettings ) + implementWidth, headlandSettings.nPasses, centerSettings ) elseif headlandSettings.mode == courseGenerator.HEADLAND_MODE_TWO_SIDE then -- force headland corners headlandSettings.minHeadlandTurnAngleDeg = 60 -- start with rows over the field with no headland. local boundary field.headlandPath, boundary = generateTwoSideHeadlands( field.boundary, field.bigIslands, - implementWidth, extendTracks, headlandSettings, centerSettings, minDistanceBetweenPoints, minSmoothAngle, maxSmoothAngle) + implementWidth, headlandSettings, centerSettings, minDistanceBetweenPoints, minSmoothAngle, maxSmoothAngle) field.track, field.bestAngle, field.nTracks, field.blocks, resultIsOk = generateTracks({ boundary }, field.bigIslands, - implementWidth, extendTracks - implementWidth / 2, 0, centerSettings ) + implementWidth - implementWidth / 2, 0, centerSettings ) end courseGenerator.debug("####### COURSE GENERATOR END ###########################################################")