-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathMotifsImposer.cls
562 lines (488 loc) · 17.5 KB
/
MotifsImposer.cls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "MotifsImposer"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = True
'===============================================================================
' Ìîäóëü : MotifsImposer
' Âåðñèÿ : 2024.02.14
' Àâòîð : elvin-nsk ([email protected])
' Ñàéò : https://github.com/elvin-nsk/LowCoupledFromCore
' Íàçíà÷åíèå :
' Çàâèñèìîñòè : LibCore, Composer, ComposerElement,
' Motif, Surface, Point, FileSpec, MarksSetter
'===============================================================================
'@ModuleDescription("MotifsImposer.")
'@PredeclaredId
Option Explicit
'===============================================================================
' # Declarations
Private Type This
Bleeds As Double
ComposedShapesByPage As Collection
CropMarksLength As Double
EdgeMarginBottom As Double
EdgeMarginLeft As Double
EdgeMarginRight As Double
EdgeMarginTop As Double
Elements As Collection
FillLastPage As Boolean
HorizontalSpace As Double
MaxPlacesInHeight As Long
MaxPlacesInWidth As Long
MotifsToImport As Variant
PlaceCropMarks As Boolean
PlacesTotalCounter As Long
PlaceWhiteBackground As Boolean
ReferencePoint As cdrReferencePoint
RemainingElements As Collection
TwoSided As Boolean
VerticalSpace As Double
End Type
Private This As This
Private Const SIDE_A_MARK As String = "A"
Private Const SIDE_B_MARK As String = "B"
Private Const BACKGROUND_MARK As String = "ïîäëîæêà"
'===============================================================================
' # Events
Public Event OnImportSurface(ByVal Surface As Surface)
Public Event OnPageImposed(ByVal Page As Page)
'===============================================================================
' # Constructors
Public Function NewFromImport( _
ByRef Motifs As Variant, _
Optional ByVal TwoSided As Boolean = False _
) As MotifsImposer
Set NewFromImport = New MotifsImposer
NewFromImport.Inject Motifs, TwoSided
End Function
Friend Sub Inject( _
ByRef Motifs As Variant, _
ByVal TwoSided As Boolean _
)
With This
Set .ComposedShapesByPage = New Collection
.CropMarksLength = 3
.FillLastPage = False
.ReferencePoint = cdrCenter
.TwoSided = TwoSided
Set .MotifsToImport = Motifs
End With
End Sub
'===============================================================================
' # Public
Public Property Get Bleeds() As Double
Bleeds = This.Bleeds
End Property
Public Property Let Bleeds(RHS As Double)
This.Bleeds = RHS
End Property
Public Property Get ComposedShapesByPage() As Collection
Set ComposedShapesByPage = This.ComposedShapesByPage
End Property
Public Property Get CropMarksLength() As Double
CropMarksLength = This.CropMarksLength
End Property
Public Property Let CropMarksLength(RHS As Double)
This.CropMarksLength = RHS
End Property
Public Property Get EdgeMarginBottom() As Double
EdgeMarginBottom = This.EdgeMarginBottom
End Property
Public Property Let EdgeMarginBottom(RHS As Double)
This.EdgeMarginBottom = RHS
End Property
Public Property Get EdgeMarginLeft() As Double
EdgeMarginLeft = This.EdgeMarginLeft
End Property
Public Property Let EdgeMarginLeft(RHS As Double)
This.EdgeMarginLeft = RHS
End Property
Public Property Get EdgeMarginRight() As Double
EdgeMarginRight = This.EdgeMarginRight
End Property
Public Property Let EdgeMarginRight(RHS As Double)
This.EdgeMarginRight = RHS
End Property
Public Property Get EdgeMarginTop() As Double
EdgeMarginTop = This.EdgeMarginTop
End Property
Public Property Let EdgeMarginTop(RHS As Double)
This.EdgeMarginTop = RHS
End Property
Public Property Get FillLastPage() As Boolean
FillLastPage = This.FillLastPage
End Property
Public Property Let FillLastPage(RHS As Boolean)
This.FillLastPage = RHS
End Property
Public Property Get HorizontalSpace() As Double
HorizontalSpace = This.HorizontalSpace
End Property
Public Property Let HorizontalSpace(RHS As Double)
This.HorizontalSpace = RHS
End Property
Public Sub ImposeOnCurrentPageOnly()
Impose False
End Sub
Public Sub ImposeAutoAddPages()
Impose True
End Sub
Public Property Get MaxPlacesInHeight() As Long
MaxPlacesInHeight = This.MaxPlacesInHeight
End Property
Public Property Let MaxPlacesInHeight(RHS As Long)
This.MaxPlacesInHeight = RHS
End Property
Public Property Get MaxPlacesInWidth() As Long
MaxPlacesInWidth = This.MaxPlacesInWidth
End Property
Public Property Let MaxPlacesInWidth(RHS As Long)
This.MaxPlacesInWidth = RHS
End Property
Public Property Get PlaceCropMarks() As Boolean
PlaceCropMarks = This.PlaceCropMarks
End Property
Public Property Let PlaceCropMarks(RHS As Boolean)
This.PlaceCropMarks = RHS
End Property
Public Property Get PlacesTotal() As Long
PlacesTotal = This.PlacesTotalCounter
End Property
Public Property Get PlaceWhiteBackground() As Boolean
PlaceWhiteBackground = This.PlaceWhiteBackground
End Property
Public Property Let PlaceWhiteBackground(RHS As Boolean)
This.PlaceWhiteBackground = RHS
End Property
Public Property Get ReferencePoint() As cdrReferencePoint
ReferencePoint = This.ReferencePoint
End Property
Public Property Let ReferencePoint(RHS As cdrReferencePoint)
This.ReferencePoint = RHS
End Property
Public Property Get RemainingElements() As Collection
Set RemainingElements = This.RemainingElements
End Property
Public Property Get Self() As MotifsImposer
Set Self = Me
End Property
Public Sub SetEdgeMarginsEqual(ByVal Margin As Double)
This.EdgeMarginBottom = Margin
This.EdgeMarginLeft = Margin
This.EdgeMarginRight = Margin
This.EdgeMarginTop = Margin
End Sub
Public Property Get VerticalSpace() As Double
VerticalSpace = This.VerticalSpace
End Property
Public Property Let VerticalSpace(RHS As Double)
This.VerticalSpace = RHS
End Property
'===============================================================================
' # Logic
Private Sub Impose( _
Optional ByVal AutoAddPages As Boolean _
)
With This
Set .Elements = ImportAsMarkedElements(.MotifsToImport)
If .Elements.Count = 0 Then Exit Sub
Dim Elements As Collection
Set Elements = .Elements
Dim ImpositionIndex As Long
Dim LastPivot As Point
Dim LastCount As Long
Dim LastIteration As Boolean
Dim ComposedShapes As ShapeRange
Dim ElementsComposer As Composer
Dim RawImpositionRanges As New Collection
Dim ImpositionArea As Rect
Set ImpositionArea = GetImpositionArea
Do
ImpositionIndex = ImpositionIndex + 1
Set ElementsComposer = _
Composer.NewAndCompose( _
Elements:=Elements, _
StartingPoint:=Point.New_(-20000, 20000), _
MaxPlacesInWidth:=MaxPlacesInWidth, _
MaxPlacesInHeight:=MaxPlacesInHeight, _
MaxWidth:=ImpositionArea.Width, _
MaxHeight:=ImpositionArea.Height, _
HorizontalSpace:=.HorizontalSpace, _
VerticalSpace:=.VerticalSpace _
)
Set ComposedShapes = _
ElementsToShapes(ElementsComposer.ComposedElements)
Set LastPivot = _
AlignImposition(ComposedShapes, ImpositionArea, LastPivot)
LastCount = ElementsComposer.ComposedElements.Count
If Not AutoAddPages Then
RaiseEvent OnPageImposed(ActivePage)
Exit Do
End If
RawImpositionRanges.Add ComposedShapes
Set Elements = ElementsComposer.RemainingElements
If Elements.Count < LastCount _
And Elements.Count > 0 _
And .FillLastPage Then
If .FillLastPage Then
AddRandomElements _
Elements, _
LastCount - ElementsComposer.RemainingElements.Count
End If
End If
Loop While Elements.Count > 0
ProcessImpositions RawImpositionRanges, AutoAddPages
End With
End Sub
'===============================================================================
' # Helpers
Private Property Get GetImpositionArea() As Rect
Set GetImpositionArea = ActivePage.BoundingBox.GetCopy
With This
GetImpositionArea.Inflate _
-.EdgeMarginLeft, -.EdgeMarginTop, -.EdgeMarginRight, -.EdgeMarginBottom
End With
End Property
Private Function AlignImposition( _
ByVal ComposedShapes As ShapeRange, _
ByVal ImpositionArea As Rect, _
ByVal Pivot As Point _
) As Point
If Pivot Is Nothing Then
Align ComposedShapes, ImpositionArea, This.ReferencePoint
Set AlignImposition = _
Point.New_( _
ComposedShapes.LeftX, _
ComposedShapes.TopY _
)
Else
ComposedShapes.LeftX = Pivot.x
ComposedShapes.TopY = Pivot.y
End If
End Function
Private Sub AddRandomElements( _
ByVal ioElements As Collection, _
ByVal Number As Long _
)
VBA.Randomize
Dim Index As Long
Dim RandomElement As ComposerElement
Dim Shapes As ShapeRange
Dim NewElement As ComposerElement
For Index = 1 To Number
Set RandomElement = This.Elements(RndInt(1, This.Elements.Count))
Set Shapes = RandomElement.Shapes.Duplicate
Set NewElement = ComposerElement.New_(Shapes)
ioElements.Add NewElement
Next Index
End Sub
Private Sub ProcessImpositions( _
ByVal RawImpositionRanges As Collection, _
ByVal AutoAddPages As Boolean _
)
Dim ImpositionPages As Collection
If AutoAddPages Then
Set ImpositionPages = DistributeByMultiplePages(RawImpositionRanges)
Else
Set ImpositionPages = New Collection
ImpositionPages.Add ActivePage
End If
If This.TwoSided Then
Set This.ComposedShapesByPage = SeparateSides(ImpositionPages)
Else
Set This.ComposedShapesByPage = RawImpositionRanges
End If
If This.PlaceCropMarks Then _
PlaceCropMarksOnImpositions This.ComposedShapesByPage
End Sub
Private Function DistributeByMultiplePages( _
ByVal ImpositionRanges As Collection _
) As Collection
Set DistributeByMultiplePages = New Collection
Dim Index As Long
Dim StartingPageIndex As Long
StartingPageIndex = ActivePage.Index
Dim Shapes As ShapeRange
Dim Page As Page
DistributeByMultiplePages.Add ActivePage
If ImpositionRanges.Count > 1 Then _
ActiveDocument.AddPages ImpositionRanges.Count - 1
ActiveDocument.Pages(StartingPageIndex).Activate
RaiseEvent OnPageImposed(ActivePage)
For Index = 2 To ImpositionRanges.Count
Set Shapes = ImpositionRanges(Index)
Set Page = ActiveDocument.Pages(Index + StartingPageIndex - 1)
DistributeByMultiplePages.Add Page
Shapes.MoveToLayer Page.ActiveLayer
RaiseEvent OnPageImposed(Page)
Next Index
End Function
Private Function SeparateSides( _
ByVal ImpositionPages As Collection _
) As Collection
Set SeparateSides = New Collection
Dim Page As Page
Dim TargetPage As Page
For Each Page In ImpositionPages
Set TargetPage = AddPage(Page)
SeparateSide Page, TargetPage, SeparateSides
Next Page
End Function
Private Sub SeparateSide( _
ByVal SourcePage As Page, _
ByVal TargetPage As Page, _
ByVal ioSides As Collection _
)
Dim SideA As New ShapeRange
SideA.AddRange SourcePage.Shapes.All
Dim SideB As ShapeRange
Set SideB = GetBSides(SourcePage.Shapes)
SideA.RemoveRange SideB
ioSides.Add SideA
ioSides.Add SideB
SourcePage.Activate
Dim Shape As Shape
For Each Shape In SideB
Shape.RightX = _
SourcePage.RightX - (Shape.LeftX - SourcePage.LeftX)
Shape.MoveToLayer TargetPage.ActiveLayer
Next Shape
End Sub
Private Property Get GetBSides(ByVal Shapes As Shapes) As ShapeRange
Set GetBSides = Shapes.FindShapes(Name:=SIDE_B_MARK, Recursive:=False)
End Property
Private Sub PlaceCropMarksOnImpositions(ByVal ImpositionRanges As Collection)
Dim Range As ShapeRange
Dim Shape As Shape
For Each Range In ImpositionRanges
Range.FirstShape.Page.Activate
With MarksSetter.New_(Range)
.Bleeds = This.Bleeds
.PlaceWhiteUndermark = False
.Size = 3
.SetMarksOnNewLayer
End With
Next Range
End Sub
Private Function ShapesToElements(ByVal Shapes As ShapeRange) As Collection
Dim Shape As Shape
Set ShapesToElements = New Collection
For Each Shape In Shapes
ShapesToElements.Add ComposerElement.New_(Shape)
Next Shape
End Function
Private Function ElementsToShapes( _
ByVal ComposerElements As Collection _
) As ShapeRange
Dim Item As ComposerElement
Set ElementsToShapes = New ShapeRange
For Each Item In ComposerElements
ElementsToShapes.AddRange Item.Shapes
Next Item
End Function
Private Function ImportAsMarkedElements(ByRef Motifs As Variant) As Collection
Set ImportAsMarkedElements = New Collection
Dim MaybeMotif As Variant
Dim Shapes As ShapeRange
For Each MaybeMotif In Motifs
MotifOrThrow MaybeMotif
Set Shapes = ImportAsMarkedShapes(MaybeMotif)
AppendCollection _
ImportAsMarkedElements, _
DuplicateRangesAsElements(Shapes, MaybeMotif.Quantity)
Next MaybeMotif
End Function
Private Function ImportAsMarkedShapes( _
ByVal Motif As Motif _
) As ShapeRange
Dim ShapesToElement As ShapeRange
Set ImportAsMarkedShapes = CreateShapeRange
With Motif
This.PlacesTotalCounter = This.PlacesTotalCounter + .Quantity
ImportContent .SurfaceA
If This.PlaceWhiteBackground Then AddWhiteBackground .SurfaceA.Content
.SurfaceA.Content.Name = SIDE_A_MARK
ImportAsMarkedShapes.Add .SurfaceA.Content
If This.TwoSided Then
If .HasSurfaceB Then
ImportContent (.SurfaceB)
If This.PlaceWhiteBackground Then AddWhiteBackground .SurfaceB.Content
Else
Set .SurfaceB.Content = _
DrawWhiteRectangle( _
.SurfaceA.Content.Layer, _
.SurfaceA.Content.BoundingBox _
)
End If
.SurfaceB.Content.SetPosition .SurfaceA.Content.PositionX, .SurfaceA.Content.PositionY
.SurfaceB.Content.Name = SIDE_B_MARK
ImportAsMarkedShapes.Add .SurfaceB.Content
End If
End With
End Function
Private Function DuplicateRangesAsElements( _
ByVal Range As ShapeRange, _
ByVal Quantity As Long _
) As Collection
Set DuplicateRangesAsElements = New Collection
DuplicateRangesAsElements.Add ComposerElement.New_(Range)
If Quantity = 1 Then Exit Function
Dim Index As Long
For Index = 1 To Quantity - 1
DuplicateRangesAsElements.Add ComposerElement.New_(Range.Duplicate)
Next Index
End Function
Private Sub ImportContent(ByVal Surface As Surface)
ActiveLayer.Import Surface.File
Set Surface.Content = ActiveShape
RaiseEvent OnImportSurface(Surface)
End Sub
Private Sub AddWhiteBackground(ByRef ioShape As Shape)
Dim BGShape As Shape
Set BGShape = DrawWhiteRectangle(ioShape.Layer, ioShape.BoundingBox)
BGShape.Name = BACKGROUND_MARK
BGShape.OrderBackOf ioShape
Set ioShape = PackShapes(BGShape, ioShape).Group
End Sub
Private Function DrawWhiteRectangle( _
ByVal Layer As Layer, _
ByVal Box As Rect _
) As Shape
Set DrawWhiteRectangle = Layer.CreateRectangleRect(Box)
DrawWhiteRectangle.Fill.ApplyUniformFill CreateCMYKColor(0, 0, 0, 0)
DrawWhiteRectangle.Outline.SetNoOutline
End Function
Private Property Get GetMotifsCopy(ByRef Motifs As Variant) As Collection
Set GetMotifsCopy = New Collection
Dim Motif As Motif
Dim Item As Variant
For Each Item In Motifs
MotifOrThrow Item
Set Motif = Item.GetCopy
GetMotifsCopy.Add Motif
Next Item
End Property
Private Property Get BottomMarginY() As Double
BottomMarginY = ActivePage.BottomY + This.EdgeMarginBottom
End Property
Private Property Get LeftMarginX() As Double
LeftMarginX = ActivePage.LeftX + This.EdgeMarginLeft
End Property
Private Property Get RightMarginX() As Double
RightMarginX = ActivePage.RightX - This.EdgeMarginRight
End Property
Private Property Get TopMarginY() As Double
TopMarginY = ActivePage.TopY - This.EdgeMarginTop
End Property
Public Sub MotifOrThrow(ByRef MaybeMotif As Variant)
If Not ObjectAssigned(MaybeMotif) Then GoTo Fail
If Not TypeOf MaybeMotif Is Motif Then GoTo Fail
Exit Sub
Fail:
Throw "Motifs äîëæåí ñîäåðæàòü îáúåêòû òèïà Motif"
End Sub