Skip to content

Commit

Permalink
field_parameters and field_provider with field_parameters persistent
Browse files Browse the repository at this point in the history
  • Loading branch information
LukasBaecker committed Sep 27, 2024
1 parent 1ed2422 commit fe816ee
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 255 deletions.
2 changes: 2 additions & 0 deletions field_friend/automations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from .battery_watcher import BatteryWatcher
from .coverage_planer import CoveragePlanner
from .field import Field, FieldObstacle, Row
from .field_parameters import FieldParameters
from .field_provider import FieldProvider
from .implements.implement import Implement
from .kpi_provider import KpiProvider
Expand All @@ -20,6 +21,7 @@
'DetectorError',
'Field',
'FieldObstacle',
'Field_Parameters',
'FieldProvider',
'Implement',
'CoverageNavigation',
Expand Down
60 changes: 8 additions & 52 deletions field_friend/automations/field.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import math
from dataclasses import dataclass, field
from uuid import uuid4

import rosys
from rosys.geometry import Point
from shapely import offset_curve
from shapely.geometry import LineString, Polygon
from shapely.geometry import Polygon

from field_friend.localization import GeoPoint, GeoPointCollection, reference
from field_friend.localization import GeoPointCollection


@dataclass(slots=True, kw_only=True)
Expand All @@ -34,67 +30,27 @@ def line_segment(self) -> rosys.geometry.LineSegment:
@dataclass(slots=True, kw_only=True)
class Field(GeoPointCollection):
visualized: bool = False
first_row_start: GeoPoint | None = None
first_row_end: GeoPoint | None = None
row_spacing: float = 0.5
row_number: int = 10
obstacles: list[FieldObstacle] = field(default_factory=list)
outline_buffer_width: float = 2
rows: list[Row] = field(default_factory=list)
crop: str | None = None

@property
def outline(self) -> list[GeoPoint]:
assert self.first_row_start is not None
assert self.first_row_end is not None
ab_line_cartesian = LineString([self.first_row_start.cartesian().tuple, self.first_row_end.cartesian().tuple])
last_row_linestring = offset_curve(ab_line_cartesian, - self.row_spacing * self.row_number)
end_row_points: list[Point] = []
for point in last_row_linestring.coords:
end_row_points.append(Point(x=point[0], y=point[1]))
outline_unbuffered: list[Point] = []
for i, point in enumerate(end_row_points):
outline_unbuffered.append(point)
outline_unbuffered.append(self.first_row_end.cartesian())
outline_unbuffered.append(self.first_row_start.cartesian())
outline_polygon = Polygon([p.tuple for p in outline_unbuffered])
bufferd_polygon = outline_polygon.buffer(
self.outline_buffer_width, join_style='mitre', mitre_limit=math.inf)
bufferd_polygon_coords = bufferd_polygon.exterior.coords
outline: list[GeoPoint] = []
for p in bufferd_polygon_coords:
outline.append(self.first_row_start.shifted(Point(x=p[0], y=p[1])))
return outline
def outline(self) -> list[rosys.geometry.Point]:
return self.cartesian()

@ property
@property
def outline_as_tuples(self) -> list[tuple[float, float]]:
return [p.tuple for p in self.outline]

def area(self) -> float:
outline = self.outline
if not outline:
return 0.0
polygon = Polygon([(p.lat, p.long) for p in outline])
polygon = Polygon([(p.x, p.y) for p in outline])
return polygon.area

def worked_area(self, worked_rows: int) -> float:
worked_area = 0.0
if self.area() > 0:
worked_area = worked_rows * self.area() / len(self.rows)
return worked_area

@ property
def rows(self) -> list[Row]:
assert self.first_row_start is not None
assert self.first_row_end is not None
first_row_start_cartesian = Point(x=0, y=0) # first_row_start as reference for calculation
first_row_end_cartesian = self.first_row_end.cartesian()
ab_line_cartesian = LineString([first_row_start_cartesian.tuple, first_row_end_cartesian.tuple])
rows = []
for i in range(int(self.row_number)+1):
offset = i * self.row_spacing
offset_row_coordinated = offset_curve(ab_line_cartesian, -offset).coords
row_points: list[GeoPoint] = []
for point in offset_row_coordinated:
row_points.append(self.first_row_start.shifted(Point(x=point[0], y=point[1])))
row = Row(id=str(uuid4()), name=f'{i + 1}', points=row_points)
rows.append(row)
return rows
94 changes: 94 additions & 0 deletions field_friend/automations/field_parameters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import math
from dataclasses import dataclass
from typing import Any
from uuid import uuid4

from rosys.geometry import Point
from shapely import offset_curve
from shapely.geometry import LineString, Polygon
from typing_extensions import Self

from field_friend.localization import GeoPoint

from . import Field, Row


class FieldParameters():

def __init__(self,
id: str, # pylint: disable=redefined-builtin
name: str,
first_row_start: GeoPoint,
first_row_end: GeoPoint,
row_spacing: float = 0.5,
row_number: int = 10,
outline_buffer_width: float = 2) -> None:
self.id: str = id
self.name: str = name
self.first_row_start: GeoPoint = first_row_start
self.first_row_end: GeoPoint = first_row_end
self.row_spacing: float = row_spacing
self.row_number: int = row_number
self.outline_buffer_width: float = outline_buffer_width

@property
def field(self) -> 'Field':
return Field(id=self.id, name=self.name, points=self._generate_outline(), obstacles=[], rows=self._generate_rows())

def _generate_outline(self) -> list[GeoPoint]:
assert self.first_row_start is not None
assert self.first_row_end is not None
ab_line_cartesian = LineString([self.first_row_start.cartesian().tuple, self.first_row_end.cartesian().tuple])
last_row_linestring = offset_curve(ab_line_cartesian, - self.row_spacing * self.row_number)
end_row_points: list[Point] = []
for point in last_row_linestring.coords:
end_row_points.append(Point(x=point[0], y=point[1]))
outline_unbuffered: list[Point] = []
for i, point in enumerate(end_row_points):
outline_unbuffered.append(point)
outline_unbuffered.append(self.first_row_end.cartesian())
outline_unbuffered.append(self.first_row_start.cartesian())
outline_polygon = Polygon([p.tuple for p in outline_unbuffered])
bufferd_polygon = outline_polygon.buffer(
self.outline_buffer_width, join_style='mitre', mitre_limit=math.inf)
bufferd_polygon_coords = bufferd_polygon.exterior.coords
outline: list[GeoPoint] = []
for p in bufferd_polygon_coords:
outline.append(self.first_row_start.shifted(Point(x=p[0], y=p[1])))
return outline

def _generate_rows(self) -> list[Row]:
assert self.first_row_start is not None
assert self.first_row_end is not None
first_row_start_cartesian = Point(x=0, y=0) # first_row_start as reference for calculation
first_row_end_cartesian = self.first_row_end.cartesian()
ab_line_cartesian = LineString([first_row_start_cartesian.tuple, first_row_end_cartesian.tuple])
rows = []
for i in range(int(self.row_number)):
offset = i * self.row_spacing
offset_row_coordinated = offset_curve(ab_line_cartesian, -offset).coords
row_points: list[GeoPoint] = []
for point in offset_row_coordinated:
row_points.append(self.first_row_start.shifted(Point(x=point[0], y=point[1])))
row = Row(id=str(uuid4()), name=f'{i + 1}', points=row_points)
rows.append(row)
return rows

def to_dict(self) -> dict:
return {
'id': self.id,
'name': self.name,
'first_row_start': self.first_row_start,
'first_row_end': self.first_row_end,
'row_spacing': self.row_spacing,
'row_number': self.row_number,
'outline_buffer_width': self.outline_buffer_width,
}

@classmethod
def args_from_dict(cls, data: dict[str, Any]) -> dict:
return data

@classmethod
def from_dict(cls, data: dict[str, Any]) -> Self:
return cls(**cls.args_from_dict(data))
Loading

0 comments on commit fe816ee

Please sign in to comment.