select index to keep from candidate list by external function

Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
0
down vote
favorite
Given a shape (a closed LineString, i.e. sequence of Points, where the first and the last points are equal) that contains other duplicates than the first and last point.
The algorithm finds all duplicated points and for each deletes all of them but one(or two). The tricky part is to decide which to keep: if either is equal to the first or last, keep it. Else keep the one, that has the least areal error.
object PolygonValidator
class LineString(val lineString: Seq[LngLat])
def closeLine: Seq[LngLat] = lineString match
case head :: tail if head != tail.last â lineString :+ head
case closedLine â closedLine
/**
* calculates a number representing the area surrounded of the given lineString.<br/>
* assumes a flat interpretation, so use only for smaller geometries.
*
* @return <ul><li>value > zero when lineString is oriented clockwise<li>value < zero when lineString is oriented counter clockwise<li>zero when area is empty</ul>
*/
def areaRepresentation: Double = pairwise(lineString).foldLeft(0d)((sum, line) â line match
case (a, b) â sum + (b.lng - a.lng) * (b.lat + a.lat)
)
implicit def seqToLineString(s: Seq[LngLat]): LineString = new LineString(s)
def findDuplicate[C](shape: Seq[C]): Seq[C] = shape.tail.diff(shape.tail.distinct).distinct.reverse
private def pairwise[C](linear: Seq[C]): Seq[(C, C)] = linear.zip(linear.tail)
def removeDoublePoints(shape: Seq[LngLat]): Seq[LngLat] =
var pointsToDelete: Set[Int] = Set()
for (duplicate â findDuplicate(shape))
val positionsOfDuplicate: Seq[Int] = shape.zipWithIndex.filter(_._1 == duplicate).map(_._2)
// [â¦]
// keep original point with the smallest error
// TODO: make nicer :)
var start = if (positionsOfDuplicate.head == 0) 1 else 0
var end = if (positionsOfDuplicate.last == shape.size - 1) positionsOfDuplicate.size - 1 else positionsOfDuplicate.size
if (start == 0 && end == positionsOfDuplicate.size)
// we need to keep either
val startIdx = positionsOfDuplicate.head
val endIdx = positionsOfDuplicate.last
val startError = shape.slice(startIdx - 1, startIdx + 2).closeLine.areaRepresentation.abs
val endError = shape.slice(endIdx - 1, endIdx + 2).closeLine.areaRepresentation.abs
if (startError > endError) start += 1
else end -= 1
pointsToDelete = pointsToDelete ++ positionsOfDuplicate.slice(start, end)
shape.zipWithIndex.filterNot( case (_, idx) â pointsToDelete.contains(idx) ).map(_._1)
}
The part I am not so happy with is the big block in the removeDoublePoints function that only determines whether we should keep the first or the last of the given duplicate points.
Who has a nicer i.e. more readable or shorter version?
algorithm scala
add a comment |Â
up vote
0
down vote
favorite
Given a shape (a closed LineString, i.e. sequence of Points, where the first and the last points are equal) that contains other duplicates than the first and last point.
The algorithm finds all duplicated points and for each deletes all of them but one(or two). The tricky part is to decide which to keep: if either is equal to the first or last, keep it. Else keep the one, that has the least areal error.
object PolygonValidator
class LineString(val lineString: Seq[LngLat])
def closeLine: Seq[LngLat] = lineString match
case head :: tail if head != tail.last â lineString :+ head
case closedLine â closedLine
/**
* calculates a number representing the area surrounded of the given lineString.<br/>
* assumes a flat interpretation, so use only for smaller geometries.
*
* @return <ul><li>value > zero when lineString is oriented clockwise<li>value < zero when lineString is oriented counter clockwise<li>zero when area is empty</ul>
*/
def areaRepresentation: Double = pairwise(lineString).foldLeft(0d)((sum, line) â line match
case (a, b) â sum + (b.lng - a.lng) * (b.lat + a.lat)
)
implicit def seqToLineString(s: Seq[LngLat]): LineString = new LineString(s)
def findDuplicate[C](shape: Seq[C]): Seq[C] = shape.tail.diff(shape.tail.distinct).distinct.reverse
private def pairwise[C](linear: Seq[C]): Seq[(C, C)] = linear.zip(linear.tail)
def removeDoublePoints(shape: Seq[LngLat]): Seq[LngLat] =
var pointsToDelete: Set[Int] = Set()
for (duplicate â findDuplicate(shape))
val positionsOfDuplicate: Seq[Int] = shape.zipWithIndex.filter(_._1 == duplicate).map(_._2)
// [â¦]
// keep original point with the smallest error
// TODO: make nicer :)
var start = if (positionsOfDuplicate.head == 0) 1 else 0
var end = if (positionsOfDuplicate.last == shape.size - 1) positionsOfDuplicate.size - 1 else positionsOfDuplicate.size
if (start == 0 && end == positionsOfDuplicate.size)
// we need to keep either
val startIdx = positionsOfDuplicate.head
val endIdx = positionsOfDuplicate.last
val startError = shape.slice(startIdx - 1, startIdx + 2).closeLine.areaRepresentation.abs
val endError = shape.slice(endIdx - 1, endIdx + 2).closeLine.areaRepresentation.abs
if (startError > endError) start += 1
else end -= 1
pointsToDelete = pointsToDelete ++ positionsOfDuplicate.slice(start, end)
shape.zipWithIndex.filterNot( case (_, idx) â pointsToDelete.contains(idx) ).map(_._1)
}
The part I am not so happy with is the big block in the removeDoublePoints function that only determines whether we should keep the first or the last of the given duplicate points.
Who has a nicer i.e. more readable or shorter version?
algorithm scala
add a comment |Â
up vote
0
down vote
favorite
up vote
0
down vote
favorite
Given a shape (a closed LineString, i.e. sequence of Points, where the first and the last points are equal) that contains other duplicates than the first and last point.
The algorithm finds all duplicated points and for each deletes all of them but one(or two). The tricky part is to decide which to keep: if either is equal to the first or last, keep it. Else keep the one, that has the least areal error.
object PolygonValidator
class LineString(val lineString: Seq[LngLat])
def closeLine: Seq[LngLat] = lineString match
case head :: tail if head != tail.last â lineString :+ head
case closedLine â closedLine
/**
* calculates a number representing the area surrounded of the given lineString.<br/>
* assumes a flat interpretation, so use only for smaller geometries.
*
* @return <ul><li>value > zero when lineString is oriented clockwise<li>value < zero when lineString is oriented counter clockwise<li>zero when area is empty</ul>
*/
def areaRepresentation: Double = pairwise(lineString).foldLeft(0d)((sum, line) â line match
case (a, b) â sum + (b.lng - a.lng) * (b.lat + a.lat)
)
implicit def seqToLineString(s: Seq[LngLat]): LineString = new LineString(s)
def findDuplicate[C](shape: Seq[C]): Seq[C] = shape.tail.diff(shape.tail.distinct).distinct.reverse
private def pairwise[C](linear: Seq[C]): Seq[(C, C)] = linear.zip(linear.tail)
def removeDoublePoints(shape: Seq[LngLat]): Seq[LngLat] =
var pointsToDelete: Set[Int] = Set()
for (duplicate â findDuplicate(shape))
val positionsOfDuplicate: Seq[Int] = shape.zipWithIndex.filter(_._1 == duplicate).map(_._2)
// [â¦]
// keep original point with the smallest error
// TODO: make nicer :)
var start = if (positionsOfDuplicate.head == 0) 1 else 0
var end = if (positionsOfDuplicate.last == shape.size - 1) positionsOfDuplicate.size - 1 else positionsOfDuplicate.size
if (start == 0 && end == positionsOfDuplicate.size)
// we need to keep either
val startIdx = positionsOfDuplicate.head
val endIdx = positionsOfDuplicate.last
val startError = shape.slice(startIdx - 1, startIdx + 2).closeLine.areaRepresentation.abs
val endError = shape.slice(endIdx - 1, endIdx + 2).closeLine.areaRepresentation.abs
if (startError > endError) start += 1
else end -= 1
pointsToDelete = pointsToDelete ++ positionsOfDuplicate.slice(start, end)
shape.zipWithIndex.filterNot( case (_, idx) â pointsToDelete.contains(idx) ).map(_._1)
}
The part I am not so happy with is the big block in the removeDoublePoints function that only determines whether we should keep the first or the last of the given duplicate points.
Who has a nicer i.e. more readable or shorter version?
algorithm scala
Given a shape (a closed LineString, i.e. sequence of Points, where the first and the last points are equal) that contains other duplicates than the first and last point.
The algorithm finds all duplicated points and for each deletes all of them but one(or two). The tricky part is to decide which to keep: if either is equal to the first or last, keep it. Else keep the one, that has the least areal error.
object PolygonValidator
class LineString(val lineString: Seq[LngLat])
def closeLine: Seq[LngLat] = lineString match
case head :: tail if head != tail.last â lineString :+ head
case closedLine â closedLine
/**
* calculates a number representing the area surrounded of the given lineString.<br/>
* assumes a flat interpretation, so use only for smaller geometries.
*
* @return <ul><li>value > zero when lineString is oriented clockwise<li>value < zero when lineString is oriented counter clockwise<li>zero when area is empty</ul>
*/
def areaRepresentation: Double = pairwise(lineString).foldLeft(0d)((sum, line) â line match
case (a, b) â sum + (b.lng - a.lng) * (b.lat + a.lat)
)
implicit def seqToLineString(s: Seq[LngLat]): LineString = new LineString(s)
def findDuplicate[C](shape: Seq[C]): Seq[C] = shape.tail.diff(shape.tail.distinct).distinct.reverse
private def pairwise[C](linear: Seq[C]): Seq[(C, C)] = linear.zip(linear.tail)
def removeDoublePoints(shape: Seq[LngLat]): Seq[LngLat] =
var pointsToDelete: Set[Int] = Set()
for (duplicate â findDuplicate(shape))
val positionsOfDuplicate: Seq[Int] = shape.zipWithIndex.filter(_._1 == duplicate).map(_._2)
// [â¦]
// keep original point with the smallest error
// TODO: make nicer :)
var start = if (positionsOfDuplicate.head == 0) 1 else 0
var end = if (positionsOfDuplicate.last == shape.size - 1) positionsOfDuplicate.size - 1 else positionsOfDuplicate.size
if (start == 0 && end == positionsOfDuplicate.size)
// we need to keep either
val startIdx = positionsOfDuplicate.head
val endIdx = positionsOfDuplicate.last
val startError = shape.slice(startIdx - 1, startIdx + 2).closeLine.areaRepresentation.abs
val endError = shape.slice(endIdx - 1, endIdx + 2).closeLine.areaRepresentation.abs
if (startError > endError) start += 1
else end -= 1
pointsToDelete = pointsToDelete ++ positionsOfDuplicate.slice(start, end)
shape.zipWithIndex.filterNot( case (_, idx) â pointsToDelete.contains(idx) ).map(_._1)
}
The part I am not so happy with is the big block in the removeDoublePoints function that only determines whether we should keep the first or the last of the given duplicate points.
Who has a nicer i.e. more readable or shorter version?
algorithm scala
edited Jan 29 at 13:40
Julien Rousé
446416
446416
asked Jan 29 at 13:33
Jan
17616
17616
add a comment |Â
add a comment |Â
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f186256%2fselect-index-to-keep-from-candidate-list-by-external-function%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password