Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
P
Packing_Polygons_Pycharm
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
tolgayurt
Packing_Polygons_Pycharm
Commits
4c01129e
Commit
4c01129e
authored
4 years ago
by
tolgayurt
Browse files
Options
Downloads
Patches
Plain Diff
added header doc_string for the to the packing_algo.py, and commented
polygon_creator.py
parent
07c3db5a
No related branches found
Branches containing commit
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
mysite/plots/packing_algo.py
+13
-0
13 additions, 0 deletions
mysite/plots/packing_algo.py
mysite/plots/polygon_creator.py
+123
-25
123 additions, 25 deletions
mysite/plots/polygon_creator.py
with
136 additions
and
25 deletions
mysite/plots/packing_algo.py
+
13
−
0
View file @
4c01129e
"""
This module represents a approximation algorithm for the optimal packing of convex polygons.
The guideline and heart of this algorithm is the paper:
Alt H., de Berg M., Knauer C. (2015)
Approximating Minimum-Area Rectangular and Convex Containers for Packing Convex Polygons.
In: Bansal N., Finocchi I. (eds) Algorithms - ESA 2015. Lecture Notes in Computer Science,
vol 9294. Springer, Berlin, Heidelberg. https://doi.org/10.1007/978-3-662-48350-3_3
DOI:
https://doi.org/10.1007/978-3-662-48350-3_3
"""
import
copy
import
numpy
import
math
...
...
This diff is collapsed.
Click to expand it.
mysite/plots/polygon_creator.py
+
123
−
25
View file @
4c01129e
# Zerlegen des Polygons
#import import_ipynb
"""
This module can cut a rectangular with known area into random convex polygons.
These convex polygons can be packed with the approximation algorithm from the module packing_algo.py.
The purpose is to compare the area between the packed container and the optimal rectangular area.
# Voronoi diagramm
import
scipy.spatial
as
spatial
from
collections
import
defaultdict
This module has two different algorithm to cut the rectangular into convex polygons.
"""
import
scipy.spatial
as
spatial
# package with voronoi diagramm
import
random
import
numpy
from
shapely.geometry
import
Polygon
,
MultiPolygon
from
shapely.geometry
import
Polygon
from
.packing_algo
import
ConvexPolygon
,
Point_xy
,
plot_polygons_in_single_plot
def
rectangle_cutter
(
rect_width
:
float
,
rect_height
:
float
,
cut_count
:
int
,
intervals
=
[
0
,
0.01
,
0.05
,
1
],
weights
=
[
0
,
0
,
0.5
,
1
],
render
=
False
,
plot_width
=
700
,
plot_height
=
700
)
->
[
ConvexPolygon
]:
"""
Cuts the given rectangle into several convex polygons
Workflow of the algorithm:
0. Check the convex polygon area and assign it to his interval, every interval has his own weight partner which
represent the chance to cut the convex polygon.
Weight 0.5 means a 50%, weight 1.0 means a 100% chance that the polygon goes threw steps 1-4 which means
it will be cut into two new convex polygons.
1. Chooses two random viable edges.
2. Takes a random point from each edge chosen in step 1
3. Builds the shortest distance between the points chosen in step 2
4. The distance in step 3 is the border which cuts the old convex polygon into two new ones.
5. Step 0-4 will repeated until the cut_count is 0 or all polygons stopped to get cut because of step 0.
Args:
rect_width (float): the width of the starting rectangular
rect_height (float): the height of the starting rectangular
cut_count (int): the maximal cut count, example cut_count=5 means 2^5 convex polygons as result
which would be the the best case where every convex polygon cut decision was True
intervals ([float]): the area intervals which sort the convex polygons into different weigh groups
weights ([float]): the weights which represent the chance that a polygon will be cut
render (bool): if True the cut steps will also be rendered else not
plot_width (int): the width of the plot objects
plot_height (int): the height of the plot objects
Returns:
all_polygons ([ConvexPolygon]): all cut convex polygons
"""
if
len
(
intervals
)
!=
len
(
weights
):
raise
ValueError
(
"
the number of values from weights and intervals need to be the same
"
)
rectangle_polygon
=
ConvexPolygon
([(
0
,
0
),
(
0
,
rect_height
),
(
rect_width
,
rect_height
),
(
rect_width
,
0
),
(
0
,
0
)])
...
...
@@ -22,17 +51,17 @@ def rectangle_cutter(rect_width: float, rect_height: float, cut_count: int, inte
if
cut_count
<
0
:
raise
ValueError
(
"
the cut cut_count need to be positive to cut the polygon
"
)
while
cut_count
>
0
and
len
(
polygons_to_cut
)
>
0
:
cut
ted
_polygons
=
[]
cut_polygons
=
[]
for
polygon
in
polygons_to_cut
:
related_area
=
polygon
.
area
/
max_area
weight
=
find_weight
(
related_area
,
intervals
,
weights
)
rand
=
random
.
random
()
if
rand
<=
weight
:
cut
ted
_polygons
=
cut
ted
_polygons
+
cut_polygon
(
polygon
)
cut_polygons
=
cut_polygons
+
cut_polygon
(
polygon
)
else
:
polygon
.
plot_fill
=
True
small_area_polygons
.
append
(
polygon
)
polygons_to_cut
=
cut
ted
_polygons
polygons_to_cut
=
cut_polygons
cut_count
=
cut_count
-
1
if
render
:
current_polygons
=
polygons_to_cut
+
small_area_polygons
...
...
@@ -47,17 +76,42 @@ def rectangle_cutter(rect_width: float, rect_height: float, cut_count: int, inte
return
all_polygons
def
find_weight
(
x
,
intervals
,
weights
):
def
find_weight
(
area
:
float
,
intervals
:
[
float
],
weights
:
[
float
])
->
float
:
"""
Finds the cut chance for the input area
Args:
area (float): the input area
intervals ([float]): the intervals in which the input area can fall
weights ([float]): the cut chances for every interval
Returns:
weights[index] (float): the cut chance for the input area
"""
for
index
in
range
(
0
,
len
(
intervals
)):
if
x
<=
intervals
[
index
]:
if
area
<=
intervals
[
index
]:
return
weights
[
index
]
def
cut_polygon
(
polygon
:
ConvexPolygon
)
->
[
ConvexPolygon
]:
polygon
=
polygon
.
shell
# polyog
"""
Cuts a ConvexPolygon into two new ConvexPolygons
Steps:
1. Chooses two random edges from the input polygon
2. Takes a random point from each edge chosen in step 1
3. Builds the shortest distance between the points chosen in step 2
4. The distance in step 3 is the border which cuts the old convex polygon into two new ones.
Args:
polygon (ConvexPolygon): the convex input polygon which will be cut
Returns:
[ConvexPolygon(polygon_1), ConvexPolygon(polygon_2)]([ConvexPolygon]): two new ConvexPolygons
"""
polygon
=
polygon
.
shell
number_vertices
=
len
(
polygon
)
if
number_vertices
<
3
:
raise
ValueError
(
"
Polygon has not enough vertices
"
)
# Step 1 in the cut_polygon description
first_edge
=
numpy
.
random
.
randint
(
1
,
number_vertices
)
second_edge
=
numpy
.
random
.
randint
(
1
,
number_vertices
)
while
first_edge
==
second_edge
:
...
...
@@ -68,17 +122,26 @@ def cut_polygon(polygon: ConvexPolygon) -> [ConvexPolygon]:
vertex_2_first_edge
=
polygon
[
first_edge
]
vertex_1_second_edge
=
polygon
[
second_edge
-
1
]
vertex_2_second_edge
=
polygon
[
second_edge
]
# Step 2-4 in the cut_polygon description
new_vertex_1
=
random_point_between_edge
(
vertex_1_first_edge
,
vertex_2_first_edge
)
new_vertex_2
=
random_point_between_edge
(
vertex_1_second_edge
,
vertex_2_second_edge
)
polygon_1
=
polygon
[:
first_edge
]
+
[
new_vertex_1
]
+
[
new_vertex_2
]
+
polygon
[
second_edge
:]
polygon_2
=
[
new_vertex_1
]
+
polygon
[
first_edge
:
second_edge
]
+
[
new_vertex_2
]
+
[
new_vertex_1
]
# s = [1,2,5,6,7] ,s[6:] => []; daher können wir für den spezial Fall second_edge== vertices_number so vorgehen
return
[
ConvexPolygon
(
polygon_1
),
ConvexPolygon
(
polygon_2
)]
def
random_point_between_edge
(
vertex_1
:
Point_xy
,
vertex_2
:
Point_xy
)
->
Point_xy
:
new_vertex
=
(
0
,
0
)
"""
Returns a random point from an edge, the edge is build by the two input points
Uses the equation of a straight line to return a random point from the edge.
Args:
vertex_1 (Point_xy): the first input vertex/point
vertex_2 (Point_xy): the second input vertex/point
Returns:
new_vertex (Point_xy): the random point on the edge
"""
if
vertex_1
[
0
]
==
vertex_2
[
0
]:
low
,
high
=
vertex_1
[
1
],
vertex_2
[
1
]
if
low
>
high
:
...
...
@@ -92,11 +155,8 @@ def random_point_between_edge(vertex_1: Point_xy, vertex_2: Point_xy) -> Point_x
rand_number
=
numpy
.
random
.
uniform
(
low
,
high
)
new_vertex
=
(
rand_number
,
vertex_1
[
1
])
else
:
# y = m*x+n
# n = y-m*x
slope
=
(
vertex_1
[
1
]
-
vertex_2
[
1
])
/
(
vertex_1
[
0
]
-
vertex_2
[
0
])
# m = y2-y1/x2-x1 Formel für die Geradensteigung mithilfe aus zwei verschiedenen Punkten der Geraden
n
=
vertex_1
[
1
]
-
(
slope
*
vertex_1
[
0
])
slope
=
(
vertex_1
[
1
]
-
vertex_2
[
1
])
/
(
vertex_1
[
0
]
-
vertex_2
[
0
])
# m = y2-y1/x2-x1
n
=
vertex_1
[
1
]
-
(
slope
*
vertex_1
[
0
])
# n = y-m*x
low
,
high
=
vertex_1
[
1
],
vertex_2
[
1
]
if
low
>
high
:
low
,
high
=
high
,
low
...
...
@@ -106,9 +166,36 @@ def random_point_between_edge(vertex_1: Point_xy, vertex_2: Point_xy) -> Point_x
return
new_vertex
# https://gist.github.com/pv/8036995
# https://stackoverflow.com/questions/20515554/colorize-voronoi-diagram/20678647#20678647
def
voronoi_polygons_wrapper
(
rect_width
,
rect_height
,
point_count
):
def
voronoi_polygons_wrapper
(
rect_width
:
float
,
rect_height
:
float
,
point_count
:
int
)
->
[
ConvexPolygon
]:
"""
Cuts the input rectangle into voronoi cell polygons (they are convex)
Steps:
1. Creates n random points in the rectangle area, where n = point_count
2. Adds 4 distant dummy points which are far away from the rectangular to the random created points in steps 1,
the purpose of the dummy points is to be sure that the voronoi diagram is bigger than the rectangular, which
is important for step 4
3. creating the voronoi diagram with the scipy.spatial package
4. Intersect the voronoi regions which are not infinite with the input rectangular these intersections are the
cut convex polygons. The intersection is done with shapely package.
Help/Idea:
Using the scipy.spatial package for the voronoi diagram:
https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.Voronoi.html
The idea with the dummy elements is from:
https://stackoverflow.com/questions/20515554/colorize-voronoi-diagram
Using the shapely package for the intersection between the input rectangle and finite voronoi regions:
https://pypi.org/project/Shapely/
Args:
rect_width (float): the width of the input rectangle
rect_height (float): the height of the input rectangle
point_count (int): the number of random points which will created in the rectangle area, every point create a
convex polygon
Returns:
polygon_list ([ConvexPolygon]): list of voronoi polygons cut from the input rectangle
"""
boundary
=
numpy
.
array
([[
0
,
0
],
[
0
,
rect_height
],
[
rect_width
,
rect_height
],
[
rect_width
,
0
],
[
0
,
0
]])
boundary_polygon
=
Polygon
(
boundary
)
...
...
@@ -121,14 +208,14 @@ def voronoi_polygons_wrapper(rect_width, rect_height, point_count):
help_border
=
[[
border_point
,
border_point
],
[
-
border_point
,
border_point
],
[
border_point
,
-
border_point
],
[
-
border_point
,
-
border_point
]]
points
=
numpy
.
append
(
points
,
help_border
,
axis
=
0
)
# compute
V
oronoi tesselation
# compute
v
oronoi tesselation
vor
=
spatial
.
Voronoi
(
points
)
polygon_list
=
[]
for
region
in
vor
.
regions
:
if
not
-
1
in
region
:
polygon
=
[
vor
.
vertices
[
i
]
for
i
in
region
]
if
len
(
polygon
)
>
2
:
#
C
lipping polygon
#
c
lipping
the voronoi cell an creating a convex
polygon
poly
=
Polygon
(
polygon
)
clipped_poly
=
poly
.
intersection
(
boundary_polygon
)
polygon_list
.
append
(
ConvexPolygon
(
clipped_poly
.
exterior
.
coords
))
...
...
@@ -136,6 +223,17 @@ def voronoi_polygons_wrapper(rect_width, rect_height, point_count):
def
pre_decimal_finder
(
i
:
float
)
->
int
:
"""
Gives the number of pre_decimal places
This function helps to build the 4 voronoi dummy points which need to be far away from the rectangular which will
cut into voronoi cells.
Args:
i (float): the input value
Returns:
counter (int): the number of pre_decimal places
"""
if
i
<
0
:
i
=
abs
(
i
)
counter
=
0
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment