Spaces:
No application file
No application file
Create v7.2
Browse files
v7.2
ADDED
|
@@ -0,0 +1,2635 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Option Explicit
|
| 2 |
+
|
| 3 |
+
Private Const EPS As Double = 0.000001
|
| 4 |
+
Private Const ROLL_GAP As Double = 5#
|
| 5 |
+
Private Const MAX_ROLLS As Long = 100
|
| 6 |
+
|
| 7 |
+
Private Const MAX_RIGHT_WASTE As Double = 10#
|
| 8 |
+
Private Const ALIGN_TOLERANCE As Double = 0.5
|
| 9 |
+
|
| 10 |
+
' Material area is the primary objective: roll width x actual used height.
|
| 11 |
+
' Secondary terms are intentionally much smaller so they cannot beat a
|
| 12 |
+
' meaningful material saving.
|
| 13 |
+
Private Const MATERIAL_SCORE_SCALE As Double = 1000000000#
|
| 14 |
+
Private Const RIGHT_WASTE_SCORE_SCALE As Double = 100000#
|
| 15 |
+
Private Const ALIGNMENT_SCORE_SCALE As Double = 0.01
|
| 16 |
+
Private Const ROLL_COUNT_SCORE_SCALE As Double = 0.0001
|
| 17 |
+
|
| 18 |
+
Private Const MAX_LOCAL_SEEDS As Long = 5
|
| 19 |
+
Private Const MAX_PAIR_MOVES As Long = 80
|
| 20 |
+
Private Const MAX_REINSERT_MOVES As Long = 100
|
| 21 |
+
Private Const MAX_TRIPLE_MOVES As Long = 40
|
| 22 |
+
Private Const MAX_LOCAL_PASSES As Long = 3
|
| 23 |
+
|
| 24 |
+
Private Const MAX_LNS_ITERATIONS As Long = 12
|
| 25 |
+
Private Const MAX_LNS_REPAIR_POSITIONS As Long = 30
|
| 26 |
+
Private Const MAX_ROTATION_MUTATIONS As Long = 24
|
| 27 |
+
Private Const LNS_ACCEPT_WORSE_PCT As Double = 0.003
|
| 28 |
+
|
| 29 |
+
Private Const CONTACT_TOLERANCE As Double = 0.05
|
| 30 |
+
Private Const CONTACT_PLACEMENT_WEIGHT As Double = 0.35
|
| 31 |
+
Private Const GUILLOTINE_PLACEMENT_WEIGHT As Double = 0.25
|
| 32 |
+
Private Const CONTACT_SCORE_WEIGHT As Double = 0.25
|
| 33 |
+
Private Const GUILLOTINE_SCORE_WEIGHT As Double = 0.35
|
| 34 |
+
Private Const MAX_CONTACT_MOVES As Long = 60
|
| 35 |
+
Private Const MAX_CUT_MOVES As Long = 50
|
| 36 |
+
|
| 37 |
+
' Multi-width search tests pairs from at most the first 6 entered widths.
|
| 38 |
+
Private Const MAX_MULTI_WIDTH_CANDIDATES As Long = 6
|
| 39 |
+
|
| 40 |
+
Private Type TBanner
|
| 41 |
+
Label As String
|
| 42 |
+
OrigW As Double
|
| 43 |
+
OrigH As Double
|
| 44 |
+
margin As Double
|
| 45 |
+
End Type
|
| 46 |
+
|
| 47 |
+
Private Type TFreeRect
|
| 48 |
+
x As Double
|
| 49 |
+
y As Double
|
| 50 |
+
w As Double
|
| 51 |
+
h As Double
|
| 52 |
+
End Type
|
| 53 |
+
|
| 54 |
+
Private Type TPlaced
|
| 55 |
+
rid As Long
|
| 56 |
+
x As Double
|
| 57 |
+
y As Double
|
| 58 |
+
w As Double
|
| 59 |
+
h As Double
|
| 60 |
+
Rotated As Boolean
|
| 61 |
+
End Type
|
| 62 |
+
|
| 63 |
+
Private Type TRoll
|
| 64 |
+
placed() As TPlaced
|
| 65 |
+
placedCount As Long
|
| 66 |
+
UsedHeight As Double
|
| 67 |
+
End Type
|
| 68 |
+
|
| 69 |
+
Private Function MinD(ByVal a As Double, ByVal b As Double) As Double
|
| 70 |
+
If a < b Then
|
| 71 |
+
MinD = a
|
| 72 |
+
Else
|
| 73 |
+
MinD = b
|
| 74 |
+
End If
|
| 75 |
+
End Function
|
| 76 |
+
|
| 77 |
+
Private Function MaxD(ByVal a As Double, ByVal b As Double) As Double
|
| 78 |
+
If a > b Then
|
| 79 |
+
MaxD = a
|
| 80 |
+
Else
|
| 81 |
+
MaxD = b
|
| 82 |
+
End If
|
| 83 |
+
End Function
|
| 84 |
+
|
| 85 |
+
Private Function AbsD(ByVal a As Double) As Double
|
| 86 |
+
If a < 0# Then
|
| 87 |
+
AbsD = -a
|
| 88 |
+
Else
|
| 89 |
+
AbsD = a
|
| 90 |
+
End If
|
| 91 |
+
End Function
|
| 92 |
+
|
| 93 |
+
Private Function AreaOf(ByRef item As TBanner) As Double
|
| 94 |
+
AreaOf = (item.OrigW + 2# * item.margin) * (item.OrigH + 2# * item.margin)
|
| 95 |
+
End Function
|
| 96 |
+
|
| 97 |
+
Private Function SortValue(ByRef item As TBanner, ByVal sortMode As Long) As Double
|
| 98 |
+
Dim w As Double
|
| 99 |
+
Dim h As Double
|
| 100 |
+
Dim shortSide As Double
|
| 101 |
+
Dim longSide As Double
|
| 102 |
+
|
| 103 |
+
w = item.OrigW + 2# * item.margin
|
| 104 |
+
h = item.OrigH + 2# * item.margin
|
| 105 |
+
shortSide = MinD(w, h)
|
| 106 |
+
longSide = MaxD(w, h)
|
| 107 |
+
|
| 108 |
+
Select Case sortMode
|
| 109 |
+
Case 1
|
| 110 |
+
SortValue = w * h
|
| 111 |
+
Case 2
|
| 112 |
+
SortValue = w
|
| 113 |
+
Case 3
|
| 114 |
+
SortValue = h
|
| 115 |
+
Case 4
|
| 116 |
+
SortValue = shortSide
|
| 117 |
+
Case 5
|
| 118 |
+
SortValue = longSide
|
| 119 |
+
Case 6
|
| 120 |
+
If shortSide > EPS Then
|
| 121 |
+
SortValue = longSide / shortSide
|
| 122 |
+
Else
|
| 123 |
+
SortValue = 0#
|
| 124 |
+
End If
|
| 125 |
+
Case Else
|
| 126 |
+
SortValue = w * h
|
| 127 |
+
End Select
|
| 128 |
+
End Function
|
| 129 |
+
|
| 130 |
+
Private Sub SortIndex(ByRef items() As TBanner, ByRef sourceIdx() As Long, ByVal n As Long, ByVal sortMode As Long, ByRef sortedIdx() As Long)
|
| 131 |
+
Dim i As Long
|
| 132 |
+
Dim j As Long
|
| 133 |
+
Dim tmp As Long
|
| 134 |
+
|
| 135 |
+
ReDim sortedIdx(1 To n)
|
| 136 |
+
For i = 1 To n
|
| 137 |
+
sortedIdx(i) = sourceIdx(i)
|
| 138 |
+
Next i
|
| 139 |
+
|
| 140 |
+
For i = 1 To n - 1
|
| 141 |
+
For j = i + 1 To n
|
| 142 |
+
If SortValue(items(sortedIdx(j)), sortMode) > SortValue(items(sortedIdx(i)), sortMode) Then
|
| 143 |
+
tmp = sortedIdx(i)
|
| 144 |
+
sortedIdx(i) = sortedIdx(j)
|
| 145 |
+
sortedIdx(j) = tmp
|
| 146 |
+
End If
|
| 147 |
+
Next j
|
| 148 |
+
Next i
|
| 149 |
+
End Sub
|
| 150 |
+
|
| 151 |
+
Private Sub BuildInitialOrder(ByRef items() As TBanner, ByVal n As Long, ByVal sortMode As Long, ByRef order() As Long)
|
| 152 |
+
Dim sourceIdx() As Long
|
| 153 |
+
Dim i As Long
|
| 154 |
+
|
| 155 |
+
ReDim sourceIdx(1 To n)
|
| 156 |
+
ReDim order(1 To n)
|
| 157 |
+
|
| 158 |
+
For i = 1 To n
|
| 159 |
+
sourceIdx(i) = i
|
| 160 |
+
Next i
|
| 161 |
+
|
| 162 |
+
SortIndex items, sourceIdx, n, sortMode, order
|
| 163 |
+
End Sub
|
| 164 |
+
|
| 165 |
+
Private Sub CopyOrder(ByRef source() As Long, ByVal sourceCount As Long, ByRef target() As Long)
|
| 166 |
+
Dim i As Long
|
| 167 |
+
|
| 168 |
+
If sourceCount <= 0 Then
|
| 169 |
+
ReDim target(1 To 1)
|
| 170 |
+
Exit Sub
|
| 171 |
+
End If
|
| 172 |
+
|
| 173 |
+
ReDim target(1 To sourceCount)
|
| 174 |
+
For i = 1 To sourceCount
|
| 175 |
+
target(i) = source(i)
|
| 176 |
+
Next i
|
| 177 |
+
End Sub
|
| 178 |
+
|
| 179 |
+
Private Sub CopyRotationPrefs(ByRef source() As Long, ByVal n As Long, ByRef target() As Long)
|
| 180 |
+
Dim i As Long
|
| 181 |
+
|
| 182 |
+
ReDim target(1 To n)
|
| 183 |
+
For i = 1 To n
|
| 184 |
+
target(i) = source(i)
|
| 185 |
+
Next i
|
| 186 |
+
End Sub
|
| 187 |
+
|
| 188 |
+
Private Sub SwapLong(ByRef arr() As Long, ByVal i As Long, ByVal j As Long)
|
| 189 |
+
Dim tmp As Long
|
| 190 |
+
|
| 191 |
+
If i = j Then Exit Sub
|
| 192 |
+
tmp = arr(i)
|
| 193 |
+
arr(i) = arr(j)
|
| 194 |
+
arr(j) = tmp
|
| 195 |
+
End Sub
|
| 196 |
+
|
| 197 |
+
Private Sub MoveItemOrder(ByRef arr() As Long, ByVal fromPos As Long, ByVal toPos As Long, ByVal n As Long)
|
| 198 |
+
Dim value As Long
|
| 199 |
+
Dim i As Long
|
| 200 |
+
|
| 201 |
+
If fromPos = toPos Then Exit Sub
|
| 202 |
+
If fromPos < 1 Or fromPos > n Then Exit Sub
|
| 203 |
+
If toPos < 1 Or toPos > n Then Exit Sub
|
| 204 |
+
|
| 205 |
+
value = arr(fromPos)
|
| 206 |
+
|
| 207 |
+
If fromPos < toPos Then
|
| 208 |
+
For i = fromPos To toPos - 1
|
| 209 |
+
arr(i) = arr(i + 1)
|
| 210 |
+
Next i
|
| 211 |
+
Else
|
| 212 |
+
For i = fromPos To toPos + 1 Step -1
|
| 213 |
+
arr(i) = arr(i - 1)
|
| 214 |
+
Next i
|
| 215 |
+
End If
|
| 216 |
+
|
| 217 |
+
arr(toPos) = value
|
| 218 |
+
End Sub
|
| 219 |
+
|
| 220 |
+
Private Sub InsertLongAt(ByRef arr() As Long, ByRef currentCount As Long, ByVal position As Long, ByVal value As Long)
|
| 221 |
+
Dim i As Long
|
| 222 |
+
|
| 223 |
+
If position < 1 Then position = 1
|
| 224 |
+
If position > currentCount + 1 Then position = currentCount + 1
|
| 225 |
+
|
| 226 |
+
For i = currentCount To position Step -1
|
| 227 |
+
arr(i + 1) = arr(i)
|
| 228 |
+
Next i
|
| 229 |
+
|
| 230 |
+
arr(position) = value
|
| 231 |
+
currentCount = currentCount + 1
|
| 232 |
+
End Sub
|
| 233 |
+
|
| 234 |
+
Private Sub RemoveLongAt(ByRef arr() As Long, ByRef currentCount As Long, ByVal position As Long)
|
| 235 |
+
Dim i As Long
|
| 236 |
+
|
| 237 |
+
If currentCount <= 0 Then Exit Sub
|
| 238 |
+
If position < 1 Or position > currentCount Then Exit Sub
|
| 239 |
+
|
| 240 |
+
For i = position To currentCount - 1
|
| 241 |
+
arr(i) = arr(i + 1)
|
| 242 |
+
Next i
|
| 243 |
+
|
| 244 |
+
currentCount = currentCount - 1
|
| 245 |
+
End Sub
|
| 246 |
+
|
| 247 |
+
Private Function ContainsLong(ByRef arr() As Long, ByVal count As Long, ByVal value As Long) As Boolean
|
| 248 |
+
Dim i As Long
|
| 249 |
+
|
| 250 |
+
For i = 1 To count
|
| 251 |
+
If arr(i) = value Then
|
| 252 |
+
ContainsLong = True
|
| 253 |
+
Exit Function
|
| 254 |
+
End If
|
| 255 |
+
Next i
|
| 256 |
+
|
| 257 |
+
ContainsLong = False
|
| 258 |
+
End Function
|
| 259 |
+
|
| 260 |
+
Private Function RectsIntersect(ByRef a As TFreeRect, ByRef b As TFreeRect) As Boolean
|
| 261 |
+
If a.x >= b.x + b.w - EPS Then
|
| 262 |
+
RectsIntersect = False
|
| 263 |
+
Exit Function
|
| 264 |
+
End If
|
| 265 |
+
If b.x >= a.x + a.w - EPS Then
|
| 266 |
+
RectsIntersect = False
|
| 267 |
+
Exit Function
|
| 268 |
+
End If
|
| 269 |
+
If a.y >= b.y + b.h - EPS Then
|
| 270 |
+
RectsIntersect = False
|
| 271 |
+
Exit Function
|
| 272 |
+
End If
|
| 273 |
+
If b.y >= a.y + a.h - EPS Then
|
| 274 |
+
RectsIntersect = False
|
| 275 |
+
Exit Function
|
| 276 |
+
End If
|
| 277 |
+
|
| 278 |
+
RectsIntersect = True
|
| 279 |
+
End Function
|
| 280 |
+
|
| 281 |
+
Private Function IsContained(ByRef a As TFreeRect, ByRef b As TFreeRect) As Boolean
|
| 282 |
+
If a.x + EPS < b.x Then
|
| 283 |
+
IsContained = False
|
| 284 |
+
Exit Function
|
| 285 |
+
End If
|
| 286 |
+
If a.y + EPS < b.y Then
|
| 287 |
+
IsContained = False
|
| 288 |
+
Exit Function
|
| 289 |
+
End If
|
| 290 |
+
If a.x + a.w > b.x + b.w + EPS Then
|
| 291 |
+
IsContained = False
|
| 292 |
+
Exit Function
|
| 293 |
+
End If
|
| 294 |
+
If a.y + a.h > b.y + b.h + EPS Then
|
| 295 |
+
IsContained = False
|
| 296 |
+
Exit Function
|
| 297 |
+
End If
|
| 298 |
+
|
| 299 |
+
IsContained = True
|
| 300 |
+
End Function
|
| 301 |
+
|
| 302 |
+
Private Sub PruneFree(ByRef freeRects() As TFreeRect, ByRef freeCount As Long)
|
| 303 |
+
Dim i As Long
|
| 304 |
+
Dim j As Long
|
| 305 |
+
Dim k As Long
|
| 306 |
+
Dim contained As Boolean
|
| 307 |
+
|
| 308 |
+
If freeCount <= 1 Then Exit Sub
|
| 309 |
+
|
| 310 |
+
i = 1
|
| 311 |
+
Do While i <= freeCount
|
| 312 |
+
contained = False
|
| 313 |
+
|
| 314 |
+
For j = 1 To freeCount
|
| 315 |
+
If i <> j Then
|
| 316 |
+
If IsContained(freeRects(i), freeRects(j)) Then
|
| 317 |
+
contained = True
|
| 318 |
+
Exit For
|
| 319 |
+
End If
|
| 320 |
+
End If
|
| 321 |
+
Next j
|
| 322 |
+
|
| 323 |
+
If contained Then
|
| 324 |
+
For k = i To freeCount - 1
|
| 325 |
+
freeRects(k) = freeRects(k + 1)
|
| 326 |
+
Next k
|
| 327 |
+
freeCount = freeCount - 1
|
| 328 |
+
Else
|
| 329 |
+
i = i + 1
|
| 330 |
+
End If
|
| 331 |
+
Loop
|
| 332 |
+
|
| 333 |
+
If freeCount <= 0 Then
|
| 334 |
+
ReDim freeRects(1 To 1)
|
| 335 |
+
Else
|
| 336 |
+
ReDim Preserve freeRects(1 To freeCount)
|
| 337 |
+
End If
|
| 338 |
+
End Sub
|
| 339 |
+
|
| 340 |
+
Private Sub AddIfValid(ByRef arr() As TFreeRect, ByRef count As Long, ByVal x As Double, ByVal y As Double, ByVal w As Double, ByVal h As Double)
|
| 341 |
+
If w <= EPS Then Exit Sub
|
| 342 |
+
If h <= EPS Then Exit Sub
|
| 343 |
+
|
| 344 |
+
count = count + 1
|
| 345 |
+
arr(count).x = x
|
| 346 |
+
arr(count).y = y
|
| 347 |
+
arr(count).w = w
|
| 348 |
+
arr(count).h = h
|
| 349 |
+
End Sub
|
| 350 |
+
|
| 351 |
+
Private Sub PlaceAndSplit(ByRef freeRects() As TFreeRect, ByRef freeCount As Long, ByVal placedX As Double, ByVal placedY As Double, ByVal placedW As Double, ByVal placedH As Double)
|
| 352 |
+
Dim oldCount As Long
|
| 353 |
+
Dim newCount As Long
|
| 354 |
+
Dim maxNew As Long
|
| 355 |
+
Dim i As Long
|
| 356 |
+
Dim fr As TFreeRect
|
| 357 |
+
Dim placed As TFreeRect
|
| 358 |
+
Dim tmp() As TFreeRect
|
| 359 |
+
|
| 360 |
+
oldCount = freeCount
|
| 361 |
+
If oldCount <= 0 Then Exit Sub
|
| 362 |
+
|
| 363 |
+
maxNew = oldCount * 4 + 10
|
| 364 |
+
ReDim tmp(1 To maxNew)
|
| 365 |
+
|
| 366 |
+
placed.x = placedX
|
| 367 |
+
placed.y = placedY
|
| 368 |
+
placed.w = placedW
|
| 369 |
+
placed.h = placedH
|
| 370 |
+
|
| 371 |
+
For i = 1 To oldCount
|
| 372 |
+
fr = freeRects(i)
|
| 373 |
+
|
| 374 |
+
If Not RectsIntersect(fr, placed) Then
|
| 375 |
+
AddIfValid tmp, newCount, fr.x, fr.y, fr.w, fr.h
|
| 376 |
+
Else
|
| 377 |
+
AddIfValid tmp, newCount, fr.x, fr.y, placed.x - fr.x, fr.h
|
| 378 |
+
AddIfValid tmp, newCount, placed.x + placed.w, fr.y, fr.x + fr.w - placed.x - placed.w, fr.h
|
| 379 |
+
AddIfValid tmp, newCount, fr.x, fr.y, fr.w, placed.y - fr.y
|
| 380 |
+
AddIfValid tmp, newCount, fr.x, placed.y + placed.h, fr.w, fr.y + fr.h - placed.y - placed.h
|
| 381 |
+
End If
|
| 382 |
+
Next i
|
| 383 |
+
|
| 384 |
+
If newCount <= 0 Then
|
| 385 |
+
ReDim freeRects(1 To 1)
|
| 386 |
+
freeCount = 0
|
| 387 |
+
Exit Sub
|
| 388 |
+
End If
|
| 389 |
+
|
| 390 |
+
ReDim freeRects(1 To newCount)
|
| 391 |
+
For i = 1 To newCount
|
| 392 |
+
freeRects(i) = tmp(i)
|
| 393 |
+
Next i
|
| 394 |
+
|
| 395 |
+
freeCount = newCount
|
| 396 |
+
PruneFree freeRects, freeCount
|
| 397 |
+
End Sub
|
| 398 |
+
|
| 399 |
+
Private Function OverlapLength(ByVal a1 As Double, ByVal a2 As Double, ByVal b1 As Double, ByVal b2 As Double) As Double
|
| 400 |
+
Dim lo As Double
|
| 401 |
+
Dim hi As Double
|
| 402 |
+
|
| 403 |
+
lo = MaxD(a1, b1)
|
| 404 |
+
hi = MinD(a2, b2)
|
| 405 |
+
|
| 406 |
+
If hi <= lo + CONTACT_TOLERANCE Then
|
| 407 |
+
OverlapLength = 0#
|
| 408 |
+
Else
|
| 409 |
+
OverlapLength = hi - lo
|
| 410 |
+
End If
|
| 411 |
+
End Function
|
| 412 |
+
|
| 413 |
+
Private Function SharedEdgeLengthBetween(ByRef a As TPlaced, ByRef b As TPlaced) As Double
|
| 414 |
+
Dim total As Double
|
| 415 |
+
Dim ov As Double
|
| 416 |
+
|
| 417 |
+
total = 0#
|
| 418 |
+
|
| 419 |
+
If AbsD(a.x + a.w - b.x) <= CONTACT_TOLERANCE Then
|
| 420 |
+
ov = OverlapLength(a.y, a.y + a.h, b.y, b.y + b.h)
|
| 421 |
+
total = total + ov
|
| 422 |
+
ElseIf AbsD(b.x + b.w - a.x) <= CONTACT_TOLERANCE Then
|
| 423 |
+
ov = OverlapLength(a.y, a.y + a.h, b.y, b.y + b.h)
|
| 424 |
+
total = total + ov
|
| 425 |
+
End If
|
| 426 |
+
|
| 427 |
+
If AbsD(a.y + a.h - b.y) <= CONTACT_TOLERANCE Then
|
| 428 |
+
ov = OverlapLength(a.x, a.x + a.w, b.x, b.x + b.w)
|
| 429 |
+
total = total + ov
|
| 430 |
+
ElseIf AbsD(b.y + b.h - a.y) <= CONTACT_TOLERANCE Then
|
| 431 |
+
ov = OverlapLength(a.x, a.x + a.w, b.x, b.x + b.w)
|
| 432 |
+
total = total + ov
|
| 433 |
+
End If
|
| 434 |
+
|
| 435 |
+
SharedEdgeLengthBetween = total
|
| 436 |
+
End Function
|
| 437 |
+
|
| 438 |
+
Private Function StrongGuillotineEdgeBetween(ByRef a As TPlaced, ByRef b As TPlaced) As Double
|
| 439 |
+
Dim ov As Double
|
| 440 |
+
Dim minSpan As Double
|
| 441 |
+
|
| 442 |
+
If AbsD(a.x + a.w - b.x) <= CONTACT_TOLERANCE Or AbsD(b.x + b.w - a.x) <= CONTACT_TOLERANCE Then
|
| 443 |
+
ov = OverlapLength(a.y, a.y + a.h, b.y, b.y + b.h)
|
| 444 |
+
minSpan = MinD(a.h, b.h)
|
| 445 |
+
If minSpan > EPS And ov >= minSpan * 0.9 Then
|
| 446 |
+
StrongGuillotineEdgeBetween = ov
|
| 447 |
+
Exit Function
|
| 448 |
+
End If
|
| 449 |
+
End If
|
| 450 |
+
|
| 451 |
+
If AbsD(a.y + a.h - b.y) <= CONTACT_TOLERANCE Or AbsD(b.y + b.h - a.y) <= CONTACT_TOLERANCE Then
|
| 452 |
+
ov = OverlapLength(a.x, a.x + a.w, b.x, b.x + b.w)
|
| 453 |
+
minSpan = MinD(a.w, b.w)
|
| 454 |
+
If minSpan > EPS And ov >= minSpan * 0.9 Then
|
| 455 |
+
StrongGuillotineEdgeBetween = ov
|
| 456 |
+
Exit Function
|
| 457 |
+
End If
|
| 458 |
+
End If
|
| 459 |
+
|
| 460 |
+
StrongGuillotineEdgeBetween = 0#
|
| 461 |
+
End Function
|
| 462 |
+
|
| 463 |
+
Private Function PlacementContactBonus(ByRef placed() As TPlaced, ByVal placedCount As Long, ByVal x As Double, ByVal y As Double, ByVal w As Double, ByVal h As Double) As Double
|
| 464 |
+
Dim candidate As TPlaced
|
| 465 |
+
Dim i As Long
|
| 466 |
+
Dim edge As Double
|
| 467 |
+
Dim total As Double
|
| 468 |
+
|
| 469 |
+
If placedCount <= 0 Then Exit Function
|
| 470 |
+
|
| 471 |
+
candidate.x = x
|
| 472 |
+
candidate.y = y
|
| 473 |
+
candidate.w = w
|
| 474 |
+
candidate.h = h
|
| 475 |
+
|
| 476 |
+
For i = 1 To placedCount
|
| 477 |
+
edge = SharedEdgeLengthBetween(candidate, placed(i))
|
| 478 |
+
total = total + edge
|
| 479 |
+
Next i
|
| 480 |
+
|
| 481 |
+
PlacementContactBonus = total
|
| 482 |
+
End Function
|
| 483 |
+
|
| 484 |
+
Private Function PlacementGuillotineBonus(ByRef placed() As TPlaced, ByVal placedCount As Long, ByVal x As Double, ByVal y As Double, ByVal w As Double, ByVal h As Double) As Double
|
| 485 |
+
Dim candidate As TPlaced
|
| 486 |
+
Dim i As Long
|
| 487 |
+
Dim edge As Double
|
| 488 |
+
Dim total As Double
|
| 489 |
+
|
| 490 |
+
If placedCount <= 0 Then Exit Function
|
| 491 |
+
|
| 492 |
+
candidate.x = x
|
| 493 |
+
candidate.y = y
|
| 494 |
+
candidate.w = w
|
| 495 |
+
candidate.h = h
|
| 496 |
+
|
| 497 |
+
For i = 1 To placedCount
|
| 498 |
+
edge = StrongGuillotineEdgeBetween(candidate, placed(i))
|
| 499 |
+
total = total + edge
|
| 500 |
+
Next i
|
| 501 |
+
|
| 502 |
+
PlacementGuillotineBonus = total
|
| 503 |
+
End Function
|
| 504 |
+
|
| 505 |
+
Private Function PlacementScoreWithContact(ByRef fr As TFreeRect, ByVal rw As Double, ByVal rh As Double, ByVal fitMode As Long, ByRef placed() As TPlaced, ByVal placedCount As Long, ByRef outContact As Double, ByRef outGuillotine As Double) As Double
|
| 506 |
+
Dim baseScore As Double
|
| 507 |
+
|
| 508 |
+
baseScore = PlacementScore(fr, rw, rh, fitMode)
|
| 509 |
+
outContact = PlacementContactBonus(placed, placedCount, fr.x, fr.y, rw, rh)
|
| 510 |
+
outGuillotine = PlacementGuillotineBonus(placed, placedCount, fr.x, fr.y, rw, rh)
|
| 511 |
+
|
| 512 |
+
PlacementScoreWithContact = baseScore - outContact * CONTACT_PLACEMENT_WEIGHT - outGuillotine * GUILLOTINE_PLACEMENT_WEIGHT
|
| 513 |
+
End Function
|
| 514 |
+
|
| 515 |
+
Private Function PlacementScore(ByRef fr As TFreeRect, ByVal rw As Double, ByVal rh As Double, ByVal fitMode As Long) As Double
|
| 516 |
+
Dim leftoverW As Double
|
| 517 |
+
Dim leftoverH As Double
|
| 518 |
+
Dim shortSide As Double
|
| 519 |
+
Dim longSide As Double
|
| 520 |
+
Dim areaWaste As Double
|
| 521 |
+
|
| 522 |
+
leftoverW = fr.w - rw
|
| 523 |
+
leftoverH = fr.h - rh
|
| 524 |
+
shortSide = MinD(leftoverW, leftoverH)
|
| 525 |
+
longSide = MaxD(leftoverW, leftoverH)
|
| 526 |
+
areaWaste = fr.w * fr.h - rw * rh
|
| 527 |
+
|
| 528 |
+
Select Case fitMode
|
| 529 |
+
Case 1
|
| 530 |
+
PlacementScore = shortSide
|
| 531 |
+
Case 2
|
| 532 |
+
PlacementScore = areaWaste
|
| 533 |
+
Case 3
|
| 534 |
+
PlacementScore = longSide
|
| 535 |
+
Case Else
|
| 536 |
+
PlacementScore = shortSide
|
| 537 |
+
End Select
|
| 538 |
+
End Function
|
| 539 |
+
|
| 540 |
+
Private Function AlignmentPenalty(ByRef placed() As TPlaced, ByVal placedCount As Long, ByVal x As Double, ByVal y As Double) As Double
|
| 541 |
+
Dim i As Long
|
| 542 |
+
Dim leftDist As Double
|
| 543 |
+
Dim topDist As Double
|
| 544 |
+
Dim bestLeft As Double
|
| 545 |
+
Dim bestTop As Double
|
| 546 |
+
|
| 547 |
+
If placedCount <= 0 Then
|
| 548 |
+
AlignmentPenalty = 0#
|
| 549 |
+
Exit Function
|
| 550 |
+
End If
|
| 551 |
+
|
| 552 |
+
bestLeft = 1E+30
|
| 553 |
+
bestTop = 1E+30
|
| 554 |
+
|
| 555 |
+
For i = 1 To placedCount
|
| 556 |
+
leftDist = AbsD(x - placed(i).x)
|
| 557 |
+
topDist = AbsD(y - placed(i).y)
|
| 558 |
+
|
| 559 |
+
If leftDist < bestLeft Then bestLeft = leftDist
|
| 560 |
+
If topDist < bestTop Then bestTop = topDist
|
| 561 |
+
Next i
|
| 562 |
+
|
| 563 |
+
If bestLeft <= ALIGN_TOLERANCE Then bestLeft = 0#
|
| 564 |
+
If bestTop <= ALIGN_TOLERANCE Then bestTop = 0#
|
| 565 |
+
|
| 566 |
+
AlignmentPenalty = bestLeft + bestTop
|
| 567 |
+
End Function
|
| 568 |
+
|
| 569 |
+
Private Function IsBetterPlacement(ByVal score As Double, ByVal alignScore As Double, ByVal tieY As Double, ByVal tieX As Double, ByVal bestScore As Double, ByVal bestAlign As Double, ByVal bestY As Double, ByVal bestX As Double) As Boolean
|
| 570 |
+
If score < bestScore - EPS Then
|
| 571 |
+
IsBetterPlacement = True
|
| 572 |
+
Exit Function
|
| 573 |
+
End If
|
| 574 |
+
|
| 575 |
+
If AbsD(score - bestScore) <= EPS Then
|
| 576 |
+
If alignScore < bestAlign - EPS Then
|
| 577 |
+
IsBetterPlacement = True
|
| 578 |
+
Exit Function
|
| 579 |
+
End If
|
| 580 |
+
|
| 581 |
+
If AbsD(alignScore - bestAlign) <= EPS Then
|
| 582 |
+
If tieY < bestY - EPS Then
|
| 583 |
+
IsBetterPlacement = True
|
| 584 |
+
Exit Function
|
| 585 |
+
End If
|
| 586 |
+
|
| 587 |
+
If AbsD(tieY - bestY) <= EPS Then
|
| 588 |
+
If tieX < bestX - EPS Then
|
| 589 |
+
IsBetterPlacement = True
|
| 590 |
+
Exit Function
|
| 591 |
+
End If
|
| 592 |
+
End If
|
| 593 |
+
End If
|
| 594 |
+
End If
|
| 595 |
+
|
| 596 |
+
IsBetterPlacement = False
|
| 597 |
+
End Function
|
| 598 |
+
|
| 599 |
+
Private Function FindBestPlacement(ByRef freeRects() As TFreeRect, ByVal freeCount As Long, ByVal reqW As Double, ByVal reqH As Double, ByVal allowRotation As Boolean, ByVal rotationMode As Long, ByVal fitMode As Long, ByRef placed() As TPlaced, ByVal placedCount As Long, ByRef bestX As Double, ByRef bestY As Double, ByRef bestW As Double, ByRef bestH As Double, ByRef bestRot As Boolean) As Boolean
|
| 600 |
+
Dim i As Long
|
| 601 |
+
Dim rw As Double
|
| 602 |
+
Dim rh As Double
|
| 603 |
+
Dim score As Double
|
| 604 |
+
Dim alignScore As Double
|
| 605 |
+
Dim bestScore As Double
|
| 606 |
+
Dim bestAlign As Double
|
| 607 |
+
Dim tieY As Double
|
| 608 |
+
Dim tieX As Double
|
| 609 |
+
Dim bestTieY As Double
|
| 610 |
+
Dim bestTieX As Double
|
| 611 |
+
Dim contactBonus As Double
|
| 612 |
+
Dim guillotineBonus As Double
|
| 613 |
+
Dim found As Boolean
|
| 614 |
+
Dim tryNormal As Boolean
|
| 615 |
+
Dim tryRotated As Boolean
|
| 616 |
+
|
| 617 |
+
bestScore = 1E+30
|
| 618 |
+
bestAlign = 1E+30
|
| 619 |
+
bestTieY = 1E+30
|
| 620 |
+
bestTieX = 1E+30
|
| 621 |
+
found = False
|
| 622 |
+
|
| 623 |
+
tryNormal = True
|
| 624 |
+
tryRotated = allowRotation
|
| 625 |
+
|
| 626 |
+
If allowRotation Then
|
| 627 |
+
If rotationMode = 1 Then
|
| 628 |
+
tryRotated = False
|
| 629 |
+
ElseIf rotationMode = 2 Then
|
| 630 |
+
tryNormal = False
|
| 631 |
+
End If
|
| 632 |
+
Else
|
| 633 |
+
tryRotated = False
|
| 634 |
+
End If
|
| 635 |
+
|
| 636 |
+
For i = 1 To freeCount
|
| 637 |
+
If tryNormal Then
|
| 638 |
+
rw = reqW
|
| 639 |
+
rh = reqH
|
| 640 |
+
|
| 641 |
+
If rw <= freeRects(i).w + EPS And rh <= freeRects(i).h + EPS Then
|
| 642 |
+
score = PlacementScoreWithContact(freeRects(i), rw, rh, fitMode, placed, placedCount, contactBonus, guillotineBonus)
|
| 643 |
+
alignScore = AlignmentPenalty(placed, placedCount, freeRects(i).x, freeRects(i).y)
|
| 644 |
+
tieY = freeRects(i).y
|
| 645 |
+
tieX = freeRects(i).x
|
| 646 |
+
|
| 647 |
+
If IsBetterPlacement(score, alignScore, tieY, tieX, bestScore, bestAlign, bestTieY, bestTieX) Then
|
| 648 |
+
bestScore = score
|
| 649 |
+
bestAlign = alignScore
|
| 650 |
+
bestTieY = tieY
|
| 651 |
+
bestTieX = tieX
|
| 652 |
+
bestX = freeRects(i).x
|
| 653 |
+
bestY = freeRects(i).y
|
| 654 |
+
bestW = rw
|
| 655 |
+
bestH = rh
|
| 656 |
+
bestRot = False
|
| 657 |
+
found = True
|
| 658 |
+
End If
|
| 659 |
+
End If
|
| 660 |
+
End If
|
| 661 |
+
|
| 662 |
+
If tryRotated Then
|
| 663 |
+
rw = reqH
|
| 664 |
+
rh = reqW
|
| 665 |
+
|
| 666 |
+
If rw <= freeRects(i).w + EPS And rh <= freeRects(i).h + EPS Then
|
| 667 |
+
score = PlacementScoreWithContact(freeRects(i), rw, rh, fitMode, placed, placedCount, contactBonus, guillotineBonus)
|
| 668 |
+
alignScore = AlignmentPenalty(placed, placedCount, freeRects(i).x, freeRects(i).y)
|
| 669 |
+
tieY = freeRects(i).y
|
| 670 |
+
tieX = freeRects(i).x
|
| 671 |
+
|
| 672 |
+
If IsBetterPlacement(score, alignScore, tieY, tieX, bestScore, bestAlign, bestTieY, bestTieX) Then
|
| 673 |
+
bestScore = score
|
| 674 |
+
bestAlign = alignScore
|
| 675 |
+
bestTieY = tieY
|
| 676 |
+
bestTieX = tieX
|
| 677 |
+
bestX = freeRects(i).x
|
| 678 |
+
bestY = freeRects(i).y
|
| 679 |
+
bestW = rw
|
| 680 |
+
bestH = rh
|
| 681 |
+
bestRot = True
|
| 682 |
+
found = True
|
| 683 |
+
End If
|
| 684 |
+
End If
|
| 685 |
+
End If
|
| 686 |
+
Next i
|
| 687 |
+
|
| 688 |
+
FindBestPlacement = found
|
| 689 |
+
End Function
|
| 690 |
+
|
| 691 |
+
Private Sub PackOneBinOrdered(ByRef items() As TBanner, ByRef order() As Long, ByVal orderCount As Long, ByVal rollWidth As Double, ByVal maxHeight As Double, ByVal allowRotation As Boolean, ByVal fitMode As Long, ByRef rotationPrefs() As Long, ByRef placed() As TPlaced, ByRef placedCount As Long, ByRef outIdx() As Long, ByRef outCount As Long)
|
| 692 |
+
Dim freeRects() As TFreeRect
|
| 693 |
+
Dim freeCount As Long
|
| 694 |
+
Dim k As Long
|
| 695 |
+
Dim rid As Long
|
| 696 |
+
Dim reqW As Double
|
| 697 |
+
Dim reqH As Double
|
| 698 |
+
Dim bestX As Double
|
| 699 |
+
Dim bestY As Double
|
| 700 |
+
Dim bestW As Double
|
| 701 |
+
Dim bestH As Double
|
| 702 |
+
Dim bestRot As Boolean
|
| 703 |
+
|
| 704 |
+
If orderCount <= 0 Then
|
| 705 |
+
ReDim placed(1 To 1)
|
| 706 |
+
ReDim outIdx(1 To 1)
|
| 707 |
+
placedCount = 0
|
| 708 |
+
outCount = 0
|
| 709 |
+
Exit Sub
|
| 710 |
+
End If
|
| 711 |
+
|
| 712 |
+
ReDim placed(1 To orderCount)
|
| 713 |
+
ReDim outIdx(1 To orderCount)
|
| 714 |
+
placedCount = 0
|
| 715 |
+
outCount = 0
|
| 716 |
+
|
| 717 |
+
ReDim freeRects(1 To 1)
|
| 718 |
+
freeCount = 1
|
| 719 |
+
freeRects(1).x = 0#
|
| 720 |
+
freeRects(1).y = 0#
|
| 721 |
+
freeRects(1).w = rollWidth
|
| 722 |
+
freeRects(1).h = maxHeight
|
| 723 |
+
|
| 724 |
+
For k = 1 To orderCount
|
| 725 |
+
rid = order(k)
|
| 726 |
+
reqW = items(rid).OrigW + 2# * items(rid).margin
|
| 727 |
+
reqH = items(rid).OrigH + 2# * items(rid).margin
|
| 728 |
+
|
| 729 |
+
If FindBestPlacement(freeRects, freeCount, reqW, reqH, allowRotation, rotationPrefs(rid), fitMode, placed, placedCount, bestX, bestY, bestW, bestH, bestRot) Then
|
| 730 |
+
placedCount = placedCount + 1
|
| 731 |
+
placed(placedCount).rid = rid
|
| 732 |
+
placed(placedCount).x = bestX
|
| 733 |
+
placed(placedCount).y = bestY
|
| 734 |
+
placed(placedCount).w = bestW
|
| 735 |
+
placed(placedCount).h = bestH
|
| 736 |
+
placed(placedCount).Rotated = bestRot
|
| 737 |
+
|
| 738 |
+
PlaceAndSplit freeRects, freeCount, bestX, bestY, bestW, bestH
|
| 739 |
+
Else
|
| 740 |
+
outCount = outCount + 1
|
| 741 |
+
outIdx(outCount) = rid
|
| 742 |
+
End If
|
| 743 |
+
Next k
|
| 744 |
+
End Sub
|
| 745 |
+
|
| 746 |
+
Private Sub PackMultiRollWithOrder(ByRef items() As TBanner, ByVal orderCount As Long, ByVal rollWidth As Double, ByVal maxHeight As Double, ByVal allowRotation As Boolean, ByVal fitMode As Long, ByRef order() As Long, ByRef rotationPrefs() As Long, ByRef rolls() As TRoll, ByRef rollCount As Long, ByRef notPlaced As Long)
|
| 747 |
+
Dim remaining() As Long
|
| 748 |
+
Dim nextRemaining() As Long
|
| 749 |
+
Dim placed() As TPlaced
|
| 750 |
+
Dim outIdx() As Long
|
| 751 |
+
Dim remainingCount As Long
|
| 752 |
+
Dim outCount As Long
|
| 753 |
+
Dim placedCount As Long
|
| 754 |
+
Dim i As Long
|
| 755 |
+
Dim safety As Long
|
| 756 |
+
|
| 757 |
+
rollCount = 0
|
| 758 |
+
notPlaced = 0
|
| 759 |
+
|
| 760 |
+
If orderCount <= 0 Then Exit Sub
|
| 761 |
+
|
| 762 |
+
ReDim rolls(1 To MAX_ROLLS)
|
| 763 |
+
ReDim remaining(1 To orderCount)
|
| 764 |
+
|
| 765 |
+
For i = 1 To orderCount
|
| 766 |
+
remaining(i) = order(i)
|
| 767 |
+
Next i
|
| 768 |
+
remainingCount = orderCount
|
| 769 |
+
|
| 770 |
+
Do While remainingCount > 0
|
| 771 |
+
safety = safety + 1
|
| 772 |
+
If safety > MAX_ROLLS Then
|
| 773 |
+
notPlaced = remainingCount
|
| 774 |
+
Exit Do
|
| 775 |
+
End If
|
| 776 |
+
|
| 777 |
+
PackOneBinOrdered items, remaining, remainingCount, rollWidth, maxHeight, allowRotation, fitMode, rotationPrefs, placed, placedCount, outIdx, outCount
|
| 778 |
+
|
| 779 |
+
If placedCount <= 0 Then
|
| 780 |
+
notPlaced = remainingCount
|
| 781 |
+
Exit Do
|
| 782 |
+
End If
|
| 783 |
+
|
| 784 |
+
rollCount = rollCount + 1
|
| 785 |
+
rolls(rollCount).placedCount = placedCount
|
| 786 |
+
ReDim rolls(rollCount).placed(1 To placedCount)
|
| 787 |
+
|
| 788 |
+
For i = 1 To placedCount
|
| 789 |
+
rolls(rollCount).placed(i) = placed(i)
|
| 790 |
+
Next i
|
| 791 |
+
|
| 792 |
+
rolls(rollCount).UsedHeight = CalcPlacedHeight(placed, placedCount)
|
| 793 |
+
|
| 794 |
+
If outCount <= 0 Then
|
| 795 |
+
remainingCount = 0
|
| 796 |
+
Exit Do
|
| 797 |
+
End If
|
| 798 |
+
|
| 799 |
+
ReDim nextRemaining(1 To outCount)
|
| 800 |
+
For i = 1 To outCount
|
| 801 |
+
nextRemaining(i) = outIdx(i)
|
| 802 |
+
Next i
|
| 803 |
+
|
| 804 |
+
ReDim remaining(1 To outCount)
|
| 805 |
+
For i = 1 To outCount
|
| 806 |
+
remaining(i) = nextRemaining(i)
|
| 807 |
+
Next i
|
| 808 |
+
remainingCount = outCount
|
| 809 |
+
Loop
|
| 810 |
+
End Sub
|
| 811 |
+
|
| 812 |
+
Private Function CalcPlacedHeight(ByRef placed() As TPlaced, ByVal placedCount As Long) As Double
|
| 813 |
+
Dim i As Long
|
| 814 |
+
Dim h As Double
|
| 815 |
+
|
| 816 |
+
h = 0#
|
| 817 |
+
For i = 1 To placedCount
|
| 818 |
+
h = MaxD(h, placed(i).y + placed(i).h)
|
| 819 |
+
Next i
|
| 820 |
+
|
| 821 |
+
CalcPlacedHeight = h
|
| 822 |
+
End Function
|
| 823 |
+
|
| 824 |
+
Private Function CalcMaterialUsed(ByRef rolls() As TRoll, ByVal rollCount As Long, ByVal rollWidth As Double) As Double
|
| 825 |
+
Dim r As Long
|
| 826 |
+
Dim total As Double
|
| 827 |
+
|
| 828 |
+
total = 0#
|
| 829 |
+
For r = 1 To rollCount
|
| 830 |
+
total = total + rollWidth * rolls(r).UsedHeight
|
| 831 |
+
Next r
|
| 832 |
+
|
| 833 |
+
CalcMaterialUsed = total
|
| 834 |
+
End Function
|
| 835 |
+
|
| 836 |
+
Private Function CalcTrueArea(ByRef items() As TBanner, ByRef rolls() As TRoll, ByVal rollCount As Long) As Double
|
| 837 |
+
Dim r As Long
|
| 838 |
+
Dim i As Long
|
| 839 |
+
Dim rid As Long
|
| 840 |
+
Dim total As Double
|
| 841 |
+
|
| 842 |
+
total = 0#
|
| 843 |
+
For r = 1 To rollCount
|
| 844 |
+
For i = 1 To rolls(r).placedCount
|
| 845 |
+
rid = rolls(r).placed(i).rid
|
| 846 |
+
total = total + items(rid).OrigW * items(rid).OrigH
|
| 847 |
+
Next i
|
| 848 |
+
Next r
|
| 849 |
+
|
| 850 |
+
CalcTrueArea = total
|
| 851 |
+
End Function
|
| 852 |
+
|
| 853 |
+
Private Function CalcWaste(ByRef items() As TBanner, ByRef rolls() As TRoll, ByVal rollCount As Long, ByVal rollWidth As Double) As Double
|
| 854 |
+
Dim material As Double
|
| 855 |
+
Dim trueArea As Double
|
| 856 |
+
|
| 857 |
+
material = CalcMaterialUsed(rolls, rollCount, rollWidth)
|
| 858 |
+
trueArea = CalcTrueArea(items, rolls, rollCount)
|
| 859 |
+
|
| 860 |
+
If material <= EPS Then
|
| 861 |
+
CalcWaste = 1#
|
| 862 |
+
Else
|
| 863 |
+
CalcWaste = (material - trueArea) / material
|
| 864 |
+
End If
|
| 865 |
+
End Function
|
| 866 |
+
|
| 867 |
+
Private Function CalcRightWaste(ByRef rolls() As TRoll, ByVal rollCount As Long, ByVal rollWidth As Double) As Double
|
| 868 |
+
Dim r As Long
|
| 869 |
+
Dim i As Long
|
| 870 |
+
Dim rightEdge As Double
|
| 871 |
+
Dim maxRightEdge As Double
|
| 872 |
+
Dim waste As Double
|
| 873 |
+
Dim worstWaste As Double
|
| 874 |
+
|
| 875 |
+
worstWaste = 0#
|
| 876 |
+
For r = 1 To rollCount
|
| 877 |
+
maxRightEdge = 0#
|
| 878 |
+
For i = 1 To rolls(r).placedCount
|
| 879 |
+
rightEdge = rolls(r).placed(i).x + rolls(r).placed(i).w
|
| 880 |
+
maxRightEdge = MaxD(maxRightEdge, rightEdge)
|
| 881 |
+
Next i
|
| 882 |
+
|
| 883 |
+
waste = rollWidth - maxRightEdge
|
| 884 |
+
If waste < 0# Then waste = 0#
|
| 885 |
+
worstWaste = MaxD(worstWaste, waste)
|
| 886 |
+
Next r
|
| 887 |
+
|
| 888 |
+
CalcRightWaste = worstWaste
|
| 889 |
+
End Function
|
| 890 |
+
|
| 891 |
+
Private Function CalcAlignmentScore(ByRef rolls() As TRoll, ByVal rollCount As Long) As Double
|
| 892 |
+
Dim r As Long
|
| 893 |
+
Dim i As Long
|
| 894 |
+
Dim j As Long
|
| 895 |
+
Dim score As Double
|
| 896 |
+
Dim leftDist As Double
|
| 897 |
+
Dim topDist As Double
|
| 898 |
+
Dim candidateVisualTop As Double
|
| 899 |
+
Dim otherVisualTop As Double
|
| 900 |
+
Dim bestLeft As Double
|
| 901 |
+
Dim bestTop As Double
|
| 902 |
+
|
| 903 |
+
For r = 1 To rollCount
|
| 904 |
+
For i = 1 To rolls(r).placedCount
|
| 905 |
+
bestLeft = 1E+30
|
| 906 |
+
bestTop = 1E+30
|
| 907 |
+
candidateVisualTop = rolls(r).placed(i).y
|
| 908 |
+
|
| 909 |
+
For j = 1 To rolls(r).placedCount
|
| 910 |
+
If i <> j Then
|
| 911 |
+
leftDist = AbsD(rolls(r).placed(i).x - rolls(r).placed(j).x)
|
| 912 |
+
otherVisualTop = rolls(r).placed(j).y
|
| 913 |
+
topDist = AbsD(candidateVisualTop - otherVisualTop)
|
| 914 |
+
bestLeft = MinD(bestLeft, leftDist)
|
| 915 |
+
bestTop = MinD(bestTop, topDist)
|
| 916 |
+
End If
|
| 917 |
+
Next j
|
| 918 |
+
|
| 919 |
+
If bestLeft <= ALIGN_TOLERANCE Then bestLeft = 0#
|
| 920 |
+
If bestTop <= ALIGN_TOLERANCE Then bestTop = 0#
|
| 921 |
+
|
| 922 |
+
If bestLeft < 1E+20 Then score = score + bestLeft
|
| 923 |
+
If bestTop < 1E+20 Then score = score + bestTop
|
| 924 |
+
Next i
|
| 925 |
+
Next r
|
| 926 |
+
|
| 927 |
+
CalcAlignmentScore = score
|
| 928 |
+
End Function
|
| 929 |
+
|
| 930 |
+
Private Function CalcSharedEdgeLength(ByRef rolls() As TRoll, ByVal rollCount As Long) As Double
|
| 931 |
+
Dim r As Long
|
| 932 |
+
Dim i As Long
|
| 933 |
+
Dim j As Long
|
| 934 |
+
Dim total As Double
|
| 935 |
+
|
| 936 |
+
total = 0#
|
| 937 |
+
For r = 1 To rollCount
|
| 938 |
+
For i = 1 To rolls(r).placedCount - 1
|
| 939 |
+
For j = i + 1 To rolls(r).placedCount
|
| 940 |
+
total = total + SharedEdgeLengthBetween(rolls(r).placed(i), rolls(r).placed(j))
|
| 941 |
+
Next j
|
| 942 |
+
Next i
|
| 943 |
+
Next r
|
| 944 |
+
|
| 945 |
+
CalcSharedEdgeLength = total
|
| 946 |
+
End Function
|
| 947 |
+
|
| 948 |
+
Private Function CalcContactSegments(ByRef rolls() As TRoll, ByVal rollCount As Long) As Long
|
| 949 |
+
Dim r As Long
|
| 950 |
+
Dim i As Long
|
| 951 |
+
Dim j As Long
|
| 952 |
+
Dim edge As Double
|
| 953 |
+
Dim count As Long
|
| 954 |
+
|
| 955 |
+
count = 0
|
| 956 |
+
For r = 1 To rollCount
|
| 957 |
+
For i = 1 To rolls(r).placedCount - 1
|
| 958 |
+
For j = i + 1 To rolls(r).placedCount
|
| 959 |
+
edge = SharedEdgeLengthBetween(rolls(r).placed(i), rolls(r).placed(j))
|
| 960 |
+
If edge > CONTACT_TOLERANCE Then count = count + 1
|
| 961 |
+
Next j
|
| 962 |
+
Next i
|
| 963 |
+
Next r
|
| 964 |
+
|
| 965 |
+
CalcContactSegments = count
|
| 966 |
+
End Function
|
| 967 |
+
|
| 968 |
+
Private Function CalcGuillotineEdgeLength(ByRef rolls() As TRoll, ByVal rollCount As Long) As Double
|
| 969 |
+
Dim r As Long
|
| 970 |
+
Dim i As Long
|
| 971 |
+
Dim j As Long
|
| 972 |
+
Dim edge As Double
|
| 973 |
+
Dim total As Double
|
| 974 |
+
|
| 975 |
+
total = 0#
|
| 976 |
+
For r = 1 To rollCount
|
| 977 |
+
For i = 1 To rolls(r).placedCount - 1
|
| 978 |
+
For j = i + 1 To rolls(r).placedCount
|
| 979 |
+
edge = StrongGuillotineEdgeBetween(rolls(r).placed(i), rolls(r).placed(j))
|
| 980 |
+
total = total + edge
|
| 981 |
+
Next j
|
| 982 |
+
Next i
|
| 983 |
+
Next r
|
| 984 |
+
|
| 985 |
+
CalcGuillotineEdgeLength = total
|
| 986 |
+
End Function
|
| 987 |
+
|
| 988 |
+
Private Function CalcCutFriendlyPenalty(ByRef rolls() As TRoll, ByVal rollCount As Long, ByVal rollWidth As Double) As Double
|
| 989 |
+
Dim sharedEdge As Double
|
| 990 |
+
Dim strongEdge As Double
|
| 991 |
+
Dim segments As Long
|
| 992 |
+
Dim penalty As Double
|
| 993 |
+
Dim r As Long
|
| 994 |
+
Dim i As Long
|
| 995 |
+
Dim boundaryContact As Double
|
| 996 |
+
|
| 997 |
+
sharedEdge = CalcSharedEdgeLength(rolls, rollCount)
|
| 998 |
+
strongEdge = CalcGuillotineEdgeLength(rolls, rollCount)
|
| 999 |
+
segments = CalcContactSegments(rolls, rollCount)
|
| 1000 |
+
|
| 1001 |
+
boundaryContact = 0#
|
| 1002 |
+
For r = 1 To rollCount
|
| 1003 |
+
For i = 1 To rolls(r).placedCount
|
| 1004 |
+
If AbsD(rolls(r).placed(i).x) <= CONTACT_TOLERANCE Then boundaryContact = boundaryContact + rolls(r).placed(i).h
|
| 1005 |
+
If AbsD(rolls(r).placed(i).x + rolls(r).placed(i).w - rollWidth) <= CONTACT_TOLERANCE Then boundaryContact = boundaryContact + rolls(r).placed(i).h
|
| 1006 |
+
If AbsD(rolls(r).placed(i).y) <= CONTACT_TOLERANCE Then boundaryContact = boundaryContact + rolls(r).placed(i).w
|
| 1007 |
+
If AbsD(rolls(r).placed(i).y + rolls(r).placed(i).h - rolls(r).UsedHeight) <= CONTACT_TOLERANCE Then boundaryContact = boundaryContact + rolls(r).placed(i).w
|
| 1008 |
+
Next i
|
| 1009 |
+
Next r
|
| 1010 |
+
|
| 1011 |
+
penalty = CDbl(segments) * 2#
|
| 1012 |
+
penalty = penalty - sharedEdge * 0.08
|
| 1013 |
+
penalty = penalty - strongEdge * 0.18
|
| 1014 |
+
penalty = penalty - boundaryContact * 0.03
|
| 1015 |
+
|
| 1016 |
+
If penalty < 0# Then penalty = 0#
|
| 1017 |
+
CalcCutFriendlyPenalty = penalty
|
| 1018 |
+
End Function
|
| 1019 |
+
|
| 1020 |
+
Private Function CalcContactScore(ByRef rolls() As TRoll, ByVal rollCount As Long) As Double
|
| 1021 |
+
Dim sharedEdge As Double
|
| 1022 |
+
Dim segments As Long
|
| 1023 |
+
Dim score As Double
|
| 1024 |
+
|
| 1025 |
+
sharedEdge = CalcSharedEdgeLength(rolls, rollCount)
|
| 1026 |
+
segments = CalcContactSegments(rolls, rollCount)
|
| 1027 |
+
score = sharedEdge
|
| 1028 |
+
score = score - CDbl(segments) * 0.5
|
| 1029 |
+
|
| 1030 |
+
If score < 0# Then score = 0#
|
| 1031 |
+
CalcContactScore = score
|
| 1032 |
+
End Function
|
| 1033 |
+
|
| 1034 |
+
Private Function PackScore(ByRef items() As TBanner, ByRef rolls() As TRoll, ByVal rollCount As Long, ByVal notPlaced As Long, ByVal rollWidth As Double, ByRef rightWaste As Double, ByRef alignmentScore As Double, ByRef materialUsed As Double) As Double
|
| 1035 |
+
Dim excessRight As Double
|
| 1036 |
+
Dim contactScore As Double
|
| 1037 |
+
Dim cutPenalty As Double
|
| 1038 |
+
|
| 1039 |
+
rightWaste = CalcRightWaste(rolls, rollCount, rollWidth)
|
| 1040 |
+
alignmentScore = CalcAlignmentScore(rolls, rollCount)
|
| 1041 |
+
|
| 1042 |
+
' IMPORTANT: materialUsed is already the real material area consumed:
|
| 1043 |
+
' sum over rolls of (rollWidth x roll UsedHeight).
|
| 1044 |
+
' Therefore roll HEIGHT is already considered together with WIDTH.
|
| 1045 |
+
materialUsed = CalcMaterialUsed(rolls, rollCount, rollWidth)
|
| 1046 |
+
|
| 1047 |
+
If notPlaced > 0 Then
|
| 1048 |
+
PackScore = 1E+30 + CDbl(notPlaced) * 1E+25
|
| 1049 |
+
Exit Function
|
| 1050 |
+
End If
|
| 1051 |
+
|
| 1052 |
+
excessRight = rightWaste - MAX_RIGHT_WASTE
|
| 1053 |
+
If excessRight < 0# Then excessRight = 0#
|
| 1054 |
+
|
| 1055 |
+
contactScore = CalcContactScore(rolls, rollCount)
|
| 1056 |
+
cutPenalty = CalcCutFriendlyPenalty(rolls, rollCount, rollWidth)
|
| 1057 |
+
|
| 1058 |
+
' OBJECTIVE PRIORITY:
|
| 1059 |
+
' 1) Feasible layout (handled above)
|
| 1060 |
+
' 2) Minimum material area = width x used height
|
| 1061 |
+
' 3) Minimum right waste above the 10 cm target
|
| 1062 |
+
' 4) Alignment / contact / cut friendliness / roll count as tie-breakers
|
| 1063 |
+
'
|
| 1064 |
+
' The material scale is deliberately dominant. A meaningful reduction
|
| 1065 |
+
' in material area must beat improvements in the secondary metrics.
|
| 1066 |
+
PackScore = materialUsed * MATERIAL_SCORE_SCALE _
|
| 1067 |
+
+ excessRight * RIGHT_WASTE_SCORE_SCALE _
|
| 1068 |
+
+ alignmentScore * ALIGNMENT_SCORE_SCALE _
|
| 1069 |
+
- contactScore * CONTACT_SCORE_WEIGHT _
|
| 1070 |
+
+ cutPenalty * GUILLOTINE_SCORE_WEIGHT _
|
| 1071 |
+
+ CDbl(rollCount) * ROLL_COUNT_SCORE_SCALE
|
| 1072 |
+
End Function
|
| 1073 |
+
|
| 1074 |
+
Private Function EvaluateOrderScoreWithRotation(ByRef items() As TBanner, ByVal orderCount As Long, ByVal rollWidth As Double, ByVal maxHeight As Double, ByVal allowRotation As Boolean, ByVal fitMode As Long, ByRef order() As Long, ByRef rotationPrefs() As Long, ByRef outRollCount As Long, ByRef outNotPlaced As Long, ByRef outRightWaste As Double, ByRef outAlignment As Double, ByRef outMaterial As Double) As Double
|
| 1075 |
+
Dim testRolls() As TRoll
|
| 1076 |
+
|
| 1077 |
+
PackMultiRollWithOrder items, orderCount, rollWidth, maxHeight, allowRotation, fitMode, order, rotationPrefs, testRolls, outRollCount, outNotPlaced
|
| 1078 |
+
EvaluateOrderScoreWithRotation = PackScore(items, testRolls, outRollCount, outNotPlaced, rollWidth, outRightWaste, outAlignment, outMaterial)
|
| 1079 |
+
End Function
|
| 1080 |
+
|
| 1081 |
+
Private Sub AddSeed(ByRef seedOrders() As Long, ByRef seedScores() As Double, ByRef seedWidths() As Double, ByRef seedFits() As Long, ByRef seedSorts() As Long, ByRef seedCount As Long, ByVal maxSeeds As Long, ByRef candidateOrder() As Long, ByVal n As Long, ByVal candidateScore As Double, ByVal candidateWidth As Double, ByVal candidateFit As Long, ByVal candidateSort As Long)
|
| 1082 |
+
Dim pos As Long
|
| 1083 |
+
Dim i As Long
|
| 1084 |
+
Dim j As Long
|
| 1085 |
+
|
| 1086 |
+
If maxSeeds <= 0 Then Exit Sub
|
| 1087 |
+
|
| 1088 |
+
pos = 0
|
| 1089 |
+
For i = 1 To maxSeeds
|
| 1090 |
+
If i > seedCount Then
|
| 1091 |
+
pos = i
|
| 1092 |
+
Exit For
|
| 1093 |
+
End If
|
| 1094 |
+
|
| 1095 |
+
If candidateScore < seedScores(i) Then
|
| 1096 |
+
pos = i
|
| 1097 |
+
Exit For
|
| 1098 |
+
End If
|
| 1099 |
+
Next i
|
| 1100 |
+
|
| 1101 |
+
If pos = 0 Then Exit Sub
|
| 1102 |
+
|
| 1103 |
+
If seedCount < maxSeeds Then seedCount = seedCount + 1
|
| 1104 |
+
|
| 1105 |
+
For i = seedCount To pos + 1 Step -1
|
| 1106 |
+
seedScores(i) = seedScores(i - 1)
|
| 1107 |
+
seedWidths(i) = seedWidths(i - 1)
|
| 1108 |
+
seedFits(i) = seedFits(i - 1)
|
| 1109 |
+
seedSorts(i) = seedSorts(i - 1)
|
| 1110 |
+
|
| 1111 |
+
For j = 1 To n
|
| 1112 |
+
seedOrders(i, j) = seedOrders(i - 1, j)
|
| 1113 |
+
Next j
|
| 1114 |
+
Next i
|
| 1115 |
+
|
| 1116 |
+
seedScores(pos) = candidateScore
|
| 1117 |
+
seedWidths(pos) = candidateWidth
|
| 1118 |
+
seedFits(pos) = candidateFit
|
| 1119 |
+
seedSorts(pos) = candidateSort
|
| 1120 |
+
|
| 1121 |
+
For j = 1 To n
|
| 1122 |
+
seedOrders(pos, j) = candidateOrder(j)
|
| 1123 |
+
Next j
|
| 1124 |
+
End Sub
|
| 1125 |
+
|
| 1126 |
+
Private Sub CopyOrderFromSeed(ByRef seedOrders() As Long, ByVal seedNo As Long, ByVal n As Long, ByRef order() As Long)
|
| 1127 |
+
Dim i As Long
|
| 1128 |
+
|
| 1129 |
+
ReDim order(1 To n)
|
| 1130 |
+
For i = 1 To n
|
| 1131 |
+
order(i) = seedOrders(seedNo, i)
|
| 1132 |
+
Next i
|
| 1133 |
+
End Sub
|
| 1134 |
+
|
| 1135 |
+
Private Sub BuildDestroyScores(ByRef items() As TBanner, ByRef rolls() As TRoll, ByVal rollCount As Long, ByVal rollWidth As Double, ByVal n As Long, ByVal mode As Long, ByRef ids() As Long, ByRef scores() As Double)
|
| 1136 |
+
Dim i As Long
|
| 1137 |
+
Dim r As Long
|
| 1138 |
+
Dim j As Long
|
| 1139 |
+
Dim rid As Long
|
| 1140 |
+
Dim bestLeft As Double
|
| 1141 |
+
Dim bestTop As Double
|
| 1142 |
+
Dim leftDist As Double
|
| 1143 |
+
Dim topDist As Double
|
| 1144 |
+
Dim rightWaste As Double
|
| 1145 |
+
Dim alignment As Double
|
| 1146 |
+
Dim xPos As Double
|
| 1147 |
+
Dim area As Double
|
| 1148 |
+
Dim shortSide As Double
|
| 1149 |
+
Dim longSide As Double
|
| 1150 |
+
Dim contactEdge As Double
|
| 1151 |
+
Dim strongEdge As Double
|
| 1152 |
+
|
| 1153 |
+
ReDim ids(1 To n)
|
| 1154 |
+
ReDim scores(1 To n)
|
| 1155 |
+
|
| 1156 |
+
For i = 1 To n
|
| 1157 |
+
ids(i) = i
|
| 1158 |
+
scores(i) = 0#
|
| 1159 |
+
Next i
|
| 1160 |
+
|
| 1161 |
+
For r = 1 To rollCount
|
| 1162 |
+
For i = 1 To rolls(r).placedCount
|
| 1163 |
+
rid = rolls(r).placed(i).rid
|
| 1164 |
+
rightWaste = rollWidth - rolls(r).placed(i).x - rolls(r).placed(i).w
|
| 1165 |
+
If rightWaste < 0# Then rightWaste = 0#
|
| 1166 |
+
|
| 1167 |
+
bestLeft = 1E+30
|
| 1168 |
+
bestTop = 1E+30
|
| 1169 |
+
|
| 1170 |
+
For j = 1 To rolls(r).placedCount
|
| 1171 |
+
If j <> i Then
|
| 1172 |
+
leftDist = AbsD(rolls(r).placed(i).x - rolls(r).placed(j).x)
|
| 1173 |
+
topDist = AbsD(rolls(r).placed(i).y - rolls(r).placed(j).y)
|
| 1174 |
+
bestLeft = MinD(bestLeft, leftDist)
|
| 1175 |
+
bestTop = MinD(bestTop, topDist)
|
| 1176 |
+
End If
|
| 1177 |
+
Next j
|
| 1178 |
+
|
| 1179 |
+
If bestLeft >= 1E+20 Then bestLeft = 0#
|
| 1180 |
+
If bestTop >= 1E+20 Then bestTop = 0#
|
| 1181 |
+
alignment = bestLeft + bestTop
|
| 1182 |
+
xPos = rolls(r).placed(i).x
|
| 1183 |
+
contactEdge = 0#
|
| 1184 |
+
strongEdge = 0#
|
| 1185 |
+
For j = 1 To rolls(r).placedCount
|
| 1186 |
+
If j <> i Then
|
| 1187 |
+
contactEdge = contactEdge + SharedEdgeLengthBetween(rolls(r).placed(i), rolls(r).placed(j))
|
| 1188 |
+
strongEdge = strongEdge + StrongGuillotineEdgeBetween(rolls(r).placed(i), rolls(r).placed(j))
|
| 1189 |
+
End If
|
| 1190 |
+
Next j
|
| 1191 |
+
area = AreaOf(items(rid))
|
| 1192 |
+
shortSide = MinD(items(rid).OrigW + 2# * items(rid).margin, items(rid).OrigH + 2# * items(rid).margin)
|
| 1193 |
+
longSide = MaxD(items(rid).OrigW + 2# * items(rid).margin, items(rid).OrigH + 2# * items(rid).margin)
|
| 1194 |
+
|
| 1195 |
+
Select Case mode
|
| 1196 |
+
Case 1
|
| 1197 |
+
scores(rid) = rightWaste * 10# + alignment
|
| 1198 |
+
Case 2
|
| 1199 |
+
scores(rid) = area
|
| 1200 |
+
Case 3
|
| 1201 |
+
scores(rid) = alignment * 2# + rightWaste
|
| 1202 |
+
Case 4
|
| 1203 |
+
scores(rid) = longSide * 2# + rightWaste
|
| 1204 |
+
Case 5
|
| 1205 |
+
scores(rid) = xPos + rightWaste
|
| 1206 |
+
Case 6
|
| 1207 |
+
scores(rid) = -contactEdge + rightWaste * 0.2 + alignment * 0.1
|
| 1208 |
+
Case 7
|
| 1209 |
+
scores(rid) = -strongEdge + rightWaste * 0.1 + alignment * 0.1
|
| 1210 |
+
Case Else
|
| 1211 |
+
scores(rid) = rightWaste * 10# + alignment
|
| 1212 |
+
End Select
|
| 1213 |
+
Next i
|
| 1214 |
+
Next r
|
| 1215 |
+
|
| 1216 |
+
For i = 1 To n - 1
|
| 1217 |
+
For j = i + 1 To n
|
| 1218 |
+
If scores(ids(j)) > scores(ids(i)) Then
|
| 1219 |
+
SwapLong ids, i, j
|
| 1220 |
+
End If
|
| 1221 |
+
Next j
|
| 1222 |
+
Next i
|
| 1223 |
+
End Sub
|
| 1224 |
+
|
| 1225 |
+
Private Function GetDestroyCount(ByVal n As Long, ByVal iteration As Long) As Long
|
| 1226 |
+
Dim d As Long
|
| 1227 |
+
|
| 1228 |
+
If n <= 12 Then
|
| 1229 |
+
d = 3
|
| 1230 |
+
ElseIf n <= 25 Then
|
| 1231 |
+
d = 4
|
| 1232 |
+
ElseIf n <= 50 Then
|
| 1233 |
+
d = 5
|
| 1234 |
+
Else
|
| 1235 |
+
d = 6
|
| 1236 |
+
End If
|
| 1237 |
+
|
| 1238 |
+
If iteration Mod 4 = 0 Then d = d + 1
|
| 1239 |
+
If d > n - 1 Then d = n - 1
|
| 1240 |
+
If d < 1 Then d = 1
|
| 1241 |
+
|
| 1242 |
+
GetDestroyCount = d
|
| 1243 |
+
End Function
|
| 1244 |
+
|
| 1245 |
+
Private Sub BuildDestroyList(ByRef items() As TBanner, ByRef rolls() As TRoll, ByVal rollCount As Long, ByVal rollWidth As Double, ByVal n As Long, ByVal destroyCount As Long, ByVal mode As Long, ByRef selected() As Long, ByRef selectedCount As Long)
|
| 1246 |
+
Dim ids() As Long
|
| 1247 |
+
Dim scores() As Double
|
| 1248 |
+
Dim i As Long
|
| 1249 |
+
|
| 1250 |
+
BuildDestroyScores items, rolls, rollCount, rollWidth, n, mode, ids, scores
|
| 1251 |
+
|
| 1252 |
+
selectedCount = destroyCount
|
| 1253 |
+
If selectedCount > n - 1 Then selectedCount = n - 1
|
| 1254 |
+
If selectedCount < 1 Then
|
| 1255 |
+
ReDim selected(1 To 1)
|
| 1256 |
+
selectedCount = 0
|
| 1257 |
+
Exit Sub
|
| 1258 |
+
End If
|
| 1259 |
+
|
| 1260 |
+
ReDim selected(1 To selectedCount)
|
| 1261 |
+
|
| 1262 |
+
For i = 1 To selectedCount
|
| 1263 |
+
selected(i) = ids(i)
|
| 1264 |
+
Next i
|
| 1265 |
+
End Sub
|
| 1266 |
+
|
| 1267 |
+
Private Sub BuildOrderWithoutSelected(ByRef order() As Long, ByVal orderCount As Long, ByRef selected() As Long, ByVal selectedCount As Long, ByRef baseOrder() As Long, ByRef baseCount As Long, ByRef removed() As Long, ByRef removedCount As Long)
|
| 1268 |
+
Dim i As Long
|
| 1269 |
+
Dim rid As Long
|
| 1270 |
+
|
| 1271 |
+
ReDim baseOrder(1 To orderCount)
|
| 1272 |
+
ReDim removed(1 To selectedCount)
|
| 1273 |
+
baseCount = 0
|
| 1274 |
+
removedCount = 0
|
| 1275 |
+
|
| 1276 |
+
For i = 1 To orderCount
|
| 1277 |
+
rid = order(i)
|
| 1278 |
+
If ContainsLong(selected, selectedCount, rid) Then
|
| 1279 |
+
removedCount = removedCount + 1
|
| 1280 |
+
removed(removedCount) = rid
|
| 1281 |
+
Else
|
| 1282 |
+
baseCount = baseCount + 1
|
| 1283 |
+
baseOrder(baseCount) = rid
|
| 1284 |
+
End If
|
| 1285 |
+
Next i
|
| 1286 |
+
End Sub
|
| 1287 |
+
|
| 1288 |
+
Private Sub SortRemovedByArea(ByRef items() As TBanner, ByRef removed() As Long, ByVal removedCount As Long)
|
| 1289 |
+
Dim i As Long
|
| 1290 |
+
Dim j As Long
|
| 1291 |
+
Dim tmp As Long
|
| 1292 |
+
|
| 1293 |
+
For i = 1 To removedCount - 1
|
| 1294 |
+
For j = i + 1 To removedCount
|
| 1295 |
+
If AreaOf(items(removed(j))) > AreaOf(items(removed(i))) Then
|
| 1296 |
+
tmp = removed(i)
|
| 1297 |
+
removed(i) = removed(j)
|
| 1298 |
+
removed(j) = tmp
|
| 1299 |
+
End If
|
| 1300 |
+
Next j
|
| 1301 |
+
Next i
|
| 1302 |
+
End Sub
|
| 1303 |
+
|
| 1304 |
+
Private Sub AddRepairPosition(ByRef positions() As Long, ByRef count As Long, ByVal value As Long, ByVal maxValue As Long)
|
| 1305 |
+
Dim i As Long
|
| 1306 |
+
|
| 1307 |
+
If value < 1 Then value = 1
|
| 1308 |
+
If value > maxValue Then value = maxValue
|
| 1309 |
+
|
| 1310 |
+
For i = 1 To count
|
| 1311 |
+
If positions(i) = value Then Exit Sub
|
| 1312 |
+
Next i
|
| 1313 |
+
|
| 1314 |
+
count = count + 1
|
| 1315 |
+
positions(count) = value
|
| 1316 |
+
End Sub
|
| 1317 |
+
|
| 1318 |
+
Private Sub BuildRepairPositions(ByVal baseCount As Long, ByRef positions() As Long, ByRef positionCount As Long)
|
| 1319 |
+
Dim i As Long
|
| 1320 |
+
Dim stepValue As Double
|
| 1321 |
+
Dim value As Long
|
| 1322 |
+
|
| 1323 |
+
positionCount = 0
|
| 1324 |
+
ReDim positions(1 To MAX_LNS_REPAIR_POSITIONS)
|
| 1325 |
+
|
| 1326 |
+
If baseCount + 1 <= MAX_LNS_REPAIR_POSITIONS Then
|
| 1327 |
+
For i = 1 To baseCount + 1
|
| 1328 |
+
AddRepairPosition positions, positionCount, i, baseCount + 1
|
| 1329 |
+
Next i
|
| 1330 |
+
Exit Sub
|
| 1331 |
+
End If
|
| 1332 |
+
|
| 1333 |
+
AddRepairPosition positions, positionCount, 1, baseCount + 1
|
| 1334 |
+
AddRepairPosition positions, positionCount, baseCount + 1, baseCount + 1
|
| 1335 |
+
|
| 1336 |
+
stepValue = CDbl(baseCount) / CDbl(MAX_LNS_REPAIR_POSITIONS - 2)
|
| 1337 |
+
For i = 0 To MAX_LNS_REPAIR_POSITIONS - 3
|
| 1338 |
+
value = 1 + CLng(Int(CDbl(i) * stepValue))
|
| 1339 |
+
AddRepairPosition positions, positionCount, value, baseCount + 1
|
| 1340 |
+
Next i
|
| 1341 |
+
End Sub
|
| 1342 |
+
|
| 1343 |
+
Private Sub RepairDestroyedItems(ByRef items() As TBanner, ByVal n As Long, ByVal rollWidth As Double, ByVal maxHeight As Double, ByVal allowRotation As Boolean, ByVal fitMode As Long, ByRef baseOrder() As Long, ByVal baseCount As Long, ByRef removed() As Long, ByVal removedCount As Long, ByRef rotationPrefs() As Long, ByRef outOrder() As Long, ByRef outScore As Double)
|
| 1344 |
+
Dim currentCount As Long
|
| 1345 |
+
Dim positions() As Long
|
| 1346 |
+
Dim positionCount As Long
|
| 1347 |
+
Dim i As Long
|
| 1348 |
+
Dim p As Long
|
| 1349 |
+
Dim rid As Long
|
| 1350 |
+
Dim mode As Long
|
| 1351 |
+
Dim oldPref As Long
|
| 1352 |
+
Dim testScore As Double
|
| 1353 |
+
Dim bestLocalScore As Double
|
| 1354 |
+
Dim bestPosition As Long
|
| 1355 |
+
Dim bestMode As Long
|
| 1356 |
+
Dim testRollCount As Long
|
| 1357 |
+
Dim testNotPlaced As Long
|
| 1358 |
+
Dim testRight As Double
|
| 1359 |
+
Dim testAlign As Double
|
| 1360 |
+
Dim testMaterial As Double
|
| 1361 |
+
|
| 1362 |
+
ReDim outOrder(1 To n)
|
| 1363 |
+
currentCount = 0
|
| 1364 |
+
For i = 1 To baseCount
|
| 1365 |
+
outOrder(i) = baseOrder(i)
|
| 1366 |
+
Next i
|
| 1367 |
+
currentCount = baseCount
|
| 1368 |
+
SortRemovedByArea items, removed, removedCount
|
| 1369 |
+
|
| 1370 |
+
For i = 1 To removedCount
|
| 1371 |
+
rid = removed(i)
|
| 1372 |
+
BuildRepairPositions currentCount, positions, positionCount
|
| 1373 |
+
bestLocalScore = 1E+30
|
| 1374 |
+
bestPosition = 1
|
| 1375 |
+
bestMode = 0
|
| 1376 |
+
oldPref = rotationPrefs(rid)
|
| 1377 |
+
|
| 1378 |
+
For p = 1 To positionCount
|
| 1379 |
+
For mode = 0 To 2
|
| 1380 |
+
If Not allowRotation And mode <> 0 Then GoTo NextRepairMode
|
| 1381 |
+
|
| 1382 |
+
InsertLongAt outOrder, currentCount, positions(p), rid
|
| 1383 |
+
rotationPrefs(rid) = mode
|
| 1384 |
+
|
| 1385 |
+
testScore = EvaluateOrderScoreWithRotation(items, currentCount, rollWidth, maxHeight, allowRotation, fitMode, outOrder, rotationPrefs, testRollCount, testNotPlaced, testRight, testAlign, testMaterial)
|
| 1386 |
+
|
| 1387 |
+
If testScore < bestLocalScore - EPS Then
|
| 1388 |
+
bestLocalScore = testScore
|
| 1389 |
+
bestPosition = positions(p)
|
| 1390 |
+
bestMode = mode
|
| 1391 |
+
End If
|
| 1392 |
+
|
| 1393 |
+
RemoveLongAt outOrder, currentCount, positions(p)
|
| 1394 |
+
NextRepairMode:
|
| 1395 |
+
Next mode
|
| 1396 |
+
Next p
|
| 1397 |
+
|
| 1398 |
+
InsertLongAt outOrder, currentCount, bestPosition, rid
|
| 1399 |
+
rotationPrefs(rid) = bestMode
|
| 1400 |
+
Next i
|
| 1401 |
+
|
| 1402 |
+
outScore = EvaluateOrderScoreWithRotation(items, currentCount, rollWidth, maxHeight, allowRotation, fitMode, outOrder, rotationPrefs, testRollCount, testNotPlaced, testRight, testAlign, testMaterial)
|
| 1403 |
+
End Sub
|
| 1404 |
+
|
| 1405 |
+
Private Function GetCurrentRotation(ByRef rolls() As TRoll, ByVal rollCount As Long, ByVal rid As Long) As Boolean
|
| 1406 |
+
Dim r As Long
|
| 1407 |
+
Dim i As Long
|
| 1408 |
+
|
| 1409 |
+
For r = 1 To rollCount
|
| 1410 |
+
For i = 1 To rolls(r).placedCount
|
| 1411 |
+
If rolls(r).placed(i).rid = rid Then
|
| 1412 |
+
GetCurrentRotation = rolls(r).placed(i).Rotated
|
| 1413 |
+
Exit Function
|
| 1414 |
+
End If
|
| 1415 |
+
Next i
|
| 1416 |
+
Next r
|
| 1417 |
+
|
| 1418 |
+
GetCurrentRotation = False
|
| 1419 |
+
End Function
|
| 1420 |
+
|
| 1421 |
+
Private Sub TryRotationMutation(ByRef items() As TBanner, ByVal n As Long, ByVal rollWidth As Double, ByVal maxHeight As Double, ByVal allowRotation As Boolean, ByVal fitMode As Long, ByRef order() As Long, ByRef rotationPrefs() As Long, ByRef currentScore As Double)
|
| 1422 |
+
Dim currentRolls() As TRoll
|
| 1423 |
+
Dim currentRollCount As Long
|
| 1424 |
+
Dim currentNotPlaced As Long
|
| 1425 |
+
Dim currentRight As Double
|
| 1426 |
+
Dim currentAlign As Double
|
| 1427 |
+
Dim currentMaterial As Double
|
| 1428 |
+
Dim ids() As Long
|
| 1429 |
+
Dim scores() As Double
|
| 1430 |
+
Dim i As Long
|
| 1431 |
+
Dim rid As Long
|
| 1432 |
+
Dim oldPref As Long
|
| 1433 |
+
Dim newPref As Long
|
| 1434 |
+
Dim actualRotated As Boolean
|
| 1435 |
+
Dim testScore As Double
|
| 1436 |
+
Dim testRollCount As Long
|
| 1437 |
+
Dim testNotPlaced As Long
|
| 1438 |
+
Dim testRight As Double
|
| 1439 |
+
Dim testAlign As Double
|
| 1440 |
+
Dim testMaterial As Double
|
| 1441 |
+
Dim mutationCount As Long
|
| 1442 |
+
|
| 1443 |
+
If Not allowRotation Then Exit Sub
|
| 1444 |
+
|
| 1445 |
+
PackMultiRollWithOrder items, n, rollWidth, maxHeight, allowRotation, fitMode, order, rotationPrefs, currentRolls, currentRollCount, currentNotPlaced
|
| 1446 |
+
If currentNotPlaced > 0 Then Exit Sub
|
| 1447 |
+
|
| 1448 |
+
BuildDestroyScores items, currentRolls, currentRollCount, rollWidth, n, 1, ids, scores
|
| 1449 |
+
|
| 1450 |
+
mutationCount = MinD(MAX_ROTATION_MUTATIONS, n)
|
| 1451 |
+
|
| 1452 |
+
For i = 1 To mutationCount
|
| 1453 |
+
rid = ids(i)
|
| 1454 |
+
oldPref = rotationPrefs(rid)
|
| 1455 |
+
actualRotated = GetCurrentRotation(currentRolls, currentRollCount, rid)
|
| 1456 |
+
|
| 1457 |
+
If oldPref = 0 Then
|
| 1458 |
+
If actualRotated Then
|
| 1459 |
+
newPref = 1
|
| 1460 |
+
Else
|
| 1461 |
+
newPref = 2
|
| 1462 |
+
End If
|
| 1463 |
+
ElseIf oldPref = 1 Then
|
| 1464 |
+
newPref = 2
|
| 1465 |
+
Else
|
| 1466 |
+
newPref = 1
|
| 1467 |
+
End If
|
| 1468 |
+
|
| 1469 |
+
rotationPrefs(rid) = newPref
|
| 1470 |
+
testScore = EvaluateOrderScoreWithRotation(items, n, rollWidth, maxHeight, allowRotation, fitMode, order, rotationPrefs, testRollCount, testNotPlaced, testRight, testAlign, testMaterial)
|
| 1471 |
+
|
| 1472 |
+
If testNotPlaced = 0 And testScore < currentScore - EPS Then
|
| 1473 |
+
currentScore = testScore
|
| 1474 |
+
PackMultiRollWithOrder items, n, rollWidth, maxHeight, allowRotation, fitMode, order, rotationPrefs, currentRolls, currentRollCount, currentNotPlaced
|
| 1475 |
+
Else
|
| 1476 |
+
rotationPrefs(rid) = oldPref
|
| 1477 |
+
End If
|
| 1478 |
+
Next i
|
| 1479 |
+
End Sub
|
| 1480 |
+
|
| 1481 |
+
Private Sub OptimizeOrder(ByRef items() As TBanner, ByVal n As Long, ByVal rollWidth As Double, ByVal maxHeight As Double, ByVal allowRotation As Boolean, ByVal fitMode As Long, ByRef order() As Long, ByRef rotationPrefs() As Long, ByRef finalScore As Double)
|
| 1482 |
+
Dim currentScore As Double
|
| 1483 |
+
Dim testScore As Double
|
| 1484 |
+
Dim testRollCount As Long
|
| 1485 |
+
Dim testNotPlaced As Long
|
| 1486 |
+
Dim testRight As Double
|
| 1487 |
+
Dim testAlign As Double
|
| 1488 |
+
Dim testMaterial As Double
|
| 1489 |
+
Dim i As Long
|
| 1490 |
+
Dim j As Long
|
| 1491 |
+
Dim moveCount As Long
|
| 1492 |
+
Dim passNo As Long
|
| 1493 |
+
Dim improved As Boolean
|
| 1494 |
+
|
| 1495 |
+
currentScore = EvaluateOrderScoreWithRotation(items, n, rollWidth, maxHeight, allowRotation, fitMode, order, rotationPrefs, testRollCount, testNotPlaced, testRight, testAlign, testMaterial)
|
| 1496 |
+
|
| 1497 |
+
For passNo = 1 To MAX_LOCAL_PASSES
|
| 1498 |
+
improved = False
|
| 1499 |
+
|
| 1500 |
+
For i = 1 To n - 1
|
| 1501 |
+
SwapLong order, i, i + 1
|
| 1502 |
+
testScore = EvaluateOrderScoreWithRotation(items, n, rollWidth, maxHeight, allowRotation, fitMode, order, rotationPrefs, testRollCount, testNotPlaced, testRight, testAlign, testMaterial)
|
| 1503 |
+
If testScore < currentScore - EPS Then
|
| 1504 |
+
currentScore = testScore
|
| 1505 |
+
improved = True
|
| 1506 |
+
Else
|
| 1507 |
+
SwapLong order, i, i + 1
|
| 1508 |
+
End If
|
| 1509 |
+
Next i
|
| 1510 |
+
|
| 1511 |
+
moveCount = 0
|
| 1512 |
+
For i = 1 To n - 2
|
| 1513 |
+
For j = i + 2 To n
|
| 1514 |
+
moveCount = moveCount + 1
|
| 1515 |
+
If moveCount > MAX_PAIR_MOVES Then Exit For
|
| 1516 |
+
|
| 1517 |
+
SwapLong order, i, j
|
| 1518 |
+
testScore = EvaluateOrderScoreWithRotation(items, n, rollWidth, maxHeight, allowRotation, fitMode, order, rotationPrefs, testRollCount, testNotPlaced, testRight, testAlign, testMaterial)
|
| 1519 |
+
If testScore < currentScore - EPS Then
|
| 1520 |
+
currentScore = testScore
|
| 1521 |
+
improved = True
|
| 1522 |
+
Else
|
| 1523 |
+
SwapLong order, i, j
|
| 1524 |
+
End If
|
| 1525 |
+
Next j
|
| 1526 |
+
If moveCount >= MAX_PAIR_MOVES Then Exit For
|
| 1527 |
+
Next i
|
| 1528 |
+
|
| 1529 |
+
moveCount = 0
|
| 1530 |
+
For i = 1 To n
|
| 1531 |
+
For j = 1 To n
|
| 1532 |
+
If i <> j Then
|
| 1533 |
+
moveCount = moveCount + 1
|
| 1534 |
+
If moveCount > MAX_REINSERT_MOVES Then Exit For
|
| 1535 |
+
|
| 1536 |
+
MoveItemOrder order, i, j, n
|
| 1537 |
+
testScore = EvaluateOrderScoreWithRotation(items, n, rollWidth, maxHeight, allowRotation, fitMode, order, rotationPrefs, testRollCount, testNotPlaced, testRight, testAlign, testMaterial)
|
| 1538 |
+
|
| 1539 |
+
If testScore < currentScore - EPS Then
|
| 1540 |
+
currentScore = testScore
|
| 1541 |
+
improved = True
|
| 1542 |
+
Else
|
| 1543 |
+
MoveItemOrder order, j, i, n
|
| 1544 |
+
End If
|
| 1545 |
+
End If
|
| 1546 |
+
Next j
|
| 1547 |
+
If moveCount >= MAX_REINSERT_MOVES Then Exit For
|
| 1548 |
+
Next i
|
| 1549 |
+
|
| 1550 |
+
moveCount = 0
|
| 1551 |
+
For i = 1 To n - 2
|
| 1552 |
+
If moveCount >= MAX_TRIPLE_MOVES Then Exit For
|
| 1553 |
+
|
| 1554 |
+
SwapLong order, i + 1, i + 2
|
| 1555 |
+
moveCount = moveCount + 1
|
| 1556 |
+
testScore = EvaluateOrderScoreWithRotation(items, n, rollWidth, maxHeight, allowRotation, fitMode, order, rotationPrefs, testRollCount, testNotPlaced, testRight, testAlign, testMaterial)
|
| 1557 |
+
If testScore < currentScore - EPS Then
|
| 1558 |
+
currentScore = testScore
|
| 1559 |
+
improved = True
|
| 1560 |
+
Else
|
| 1561 |
+
SwapLong order, i + 1, i + 2
|
| 1562 |
+
End If
|
| 1563 |
+
|
| 1564 |
+
If moveCount >= MAX_TRIPLE_MOVES Then Exit For
|
| 1565 |
+
|
| 1566 |
+
SwapLong order, i, i + 1
|
| 1567 |
+
moveCount = moveCount + 1
|
| 1568 |
+
testScore = EvaluateOrderScoreWithRotation(items, n, rollWidth, maxHeight, allowRotation, fitMode, order, rotationPrefs, testRollCount, testNotPlaced, testRight, testAlign, testMaterial)
|
| 1569 |
+
If testScore < currentScore - EPS Then
|
| 1570 |
+
currentScore = testScore
|
| 1571 |
+
improved = True
|
| 1572 |
+
Else
|
| 1573 |
+
SwapLong order, i, i + 1
|
| 1574 |
+
End If
|
| 1575 |
+
|
| 1576 |
+
If moveCount >= MAX_TRIPLE_MOVES Then Exit For
|
| 1577 |
+
|
| 1578 |
+
SwapLong order, i, i + 2
|
| 1579 |
+
moveCount = moveCount + 1
|
| 1580 |
+
testScore = EvaluateOrderScoreWithRotation(items, n, rollWidth, maxHeight, allowRotation, fitMode, order, rotationPrefs, testRollCount, testNotPlaced, testRight, testAlign, testMaterial)
|
| 1581 |
+
If testScore < currentScore - EPS Then
|
| 1582 |
+
currentScore = testScore
|
| 1583 |
+
improved = True
|
| 1584 |
+
Else
|
| 1585 |
+
SwapLong order, i, i + 2
|
| 1586 |
+
End If
|
| 1587 |
+
Next i
|
| 1588 |
+
|
| 1589 |
+
If Not improved Then Exit For
|
| 1590 |
+
Next passNo
|
| 1591 |
+
|
| 1592 |
+
OptimizeContactAndCut items, n, rollWidth, maxHeight, allowRotation, fitMode, order, rotationPrefs, currentScore
|
| 1593 |
+
|
| 1594 |
+
finalScore = currentScore
|
| 1595 |
+
End Sub
|
| 1596 |
+
|
| 1597 |
+
Private Sub OptimizeContactAndCut(ByRef items() As TBanner, ByVal n As Long, ByVal rollWidth As Double, ByVal maxHeight As Double, ByVal allowRotation As Boolean, ByVal fitMode As Long, ByRef order() As Long, ByRef rotationPrefs() As Long, ByRef currentScore As Double)
|
| 1598 |
+
Dim i As Long
|
| 1599 |
+
Dim j As Long
|
| 1600 |
+
Dim moveCount As Long
|
| 1601 |
+
Dim testScore As Double
|
| 1602 |
+
Dim testRollCount As Long
|
| 1603 |
+
Dim testNotPlaced As Long
|
| 1604 |
+
Dim testRight As Double
|
| 1605 |
+
Dim testAlign As Double
|
| 1606 |
+
Dim testMaterial As Double
|
| 1607 |
+
Dim improved As Boolean
|
| 1608 |
+
Dim passNo As Long
|
| 1609 |
+
|
| 1610 |
+
For passNo = 1 To 2
|
| 1611 |
+
improved = False
|
| 1612 |
+
moveCount = 0
|
| 1613 |
+
|
| 1614 |
+
For i = 1 To n - 1
|
| 1615 |
+
SwapLong order, i, i + 1
|
| 1616 |
+
testScore = EvaluateOrderScoreWithRotation(items, n, rollWidth, maxHeight, allowRotation, fitMode, order, rotationPrefs, testRollCount, testNotPlaced, testRight, testAlign, testMaterial)
|
| 1617 |
+
moveCount = moveCount + 1
|
| 1618 |
+
|
| 1619 |
+
If testScore < currentScore - EPS Then
|
| 1620 |
+
currentScore = testScore
|
| 1621 |
+
improved = True
|
| 1622 |
+
Else
|
| 1623 |
+
SwapLong order, i, i + 1
|
| 1624 |
+
End If
|
| 1625 |
+
|
| 1626 |
+
If moveCount >= MAX_CONTACT_MOVES Then Exit For
|
| 1627 |
+
Next i
|
| 1628 |
+
|
| 1629 |
+
If moveCount < MAX_CONTACT_MOVES Then
|
| 1630 |
+
For i = 1 To n - 2
|
| 1631 |
+
For j = i + 2 To n
|
| 1632 |
+
SwapLong order, i, j
|
| 1633 |
+
testScore = EvaluateOrderScoreWithRotation(items, n, rollWidth, maxHeight, allowRotation, fitMode, order, rotationPrefs, testRollCount, testNotPlaced, testRight, testAlign, testMaterial)
|
| 1634 |
+
moveCount = moveCount + 1
|
| 1635 |
+
|
| 1636 |
+
If testScore < currentScore - EPS Then
|
| 1637 |
+
currentScore = testScore
|
| 1638 |
+
improved = True
|
| 1639 |
+
Else
|
| 1640 |
+
SwapLong order, i, j
|
| 1641 |
+
End If
|
| 1642 |
+
|
| 1643 |
+
If moveCount >= MAX_CUT_MOVES Then Exit For
|
| 1644 |
+
Next j
|
| 1645 |
+
If moveCount >= MAX_CUT_MOVES Then Exit For
|
| 1646 |
+
Next i
|
| 1647 |
+
End If
|
| 1648 |
+
|
| 1649 |
+
If Not improved Then Exit For
|
| 1650 |
+
Next passNo
|
| 1651 |
+
End Sub
|
| 1652 |
+
|
| 1653 |
+
Private Function GetLNSIterationLimit(ByVal n As Long) As Long
|
| 1654 |
+
If n <= 30 Then
|
| 1655 |
+
GetLNSIterationLimit = MAX_LNS_ITERATIONS
|
| 1656 |
+
ElseIf n <= 60 Then
|
| 1657 |
+
GetLNSIterationLimit = 8
|
| 1658 |
+
Else
|
| 1659 |
+
GetLNSIterationLimit = 6
|
| 1660 |
+
End If
|
| 1661 |
+
End Function
|
| 1662 |
+
|
| 1663 |
+
Private Sub OptimizeWithLNS(ByRef items() As TBanner, ByVal n As Long, ByVal rollWidth As Double, ByVal maxHeight As Double, ByVal allowRotation As Boolean, ByVal fitMode As Long, ByRef order() As Long, ByRef rotationPrefs() As Long, ByRef finalScore As Double, ByRef lnsIterationsUsed As Long, ByRef lnsImprovements As Long)
|
| 1664 |
+
Dim currentScore As Double
|
| 1665 |
+
Dim repairedScore As Double
|
| 1666 |
+
Dim optimizedScore As Double
|
| 1667 |
+
Dim iteration As Long
|
| 1668 |
+
Dim destroyCount As Long
|
| 1669 |
+
Dim selectionMode As Long
|
| 1670 |
+
Dim selected() As Long
|
| 1671 |
+
Dim selectedCount As Long
|
| 1672 |
+
Dim baseOrder() As Long
|
| 1673 |
+
Dim baseCount As Long
|
| 1674 |
+
Dim removed() As Long
|
| 1675 |
+
Dim removedCount As Long
|
| 1676 |
+
Dim trialOrder() As Long
|
| 1677 |
+
Dim trialPrefs() As Long
|
| 1678 |
+
Dim currentRolls() As TRoll
|
| 1679 |
+
Dim trialRolls() As TRoll
|
| 1680 |
+
Dim currentRollCount As Long
|
| 1681 |
+
Dim currentNotPlaced As Long
|
| 1682 |
+
Dim trialRollCount As Long
|
| 1683 |
+
Dim trialNotPlaced As Long
|
| 1684 |
+
Dim currentRight As Double
|
| 1685 |
+
Dim currentAlign As Double
|
| 1686 |
+
Dim currentMaterial As Double
|
| 1687 |
+
Dim trialRight As Double
|
| 1688 |
+
Dim trialAlign As Double
|
| 1689 |
+
Dim trialMaterial As Double
|
| 1690 |
+
Dim tempScore As Double
|
| 1691 |
+
Dim acceptWorse As Boolean
|
| 1692 |
+
Dim i As Long
|
| 1693 |
+
Dim iterationLimit As Long
|
| 1694 |
+
|
| 1695 |
+
lnsIterationsUsed = 0
|
| 1696 |
+
lnsImprovements = 0
|
| 1697 |
+
|
| 1698 |
+
currentScore = EvaluateOrderScoreWithRotation(items, n, rollWidth, maxHeight, allowRotation, fitMode, order, rotationPrefs, currentRollCount, currentNotPlaced, currentRight, currentAlign, currentMaterial)
|
| 1699 |
+
OptimizeOrder items, n, rollWidth, maxHeight, allowRotation, fitMode, order, rotationPrefs, optimizedScore
|
| 1700 |
+
currentScore = optimizedScore
|
| 1701 |
+
|
| 1702 |
+
If n < 3 Then
|
| 1703 |
+
finalScore = currentScore
|
| 1704 |
+
Exit Sub
|
| 1705 |
+
End If
|
| 1706 |
+
|
| 1707 |
+
iterationLimit = GetLNSIterationLimit(n)
|
| 1708 |
+
|
| 1709 |
+
For iteration = 1 To iterationLimit
|
| 1710 |
+
lnsIterationsUsed = iteration
|
| 1711 |
+
destroyCount = GetDestroyCount(n, iteration)
|
| 1712 |
+
selectionMode = ((iteration - 1) Mod 7) + 1
|
| 1713 |
+
|
| 1714 |
+
PackMultiRollWithOrder items, n, rollWidth, maxHeight, allowRotation, fitMode, order, rotationPrefs, currentRolls, currentRollCount, currentNotPlaced
|
| 1715 |
+
If currentNotPlaced > 0 Then Exit For
|
| 1716 |
+
|
| 1717 |
+
BuildDestroyList items, currentRolls, currentRollCount, rollWidth, n, destroyCount, selectionMode, selected, selectedCount
|
| 1718 |
+
BuildOrderWithoutSelected order, n, selected, selectedCount, baseOrder, baseCount, removed, removedCount
|
| 1719 |
+
|
| 1720 |
+
CopyRotationPrefs rotationPrefs, n, trialPrefs
|
| 1721 |
+
For i = 1 To selectedCount
|
| 1722 |
+
trialPrefs(selected(i)) = 0
|
| 1723 |
+
Next i
|
| 1724 |
+
|
| 1725 |
+
RepairDestroyedItems items, n, rollWidth, maxHeight, allowRotation, fitMode, baseOrder, baseCount, removed, removedCount, trialPrefs, trialOrder, repairedScore
|
| 1726 |
+
|
| 1727 |
+
acceptWorse = False
|
| 1728 |
+
If repairedScore < currentScore - EPS Then
|
| 1729 |
+
acceptWorse = True
|
| 1730 |
+
ElseIf iteration Mod 5 = 0 Then
|
| 1731 |
+
If repairedScore < currentScore * (1# + LNS_ACCEPT_WORSE_PCT) Then
|
| 1732 |
+
acceptWorse = True
|
| 1733 |
+
End If
|
| 1734 |
+
End If
|
| 1735 |
+
|
| 1736 |
+
If acceptWorse Then
|
| 1737 |
+
CopyOrder trialOrder, n, order
|
| 1738 |
+
CopyRotationPrefs trialPrefs, n, rotationPrefs
|
| 1739 |
+
currentScore = repairedScore
|
| 1740 |
+
lnsImprovements = lnsImprovements + 1
|
| 1741 |
+
|
| 1742 |
+
OptimizeOrder items, n, rollWidth, maxHeight, allowRotation, fitMode, order, rotationPrefs, optimizedScore
|
| 1743 |
+
If optimizedScore < currentScore - EPS Then
|
| 1744 |
+
currentScore = optimizedScore
|
| 1745 |
+
End If
|
| 1746 |
+
End If
|
| 1747 |
+
|
| 1748 |
+
TryRotationMutation items, n, rollWidth, maxHeight, allowRotation, fitMode, order, rotationPrefs, currentScore
|
| 1749 |
+
|
| 1750 |
+
tempScore = EvaluateOrderScoreWithRotation(items, n, rollWidth, maxHeight, allowRotation, fitMode, order, rotationPrefs, trialRollCount, trialNotPlaced, trialRight, trialAlign, trialMaterial)
|
| 1751 |
+
If tempScore < currentScore - EPS Then currentScore = tempScore
|
| 1752 |
+
Next iteration
|
| 1753 |
+
|
| 1754 |
+
finalScore = currentScore
|
| 1755 |
+
End Sub
|
| 1756 |
+
|
| 1757 |
+
Private Sub MoveShapeToBottomLeft(ByVal sh As Shape, ByVal targetX As Double, ByVal targetY As Double)
|
| 1758 |
+
Dim bx As Double
|
| 1759 |
+
Dim by As Double
|
| 1760 |
+
Dim bw As Double
|
| 1761 |
+
Dim bh As Double
|
| 1762 |
+
|
| 1763 |
+
sh.GetBoundingBox bx, by, bw, bh, False
|
| 1764 |
+
sh.Move targetX - bx, targetY - by
|
| 1765 |
+
End Sub
|
| 1766 |
+
|
| 1767 |
+
Private Sub ApplyNestingToObjects(ByRef items() As TBanner, ByRef sourceShapes() As Shape, ByRef rolls() As TRoll, ByVal rollCount As Long, ByVal rollWidth As Double)
|
| 1768 |
+
Dim totalHeight As Double
|
| 1769 |
+
Dim rollOffsetY As Double
|
| 1770 |
+
Dim r As Long
|
| 1771 |
+
Dim i As Long
|
| 1772 |
+
Dim rid As Long
|
| 1773 |
+
Dim margin As Double
|
| 1774 |
+
Dim targetX As Double
|
| 1775 |
+
Dim targetY As Double
|
| 1776 |
+
Dim pageLeft As Double
|
| 1777 |
+
Dim pageBottom As Double
|
| 1778 |
+
Dim pageTop As Double
|
| 1779 |
+
Dim rollTop As Double
|
| 1780 |
+
Dim sh As Shape
|
| 1781 |
+
|
| 1782 |
+
totalHeight = 0#
|
| 1783 |
+
For r = 1 To rollCount
|
| 1784 |
+
totalHeight = totalHeight + rolls(r).UsedHeight
|
| 1785 |
+
If r < rollCount Then totalHeight = totalHeight + ROLL_GAP
|
| 1786 |
+
Next r
|
| 1787 |
+
|
| 1788 |
+
If totalHeight <= EPS Then totalHeight = 10#
|
| 1789 |
+
|
| 1790 |
+
ActivePage.SizeWidth = rollWidth
|
| 1791 |
+
ActivePage.SizeHeight = totalHeight
|
| 1792 |
+
|
| 1793 |
+
pageLeft = ActivePage.LeftX
|
| 1794 |
+
pageBottom = ActivePage.BottomY
|
| 1795 |
+
pageTop = ActivePage.TopY
|
| 1796 |
+
rollOffsetY = 0#
|
| 1797 |
+
|
| 1798 |
+
For r = 1 To rollCount
|
| 1799 |
+
rollTop = pageTop - rollOffsetY
|
| 1800 |
+
|
| 1801 |
+
For i = 1 To rolls(r).placedCount
|
| 1802 |
+
rid = rolls(r).placed(i).rid
|
| 1803 |
+
Set sh = sourceShapes(rid)
|
| 1804 |
+
margin = items(rid).margin
|
| 1805 |
+
|
| 1806 |
+
If rolls(r).placed(i).Rotated Then sh.Rotate 90#
|
| 1807 |
+
|
| 1808 |
+
targetX = pageLeft + rolls(r).placed(i).x + margin
|
| 1809 |
+
targetY = rollTop - rolls(r).placed(i).y - rolls(r).placed(i).h + margin
|
| 1810 |
+
MoveShapeToBottomLeft sh, targetX, targetY
|
| 1811 |
+
Next i
|
| 1812 |
+
|
| 1813 |
+
rollOffsetY = rollOffsetY + rolls(r).UsedHeight
|
| 1814 |
+
If r < rollCount Then rollOffsetY = rollOffsetY + ROLL_GAP
|
| 1815 |
+
Next r
|
| 1816 |
+
|
| 1817 |
+
ActiveDocument.ClearSelection
|
| 1818 |
+
For r = 1 To rollCount
|
| 1819 |
+
For i = 1 To rolls(r).placedCount
|
| 1820 |
+
rid = rolls(r).placed(i).rid
|
| 1821 |
+
sourceShapes(rid).CreateSelection
|
| 1822 |
+
Next i
|
| 1823 |
+
Next r
|
| 1824 |
+
End Sub
|
| 1825 |
+
|
| 1826 |
+
Private Sub ParseWidthList(ByVal txt As String, ByRef widths() As Double, ByRef widthCount As Long)
|
| 1827 |
+
Dim parts() As String
|
| 1828 |
+
Dim i As Long
|
| 1829 |
+
Dim v As Double
|
| 1830 |
+
|
| 1831 |
+
widthCount = 0
|
| 1832 |
+
parts = Split(txt, ",")
|
| 1833 |
+
ReDim widths(1 To UBound(parts) + 1)
|
| 1834 |
+
|
| 1835 |
+
For i = LBound(parts) To UBound(parts)
|
| 1836 |
+
If Len(Trim$(parts(i))) > 0 Then
|
| 1837 |
+
v = Val(Trim$(parts(i)))
|
| 1838 |
+
If v > 0# Then
|
| 1839 |
+
widthCount = widthCount + 1
|
| 1840 |
+
widths(widthCount) = v
|
| 1841 |
+
End If
|
| 1842 |
+
End If
|
| 1843 |
+
Next i
|
| 1844 |
+
|
| 1845 |
+
If widthCount <= 0 Then
|
| 1846 |
+
ReDim widths(1 To 1)
|
| 1847 |
+
Else
|
| 1848 |
+
ReDim Preserve widths(1 To widthCount)
|
| 1849 |
+
End If
|
| 1850 |
+
End Sub
|
| 1851 |
+
|
| 1852 |
+
Private Function SortModeName(ByVal mode As Long) As String
|
| 1853 |
+
Select Case mode
|
| 1854 |
+
Case 1
|
| 1855 |
+
SortModeName = "Area Descending"
|
| 1856 |
+
Case 2
|
| 1857 |
+
SortModeName = "Width Descending"
|
| 1858 |
+
Case 3
|
| 1859 |
+
SortModeName = "Height Descending"
|
| 1860 |
+
Case 4
|
| 1861 |
+
SortModeName = "Short Side Descending"
|
| 1862 |
+
Case 5
|
| 1863 |
+
SortModeName = "Long Side Descending"
|
| 1864 |
+
Case 6
|
| 1865 |
+
SortModeName = "Aspect Ratio Descending"
|
| 1866 |
+
Case Else
|
| 1867 |
+
SortModeName = "Unknown"
|
| 1868 |
+
End Select
|
| 1869 |
+
End Function
|
| 1870 |
+
|
| 1871 |
+
Private Function FitModeName(ByVal mode As Long) As String
|
| 1872 |
+
Select Case mode
|
| 1873 |
+
Case 1
|
| 1874 |
+
FitModeName = "BSSF"
|
| 1875 |
+
Case 2
|
| 1876 |
+
FitModeName = "BAF"
|
| 1877 |
+
Case 3
|
| 1878 |
+
FitModeName = "BLSF"
|
| 1879 |
+
Case Else
|
| 1880 |
+
FitModeName = "Unknown"
|
| 1881 |
+
End Select
|
| 1882 |
+
End Function
|
| 1883 |
+
|
| 1884 |
+
|
| 1885 |
+
|
| 1886 |
+
' -----------------------------------------------------------------------------
|
| 1887 |
+
' MULTI-WIDTH HELPERS
|
| 1888 |
+
' This version compares the existing best single-width result against layouts
|
| 1889 |
+
' using two different roll widths. Each object is assigned to exactly one group.
|
| 1890 |
+
' The partition candidates are generated from several sort strategies and
|
| 1891 |
+
' split points, then both groups are packed and scored independently. This is a
|
| 1892 |
+
' bounded heuristic: it compares one-width against two-width solutions, not all
|
| 1893 |
+
' possible arbitrary partitions and not three-or-more-width combinations.
|
| 1894 |
+
' -----------------------------------------------------------------------------
|
| 1895 |
+
Private Sub OptimizeSubsetOrder(ByRef items() As TBanner, ByVal subsetCount As Long, ByVal rollWidth As Double, ByVal maxHeight As Double, ByVal allowRotation As Boolean, ByVal fitMode As Long, ByRef order() As Long, ByRef rotationPrefs() As Long, ByRef finalScore As Double)
|
| 1896 |
+
Dim currentScore As Double
|
| 1897 |
+
Dim testScore As Double
|
| 1898 |
+
Dim testRollCount As Long
|
| 1899 |
+
Dim testNotPlaced As Long
|
| 1900 |
+
Dim testRight As Double
|
| 1901 |
+
Dim testAlign As Double
|
| 1902 |
+
Dim testMaterial As Double
|
| 1903 |
+
Dim i As Long
|
| 1904 |
+
Dim j As Long
|
| 1905 |
+
Dim passNo As Long
|
| 1906 |
+
Dim improved As Boolean
|
| 1907 |
+
Dim moves As Long
|
| 1908 |
+
|
| 1909 |
+
If subsetCount <= 1 Then
|
| 1910 |
+
finalScore = EvaluateOrderScoreWithRotation(items, subsetCount, rollWidth, maxHeight, allowRotation, fitMode, order, rotationPrefs, testRollCount, testNotPlaced, testRight, testAlign, testMaterial)
|
| 1911 |
+
Exit Sub
|
| 1912 |
+
End If
|
| 1913 |
+
|
| 1914 |
+
currentScore = EvaluateOrderScoreWithRotation(items, subsetCount, rollWidth, maxHeight, allowRotation, fitMode, order, rotationPrefs, testRollCount, testNotPlaced, testRight, testAlign, testMaterial)
|
| 1915 |
+
|
| 1916 |
+
For passNo = 1 To 2
|
| 1917 |
+
improved = False
|
| 1918 |
+
|
| 1919 |
+
For i = 1 To subsetCount - 1
|
| 1920 |
+
SwapLong order, i, i + 1
|
| 1921 |
+
testScore = EvaluateOrderScoreWithRotation(items, subsetCount, rollWidth, maxHeight, allowRotation, fitMode, order, rotationPrefs, testRollCount, testNotPlaced, testRight, testAlign, testMaterial)
|
| 1922 |
+
If testNotPlaced = 0 And testScore < currentScore - EPS Then
|
| 1923 |
+
currentScore = testScore
|
| 1924 |
+
improved = True
|
| 1925 |
+
Else
|
| 1926 |
+
SwapLong order, i, i + 1
|
| 1927 |
+
End If
|
| 1928 |
+
Next i
|
| 1929 |
+
|
| 1930 |
+
moves = 0
|
| 1931 |
+
For i = 1 To subsetCount - 1
|
| 1932 |
+
For j = i + 1 To subsetCount
|
| 1933 |
+
If j <> i + 1 Then
|
| 1934 |
+
SwapLong order, i, j
|
| 1935 |
+
testScore = EvaluateOrderScoreWithRotation(items, subsetCount, rollWidth, maxHeight, allowRotation, fitMode, order, rotationPrefs, testRollCount, testNotPlaced, testRight, testAlign, testMaterial)
|
| 1936 |
+
moves = moves + 1
|
| 1937 |
+
|
| 1938 |
+
If testNotPlaced = 0 And testScore < currentScore - EPS Then
|
| 1939 |
+
currentScore = testScore
|
| 1940 |
+
improved = True
|
| 1941 |
+
Else
|
| 1942 |
+
SwapLong order, i, j
|
| 1943 |
+
End If
|
| 1944 |
+
|
| 1945 |
+
If moves >= MAX_PAIR_MOVES Then Exit For
|
| 1946 |
+
End If
|
| 1947 |
+
Next j
|
| 1948 |
+
If moves >= MAX_PAIR_MOVES Then Exit For
|
| 1949 |
+
Next i
|
| 1950 |
+
|
| 1951 |
+
If Not improved Then Exit For
|
| 1952 |
+
Next passNo
|
| 1953 |
+
|
| 1954 |
+
finalScore = currentScore
|
| 1955 |
+
End Sub
|
| 1956 |
+
|
| 1957 |
+
Private Function TotalRollHeight(ByRef rolls() As TRoll, ByVal rollCount As Long) As Double
|
| 1958 |
+
Dim r As Long
|
| 1959 |
+
Dim totalHeight As Double
|
| 1960 |
+
|
| 1961 |
+
totalHeight = 0#
|
| 1962 |
+
For r = 1 To rollCount
|
| 1963 |
+
totalHeight = totalHeight + rolls(r).UsedHeight
|
| 1964 |
+
If r < rollCount Then totalHeight = totalHeight + ROLL_GAP
|
| 1965 |
+
Next r
|
| 1966 |
+
|
| 1967 |
+
If totalHeight <= EPS Then totalHeight = 10#
|
| 1968 |
+
TotalRollHeight = totalHeight
|
| 1969 |
+
End Function
|
| 1970 |
+
|
| 1971 |
+
Private Sub ApplyNestingToPage(ByRef items() As TBanner, ByRef sourceShapes() As Shape, ByRef rolls() As TRoll, ByVal rollCount As Long, ByVal rollWidth As Double, ByVal targetPage As Page)
|
| 1972 |
+
Dim rollOffsetY As Double
|
| 1973 |
+
Dim r As Long
|
| 1974 |
+
Dim i As Long
|
| 1975 |
+
Dim rid As Long
|
| 1976 |
+
Dim margin As Double
|
| 1977 |
+
Dim targetX As Double
|
| 1978 |
+
Dim targetY As Double
|
| 1979 |
+
Dim pageLeft As Double
|
| 1980 |
+
Dim pageTop As Double
|
| 1981 |
+
Dim rollTop As Double
|
| 1982 |
+
Dim sh As Shape
|
| 1983 |
+
Dim totalHeight As Double
|
| 1984 |
+
|
| 1985 |
+
totalHeight = TotalRollHeight(rolls, rollCount)
|
| 1986 |
+
targetPage.SetSize rollWidth, totalHeight
|
| 1987 |
+
targetPage.Activate
|
| 1988 |
+
|
| 1989 |
+
pageLeft = targetPage.LeftX
|
| 1990 |
+
pageTop = targetPage.TopY
|
| 1991 |
+
rollOffsetY = 0#
|
| 1992 |
+
ActiveDocument.ClearSelection
|
| 1993 |
+
|
| 1994 |
+
For r = 1 To rollCount
|
| 1995 |
+
rollTop = pageTop - rollOffsetY
|
| 1996 |
+
|
| 1997 |
+
For i = 1 To rolls(r).placedCount
|
| 1998 |
+
rid = rolls(r).placed(i).rid
|
| 1999 |
+
Set sh = sourceShapes(rid)
|
| 2000 |
+
|
| 2001 |
+
' Move the original object to the output page's active layer.
|
| 2002 |
+
sh.MoveToLayer targetPage.ActiveLayer
|
| 2003 |
+
margin = items(rid).margin
|
| 2004 |
+
|
| 2005 |
+
If rolls(r).placed(i).Rotated Then sh.Rotate 90#
|
| 2006 |
+
|
| 2007 |
+
targetX = pageLeft + rolls(r).placed(i).x + margin
|
| 2008 |
+
targetY = rollTop - rolls(r).placed(i).y - rolls(r).placed(i).h + margin
|
| 2009 |
+
MoveShapeToBottomLeft sh, targetX, targetY
|
| 2010 |
+
sh.CreateSelection
|
| 2011 |
+
Next i
|
| 2012 |
+
|
| 2013 |
+
rollOffsetY = rollOffsetY + rolls(r).UsedHeight
|
| 2014 |
+
If r < rollCount Then rollOffsetY = rollOffsetY + ROLL_GAP
|
| 2015 |
+
Next r
|
| 2016 |
+
End Sub
|
| 2017 |
+
|
| 2018 |
+
Private Sub FindBestTwoWidthLayout(ByRef items() As TBanner, ByVal n As Long, ByRef widths() As Double, ByVal widthCount As Long, ByVal maxHeight As Double, ByVal allowRotation As Boolean, ByRef outOrderA() As Long, ByRef outCountA As Long, ByRef outWidthA As Double, ByRef outFitA As Long, ByRef outOrderB() As Long, ByRef outCountB As Long, ByRef outWidthB As Double, ByRef outFitB As Long, ByRef outMaterial As Double, ByRef outScore As Double)
|
| 2019 |
+
Dim sortedOrder() As Long
|
| 2020 |
+
Dim candidateOrderA() As Long
|
| 2021 |
+
Dim candidateOrderB() As Long
|
| 2022 |
+
Dim bestOrderA() As Long
|
| 2023 |
+
Dim bestOrderB() As Long
|
| 2024 |
+
Dim rotationPrefs() As Long
|
| 2025 |
+
Dim candidateRollsA() As TRoll
|
| 2026 |
+
Dim candidateRollsB() As TRoll
|
| 2027 |
+
Dim rollCountA As Long
|
| 2028 |
+
Dim rollCountB As Long
|
| 2029 |
+
Dim notPlacedA As Long
|
| 2030 |
+
Dim notPlacedB As Long
|
| 2031 |
+
Dim candidateCountA As Long
|
| 2032 |
+
Dim candidateCountB As Long
|
| 2033 |
+
Dim candidateWidthA As Double
|
| 2034 |
+
Dim candidateWidthB As Double
|
| 2035 |
+
Dim candidateMaterialA As Double
|
| 2036 |
+
Dim candidateMaterialB As Double
|
| 2037 |
+
Dim candidateMaterial As Double
|
| 2038 |
+
Dim candidateScoreA As Double
|
| 2039 |
+
Dim candidateScoreB As Double
|
| 2040 |
+
Dim candidateCombinedScore As Double
|
| 2041 |
+
Dim rightA As Double
|
| 2042 |
+
Dim rightB As Double
|
| 2043 |
+
Dim alignA As Double
|
| 2044 |
+
Dim alignB As Double
|
| 2045 |
+
Dim j As Long
|
| 2046 |
+
Dim k As Long
|
| 2047 |
+
Dim widthLimit As Long
|
| 2048 |
+
Dim sortMode As Long
|
| 2049 |
+
Dim splitStep As Long
|
| 2050 |
+
Dim splitPos As Long
|
| 2051 |
+
Dim previousSplit As Long
|
| 2052 |
+
Dim direction As Long
|
| 2053 |
+
Dim fitMode As Long
|
| 2054 |
+
Dim i As Long
|
| 2055 |
+
|
| 2056 |
+
outCountA = 0
|
| 2057 |
+
outCountB = 0
|
| 2058 |
+
outWidthA = 0#
|
| 2059 |
+
outWidthB = 0#
|
| 2060 |
+
outFitA = 1
|
| 2061 |
+
outFitB = 1
|
| 2062 |
+
outMaterial = 1E+30
|
| 2063 |
+
outScore = 1E+30
|
| 2064 |
+
|
| 2065 |
+
If n < 2 Or widthCount < 2 Then Exit Sub
|
| 2066 |
+
|
| 2067 |
+
widthLimit = widthCount
|
| 2068 |
+
If widthLimit > MAX_MULTI_WIDTH_CANDIDATES Then widthLimit = MAX_MULTI_WIDTH_CANDIDATES
|
| 2069 |
+
|
| 2070 |
+
ReDim rotationPrefs(1 To n)
|
| 2071 |
+
For i = 1 To n
|
| 2072 |
+
rotationPrefs(i) = 0
|
| 2073 |
+
Next i
|
| 2074 |
+
|
| 2075 |
+
For j = 1 To widthLimit - 1
|
| 2076 |
+
For k = j + 1 To widthLimit
|
| 2077 |
+
If AbsD(widths(j) - widths(k)) > EPS Then
|
| 2078 |
+
For sortMode = 1 To 6
|
| 2079 |
+
BuildInitialOrder items, n, sortMode, sortedOrder
|
| 2080 |
+
previousSplit = 0
|
| 2081 |
+
|
| 2082 |
+
' Split points at approximately 1/5, 2/5, 3/5 and 4/5.
|
| 2083 |
+
For splitStep = 1 To 4
|
| 2084 |
+
splitPos = CLng(Int((CDbl(n) * CDbl(splitStep)) / 5#))
|
| 2085 |
+
If splitPos < 1 Then splitPos = 1
|
| 2086 |
+
If splitPos > n - 1 Then splitPos = n - 1
|
| 2087 |
+
|
| 2088 |
+
If splitPos <> previousSplit Then
|
| 2089 |
+
previousSplit = splitPos
|
| 2090 |
+
candidateCountA = splitPos
|
| 2091 |
+
candidateCountB = n - splitPos
|
| 2092 |
+
ReDim candidateOrderA(1 To candidateCountA)
|
| 2093 |
+
ReDim candidateOrderB(1 To candidateCountB)
|
| 2094 |
+
|
| 2095 |
+
For i = 1 To candidateCountA
|
| 2096 |
+
candidateOrderA(i) = sortedOrder(i)
|
| 2097 |
+
Next i
|
| 2098 |
+
For i = 1 To candidateCountB
|
| 2099 |
+
candidateOrderB(i) = sortedOrder(splitPos + i)
|
| 2100 |
+
Next i
|
| 2101 |
+
|
| 2102 |
+
For direction = 1 To 2
|
| 2103 |
+
If direction = 1 Then
|
| 2104 |
+
candidateWidthA = widths(j)
|
| 2105 |
+
candidateWidthB = widths(k)
|
| 2106 |
+
Else
|
| 2107 |
+
candidateWidthA = widths(k)
|
| 2108 |
+
candidateWidthB = widths(j)
|
| 2109 |
+
End If
|
| 2110 |
+
|
| 2111 |
+
For fitMode = 1 To 3
|
| 2112 |
+
PackMultiRollWithOrder items, candidateCountA, candidateWidthA, maxHeight, allowRotation, fitMode, candidateOrderA, rotationPrefs, candidateRollsA, rollCountA, notPlacedA
|
| 2113 |
+
candidateScoreA = PackScore(items, candidateRollsA, rollCountA, notPlacedA, candidateWidthA, rightA, alignA, candidateMaterialA)
|
| 2114 |
+
|
| 2115 |
+
If notPlacedA = 0 Then
|
| 2116 |
+
PackMultiRollWithOrder items, candidateCountB, candidateWidthB, maxHeight, allowRotation, fitMode, candidateOrderB, rotationPrefs, candidateRollsB, rollCountB, notPlacedB
|
| 2117 |
+
candidateScoreB = PackScore(items, candidateRollsB, rollCountB, notPlacedB, candidateWidthB, rightB, alignB, candidateMaterialB)
|
| 2118 |
+
|
| 2119 |
+
If notPlacedB = 0 Then
|
| 2120 |
+
candidateMaterial = candidateMaterialA + candidateMaterialB
|
| 2121 |
+
candidateCombinedScore = candidateMaterial * MATERIAL_SCORE_SCALE _
|
| 2122 |
+
+ (candidateScoreA - candidateMaterialA * MATERIAL_SCORE_SCALE) _
|
| 2123 |
+
+ (candidateScoreB - candidateMaterialB * MATERIAL_SCORE_SCALE)
|
| 2124 |
+
|
| 2125 |
+
If candidateMaterial < outMaterial - EPS _
|
| 2126 |
+
Or (AbsD(candidateMaterial - outMaterial) <= EPS And candidateCombinedScore < outScore) Then
|
| 2127 |
+
outMaterial = candidateMaterial
|
| 2128 |
+
outScore = candidateCombinedScore
|
| 2129 |
+
outWidthA = candidateWidthA
|
| 2130 |
+
outWidthB = candidateWidthB
|
| 2131 |
+
outFitA = fitMode
|
| 2132 |
+
outFitB = fitMode
|
| 2133 |
+
outCountA = candidateCountA
|
| 2134 |
+
outCountB = candidateCountB
|
| 2135 |
+
CopyOrder candidateOrderA, candidateCountA, bestOrderA
|
| 2136 |
+
CopyOrder candidateOrderB, candidateCountB, bestOrderB
|
| 2137 |
+
End If
|
| 2138 |
+
End If
|
| 2139 |
+
End If
|
| 2140 |
+
Next fitMode
|
| 2141 |
+
Next direction
|
| 2142 |
+
End If
|
| 2143 |
+
Next splitStep
|
| 2144 |
+
Next sortMode
|
| 2145 |
+
End If
|
| 2146 |
+
Next k
|
| 2147 |
+
Next j
|
| 2148 |
+
|
| 2149 |
+
If outCountA > 0 And outCountB > 0 Then
|
| 2150 |
+
CopyOrder bestOrderA, outCountA, outOrderA
|
| 2151 |
+
CopyOrder bestOrderB, outCountB, outOrderB
|
| 2152 |
+
End If
|
| 2153 |
+
End Sub
|
| 2154 |
+
|
| 2155 |
+
Public Sub RunNesting_BannerCorelDRAW()
|
| 2156 |
+
Dim doc As Document
|
| 2157 |
+
Dim sr As ShapeRange
|
| 2158 |
+
Dim sh As Shape
|
| 2159 |
+
Dim items() As TBanner
|
| 2160 |
+
Dim sourceShapes() As Shape
|
| 2161 |
+
Dim rolls() As TRoll
|
| 2162 |
+
Dim candidateRolls() As TRoll
|
| 2163 |
+
Dim candidateOrder() As Long
|
| 2164 |
+
Dim bestOrder() As Long
|
| 2165 |
+
Dim workOrder() As Long
|
| 2166 |
+
Dim workPrefs() As Long
|
| 2167 |
+
Dim bestPrefs() As Long
|
| 2168 |
+
Dim seedOrders() As Long
|
| 2169 |
+
Dim seedScores() As Double
|
| 2170 |
+
Dim seedWidths() As Double
|
| 2171 |
+
Dim seedFits() As Long
|
| 2172 |
+
Dim seedSorts() As Long
|
| 2173 |
+
Dim n As Long
|
| 2174 |
+
Dim i As Long
|
| 2175 |
+
Dim j As Long
|
| 2176 |
+
Dim oldUnit As Long
|
| 2177 |
+
Dim marginText As String
|
| 2178 |
+
Dim margin As Double
|
| 2179 |
+
Dim rollText As String
|
| 2180 |
+
Dim widths() As Double
|
| 2181 |
+
Dim widthCount As Long
|
| 2182 |
+
Dim rotateAnswer As VbMsgBoxResult
|
| 2183 |
+
Dim allowRotation As Boolean
|
| 2184 |
+
Dim maxHeight As Double
|
| 2185 |
+
Dim minNeeded As Double
|
| 2186 |
+
Dim candidateWidth As Double
|
| 2187 |
+
Dim bestWidth As Double
|
| 2188 |
+
Dim candidateSortMode As Long
|
| 2189 |
+
Dim candidateFitMode As Long
|
| 2190 |
+
Dim bestSortMode As Long
|
| 2191 |
+
Dim bestFitMode As Long
|
| 2192 |
+
Dim candidateRollCount As Long
|
| 2193 |
+
Dim candidateNotPlaced As Long
|
| 2194 |
+
Dim bestRollCount As Long
|
| 2195 |
+
Dim bestNotPlaced As Long
|
| 2196 |
+
Dim candidateScore As Double
|
| 2197 |
+
Dim bestScore As Double
|
| 2198 |
+
Dim candidateMaterial As Double
|
| 2199 |
+
Dim bestMaterial As Double
|
| 2200 |
+
Dim candidateWaste As Double
|
| 2201 |
+
Dim bestWaste As Double
|
| 2202 |
+
Dim candidateRightWaste As Double
|
| 2203 |
+
Dim bestRightWaste As Double
|
| 2204 |
+
Dim candidateAlignment As Double
|
| 2205 |
+
Dim bestAlignment As Double
|
| 2206 |
+
Dim optimizedScore As Double
|
| 2207 |
+
Dim seedCount As Long
|
| 2208 |
+
Dim lnsIterationsUsed As Long
|
| 2209 |
+
Dim lnsImprovements As Long
|
| 2210 |
+
Dim bx As Double
|
| 2211 |
+
Dim by As Double
|
| 2212 |
+
Dim bw As Double
|
| 2213 |
+
Dim bh As Double
|
| 2214 |
+
Dim sumSide As Double
|
| 2215 |
+
Dim maxMargin As Double
|
| 2216 |
+
Dim msg As String
|
| 2217 |
+
Dim errNumber As Long
|
| 2218 |
+
Dim errDescription As String
|
| 2219 |
+
Dim finalSharedEdge As Double
|
| 2220 |
+
Dim finalContactSegments As Long
|
| 2221 |
+
Dim finalGuillotineEdge As Double
|
| 2222 |
+
Dim finalCutPenalty As Double
|
| 2223 |
+
Dim multiOrderA() As Long
|
| 2224 |
+
Dim multiOrderB() As Long
|
| 2225 |
+
Dim multiPrefs() As Long
|
| 2226 |
+
Dim multiRollsA() As TRoll
|
| 2227 |
+
Dim multiRollsB() As TRoll
|
| 2228 |
+
Dim multiCountA As Long
|
| 2229 |
+
Dim multiCountB As Long
|
| 2230 |
+
Dim multiWidthA As Double
|
| 2231 |
+
Dim multiWidthB As Double
|
| 2232 |
+
Dim multiFitA As Long
|
| 2233 |
+
Dim multiFitB As Long
|
| 2234 |
+
Dim multiBestMaterial As Double
|
| 2235 |
+
Dim multiBestScore As Double
|
| 2236 |
+
Dim multiMaterialA As Double
|
| 2237 |
+
Dim multiMaterialB As Double
|
| 2238 |
+
Dim multiCombinedMaterial As Double
|
| 2239 |
+
Dim multiRollCountA As Long
|
| 2240 |
+
Dim multiRollCountB As Long
|
| 2241 |
+
Dim multiNotPlacedA As Long
|
| 2242 |
+
Dim multiNotPlacedB As Long
|
| 2243 |
+
Dim multiScoreA As Double
|
| 2244 |
+
Dim multiScoreB As Double
|
| 2245 |
+
Dim multiRightA As Double
|
| 2246 |
+
Dim multiRightB As Double
|
| 2247 |
+
Dim multiAlignA As Double
|
| 2248 |
+
Dim multiAlignB As Double
|
| 2249 |
+
Dim multiHeightA As Double
|
| 2250 |
+
Dim multiHeightB As Double
|
| 2251 |
+
Dim multiTrueArea As Double
|
| 2252 |
+
Dim multiWaste As Double
|
| 2253 |
+
Dim multiSavingPct As Double
|
| 2254 |
+
Dim useMultiWidth As Boolean
|
| 2255 |
+
Dim outputPageA As Page
|
| 2256 |
+
Dim outputPageB As Page
|
| 2257 |
+
|
| 2258 |
+
On Error GoTo ErrHandler
|
| 2259 |
+
|
| 2260 |
+
Set doc = ActiveDocument
|
| 2261 |
+
If doc Is Nothing Then
|
| 2262 |
+
MsgBox "Tidak ada document CorelDRAW aktif.", vbExclamation, "Auto Nesting"
|
| 2263 |
+
Exit Sub
|
| 2264 |
+
End If
|
| 2265 |
+
|
| 2266 |
+
oldUnit = doc.Unit
|
| 2267 |
+
Set sr = ActiveSelectionRange
|
| 2268 |
+
|
| 2269 |
+
If sr Is Nothing Then
|
| 2270 |
+
MsgBox "Pilih object/banner terlebih dahulu.", vbExclamation, "Auto Nesting"
|
| 2271 |
+
Exit Sub
|
| 2272 |
+
End If
|
| 2273 |
+
|
| 2274 |
+
If sr.count <= 0 Then
|
| 2275 |
+
MsgBox "Pilih minimal 1 object/banner terlebih dahulu.", vbExclamation, "Auto Nesting"
|
| 2276 |
+
Exit Sub
|
| 2277 |
+
End If
|
| 2278 |
+
|
| 2279 |
+
n = sr.count
|
| 2280 |
+
doc.Unit = cdrCentimeter
|
| 2281 |
+
ReDim items(1 To n)
|
| 2282 |
+
ReDim sourceShapes(1 To n)
|
| 2283 |
+
|
| 2284 |
+
i = 0
|
| 2285 |
+
For Each sh In sr
|
| 2286 |
+
i = i + 1
|
| 2287 |
+
Set sourceShapes(i) = sh
|
| 2288 |
+
sh.GetBoundingBox bx, by, bw, bh, False
|
| 2289 |
+
|
| 2290 |
+
If bw <= EPS Or bh <= EPS Then
|
| 2291 |
+
doc.Unit = oldUnit
|
| 2292 |
+
MsgBox "Object nomor " & CStr(i) & " memiliki bounding box tidak valid.", vbCritical, "Auto Nesting"
|
| 2293 |
+
Exit Sub
|
| 2294 |
+
End If
|
| 2295 |
+
|
| 2296 |
+
items(i).Label = "Object " & CStr(i)
|
| 2297 |
+
items(i).OrigW = bw
|
| 2298 |
+
items(i).OrigH = bh
|
| 2299 |
+
items(i).margin = 0#
|
| 2300 |
+
Next sh
|
| 2301 |
+
|
| 2302 |
+
marginText = InputBox("Margin / clearance per sisi (cm):", "Auto Nesting - Margin", "0")
|
| 2303 |
+
If Len(Trim$(marginText)) > 0 Then margin = Val(Trim$(marginText)) Else margin = 0#
|
| 2304 |
+
If margin < 0# Then margin = 0#
|
| 2305 |
+
|
| 2306 |
+
For i = 1 To n
|
| 2307 |
+
items(i).margin = margin
|
| 2308 |
+
Next i
|
| 2309 |
+
|
| 2310 |
+
rollText = InputBox("Masukkan daftar lebar roll dalam cm." & vbCrLf & "Contoh: 150,200,250,300", "Auto Nesting - Roll Width", "109,159,219,259,319")
|
| 2311 |
+
If Len(Trim$(rollText)) = 0 Then
|
| 2312 |
+
doc.Unit = oldUnit
|
| 2313 |
+
MsgBox "Lebar roll tidak diberikan.", vbExclamation, "Auto Nesting"
|
| 2314 |
+
Exit Sub
|
| 2315 |
+
End If
|
| 2316 |
+
|
| 2317 |
+
ParseWidthList rollText, widths, widthCount
|
| 2318 |
+
If widthCount <= 0 Then
|
| 2319 |
+
doc.Unit = oldUnit
|
| 2320 |
+
MsgBox "Daftar lebar roll tidak valid.", vbCritical, "Auto Nesting"
|
| 2321 |
+
Exit Sub
|
| 2322 |
+
End If
|
| 2323 |
+
|
| 2324 |
+
rotateAnswer = MsgBox("Izinkan object diputar 90°?", vbYesNo + vbQuestion, "Auto Nesting - Rotation")
|
| 2325 |
+
allowRotation = (rotateAnswer = vbYes)
|
| 2326 |
+
|
| 2327 |
+
sumSide = 0#
|
| 2328 |
+
maxMargin = 0#
|
| 2329 |
+
For i = 1 To n
|
| 2330 |
+
sumSide = sumSide + MaxD(items(i).OrigW, items(i).OrigH)
|
| 2331 |
+
maxMargin = MaxD(maxMargin, items(i).margin)
|
| 2332 |
+
Next i
|
| 2333 |
+
|
| 2334 |
+
maxHeight = sumSide + maxMargin * (n + 2) + 100#
|
| 2335 |
+
minNeeded = 0#
|
| 2336 |
+
|
| 2337 |
+
For i = 1 To n
|
| 2338 |
+
If allowRotation Then
|
| 2339 |
+
minNeeded = MaxD(minNeeded, MinD(items(i).OrigW, items(i).OrigH) + 2# * items(i).margin)
|
| 2340 |
+
Else
|
| 2341 |
+
minNeeded = MaxD(minNeeded, items(i).OrigW + 2# * items(i).margin)
|
| 2342 |
+
End If
|
| 2343 |
+
Next i
|
| 2344 |
+
|
| 2345 |
+
ReDim seedOrders(1 To MAX_LOCAL_SEEDS, 1 To n)
|
| 2346 |
+
ReDim seedScores(1 To MAX_LOCAL_SEEDS)
|
| 2347 |
+
ReDim seedWidths(1 To MAX_LOCAL_SEEDS)
|
| 2348 |
+
ReDim seedFits(1 To MAX_LOCAL_SEEDS)
|
| 2349 |
+
ReDim seedSorts(1 To MAX_LOCAL_SEEDS)
|
| 2350 |
+
|
| 2351 |
+
For i = 1 To MAX_LOCAL_SEEDS
|
| 2352 |
+
seedScores(i) = 1E+30
|
| 2353 |
+
Next i
|
| 2354 |
+
|
| 2355 |
+
seedCount = 0
|
| 2356 |
+
bestScore = 1E+30
|
| 2357 |
+
bestMaterial = 1E+30
|
| 2358 |
+
bestWaste = 1#
|
| 2359 |
+
bestRightWaste = 1E+30
|
| 2360 |
+
bestAlignment = 1E+30
|
| 2361 |
+
bestWidth = 0#
|
| 2362 |
+
bestRollCount = 0
|
| 2363 |
+
bestNotPlaced = n
|
| 2364 |
+
bestSortMode = 1
|
| 2365 |
+
bestFitMode = 1
|
| 2366 |
+
|
| 2367 |
+
ReDim bestOrder(1 To n)
|
| 2368 |
+
ReDim bestPrefs(1 To n)
|
| 2369 |
+
For i = 1 To n
|
| 2370 |
+
bestPrefs(i) = 0
|
| 2371 |
+
Next i
|
| 2372 |
+
|
| 2373 |
+
For j = 1 To widthCount
|
| 2374 |
+
candidateWidth = widths(j)
|
| 2375 |
+
|
| 2376 |
+
If candidateWidth + EPS >= minNeeded Then
|
| 2377 |
+
For candidateSortMode = 1 To 6
|
| 2378 |
+
BuildInitialOrder items, n, candidateSortMode, candidateOrder
|
| 2379 |
+
|
| 2380 |
+
For candidateFitMode = 1 To 3
|
| 2381 |
+
ReDim workPrefs(1 To n)
|
| 2382 |
+
For i = 1 To n
|
| 2383 |
+
workPrefs(i) = 0
|
| 2384 |
+
Next i
|
| 2385 |
+
|
| 2386 |
+
PackMultiRollWithOrder items, n, candidateWidth, maxHeight, allowRotation, candidateFitMode, candidateOrder, workPrefs, candidateRolls, candidateRollCount, candidateNotPlaced
|
| 2387 |
+
candidateScore = PackScore(items, candidateRolls, candidateRollCount, candidateNotPlaced, candidateWidth, candidateRightWaste, candidateAlignment, candidateMaterial)
|
| 2388 |
+
|
| 2389 |
+
If candidateNotPlaced = 0 Then
|
| 2390 |
+
candidateWaste = CalcWaste(items, candidateRolls, candidateRollCount, candidateWidth)
|
| 2391 |
+
Else
|
| 2392 |
+
candidateWaste = 1#
|
| 2393 |
+
End If
|
| 2394 |
+
|
| 2395 |
+
AddSeed seedOrders, seedScores, seedWidths, seedFits, seedSorts, seedCount, MAX_LOCAL_SEEDS, candidateOrder, n, candidateScore, candidateWidth, candidateFitMode, candidateSortMode
|
| 2396 |
+
|
| 2397 |
+
If candidateScore < bestScore - EPS Then
|
| 2398 |
+
bestScore = candidateScore
|
| 2399 |
+
bestWidth = candidateWidth
|
| 2400 |
+
bestRollCount = candidateRollCount
|
| 2401 |
+
bestNotPlaced = candidateNotPlaced
|
| 2402 |
+
bestSortMode = candidateSortMode
|
| 2403 |
+
bestFitMode = candidateFitMode
|
| 2404 |
+
bestMaterial = candidateMaterial
|
| 2405 |
+
bestWaste = candidateWaste
|
| 2406 |
+
bestRightWaste = candidateRightWaste
|
| 2407 |
+
bestAlignment = candidateAlignment
|
| 2408 |
+
|
| 2409 |
+
CopyOrder candidateOrder, n, bestOrder
|
| 2410 |
+
CopyRotationPrefs workPrefs, n, bestPrefs
|
| 2411 |
+
End If
|
| 2412 |
+
Next candidateFitMode
|
| 2413 |
+
Next candidateSortMode
|
| 2414 |
+
End If
|
| 2415 |
+
Next j
|
| 2416 |
+
|
| 2417 |
+
' Even if no single width can hold all selected objects, continue: a
|
| 2418 |
+
' feasible combination of two widths may still exist.
|
| 2419 |
+
|
| 2420 |
+
For i = 1 To seedCount
|
| 2421 |
+
CopyOrderFromSeed seedOrders, i, n, workOrder
|
| 2422 |
+
ReDim workPrefs(1 To n)
|
| 2423 |
+
For j = 1 To n
|
| 2424 |
+
workPrefs(j) = 0
|
| 2425 |
+
Next j
|
| 2426 |
+
|
| 2427 |
+
optimizedScore = 1E+30
|
| 2428 |
+
OptimizeOrder items, n, seedWidths(i), maxHeight, allowRotation, seedFits(i), workOrder, workPrefs, optimizedScore
|
| 2429 |
+
|
| 2430 |
+
PackMultiRollWithOrder items, n, seedWidths(i), maxHeight, allowRotation, seedFits(i), workOrder, workPrefs, candidateRolls, candidateRollCount, candidateNotPlaced
|
| 2431 |
+
candidateScore = PackScore(items, candidateRolls, candidateRollCount, candidateNotPlaced, seedWidths(i), candidateRightWaste, candidateAlignment, candidateMaterial)
|
| 2432 |
+
|
| 2433 |
+
If candidateNotPlaced = 0 Then
|
| 2434 |
+
candidateWaste = CalcWaste(items, candidateRolls, candidateRollCount, seedWidths(i))
|
| 2435 |
+
Else
|
| 2436 |
+
candidateWaste = 1#
|
| 2437 |
+
End If
|
| 2438 |
+
|
| 2439 |
+
If candidateScore < bestScore - EPS Then
|
| 2440 |
+
bestScore = candidateScore
|
| 2441 |
+
bestWidth = seedWidths(i)
|
| 2442 |
+
bestRollCount = candidateRollCount
|
| 2443 |
+
bestNotPlaced = candidateNotPlaced
|
| 2444 |
+
bestSortMode = seedSorts(i)
|
| 2445 |
+
bestFitMode = seedFits(i)
|
| 2446 |
+
bestMaterial = candidateMaterial
|
| 2447 |
+
bestWaste = candidateWaste
|
| 2448 |
+
bestRightWaste = candidateRightWaste
|
| 2449 |
+
bestAlignment = candidateAlignment
|
| 2450 |
+
CopyOrder workOrder, n, bestOrder
|
| 2451 |
+
CopyRotationPrefs workPrefs, n, bestPrefs
|
| 2452 |
+
End If
|
| 2453 |
+
Next i
|
| 2454 |
+
|
| 2455 |
+
lnsIterationsUsed = 0
|
| 2456 |
+
lnsImprovements = 0
|
| 2457 |
+
|
| 2458 |
+
If bestNotPlaced = 0 And bestWidth > EPS Then
|
| 2459 |
+
CopyOrder bestOrder, n, workOrder
|
| 2460 |
+
CopyRotationPrefs bestPrefs, n, workPrefs
|
| 2461 |
+
optimizedScore = bestScore
|
| 2462 |
+
|
| 2463 |
+
OptimizeWithLNS items, n, bestWidth, maxHeight, allowRotation, bestFitMode, workOrder, workPrefs, optimizedScore, lnsIterationsUsed, lnsImprovements
|
| 2464 |
+
|
| 2465 |
+
PackMultiRollWithOrder items, n, bestWidth, maxHeight, allowRotation, bestFitMode, workOrder, workPrefs, candidateRolls, candidateRollCount, candidateNotPlaced
|
| 2466 |
+
candidateScore = PackScore(items, candidateRolls, candidateRollCount, candidateNotPlaced, bestWidth, candidateRightWaste, candidateAlignment, candidateMaterial)
|
| 2467 |
+
|
| 2468 |
+
If candidateNotPlaced = 0 And candidateScore < bestScore - EPS Then
|
| 2469 |
+
bestScore = candidateScore
|
| 2470 |
+
bestRollCount = candidateRollCount
|
| 2471 |
+
bestNotPlaced = candidateNotPlaced
|
| 2472 |
+
bestMaterial = candidateMaterial
|
| 2473 |
+
bestWaste = CalcWaste(items, candidateRolls, candidateRollCount, bestWidth)
|
| 2474 |
+
bestRightWaste = candidateRightWaste
|
| 2475 |
+
bestAlignment = candidateAlignment
|
| 2476 |
+
CopyOrder workOrder, n, bestOrder
|
| 2477 |
+
CopyRotationPrefs workPrefs, n, bestPrefs
|
| 2478 |
+
End If
|
| 2479 |
+
End If
|
| 2480 |
+
|
| 2481 |
+
' Search for a two-width partition after the strongest single-width layout
|
| 2482 |
+
' has been found. A second width is accepted only if it reduces total
|
| 2483 |
+
' material area compared with the best single-width result.
|
| 2484 |
+
If widthCount >= 2 And n >= 2 Then
|
| 2485 |
+
FindBestTwoWidthLayout items, n, widths, widthCount, maxHeight, allowRotation, _
|
| 2486 |
+
multiOrderA, multiCountA, multiWidthA, multiFitA, _
|
| 2487 |
+
multiOrderB, multiCountB, multiWidthB, multiFitB, multiBestMaterial, multiBestScore
|
| 2488 |
+
|
| 2489 |
+
If multiCountA > 0 And multiCountB > 0 Then
|
| 2490 |
+
ReDim multiPrefs(1 To n)
|
| 2491 |
+
For i = 1 To n
|
| 2492 |
+
multiPrefs(i) = 0
|
| 2493 |
+
Next i
|
| 2494 |
+
|
| 2495 |
+
OptimizeSubsetOrder items, multiCountA, multiWidthA, maxHeight, allowRotation, multiFitA, multiOrderA, multiPrefs, optimizedScore
|
| 2496 |
+
OptimizeSubsetOrder items, multiCountB, multiWidthB, maxHeight, allowRotation, multiFitB, multiOrderB, multiPrefs, optimizedScore
|
| 2497 |
+
|
| 2498 |
+
PackMultiRollWithOrder items, multiCountA, multiWidthA, maxHeight, allowRotation, multiFitA, multiOrderA, multiPrefs, multiRollsA, multiRollCountA, multiNotPlacedA
|
| 2499 |
+
multiScoreA = PackScore(items, multiRollsA, multiRollCountA, multiNotPlacedA, multiWidthA, multiRightA, multiAlignA, multiMaterialA)
|
| 2500 |
+
|
| 2501 |
+
PackMultiRollWithOrder items, multiCountB, multiWidthB, maxHeight, allowRotation, multiFitB, multiOrderB, multiPrefs, multiRollsB, multiRollCountB, multiNotPlacedB
|
| 2502 |
+
multiScoreB = PackScore(items, multiRollsB, multiRollCountB, multiNotPlacedB, multiWidthB, multiRightB, multiAlignB, multiMaterialB)
|
| 2503 |
+
|
| 2504 |
+
If multiNotPlacedA = 0 And multiNotPlacedB = 0 Then
|
| 2505 |
+
multiCombinedMaterial = multiMaterialA + multiMaterialB
|
| 2506 |
+
|
| 2507 |
+
If multiCombinedMaterial < bestMaterial - EPS Then
|
| 2508 |
+
useMultiWidth = True
|
| 2509 |
+
multiBestMaterial = multiCombinedMaterial
|
| 2510 |
+
End If
|
| 2511 |
+
End If
|
| 2512 |
+
End If
|
| 2513 |
+
End If
|
| 2514 |
+
|
| 2515 |
+
If useMultiWidth Then
|
| 2516 |
+
multiHeightA = TotalRollHeight(multiRollsA, multiRollCountA)
|
| 2517 |
+
multiHeightB = TotalRollHeight(multiRollsB, multiRollCountB)
|
| 2518 |
+
|
| 2519 |
+
' Each chosen stock width receives its own accurately sized CorelDRAW page.
|
| 2520 |
+
Set outputPageA = doc.AddPagesEx(1, multiWidthA, multiHeightA)
|
| 2521 |
+
outputPageA.Name = "Nesting " & Format$(multiWidthA, "0.##") & " cm"
|
| 2522 |
+
ApplyNestingToPage items, sourceShapes, multiRollsA, multiRollCountA, multiWidthA, outputPageA
|
| 2523 |
+
|
| 2524 |
+
Set outputPageB = doc.AddPagesEx(1, multiWidthB, multiHeightB)
|
| 2525 |
+
outputPageB.Name = "Nesting " & Format$(multiWidthB, "0.##") & " cm"
|
| 2526 |
+
ApplyNestingToPage items, sourceShapes, multiRollsB, multiRollCountB, multiWidthB, outputPageB
|
| 2527 |
+
|
| 2528 |
+
doc.Unit = oldUnit
|
| 2529 |
+
|
| 2530 |
+
multiTrueArea = CalcTrueArea(items, multiRollsA, multiRollCountA) + CalcTrueArea(items, multiRollsB, multiRollCountB)
|
| 2531 |
+
If multiBestMaterial > EPS Then
|
| 2532 |
+
multiWaste = (multiBestMaterial - multiTrueArea) / multiBestMaterial
|
| 2533 |
+
Else
|
| 2534 |
+
multiWaste = 0#
|
| 2535 |
+
End If
|
| 2536 |
+
If bestWidth > EPS And bestRollCount > 0 And bestNotPlaced = 0 And bestMaterial < 1E+29 Then
|
| 2537 |
+
multiSavingPct = ((bestMaterial - multiBestMaterial) / bestMaterial) * 100#
|
| 2538 |
+
Else
|
| 2539 |
+
multiSavingPct = -1#
|
| 2540 |
+
End If
|
| 2541 |
+
|
| 2542 |
+
msg = "AUTO NESTING V6 - MULTI-WIDTH SELESAI" & vbCrLf & vbCrLf
|
| 2543 |
+
msg = msg & "Object total: " & CStr(n) & vbCrLf
|
| 2544 |
+
msg = msg & "Halaman output: 2 halaman, masing-masing ukuran roll berbeda" & vbCrLf & vbCrLf
|
| 2545 |
+
msg = msg & "Halaman " & CStr(outputPageA.Index) & ": lebar " & Format$(multiWidthA, "0.00") & " cm" & vbCrLf
|
| 2546 |
+
msg = msg & "Object: " & CStr(multiCountA) & " | Jumlah roll: " & CStr(multiRollCountA) & vbCrLf
|
| 2547 |
+
msg = msg & "Tinggi layout: " & Format$(multiHeightA, "0.00") & " cm" & vbCrLf & vbCrLf
|
| 2548 |
+
msg = msg & "Halaman " & CStr(outputPageB.Index) & ": lebar " & Format$(multiWidthB, "0.00") & " cm" & vbCrLf
|
| 2549 |
+
msg = msg & "Object: " & CStr(multiCountB) & " | Jumlah roll: " & CStr(multiRollCountB) & vbCrLf
|
| 2550 |
+
msg = msg & "Tinggi layout: " & Format$(multiHeightB, "0.00") & " cm" & vbCrLf & vbCrLf
|
| 2551 |
+
msg = msg & "Total material: " & Format$(multiBestMaterial, "0.00") & " cm2" & vbCrLf
|
| 2552 |
+
msg = msg & "Estimasi waste: " & Format$(multiWaste * 100#, "0.00") & "%" & vbCrLf
|
| 2553 |
+
If multiSavingPct >= 0# Then
|
| 2554 |
+
msg = msg & "Penghematan material vs 1 ukuran: " & Format$(multiSavingPct, "0.00") & "%" & vbCrLf
|
| 2555 |
+
Else
|
| 2556 |
+
msg = msg & "Pembanding 1 ukuran: tidak ada solusi yang feasible" & vbCrLf
|
| 2557 |
+
End If
|
| 2558 |
+
msg = msg & "Rotasi diizinkan: " & IIf(allowRotation, "Ya", "Tidak") & vbCrLf
|
| 2559 |
+
msg = msg & "Catatan: semua object dialokasikan tepat satu kali ke salah satu dari dua halaman output."
|
| 2560 |
+
|
| 2561 |
+
MsgBox msg, vbInformation, "Auto Nesting V6 - Multi-Width"
|
| 2562 |
+
Exit Sub
|
| 2563 |
+
End If
|
| 2564 |
+
|
| 2565 |
+
If bestWidth <= EPS Or bestRollCount <= 0 Or bestNotPlaced > 0 Then
|
| 2566 |
+
doc.Unit = oldUnit
|
| 2567 |
+
msg = "Tidak ditemukan konfigurasi roll yang feasible." & vbCrLf & vbCrLf
|
| 2568 |
+
msg = msg & "Minimum roll width: " & Format$(minNeeded, "0.00") & " cm"
|
| 2569 |
+
MsgBox msg, vbCritical, "Auto Nesting"
|
| 2570 |
+
Exit Sub
|
| 2571 |
+
End If
|
| 2572 |
+
|
| 2573 |
+
PackMultiRollWithOrder items, n, bestWidth, maxHeight, allowRotation, bestFitMode, bestOrder, bestPrefs, rolls, bestRollCount, bestNotPlaced
|
| 2574 |
+
|
| 2575 |
+
If bestNotPlaced > 0 Then
|
| 2576 |
+
doc.Unit = oldUnit
|
| 2577 |
+
MsgBox "Layout final menjadi tidak feasible. Object tidak akan dipindahkan.", vbCritical, "Auto Nesting V6"
|
| 2578 |
+
Exit Sub
|
| 2579 |
+
End If
|
| 2580 |
+
|
| 2581 |
+
bestMaterial = CalcMaterialUsed(rolls, bestRollCount, bestWidth)
|
| 2582 |
+
bestWaste = CalcWaste(items, rolls, bestRollCount, bestWidth)
|
| 2583 |
+
bestRightWaste = CalcRightWaste(rolls, bestRollCount, bestWidth)
|
| 2584 |
+
bestAlignment = CalcAlignmentScore(rolls, bestRollCount)
|
| 2585 |
+
finalSharedEdge = CalcSharedEdgeLength(rolls, bestRollCount)
|
| 2586 |
+
finalContactSegments = CalcContactSegments(rolls, bestRollCount)
|
| 2587 |
+
finalGuillotineEdge = CalcGuillotineEdgeLength(rolls, bestRollCount)
|
| 2588 |
+
finalCutPenalty = CalcCutFriendlyPenalty(rolls, bestRollCount, bestWidth)
|
| 2589 |
+
|
| 2590 |
+
ApplyNestingToObjects items, sourceShapes, rolls, bestRollCount, bestWidth
|
| 2591 |
+
doc.Unit = oldUnit
|
| 2592 |
+
|
| 2593 |
+
msg = "AUTO NESTING V6 SELESAI (SINGLE-WIDTH TERBAIK)" & vbCrLf & vbCrLf
|
| 2594 |
+
msg = msg & "Object: " & CStr(n) & vbCrLf
|
| 2595 |
+
msg = msg & "Roll width: " & Format$(bestWidth, "0.00") & " cm" & vbCrLf
|
| 2596 |
+
msg = msg & "Jumlah roll: " & CStr(bestRollCount) & vbCrLf
|
| 2597 |
+
msg = msg & "Tidak ditempatkan: " & CStr(bestNotPlaced) & vbCrLf
|
| 2598 |
+
msg = msg & "Material digunakan: " & Format$(bestMaterial, "0.00") & " cm2" & vbCrLf
|
| 2599 |
+
msg = msg & "Catatan: material = lebar roll x total height terpakai" & vbCrLf
|
| 2600 |
+
msg = msg & "Waste estimasi: " & Format$(bestWaste * 100#, "0.00") & "%" & vbCrLf
|
| 2601 |
+
msg = msg & "Waste kanan maksimum: " & Format$(bestRightWaste, "0.00") & " cm" & vbCrLf
|
| 2602 |
+
|
| 2603 |
+
If bestRightWaste <= MAX_RIGHT_WASTE + EPS Then
|
| 2604 |
+
msg = msg & "Right waste status: OK" & vbCrLf
|
| 2605 |
+
Else
|
| 2606 |
+
msg = msg & "Right waste status: > 10 cm" & vbCrLf
|
| 2607 |
+
End If
|
| 2608 |
+
|
| 2609 |
+
msg = msg & "Visual alignment score: " & Format$(bestAlignment, "0.00") & vbCrLf
|
| 2610 |
+
msg = msg & "Shared edge: " & Format$(finalSharedEdge, "0.00") & " cm" & vbCrLf
|
| 2611 |
+
msg = msg & "Contact segments: " & CStr(finalContactSegments) & vbCrLf
|
| 2612 |
+
msg = msg & "Strong guillotine edge: " & Format$(finalGuillotineEdge, "0.00") & " cm" & vbCrLf
|
| 2613 |
+
msg = msg & "Cut-friendly penalty: " & Format$(finalCutPenalty, "0.00") & vbCrLf
|
| 2614 |
+
msg = msg & "Seed sort: " & SortModeName(bestSortMode) & vbCrLf
|
| 2615 |
+
msg = msg & "Fitness: " & FitModeName(bestFitMode) & vbCrLf
|
| 2616 |
+
msg = msg & "LNS iterations: " & CStr(lnsIterationsUsed) & vbCrLf
|
| 2617 |
+
msg = msg & "LNS accepted moves: " & CStr(lnsImprovements) & vbCrLf
|
| 2618 |
+
msg = msg & "Optimization: SWAP + REINSERT + 3-OBJECT + CONTACT-POINT + GUILLOTINE + DESTROY/REPAIR + ROTATION MUTATION"
|
| 2619 |
+
|
| 2620 |
+
MsgBox msg, vbInformation, "Auto Nesting V6"
|
| 2621 |
+
Exit Sub
|
| 2622 |
+
|
| 2623 |
+
ErrHandler:
|
| 2624 |
+
errNumber = Err.Number
|
| 2625 |
+
errDescription = Err.Description
|
| 2626 |
+
On Error Resume Next
|
| 2627 |
+
If Not doc Is Nothing Then doc.Unit = oldUnit
|
| 2628 |
+
On Error GoTo 0
|
| 2629 |
+
MsgBox "Macro berhenti karena error." & vbCrLf & vbCrLf & "Error " & CStr(errNumber) & ": " & errDescription, vbCritical, "Auto Nesting V6"
|
| 2630 |
+
End Sub
|
| 2631 |
+
|
| 2632 |
+
|
| 2633 |
+
|
| 2634 |
+
|
| 2635 |
+
|