公開しました。
ボイスタイマー - Google Play の Android アプリ
よろしければお使いください。
何かあってもいきなり星1つとかなさらずに。
ご意見いただければと思います…。
アイコン描いた。今風にしてみた。
どんなソフトか分かるかなぁ…。
各サイズのアイコンを作成するのに以下のサイトが便利でした。
Makeappicon - Generate app icons of all sizes with a click!
これで公開できるかな。
だいぶ出来てきた。
要は手放しで使えるタイマーを作っています。
ユーザーが「10秒!」と言うと
「10秒、9秒、8秒…」と声でカウントダウンしてくれるようなタイマー。
テストで「12秒!」と言ったらこの認識結果…。
要調整。
Androidスマホにして、せっかくプログラマブルな端末を手にしたのだから
日常の不便をプログラムで解決してしまいたい。
まずは下調べ。Androidの音声入力、認識、発声ってどんな感じなのかなと。
良いサイトがあった。
Androidで音声入力した内容を認識し,そのまま音声合成。「おうむ返し」アプリのソースコード - 主に言語とシステム開発に関して
ソースコードをコピペして起動…
くりま「Ten minutes before 8 o'clock!
アプリ「ten minutes before 8 o clock
お~。すごい。流暢にオウム返ししてくれる。
こんなんがつくれちゃうのかぁー。
日本語入力だとどうなんだろ。
でも、なんとなく行けそうな予感。
前回の続き。
WPFを使って実験用アプリを作ってみた。
試してみるとズームアウトがどうもじれったい。
実際現実世界もこんなかんじかもと思いつつも使いづらいのはよろしくない。
そこで、ズームアウト時の拡大率にはズームイン時の拡大率の逆数使うようにしてみた。
それが上のチェックボックス。
いいような気もするが、そんなことするならなんでモデリングしたんだっけか…。
以下ソースコード。
MainWindow.xaml
<Window x:Class="ImageZooming.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525" Loaded="window_Loaded"> <DockPanel Height="Auto" Width="Auto" LastChildFill="True"> <CheckBox DockPanel.Dock="Top" Name="checkBox" Content="縮小率に拡大率の逆数を使う" Canvas.Left="109" Canvas.Top="59" Checked="checkBox_Checked" Unchecked="checkBox_Unchecked"/> <ScrollViewer DockPanel.Dock="Bottom" x:Name="scrollViewer" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" PreviewMouseWheel="scrollViewer_PreviewMouseWheel"> <Canvas x:Name="canvas"> <Image x:Name="image" Stretch="Fill" Width="{Binding Source.PixelWidth, RelativeSource={RelativeSource Self}}" Height="{Binding Source.PixelHeight, RelativeSource={RelativeSource Self}}"/> </Canvas> </ScrollViewer> </DockPanel> </Window>
MainWindow.xaml.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace ImageZooming { /// <summary> /// MainWindow.xaml の相互作用ロジックs /// </summary> public partial class MainWindow : Window { const double MAGNIFICATION_LEVEL_1 = 1.1; const double VIEW_ANGLE = Math.PI / 4; private TransformGroup _canvasTransformGroup = new TransformGroup(); private int _zoomLevel = 0; private double _canvasOriginalWidth; private double _canvasOriginalHeight; public MainWindow() { InitializeComponent(); } private void window_Loaded(object sender, RoutedEventArgs e) { string currentDirectory = System.IO.Directory.GetCurrentDirectory(); string filePath = System.IO.Path.Combine(currentDirectory, "image.jpg"); BitmapImage bi = new BitmapImage(); bi.BeginInit(); bi.UriSource = new Uri(filePath); bi.EndInit(); image.Source = bi; // キャンバスのサイズをロードしたコントロールに合わせる canvas.Width = image.Width; canvas.Height = image.Height; _canvasOriginalWidth = image.Width; _canvasOriginalHeight = image.Height; } void scrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e) { if ((Keyboard.Modifiers & ModifierKeys.Control) != ModifierKeys.None) { changeCanvasScale(e.Delta); e.Handled = true; } } private void changeCanvasScale(int delta) { int originalZoomLevel = _zoomLevel; int zoomType = 0; if (checkBox.IsChecked.Value) { zoomType = 1; } double magnification = GetMagnification(zoomType, _zoomLevel); // 拡大操作時に中央に表示していたものがそのまま中央に表示されるようにする // そのためにまず中央に表示されている点の元の画像サイズの画像上での位置を求める double centerX = (scrollViewer.HorizontalOffset + scrollViewer.ViewportWidth / 2) / magnification; double centerY = (scrollViewer.VerticalOffset + scrollViewer.ViewportHeight / 2) / magnification; if (delta > 0) { _zoomLevel += 1; } else { _zoomLevel -= 1; } // 拡大率が異常になったら元の拡大率に戻す magnification = GetMagnification(zoomType, _zoomLevel); if (magnification <= 0 || double.IsInfinity(magnification) || double.IsNegativeInfinity(magnification)) { _zoomLevel = originalZoomLevel; return; } _canvasTransformGroup.Children.Clear(); _canvasTransformGroup.Children.Add(new ScaleTransform(magnification, magnification)); canvas.RenderTransform = _canvasTransformGroup; canvas.Width = _canvasOriginalWidth * magnification; canvas.Height = _canvasOriginalHeight * magnification; // 中央に表示されていたものがそのまま中央に表示されるようにスクロールする scrollViewer.ScrollToHorizontalOffset(centerX * magnification - scrollViewer.ViewportWidth / 2); scrollViewer.ScrollToVerticalOffset(centerY * magnification - scrollViewer.ViewportHeight / 2); } /// <summary> /// 拡大レベルに応じた拡大率を得る /// </summary> /// <param name="zoomType">拡大縮小の方式 0:通常 0以外:縮小時の拡大率を拡大時の逆数で代用する</param> /// <param name="zoomLevel">拡大レベル 0だと等倍 正だと拡大 負だと縮小</param> /// <returns>拡大率</returns> private double GetMagnification(int zoomType, int zoomLevel) { double x = 0.1 / (2.0 * MAGNIFICATION_LEVEL_1 * Math.Tan(VIEW_ANGLE / 2)); if (zoomType == 0) { return 1 / (1 - (x * zoomLevel) * Math.Tan(VIEW_ANGLE / 2) * 2); } else { double d = 1 / (1 - (x * Math.Abs(zoomLevel)) * Math.Tan(VIEW_ANGLE / 2) * 2); if (zoomLevel >= 0) { return d; } else { return 1 / d; } } } private void checkBox_Checked(object sender, RoutedEventArgs e) { _zoomLevel = 0; } private void checkBox_Unchecked(object sender, RoutedEventArgs e) { _zoomLevel = 0; } } }
前回の続き。
Windowsアプリでよく見る Ctrl + マウスホイール での拡大表示の
拡大率を現実世界をモデリングして求めてみようという話。
ある人が視野角θで対象物を見ていて、それが高さhで見えているとする。
そこから人がxだけ前進すると対象物の見える範囲がh'になるとする。
hだけ見えていたのがh'しか見えなくなるのだから
拡大率 = h / h'
だ。
ある距離x進んだ時の拡大率が知りたいのだから
h'をxとhで表せれば良さそう。
図の赤い三角形に着目すると
赤い三角形右辺の長さ = (h - h')
であることが分かる。
同時に
赤い三角形右辺の長さ = x * tan(θ/2) * 2
でもあるので
(h - h') = x * tan(θ/2) * 2
式を変形すると
h' = h - x * tan(θ/2) * 2
よって
拡大率 = h / (h - x * tan(θ/2) * 2)
110%(=1.1)の拡大率になるxはというと
1.1 = h / (h - x * tan(θ/2) * 2) 1.1 * (h - x * tan(θ/2) * 2) = h 1.1 * h - 1.1 * x * tan(θ/2) * 2 = h -1.1 * x * tan(θ/2) * 2 = -0.1 * h x = h / (22 * tan(θ/2))
ここで
θ = 45°
とすると
tan(θ/2) ≒ 0.4142135623730950488016887242097 x ≒ h * 0.10973698010786795676371312382771
例えばhが100の時は1.1倍になるxは約11。
で、約11ずつ進んでいくと拡大率はどうなるのかグラフにしてみる。
なんかそれっぽいけどどうなんだろ。
次は実際にアプリにして感じを見てみる。