[[20221119091242]] 『図形の配置と回転』(REI) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『図形の配置と回転』(REI)

お世話になります。

上手く書けるかわかりませんが、頑張ってみます。

あるイラストが1枚あります。このイラストはExcelマクロ有効ブックと同じフォルダー内にあります。このイラストを使って次のようなことは可能なのでしょうか。

・ユーザーにイラストの枚数を入力させる(2、4、6といったように偶数)
・入力された数字分、イラストを適当に配置する。(左を揃えたりせず、適当に)
・配置する範囲はA4用紙サイズ内
・配置されたイラストが、ランダムに回転している。(回転角度も適当に。もちろん回転しないものがあっても構いません)

よろしくお願いいたします。

< 使用 Excel:Office365、使用 OS:Windows10 >


可能です
(ファイナルアンサー) 2022/11/19(土) 10:22:25

 可能は可能だろうが、前提が漠然とし過ぎています。
 そして、ご自分ではどこまでトライされているのでしょうか?

 質問を継続するなら、下記の点について明確にする必要があるでしょう。
 ・イラストとは具体的にどんな種類のファイルか(拡張子)
 ・大きさは?
 ・2、4、6個とのこと。配置の方針は?
 ・回転した時、重なりは許容できるのか
 ・回転した時、A4に収まるセル範囲をはみ出すことは許容できるのか 等

 イラストの数との関係もあるので、配置するところが難しい気がします。

 回転のコードはマクロ記録を見ればすぐわかります。
 たとえばこんな感じ。
     Dim rot As Double
     Dim shp As Shape
     For Each shp In ActiveSheet.Shapes
         rot = 360 * Rnd()
         shp.IncrementRotation rot
     Next
 とりあえず私はここまで。
  
(γ) 2022/11/19(土) 15:34:01

γさん

ありがとうございます。申し訳ございません、私は初心者で一人で作ることができず、おたずねしている次第です。お許しください。

 ・イラストとは具体的にどんな種類のファイルか(拡張子)
 ・大きさは?

→イラストの表現が間違いでした。大変失礼しました。Excelの挿入で描ける図形です。大きさ的にはデフォルトのCellのサイズでいうと、B2:B3くらいの大きさです。

 ・2、4、6個とのこと。配置の方針は?

→図形は長方形で、配置の方針はありません。個数が多くなったときに、均等に散らばれば良いなと思っております。

 ・回転した時、重なりは許容できるのか

→重なりはなしです。

 ・回転した時、A4に収まるセル範囲をはみ出すことは許容できるのか 等

→印刷の関係で、はみ出すことはなしです。

この程度の補足説明で大丈夫でしょうか。

お時間ございますときに、ご教示いただけましたら幸いです。
(REI) 2022/11/19(土) 19:02:24


 図形の配置はご自分で手でやってください。
 手で簡単にできることですから、ご自分の好みで、好きなように配置してください。

 回転する部分は、以下のマクロを使って下さい。
 フォームのボタンをワークシートにおいて、それにマクロを登録するとよいでしょう。
 ボタンを押すたびに、ランダムな角度で回転するはずです。

 Sub test()
     Dim rot As Double
     Dim shp As Shape

     For Each shp In ActiveSheet.Shapes
         If shp.Type = msoAutoShape Then 'オートシェイプに限定
             'A4縦に収まるセル範囲[A1:H39]の中の図形に限定
             If Not Intersect(shp.TopLeftCell, [A1:H39]) Is Nothing Then
                 rot = 360 * Rnd()
                 shp.IncrementRotation rot   'Autoshapeをランダムに回転
             End If
         End If
     Next
 End Sub
 私の発言はここまでとします。
  
(γ) 2022/11/19(土) 20:19:39

γさん

ありがとうございます。図形を手で配置して、それらをランダムに回転させることには成功しました。

図形の配置ですが、実は1枚だけではなく、配置や回転が異なるパタンで複数印刷をするため、マクロで動かしたいのです。

お時間のある方、ご教示いただけないでしょうか。本当に申し訳ございません。
(REI) 2022/11/20(日) 08:04:27


回転させると重なり判定が難しくなるけどどうすんの?
図形の最大個数は何個?
配置や回転が異なるパタンは何パターン必要なの?
その数次第ですが、γさんのランダムに回転させた図形を人間の目視で配置させた方が早いと思う。
重なり判定の関数があるなら乱数で位置決めればいいけど、個数が多いと収束しなくなるよ。
(スガリモノ) 2022/11/20(日) 09:02:25

スガリモノさん

ご教示ありがとうございます。いまExcelで試していたのですが、γさん、スガリモノさんのおっしゃる通りかもしれません。多少図形サイズを小さくするとして、最大で20枚は配置したいので、収束しないといけませんね。20〜30枚程度の印刷ですので、印刷前にそれぞれのシートに手を加えて、なんとか対応をしてみます。

ありがとうございました。
(REI) 2022/11/20(日) 10:00:17


 追記します。

 回転だけでなく、既存の図形の位置をランダムに微修正するなら、
     rot = 360 * Rnd()
     shp.IncrementRotation rot   'Autoshapeをランダムに回転
     shp.IncrementLeft 5 * (Rnd() - 0.5)
     shp.IncrementTop 5 * (Rnd() - 0.5)
 といった方法もあるでしょう。

 そもそもの話、質問者さんの期待するランダム性が、
 こちらでは想像ができないわけです。
 最大20個であれば、余裕で配置はできるとは思います。
 例えば、横4個、縦5個の格子状に20個を配置することはできますが、
 たぶん、そうした規則的な配置ではなく、もっと不規則性のある自由な配置を想定しているのでしょう。

 となると、位置そのものをランダムに設定していくことになりますが、
 その際、追加するたびに、回転を加味した重なりチェックが必要になります。
 もちろんやってできないことはないのでしょうけど、
 そもそも何に使うものか、どんな重要なものかもわからないのに、
 時間と労力を費やす気になれないのが正直なところです。

 シートコピーして、ご自分の気のすむような配置に修正していただく、
 という方針をとられるとのことで、現実的な対応と思いました。
  
(γ) 2022/11/20(日) 12:01:08

申し訳ございません。一度手作業でやろうと考えたのですが、ネットを調べていると重なりを許容しないようにするコードがあり、それを少しだけ触って自分なりのものを作成してみました。回転は省こうと思いますが、それでもやはり重なっています。

お時間ございます方、下記のコードの問題点を教えていただけますでしょうか。

オートシェイプはduplicateをつかって複数枚 ws1に貼り付けています。

With ws1

    For i = 1 To .Shapes.Count
        Set ShpR1 = .Range(.Shapes(i).TopLeftCell, .Shapes(i).BottomRightCell)
            For j = i + 1 To .Shapes.Count
                If i <> j Then
                    Set ShpR2 = .Range(.Shapes(j).TopLeftCell, .Shapes(j).BottomRightCell)
                        If Not Intersect(ShpR1, ShpR2) Is Nothing Then
                            .Shapes(j).IncrementLeft 300 * (Rnd() - 0.5)
                            .Shapes(j).IncrementTop 300 * (Rnd() - 0.5)
            End If
                End If
             Next j
     next i
(REI) 2022/11/21(月) 18:31:53

こんばんわ ^^。。。
なかなか。むつかしいですよね。ずっと拝見いたしておりましたが。
γさんのご説明にもありますが。なかなか。大変なのでは。
この学校にも別の方法で、衝突判定の見本みたいなのを
作成されていたよぉですよ。←私はついていけませんでした(*^^*)
ところで
 If Not Intersect(ShpR1, ShpR2) Is Nothing Then

これって、重なっていたら。。。あれこれ回転みたいな気が
するのですが??;。え
ちがうのかな。。。^^;
自信が無くなってきました。( ̄▽ ̄)
独自で作ったコードですと
4まいくらいでしたらスムーズに動きますが、20枚くらいになると
重ならない事が限りなくなくなってきて、無限ループ状態になりました。
m(__)m
(隠居Z) 2022/11/21(月) 19:13:46


すみません
回転しませんでしたね。移動の間違いです。
notを外すと
図形2個が
重ならずに、移動しているようですよ。
m(__)m
(隠居Z) 2022/11/21(月) 19:36:56

2022/11/21(月) 19:13:46

もちろん、A4一枚印刷可能範囲くらいの
範囲での事です。^^;
ひろ〜い範囲なら20枚くらいなら楽々です。
m(__)m
(隠居Z) 2022/11/21(月) 21:00:19

隠居Zさん

お返事ありがとうございます。b4でも構いませんので、ご教示いただけますか。
(REI) 2022/11/21(月) 21:20:02


オートシェイブですが、以下を書いております。これらのあとに上のものが来ます。

With ws1.Range("B2")

    Set shp = ActiveSheet.Shapes.AddShape(Type:=msoShapeHeart, Left:=.Left, Top:=.Top, Width:=70, Height:=70)
End With

'図形の描画数をセット
On Error Resume Next
myNum = InputBox("10〜20くらいの偶数を入れてください")

    If myNum < 6 Or myNum > 20 Or myNum Mod 2 = 1 Then
        MsgBox "10〜20の偶数を入力してください"
        ws1.Shapes.SelectAll
            Selection.ShapeRange.Delete
        Exit Sub
    End If

'入力された分だけ描画
For k = 2 To myNum

    ReDim shp2(myNum)
    Set shp2(k) = shp.Duplicate
Next k
(REI) 2022/11/21(月) 21:25:21

こんばんわ^^
すぐ、アップ出来れば良いのですが、回転時使用セル範囲を求めるロジックで
確信が持てていませんので、暫時、御猶予を、只今、検証中^^;
m(_ _)m。挑戦は致しておりますが、少々、時間がかかりそうなので、引き続き
他の回答者様のアドバイスもお待ちくださいませ。
m(__)m
(隠居Z) 2022/11/21(月) 22:28:05

サイズが70ですが
35では
だめでせうか。。。^^;

明日にでも、アップしておきますので。表示範囲、見込使用予定範囲
画像サイズ、、などなど。ご変更、ご勘案下さいませ。
重なり判定ロジック等々で、無駄な事をしておるやもしれませんので
。。。←かなり可能性大。( ̄▽ ̄;)
突っ込み大歓迎。宜しくお願い致します。m(__)m
(隠居Z) 2022/11/21(月) 23:34:37

おはよう〜ございます。^^
ツッコミどころ満載のコードだと思います。A^^;

シート名 Sheet1 が処理対象です。
停止は止まるまでESCを押し下げて下さいませ。
エラー処理は御座いません。

ご考察の際、何かの参考にでもなれば幸甚です。
お役に立たなければゴミ箱ポイお願いいたします。(*^^*)
きっと、もっとスマートな方法が有ると思います。でわ
m(_ _)m

 Option Explicit
#If Win64 Then
    Declare PtrSafe Function GetAsyncKeyState Lib "User32.dll" (ByVal vKey As Long) As Long
#Else
    Declare Function GetAsyncKeyState Lib "User32.dll" (ByVal vKey As Long) As Long
#End If
Dim sp() As Object
Dim ws1 As Worksheet
Sub OneInstanceMain()
    Dim iMax          As Long
    wsini
    accept iMax
    wsset iMax
    shapemove iMax
    Erase sp
    End
End Sub
Private Sub wsini()
    Dim i As Long
    Dim oldSp As Variant
    Set ws1 = Worksheets("Sheet1")
    With ws1
        .Cells.Clear
        For Each oldSp In .Shapes
            If oldSp.Type <> 8 Then
                oldSp.Delete
            End If
        Next
    End With
End Sub
Private Sub accept(ByRef x As Long)
    Dim myNum         As Variant
    Dim inv_flg       As Boolean
    Do
        myNum = Application.InputBox("4〜20くらいの偶数を入れてください", "図の数入力", 16, , , , , 1)
        If myNum = False Then
            Erase sp
            inv_flg = True
            Exit Do
        End If
        If myNum < 4 Or myNum > 20 Or myNum Mod 2 = 1 Then
            MsgBox "4〜20の偶数を入力してください"
        Else
            x = myNum
            Exit Do
        End If
    Loop
    If inv_flg Then End
End Sub
Private Sub wsset(ByVal iMax As Long)
    Dim i             As Long
    Dim r             As Range
    With ws1
        Set r = .Range("B5")
        ReDim sp(1 To iMax)
        Set sp(1) = .Shapes.AddShape(Type:=msoShapeHeart, Left:=r.Left, Top:=r.Top, Width:=35, Height:=35)
        For i = 2 To iMax
            Set sp(i) = sp(1).Duplicate
            Set r = r.Offset(1)
        Next
    End With
End Sub
Private Sub shapemove(ByVal iMax As Long)
    Dim rr            As Range
    Dim rng()         As Range
    Dim r()           As Range
    Dim i             As Long
    Dim y             As Long
    Dim x             As Long
    Dim cnt           As Long
    Dim rNum          As Long
    ReDim rng(1 To iMax, 1 To 1)
    ReDim r(1 To iMax)
    With ws1
        Set rr = .Range("B3:N29")
        kensukeisan iMax, x
        '* Roop Start A ************************************************************
        Do
            If GetAsyncKeyState(&H1B) Then Exit Do
            cnt = cnt + 1
        '* Roop Start B ************************************************************
            Do
                For i = 1 To iMax
                    rNum = Int((rr.Count - 1 + 1) * Rnd + 1)
                    Set rng(i, 1) = rr.Cells(rNum).Offset(-2).Resize(4, 1)
                    Set r(i) = rr.Cells(rNum)
                Next
                If kasanari_kakunin(rng, x) Then Exit Do
                y = y + 1
                If y Mod 32 = 0 Then
                    DoEvents
                    y = 0
                End If
            Loop
            For i = 1 To iMax
                With sp(i)
                    .Left = r(i).Left
                    .Top = r(i).Top
                    .Width = 35
                    .Height = 35
                    .IncrementRotation 360 * Rnd()
                End With
            Next
        'Roop End A ***************************************************************
            If cnt Mod 16 = 0 Then
                DoEvents
                cnt = 0
            End If
        Loop
        '* Roop End B **************************************************************
    End With
    Erase rng, r
End Sub
Private Function kasanari_kakunin(ByRef v() As Range, ByVal x As Long) As Boolean
    Dim i             As Long
    Dim k             As Long
    Dim j             As Long
    Dim a             As Long
    Dim tmp           As Range
    i = 1
    Do
        For k = i To UBound(v, 1) - 1
            Set tmp = v(i, 1)
            j = j + 1
            If Intersect(tmp, v(k + 1, 1)) Is Nothing Then
                a = a + 1
            End If
        Next
        i = i + 1
        If i Mod 8 = 0 Then DoEvents
        If i >= UBound(v, 1) Then Exit Do
    Loop
    If a = x Then kasanari_kakunin = True
End Function
Private Sub kensukeisan(ByVal c As Long, ByRef x As Long)
    Dim i             As Long
    Dim a             As Long
    For i = 1 To c - 1
        a = a + i
    Next
    x = a
End Sub
(隠居Z) 2022/11/22(火) 10:22:56

隠居Zさん

お忙しいところ,このような大量のコードを作成くださり本当にありがとうございます。いま実行して希望の通り動いていることを確認いたしました。

一つだけお願いがございます。実行すると,ランダムに配置されている様子が示されますが,これを最終結果だけ(つまり実行ボタンを押して,重ならないことが確認できれば,一発で表示される)ようにしていただくことはできますでしょうか。
(REI) 2022/11/22(火) 10:52:10


Private Sub shapemove(ByVal iMax As Long)
の、コメント
Roop Start A 〜  Roop Start B

Roop End A 〜 Roop End B
をコメントアウトするか、消して
印刷範囲外に、フォームコントロールのボタン[type=8]
を貼り付けて、このマクロを登録すれば、ボタンを押せば
変化すると思います。

追伸
1.サイズは独断で半分の35に設定。m(__)m
2.用紙サイズB4 配置 横置き 余白 狭いに収まるかと思います。
3.タイプが8のフォームコントロールのボタンを印刷範囲以外に設置して
  マクロを実行すれば視認しやすいですよ。[初期化でボタンだけ消さない様に
  しています。^^]
私のスキルでは。。。2.条件下では
シェイプ枚数 20
サイズ    50
Set rng(i, 1) = rr.Cells(rNum).Offset(-1).Resize(5, 2)
【うん?サイズが50以下なら、オフセットは要らないかも。w】
くらいが、限界かも。。。きちんと、計算して、必要範囲を
算出する、ロジックを追加すれば良いのでせうが。何分、足し算と
引き算くらいしか理解致しておりませんので、目分量と10本の指数えて
やっていますのでご容赦を。数学に明るい方に笑われソぉですね。とほほ〜。。。(◎_◎;)
きっと、更なる、アドバイスが有るかと思います。。。←多分。^^;
でわ
頑張ってくださいね。m(__)m
(隠居Z) 2022/11/22(火) 11:40:01


 Private Sub shapemove(ByVal iMax As Long)
    Dim rr            As Range
    Dim rng()         As Range
    Dim r()           As Range
    Dim i             As Long
    Dim y             As Long
    Dim x             As Long
    Dim cnt           As Long
    Dim rNum          As Long
    ReDim rng(1 To iMax, 1 To 1)
    ReDim r(1 To iMax)
    With ws1
        Set rr = .Range("B4:N29")
        kensukeisan iMax, x
        '* Roop Start A ************************************************************
'        Do
'            If GetAsyncKeyState(&H1B) Then Exit Do
'            cnt = cnt + 1
        '* Roop Start B ************************************************************
            Do
                For i = 1 To iMax
                    rNum = Int((rr.Count - 1 + 1) * Rnd + 1)
                    Set rng(i, 1) = rr.Cells(rNum).Resize(5, 1)
                    Set r(i) = rr.Cells(rNum)
                Next
                If kasanari_kakunin(rng, x) Then Exit Do
                y = y + 1
                If y Mod 32 = 0 Then
                    DoEvents
                    y = 0
                End If
            Loop
            For i = 1 To iMax
                With sp(i)
                    .Left = r(i).Left
                    .Top = r(i).Top
                    .Width = 50
                    .Height = 50
                    .IncrementRotation 360 * Rnd()
                End With
            Next
        'Roop End A ***************************************************************
'            If cnt Mod 16 = 0 Then
'                DoEvents
'                cnt = 0
'            End If
'        Loop
        '* Roop End B **************************************************************
    End With
    Erase rng, r
End Sub

最上部の宣言部

 '#If Win64 Then
 '    Declare PtrSafe Function GetAsyncKeyState Lib "User32.dll" (ByVal vKey As Long) As Long
 '#Else
 '    Declare Function GetAsyncKeyState Lib "User32.dll" (ByVal vKey As Long) As Long
 '#End If

です。解りにくい説明で済みませんでした。
けど、あまり大きく変化しないみたいで
変更せずに、ボタンだけ設置して
押してはESCで止めて、を繰り返してお気に入りのパターンを
探した方が早いかもですね^^;
m(_ _)m
(隠居Z) 2022/11/22(火) 14:12:19


あ、大ポカ、やっていました^^;
Private Sub shapemove(ByVal iMax As Long)
    Dim rr            As Range
    Dim rng()         As Range
    Dim r()           As Range
    Dim i             As Long
    Dim y             As Long
    Dim x             As Long
    Dim cnt           As Long
    Dim rNum          As Long
    Randomize
    ReDim rng(1 To iMax, 1 To 1)

Randomize
を入れて下さい。一回でも大きく、変化します。m(__)m
すみませ〜〜〜ん。m(__)m
(隠居Z) 2022/11/22(火) 14:18:09


 目的とかの説明がないので躊躇していましたが、
 知らんぷりも大人げないので、トライしてみました。参考にしてください。
 既に回答をいただいていますので、参考出品と言うことです。

 ・A4縦を想定(変更は可能。■部分のコードを修正のこと)
 ・シートは特定していませんので、アクティブなシートが処理対象となります。

 【使用方法】
 ・標準モジュールに全体をコピーし
 ・マクロmainをフォームコントロールのボタンに登録してください。

 ・mainを実行すると、作成枚数をInputBoxで求められます。
 ・処理が完成すると、作成枚数を表示します。
 ・乱数処理の結果、試行回数をオーバーすると、その旨メッセージが出るので、
   mainを再実行してください。(図形は削除するので、そのまま再実行で可)

 コードは少し怪しい前提を置いていますが、適当に修正してもらって結構です。

 Option Explicit

 Dim rng As Range                    'A4の対象セル範囲
 Dim numberOfShapes As Long          '作成したい図形の数
 Const maxCnt As Long = 10000        '図形作成の試行回数上限(仮置き)

 Dim boundX1#, boundX2#, boundY1#, boundY2#

 Sub main()
     Dim sp As Shape
     Dim cond As Boolean
     Dim k&, j&
     Dim boundaryTmp As Variant
     Dim cnt As Long
     Dim s As Variant

     numberOfShapes = InputBox("作成する図形の数を入力(10〜20程度)")

     Application.ScreenUpdating = False

     'Rnd -1     '乱数固定(debug用)
     Randomize

     '印刷範囲
     Set rng = [A1:H39]                          '■■■■要修正

     'オートシェイプを削除
     For Each s In ActiveSheet.Shapes
         If s.Type = msoAutoShape Then
             s.Delete
         End If
     Next

     '元になる図形
     With Range("B2")
         Set sp = ActiveSheet.Shapes.AddShape(Type:=msoShapeHeart, _
                     Left:=.Left, Top:=.Top, Width:=70, Height:=70)
     End With

     '回転してはみ出さない条件下での、図形中心の採り得る範囲を定める
     Call SetRangeBoundary(sp, rng)

     ReDim shp(1 To numberOfShapes) As Shape         '図形
     ReDim boundary(1 To numberOfShapes) As Variant  'その上限下限(x,y軸ごとに)

     Set shp(1) = sp.Duplicate
     Call setRandomPosition(shp(1))      'ランダムに位置をセット
     boundary(1) = getBoundary(shp(1))   '回転領域の外接正方形の位置(4点)
     sp.Delete

     k = 2
     Do
         Set shp(k) = shp(k - 1).Duplicate
 line1:
         cnt = cnt + 1                       '処理回数カウント
         If cnt > maxCnt Then MsgBox "回数オーバー": Exit Sub

         Call setRandomPosition(shp(k))      'ランダムに位置をセット

         boundaryTmp = getBoundary(shp(k))   '回転領域の外接正方形の位置(4点)

         For j = 1 To k - 1
             '既存の図形と重なるかをチェック
             '重なっていれば、冒頭に戻って、図形の位置を設定しなす
             cond = isDuplicate(boundaryTmp, boundary(j))
             If cond = True Then
                 GoTo line1
             End If
         Next
         boundary(k) = boundaryTmp
         k = k + 1
         DoEvents
     Loop Until k >= (numberOfShapes + 1)

     Call rotate                             '各図形をランダムに回転
     Application.ScreenUpdating = True

     Debug.Print cnt
     Dim shapesCount As Long
     For Each s In ActiveSheet.Shapes
         If s.Type = msoAutoShape Then
             shapesCount = shapesCount + 1
         End If
     Next
     MsgBox "図形の数  " & shapesCount
 End Sub
 Function SetRangeBoundary(sp As Shape, rng As Range)
     Dim r#
 '    r = ((sp.Height) ^ 2 + sp.Width ^ 2) ^ 0.5
     r = sp.Height * 1.2     'テキトーに狭くしてみた
     With rng
         boundX1 = .Left + r / 2
         boundX2 = .Left + .Width - r / 2
         boundY1 = .Top + r / 2
         boundY2 = .Top + .Height - r / 2
     End With
 End Function

 Function setRandomPosition(shp As Shape)
     Dim x#, y#
     x = boundX1 + Rnd() * (boundX2 - boundX1)
     y = boundY1 + Rnd() * (boundY2 - boundY1)
     shp.Left = x - shp.Width / 2
     shp.Top = y - shp.Height / 2
 End Function

 Function getBoundary(sp As Shape) As Variant
     Dim r#
     Dim boundX1#, boundX2#, boundY1#, boundY2#

 '    r = ((sp.Height) ^ 2 + sp.Width ^ 2) ^ 0.5
     r = sp.Height * 1.2     'テキトーなものに変更

     With sp
         boundX1 = .Left + .Width / 2 - r / 2
         boundX2 = .Left + .Width / 2 + r / 2
         boundY1 = .Top + .Height / 2 - r / 2
         boundY2 = .Top + .Height / 2 + r / 2
     End With
     getBoundary = Array(boundX1, boundX2, boundY1, boundY2)
 End Function

 '二つの長方形が重なっているかのチェック(重なる→True)
 Function isDuplicate(bound1 As Variant, bound2 As Variant) As Boolean
     Dim x11#, x12#, y11#, y12#
     Dim x21#, x22#, y21#, y22#
     Dim checkX As Boolean
     Dim checkY As Boolean

     x11 = bound1(0):  x12 = bound1(1):  y11 = bound1(2): y12 = bound1(3)
     x21 = bound2(0):  x22 = bound2(1):  y21 = bound2(2): y22 = bound2(3)

     If x11 >= x21 And x22 >= x11 Then
         checkX = True
     ElseIf (x21 >= x11 And x12 >= x21) Then
         checkX = True
     End If

     If y11 >= y21 And y22 >= y11 Then
         checkY = True
     ElseIf (y21 >= y11 And y12 >= y21) Then
         checkY = True
     End If
     isDuplicate = checkX And checkY
 End Function

 Sub rotate()
     Dim rot As Double
     Dim shp As Shape
     For Each shp In ActiveSheet.Shapes
         If shp.Type = msoAutoShape Then    'オートシェイプに限定
             If Not Intersect(shp.TopLeftCell, rng) Is Nothing Then
                 rot = 360 * Rnd()
                 shp.IncrementRotation rot   'ランダムに回転
             End If
         End If
     Next
 End Sub

 【メモ】
 ・もともと、重ならないという互いに関係のあるものを乱数で決めていくのは、
   数が少なければいいですが、数が多くなると効率は悪くなります。
   20でも1万回を超える試行になることも結構あります。
   22くらいが限界かもしれません。
   (別のアプローチとして、ある程度規則にしたがった配置を行ったうえで、
   それぞれを多少ランダムに動かすという方式を取った方がよいものと思います。)

 ・試行回数限度を超えた場合、何段階か元に戻って再実行する方法もありますが、
   失敗したら、最初からやり直すという方式です。

 ・回転を考えると、対角線を直径とする円になりますから、
   本来はそれを考慮すべきかもしれません(図形が長方形そのものなどの場合)。
   ハート形だと、実際の色付き部分は枠の長方形より狭くなるので、
   本来のものより、少し小さい回転図形を考えても、実際は影響ないとみなして、
   1.414倍を1.2倍くらいに節約しています。
 ・乱数で作成しているので、逆に10個くらいのときは、配置に偏りがでます。
   これに関する修正はするつもりはありません。
  (11/23 procedureのスペルミスを修正しました) 
 
(γ) 2022/11/22(火) 15:13:13

隠居Zさん、γさん

なんとお礼を申し上げたらよいのかわかりません。お二人には長時間費やしてもらって本当に申し訳ございませんでした。私の考えをうまく反映してくださいました。本当にありがとうございました。またγさんには不快な思いをさせてしまい、申し訳ございませんでした。

ありがとうございました。
(REI) 2022/11/22(火) 16:57:30


コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.