回答編集履歴

2

見直しキャンペーン中

2023/07/17 06:32

投稿

TN8001
TN8001

スコア9326

test CHANGED
@@ -1,495 +1,248 @@
1
1
  少なくともxamlを数行足すって程度では、できそうにもないですね。
2
-
3
2
  何かライブラリ等はないかなとも思いましたが、見つけられませんでした。
4
3
 
5
-
6
-
7
4
  案1 `OpenCV`的なもので画像を加工して重ねる。
8
-
9
5
  パフォーマンスもよさそうですし、コード量も少なそう。
10
-
11
6
  (私は魚眼にする方法は知りません^^;)
12
7
 
13
-
14
-
15
8
  案2 球に適当に切り出した画像をマテリアルにマップし続ける。
16
-
17
9
  雑に試してみましたが、特に重くはならず使えなくはないって感じでした。
18
-
19
10
  (自分でもよくわかっていない、雑なC#コードでよければ出せます)
20
11
 
21
-
22
-
23
12
  参考コード追記
24
13
 
25
-
26
-
27
14
  ---
28
15
 
29
-
30
-
31
16
  画像を加工パターン
32
-
33
17
  OpenCVとかわからないですが、GitHubでピュアC#のものを見つけたので試してみました。
34
-
35
18
  [AnthonyNystrom/GenXSource: Genetibase related source code](https://github.com/AnthonyNystrom/GenXSource) (どういったリポジトリなのか全くわかってません^^;)
36
19
 
37
-
38
-
39
20
  [IFilter.cs](https://github.com/AnthonyNystrom/GenXSource/blob/master/Other/N2F/Src/ImageWorks/Next2Friends.ImageWorks.Filters/IFilter.cs)
40
-
41
21
  [EffectFilter.cs](https://github.com/AnthonyNystrom/GenXSource/blob/master/Other/N2F/Src/ImageWorks/Next2Friends.ImageWorks.Filters/EffectsFilters/EffectFilter.cs)
42
-
43
22
  [FishEye.cs](https://github.com/AnthonyNystrom/GenXSource/blob/master/Other/N2F/Src/ImageWorks/Next2Friends.ImageWorks.Filters/EffectsFilters/FishEye.cs)
44
-
45
23
  上記3つをプロジェクトに追加(ライセンスが明示されていないので注意してください)
46
24
 
47
25
 
48
-
49
-
50
-
51
- ```xaml
26
+ ```xml
52
-
53
27
  <Window
54
-
55
28
  x:Class="Questions228869.MainWindow"
56
-
57
29
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
58
-
59
30
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
60
-
61
31
  Title="Fisheye"
62
-
63
32
  MouseMove="Window_MouseMove"
64
-
65
33
  SizeToContent="WidthAndHeight">
66
-
67
34
  <Window.Resources>
68
-
69
35
  <BitmapImage x:Key="earthImage" UriSource="Image/1280px-Tissot_indicatrix_world_map_Lambert_cyl_equal-area_proj.svg.png" />
70
-
71
36
  </Window.Resources>
72
37
 
73
-
74
-
75
38
  <Canvas Width="400" Height="300">
76
-
77
39
  <Image x:Name="sourceImage" Source="{StaticResource earthImage}" />
78
-
79
40
  <Image
80
-
81
41
  x:Name="zoomImage"
82
-
83
42
  Width="100"
84
-
85
43
  Height="100" />
86
44
 
87
-
88
-
89
45
  </Canvas>
90
-
91
46
  </Window>
92
-
93
- ```
47
+ ```
94
-
95
-
96
-
48
+
97
- ```C#
49
+ ```cs
98
-
99
50
  using System;
100
-
101
51
  using System.Windows;
102
-
103
52
  using System.Windows.Controls;
104
-
105
53
  using System.Windows.Input;
106
-
107
54
  using System.Windows.Media;
108
-
109
55
  using System.Windows.Media.Imaging;
110
-
111
56
  using Next2Friends.ImageWorks.EffectsFilters;
112
57
 
113
-
114
-
115
58
  namespace Questions228869
116
-
117
59
  {
118
-
119
60
  public partial class MainWindow : Window
120
-
121
61
  {
122
-
123
62
  private readonly RenderTargetBitmap inflateImage;
124
-
125
63
  private const double offset = 200;
126
-
127
64
  private int lastTimestamp;
128
65
 
129
-
130
-
131
66
  public MainWindow()
132
-
133
- {
67
+ {
134
-
135
68
  InitializeComponent();
136
69
 
137
-
138
-
139
70
  // CroppedBitmapで例外が出るのでひと回り大きい画像を作る
140
-
141
71
  var image = (BitmapImage)Resources["earthImage"];
142
-
143
72
  var visual = new DrawingVisual();
144
-
145
73
  var dc = visual.RenderOpen();
146
-
147
74
  var rect = new Rect(0, 0, image.PixelWidth + offset * 2, image.PixelHeight + offset * 2);
148
-
149
75
  dc.DrawRectangle(Brushes.White, null, rect);
150
-
151
76
  dc.DrawImage(image, new Rect(offset, offset, image.PixelWidth, image.PixelHeight));
152
-
153
77
  dc.Close();
154
78
 
155
-
156
-
157
79
  inflateImage = new RenderTargetBitmap((int)rect.Width, (int)rect.Height, 96, 96, PixelFormats.Pbgra32);
158
-
159
80
  inflateImage.Render(visual);
160
-
161
- }
81
+ }
162
-
163
-
164
82
 
165
83
  private void Window_MouseMove(object sender, MouseEventArgs e)
166
-
167
- {
84
+ {
168
-
169
85
  // GCが走り続けて引っかかるので適当に間引く
170
-
171
86
  if(Math.Abs(e.Timestamp - lastTimestamp) < 20) return;
172
-
173
87
  lastTimestamp = e.Timestamp;
174
88
 
175
-
176
-
177
89
  var p = e.GetPosition(sourceImage);
178
90
 
179
-
180
-
181
91
  zoomImage.SetValue(Canvas.LeftProperty, p.X - zoomImage.Width / 2);
182
-
183
92
  zoomImage.SetValue(Canvas.TopProperty, p.Y - zoomImage.Height / 2);
184
93
 
185
-
186
-
187
94
  var ratioX = sourceImage.Source.Width / sourceImage.ActualWidth;
188
-
189
95
  var ratioY = sourceImage.Source.Height / sourceImage.ActualHeight;
190
96
 
191
-
192
-
193
97
  var sourceX = ratioX * p.X;
194
-
195
98
  var sourceY = ratioY * p.Y;
196
99
 
197
-
198
-
199
100
  var w = ratioX * zoomImage.Width;
200
-
201
101
  var h = ratioY * zoomImage.Height;
202
-
203
102
  var x = sourceX - w / 2 + offset;
204
-
205
103
  var y = sourceY - h / 2 + offset;
206
-
207
104
  var rect = new Int32Rect((int)x, (int)y, (int)w, (int)h);
208
-
209
105
  try
210
-
211
106
  {
212
-
213
107
  var croppedBitmap = new CroppedBitmap(inflateImage, rect);
214
-
215
108
  zoomImage.Source = new FisheyeFilter(0.1f).ExecuteFilter(croppedBitmap);
216
-
217
109
  }
218
-
219
110
  catch { /* NOP CroppedBitmapが範囲外 */ }
220
-
221
- }
111
+ }
222
-
223
112
  }
224
-
225
113
  }
226
-
227
- ```
114
+ ```
228
-
229
-
230
115
 
231
116
  使用感
232
-
233
117
  * 画像を凸に加工しているので境目が見えなくて見た目はよい。
234
-
235
118
  * GCが走り続けて引っかかるので、適度に間引いたところまあまあ使えるかなと(高速化の余地はまだまだあるので、不満ならどうにかなる)
236
-
237
119
  * 原寸表示だと1ドットの線とかが荒れがち。
238
-
239
120
  ![イメージ説明](0d9b8293e9216706e81519b0a5011945.png)
240
-
241
121
  ---
242
122
 
243
123
 
244
-
245
-
246
-
247
124
  球体に貼るパターン
248
-
249
125
  [WPF で 3D(その5) : リード開発メモ](http://freed411.doorblog.jp/archives/31528830.html)
250
-
251
126
  基本的にはここの通り。
252
-
253
127
  `Primitive3D`と`Sphere3D`をプロジェクトに追加、`GetTextureCoordinate`を修正(元ネタはMicrosoftのサンプル 解凍時に使用許諾が出るので確認してください)
254
-
255
128
  xamlで書けることはできるだけ移したため、csは跡形ないです。
256
129
 
257
-
258
-
259
130
  ほか参考にしたサイト [WPF で地球を回してみるテスト - CX's Hatena Blog](http://cx20.hatenablog.com/entry/2014/02/11/215835)
260
131
 
261
-
262
-
263
- ```xaml
132
+ ```xml
264
-
265
133
  <Window
266
-
267
134
  x:Class="Questions228869.MainWindow"
268
-
269
135
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
270
-
271
136
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
272
-
273
137
  xmlns:local="clr-namespace:Questions228869"
274
-
275
138
  Title="Sphere3D"
276
-
277
139
  MouseMove="Window_MouseMove"
278
-
279
140
  SizeToContent="WidthAndHeight">
280
-
281
141
  <Window.Resources>
282
-
283
142
  <BitmapImage x:Key="earthImage" UriSource="Image/1280px-Tissot_indicatrix_world_map_Lambert_cyl_equal-area_proj.svg.png" />
284
-
285
143
  </Window.Resources>
286
144
 
287
-
288
-
289
145
  <Canvas Width="400" Height="300">
290
-
291
146
  <Image x:Name="sourceImage" Source="{StaticResource earthImage}" />
292
-
293
147
  <Viewport3D
294
-
295
148
  x:Name="viewport"
296
-
297
149
  Width="100"
298
-
299
150
  Height="100">
300
-
301
151
  <Viewport3D.Camera>
302
-
303
152
  <PerspectiveCamera
304
-
305
153
  LookDirection="0,0,-1"
306
-
307
154
  Position="0,0,3"
308
-
309
155
  UpDirection="0,1,0" />
310
-
311
156
  </Viewport3D.Camera>
312
-
313
157
  <ModelVisual3D>
314
-
315
158
  <ModelVisual3D.Content>
316
-
317
159
  <Model3DGroup>
318
-
319
160
  <AmbientLight Color="#ffffff" />
320
-
321
161
  <DirectionalLight Direction="-1,-1,-1" Color="#ffffff" />
322
-
323
162
  </Model3DGroup>
324
-
325
163
  </ModelVisual3D.Content>
326
-
327
164
  </ModelVisual3D>
328
-
329
165
  <local:Sphere3D x:Name="sphere" />
330
-
331
166
  </Viewport3D>
332
167
 
333
-
334
-
335
168
  </Canvas>
336
-
337
169
  </Window>
338
-
339
- ```
170
+ ```
340
-
341
-
342
-
171
+
343
- ```C#
172
+ ```cs
344
-
345
173
  using System;
346
-
347
174
  using System.Windows;
348
-
349
175
  using System.Windows.Controls;
350
-
351
176
  using System.Windows.Input;
352
-
353
177
  using System.Windows.Media;
354
-
355
178
  using System.Windows.Media.Imaging;
356
-
357
179
  using System.Windows.Media.Media3D;
358
180
 
359
-
360
-
361
181
  namespace Questions228869
362
-
363
182
  {
364
-
365
183
  public partial class MainWindow : Window
366
-
367
184
  {
368
-
369
185
  private readonly RenderTargetBitmap inflateImage;
370
-
371
186
  // 倍率 それっぽくなるように現物合わせ
372
-
373
187
  private const double scale = 0.85;
374
-
375
188
  // 球に巻き始める余白部分 6時が正面とすると3時から反時計回り?
376
-
377
189
  private const double offset = cropWidth / 4 * 3;
378
-
379
190
  // 球に巻く画像の幅 高さから逆算
380
-
381
191
  private const double cropWidth = Math.PI * cropHeight * scale;
382
-
383
192
  // 球に巻く画像の高さ viewport.Height に合わせた 特に根拠なし
384
-
385
193
  private const double cropHeight = 100 * scale;
386
194
 
387
-
388
-
389
195
  public MainWindow()
390
-
391
- {
196
+ {
392
-
393
197
  InitializeComponent();
394
198
 
395
-
396
-
397
199
  // CroppedBitmapで例外が出るのでひと回り大きい画像を作る
398
-
399
200
  // 上下右はもっと小さくていいが面倒なので全方向同じ数字で広げた
400
-
401
201
  var image = (BitmapImage)Resources["earthImage"];
402
-
403
202
  var visual = new DrawingVisual();
404
-
405
203
  var dc = visual.RenderOpen();
406
-
407
204
  var rect = new Rect(0, 0, image.PixelWidth + offset * 2, image.PixelHeight + offset * 2);
408
-
409
205
  dc.DrawRectangle(Brushes.White, null, rect);
410
-
411
206
  dc.DrawImage(image, new Rect(offset, offset, image.PixelWidth, image.PixelHeight));
412
-
413
207
  dc.Close();
414
208
 
415
-
416
-
417
209
  inflateImage = new RenderTargetBitmap((int)rect.Width, (int)rect.Height, 96, 96, PixelFormats.Pbgra32);
418
-
419
210
  inflateImage.Render(visual);
420
-
421
- }
211
+ }
422
-
423
-
424
212
 
425
213
  private void Window_MouseMove(object sender, MouseEventArgs e)
426
-
427
- {
214
+ {
428
-
429
215
  var p = e.GetPosition(sourceImage);
430
216
 
431
-
432
-
433
217
  viewport.SetValue(Canvas.LeftProperty, p.X - viewport.Width / 2);
434
-
435
218
  viewport.SetValue(Canvas.TopProperty, p.Y - viewport.Height / 2);
436
219
 
437
-
438
-
439
220
  var ratioX = sourceImage.Source.Width / sourceImage.ActualWidth;
440
-
441
221
  var ratioY = sourceImage.Source.Height / sourceImage.ActualHeight;
442
222
 
443
-
444
-
445
223
  var sourceX = ratioX * p.X;
446
-
447
224
  var sourceY = ratioY * p.Y;
448
225
 
449
-
450
-
451
226
  var x = sourceX; // 巻き始め分を大きくしたのでちょうどxで合う
452
-
453
227
  var y = sourceY - cropHeight / 2 + offset;
454
-
455
228
  var rect = new Int32Rect((int)x, (int)y, (int)cropWidth, (int)cropHeight);
456
-
457
229
  try
458
-
459
230
  {
460
-
461
231
  var croppedBitmap = new CroppedBitmap(inflateImage, rect);
462
-
463
232
  sphere.Material = new DiffuseMaterial(new ImageBrush(croppedBitmap));
464
-
465
233
  }
466
-
467
234
  catch { /* NOP CroppedBitmapが範囲外 */ }
468
-
469
- }
235
+ }
470
-
471
236
  }
472
-
473
237
  }
474
-
475
- ```
238
+ ```
476
-
477
-
478
239
 
479
240
  使用感
480
-
481
241
  * 球なので境目がわかってしまう。
482
-
483
242
  * パフォーマンスはよい(特に間引いていなくても普通に使えてる)
484
-
485
243
  * 大きさの調整等がめんどくさい。
486
-
487
244
  * 凸度?の調整が効かない。
488
-
489
245
  ![イメージ説明](79c4d0cd6210686ff1a91ca34d7179af.png)
490
-
491
246
  ---
492
247
 
493
-
494
-
495
248
  使用画像 1280x407 [テイソーの指示楕円-ランベルト正積円筒図法の場合](https://upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Tissot_indicatrix_world_map_Lambert_cyl_equal-area_proj.svg/1280px-Tissot_indicatrix_world_map_Lambert_cyl_equal-area_proj.svg.png)

1

コード追記

2019/12/14 14:07

投稿

TN8001
TN8001

スコア9326

test CHANGED
@@ -17,3 +17,479 @@
17
17
  雑に試してみましたが、特に重くはならず使えなくはないって感じでした。
18
18
 
19
19
  (自分でもよくわかっていない、雑なC#コードでよければ出せます)
20
+
21
+
22
+
23
+ 参考コード追記
24
+
25
+
26
+
27
+ ---
28
+
29
+
30
+
31
+ 画像を加工パターン
32
+
33
+ OpenCVとかわからないですが、GitHubでピュアC#のものを見つけたので試してみました。
34
+
35
+ [AnthonyNystrom/GenXSource: Genetibase related source code](https://github.com/AnthonyNystrom/GenXSource) (どういったリポジトリなのか全くわかってません^^;)
36
+
37
+
38
+
39
+ [IFilter.cs](https://github.com/AnthonyNystrom/GenXSource/blob/master/Other/N2F/Src/ImageWorks/Next2Friends.ImageWorks.Filters/IFilter.cs)
40
+
41
+ [EffectFilter.cs](https://github.com/AnthonyNystrom/GenXSource/blob/master/Other/N2F/Src/ImageWorks/Next2Friends.ImageWorks.Filters/EffectsFilters/EffectFilter.cs)
42
+
43
+ [FishEye.cs](https://github.com/AnthonyNystrom/GenXSource/blob/master/Other/N2F/Src/ImageWorks/Next2Friends.ImageWorks.Filters/EffectsFilters/FishEye.cs)
44
+
45
+ 上記3つをプロジェクトに追加(ライセンスが明示されていないので注意してください)
46
+
47
+
48
+
49
+
50
+
51
+ ```xaml
52
+
53
+ <Window
54
+
55
+ x:Class="Questions228869.MainWindow"
56
+
57
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
58
+
59
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
60
+
61
+ Title="Fisheye"
62
+
63
+ MouseMove="Window_MouseMove"
64
+
65
+ SizeToContent="WidthAndHeight">
66
+
67
+ <Window.Resources>
68
+
69
+ <BitmapImage x:Key="earthImage" UriSource="Image/1280px-Tissot_indicatrix_world_map_Lambert_cyl_equal-area_proj.svg.png" />
70
+
71
+ </Window.Resources>
72
+
73
+
74
+
75
+ <Canvas Width="400" Height="300">
76
+
77
+ <Image x:Name="sourceImage" Source="{StaticResource earthImage}" />
78
+
79
+ <Image
80
+
81
+ x:Name="zoomImage"
82
+
83
+ Width="100"
84
+
85
+ Height="100" />
86
+
87
+
88
+
89
+ </Canvas>
90
+
91
+ </Window>
92
+
93
+ ```
94
+
95
+
96
+
97
+ ```C#
98
+
99
+ using System;
100
+
101
+ using System.Windows;
102
+
103
+ using System.Windows.Controls;
104
+
105
+ using System.Windows.Input;
106
+
107
+ using System.Windows.Media;
108
+
109
+ using System.Windows.Media.Imaging;
110
+
111
+ using Next2Friends.ImageWorks.EffectsFilters;
112
+
113
+
114
+
115
+ namespace Questions228869
116
+
117
+ {
118
+
119
+ public partial class MainWindow : Window
120
+
121
+ {
122
+
123
+ private readonly RenderTargetBitmap inflateImage;
124
+
125
+ private const double offset = 200;
126
+
127
+ private int lastTimestamp;
128
+
129
+
130
+
131
+ public MainWindow()
132
+
133
+ {
134
+
135
+ InitializeComponent();
136
+
137
+
138
+
139
+ // CroppedBitmapで例外が出るのでひと回り大きい画像を作る
140
+
141
+ var image = (BitmapImage)Resources["earthImage"];
142
+
143
+ var visual = new DrawingVisual();
144
+
145
+ var dc = visual.RenderOpen();
146
+
147
+ var rect = new Rect(0, 0, image.PixelWidth + offset * 2, image.PixelHeight + offset * 2);
148
+
149
+ dc.DrawRectangle(Brushes.White, null, rect);
150
+
151
+ dc.DrawImage(image, new Rect(offset, offset, image.PixelWidth, image.PixelHeight));
152
+
153
+ dc.Close();
154
+
155
+
156
+
157
+ inflateImage = new RenderTargetBitmap((int)rect.Width, (int)rect.Height, 96, 96, PixelFormats.Pbgra32);
158
+
159
+ inflateImage.Render(visual);
160
+
161
+ }
162
+
163
+
164
+
165
+ private void Window_MouseMove(object sender, MouseEventArgs e)
166
+
167
+ {
168
+
169
+ // GCが走り続けて引っかかるので適当に間引く
170
+
171
+ if(Math.Abs(e.Timestamp - lastTimestamp) < 20) return;
172
+
173
+ lastTimestamp = e.Timestamp;
174
+
175
+
176
+
177
+ var p = e.GetPosition(sourceImage);
178
+
179
+
180
+
181
+ zoomImage.SetValue(Canvas.LeftProperty, p.X - zoomImage.Width / 2);
182
+
183
+ zoomImage.SetValue(Canvas.TopProperty, p.Y - zoomImage.Height / 2);
184
+
185
+
186
+
187
+ var ratioX = sourceImage.Source.Width / sourceImage.ActualWidth;
188
+
189
+ var ratioY = sourceImage.Source.Height / sourceImage.ActualHeight;
190
+
191
+
192
+
193
+ var sourceX = ratioX * p.X;
194
+
195
+ var sourceY = ratioY * p.Y;
196
+
197
+
198
+
199
+ var w = ratioX * zoomImage.Width;
200
+
201
+ var h = ratioY * zoomImage.Height;
202
+
203
+ var x = sourceX - w / 2 + offset;
204
+
205
+ var y = sourceY - h / 2 + offset;
206
+
207
+ var rect = new Int32Rect((int)x, (int)y, (int)w, (int)h);
208
+
209
+ try
210
+
211
+ {
212
+
213
+ var croppedBitmap = new CroppedBitmap(inflateImage, rect);
214
+
215
+ zoomImage.Source = new FisheyeFilter(0.1f).ExecuteFilter(croppedBitmap);
216
+
217
+ }
218
+
219
+ catch { /* NOP CroppedBitmapが範囲外 */ }
220
+
221
+ }
222
+
223
+ }
224
+
225
+ }
226
+
227
+ ```
228
+
229
+
230
+
231
+ 使用感
232
+
233
+ * 画像を凸に加工しているので境目が見えなくて見た目はよい。
234
+
235
+ * GCが走り続けて引っかかるので、適度に間引いたところまあまあ使えるかなと(高速化の余地はまだまだあるので、不満ならどうにかなる)
236
+
237
+ * 原寸表示だと1ドットの線とかが荒れがち。
238
+
239
+ ![イメージ説明](0d9b8293e9216706e81519b0a5011945.png)
240
+
241
+ ---
242
+
243
+
244
+
245
+
246
+
247
+ 球体に貼るパターン
248
+
249
+ [WPF で 3D(その5) : リード開発メモ](http://freed411.doorblog.jp/archives/31528830.html)
250
+
251
+ 基本的にはここの通り。
252
+
253
+ `Primitive3D`と`Sphere3D`をプロジェクトに追加、`GetTextureCoordinate`を修正(元ネタはMicrosoftのサンプル 解凍時に使用許諾が出るので確認してください)
254
+
255
+ xamlで書けることはできるだけ移したため、csは跡形ないです。
256
+
257
+
258
+
259
+ ほか参考にしたサイト [WPF で地球を回してみるテスト - CX's Hatena Blog](http://cx20.hatenablog.com/entry/2014/02/11/215835)
260
+
261
+
262
+
263
+ ```xaml
264
+
265
+ <Window
266
+
267
+ x:Class="Questions228869.MainWindow"
268
+
269
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
270
+
271
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
272
+
273
+ xmlns:local="clr-namespace:Questions228869"
274
+
275
+ Title="Sphere3D"
276
+
277
+ MouseMove="Window_MouseMove"
278
+
279
+ SizeToContent="WidthAndHeight">
280
+
281
+ <Window.Resources>
282
+
283
+ <BitmapImage x:Key="earthImage" UriSource="Image/1280px-Tissot_indicatrix_world_map_Lambert_cyl_equal-area_proj.svg.png" />
284
+
285
+ </Window.Resources>
286
+
287
+
288
+
289
+ <Canvas Width="400" Height="300">
290
+
291
+ <Image x:Name="sourceImage" Source="{StaticResource earthImage}" />
292
+
293
+ <Viewport3D
294
+
295
+ x:Name="viewport"
296
+
297
+ Width="100"
298
+
299
+ Height="100">
300
+
301
+ <Viewport3D.Camera>
302
+
303
+ <PerspectiveCamera
304
+
305
+ LookDirection="0,0,-1"
306
+
307
+ Position="0,0,3"
308
+
309
+ UpDirection="0,1,0" />
310
+
311
+ </Viewport3D.Camera>
312
+
313
+ <ModelVisual3D>
314
+
315
+ <ModelVisual3D.Content>
316
+
317
+ <Model3DGroup>
318
+
319
+ <AmbientLight Color="#ffffff" />
320
+
321
+ <DirectionalLight Direction="-1,-1,-1" Color="#ffffff" />
322
+
323
+ </Model3DGroup>
324
+
325
+ </ModelVisual3D.Content>
326
+
327
+ </ModelVisual3D>
328
+
329
+ <local:Sphere3D x:Name="sphere" />
330
+
331
+ </Viewport3D>
332
+
333
+
334
+
335
+ </Canvas>
336
+
337
+ </Window>
338
+
339
+ ```
340
+
341
+
342
+
343
+ ```C#
344
+
345
+ using System;
346
+
347
+ using System.Windows;
348
+
349
+ using System.Windows.Controls;
350
+
351
+ using System.Windows.Input;
352
+
353
+ using System.Windows.Media;
354
+
355
+ using System.Windows.Media.Imaging;
356
+
357
+ using System.Windows.Media.Media3D;
358
+
359
+
360
+
361
+ namespace Questions228869
362
+
363
+ {
364
+
365
+ public partial class MainWindow : Window
366
+
367
+ {
368
+
369
+ private readonly RenderTargetBitmap inflateImage;
370
+
371
+ // 倍率 それっぽくなるように現物合わせ
372
+
373
+ private const double scale = 0.85;
374
+
375
+ // 球に巻き始める余白部分 6時が正面とすると3時から反時計回り?
376
+
377
+ private const double offset = cropWidth / 4 * 3;
378
+
379
+ // 球に巻く画像の幅 高さから逆算
380
+
381
+ private const double cropWidth = Math.PI * cropHeight * scale;
382
+
383
+ // 球に巻く画像の高さ viewport.Height に合わせた 特に根拠なし
384
+
385
+ private const double cropHeight = 100 * scale;
386
+
387
+
388
+
389
+ public MainWindow()
390
+
391
+ {
392
+
393
+ InitializeComponent();
394
+
395
+
396
+
397
+ // CroppedBitmapで例外が出るのでひと回り大きい画像を作る
398
+
399
+ // 上下右はもっと小さくていいが面倒なので全方向同じ数字で広げた
400
+
401
+ var image = (BitmapImage)Resources["earthImage"];
402
+
403
+ var visual = new DrawingVisual();
404
+
405
+ var dc = visual.RenderOpen();
406
+
407
+ var rect = new Rect(0, 0, image.PixelWidth + offset * 2, image.PixelHeight + offset * 2);
408
+
409
+ dc.DrawRectangle(Brushes.White, null, rect);
410
+
411
+ dc.DrawImage(image, new Rect(offset, offset, image.PixelWidth, image.PixelHeight));
412
+
413
+ dc.Close();
414
+
415
+
416
+
417
+ inflateImage = new RenderTargetBitmap((int)rect.Width, (int)rect.Height, 96, 96, PixelFormats.Pbgra32);
418
+
419
+ inflateImage.Render(visual);
420
+
421
+ }
422
+
423
+
424
+
425
+ private void Window_MouseMove(object sender, MouseEventArgs e)
426
+
427
+ {
428
+
429
+ var p = e.GetPosition(sourceImage);
430
+
431
+
432
+
433
+ viewport.SetValue(Canvas.LeftProperty, p.X - viewport.Width / 2);
434
+
435
+ viewport.SetValue(Canvas.TopProperty, p.Y - viewport.Height / 2);
436
+
437
+
438
+
439
+ var ratioX = sourceImage.Source.Width / sourceImage.ActualWidth;
440
+
441
+ var ratioY = sourceImage.Source.Height / sourceImage.ActualHeight;
442
+
443
+
444
+
445
+ var sourceX = ratioX * p.X;
446
+
447
+ var sourceY = ratioY * p.Y;
448
+
449
+
450
+
451
+ var x = sourceX; // 巻き始め分を大きくしたのでちょうどxで合う
452
+
453
+ var y = sourceY - cropHeight / 2 + offset;
454
+
455
+ var rect = new Int32Rect((int)x, (int)y, (int)cropWidth, (int)cropHeight);
456
+
457
+ try
458
+
459
+ {
460
+
461
+ var croppedBitmap = new CroppedBitmap(inflateImage, rect);
462
+
463
+ sphere.Material = new DiffuseMaterial(new ImageBrush(croppedBitmap));
464
+
465
+ }
466
+
467
+ catch { /* NOP CroppedBitmapが範囲外 */ }
468
+
469
+ }
470
+
471
+ }
472
+
473
+ }
474
+
475
+ ```
476
+
477
+
478
+
479
+ 使用感
480
+
481
+ * 球なので境目がわかってしまう。
482
+
483
+ * パフォーマンスはよい(特に間引いていなくても普通に使えてる)
484
+
485
+ * 大きさの調整等がめんどくさい。
486
+
487
+ * 凸度?の調整が効かない。
488
+
489
+ ![イメージ説明](79c4d0cd6210686ff1a91ca34d7179af.png)
490
+
491
+ ---
492
+
493
+
494
+
495
+ 使用画像 1280x407 [テイソーの指示楕円-ランベルト正積円筒図法の場合](https://upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Tissot_indicatrix_world_map_Lambert_cyl_equal-area_proj.svg/1280px-Tissot_indicatrix_world_map_Lambert_cyl_equal-area_proj.svg.png)