From 6c4658da2494427ff3575d81ae4c42704673aa13 Mon Sep 17 00:00:00 2001 From: SauravNiraula Date: Thu, 25 Jan 2024 00:00:25 +0545 Subject: [PATCH 01/10] fixed bug in initstate which converted degrees to degrees instead of radians --- example/pubspec.lock | 133 ++++++++++++++++++++++++++++--------------- lib/panorama.dart | 4 +- pubspec.lock | 116 +++++++++++++++++++++---------------- 3 files changed, 158 insertions(+), 95 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index 8900253..58c0775 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,51 +5,58 @@ packages: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.11.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.3.0" charcode: dependency: transitive description: name: charcode - url: "https://pub.dartlang.org" + sha256: "8e36feea6de5ea69f2199f29cf42a450a855738c498b57c0b980e2d3cca9c362" + url: "https://pub.dev" source: hosted version: "1.2.0" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.18.0" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.1" flutter: dependency: "direct main" description: flutter @@ -59,14 +66,16 @@ packages: dependency: transitive description: name: flutter_cube - url: "https://pub.dartlang.org" + sha256: "71cf679a251166eb97f86751c56582b09abdbf859485fbf60524948813914c3b" + url: "https://pub.dev" source: hosted version: "0.1.1" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle - url: "https://pub.dartlang.org" + sha256: "0ba8a1854c2098ddbd043e47eb28451a13f4cab7db9b2696f13a39fd8853421d" + url: "https://pub.dev" source: hosted version: "2.0.0" flutter_test: @@ -78,49 +87,64 @@ packages: dependency: transitive description: name: http - url: "https://pub.dartlang.org" + sha256: "0a48a4e44ec1b6a52eb93b12d129f5b74ee6dbb27703439c965f1bd86f7be59f" + url: "https://pub.dev" source: hosted version: "0.13.0" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: e362d639ba3bc07d5a71faebb98cde68c05bfbcfbbb444b60b6f60bb67719185 + url: "https://pub.dev" source: hosted version: "4.0.0" image_picker: dependency: "direct main" description: name: image_picker - url: "https://pub.dartlang.org" + sha256: "8f496a46a16125ad07eb1964021b02cbe9e0071d657cfc5b4e0e2ce0ea2e8607" + url: "https://pub.dev" source: hosted version: "0.7.2+1" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface - url: "https://pub.dartlang.org" + sha256: f2005505f6df84c9eb580026cd3f56761187994c8a2cf65c1582cf8788873ac1 + url: "https://pub.dev" source: hosted version: "2.0.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + url: "https://pub.dev" source: hosted - version: "0.12.10" + version: "0.12.16" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + url: "https://pub.dev" + source: hosted + version: "0.5.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.10.0" motion_sensors: dependency: transitive description: name: motion_sensors - url: "https://pub.dartlang.org" + sha256: "4e2734a76cd6da633013bcdc68a9efe9fbbcff906e6d6c45040932edda3fa5d6" + url: "https://pub.dev" source: hosted version: "0.1.0" panorama: @@ -129,26 +153,29 @@ packages: path: ".." relative: true source: path - version: "0.4.0" + version: "0.4.1" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.8.3" pedantic: dependency: transitive description: name: pedantic - url: "https://pub.dartlang.org" + sha256: "8f6460c77a98ad2807cd3b98c67096db4286f56166852d0ce5951bb600a63594" + url: "https://pub.dev" source: hosted version: "1.11.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.dartlang.org" + sha256: c2c49e16d42fd6983eb55e44b7f197fdf16b4da7aab7f8e1d21da307cad3fb02 + url: "https://pub.dev" source: hosted version: "2.0.0" sky_engine: @@ -160,58 +187,74 @@ packages: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.10.0" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + url: "https://pub.dev" source: hosted - version: "0.2.19" + version: "0.6.1" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: "53bdf7e979cfbf3e28987552fd72f637e63f3c8724c9e56d9246942dc2fa36ee" + url: "https://pub.dev" source: hosted version: "1.3.0" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + web: + dependency: transitive + description: + name: web + sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "0.3.0" sdks: - dart: ">=2.12.0 <3.0.0" + dart: ">=3.2.0-194.0.dev <4.0.0" flutter: ">=1.20.0" diff --git a/lib/panorama.dart b/lib/panorama.dart index a82d87d..1fbcda1 100644 --- a/lib/panorama.dart +++ b/lib/panorama.dart @@ -393,8 +393,8 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin @override void initState() { super.initState(); - latitude = degrees(widget.latitude); - longitude = degrees(widget.longitude); + latitude = radians(widget.latitude); + longitude = radians(widget.longitude); _streamController = StreamController.broadcast(); _stream = _streamController.stream; diff --git a/pubspec.lock b/pubspec.lock index ae41e5e..10e69b4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,51 +5,50 @@ packages: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.11.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" source: hosted - version: "1.1.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" + version: "1.3.0" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.18.0" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.1" flutter: dependency: "direct main" description: flutter @@ -59,7 +58,8 @@ packages: dependency: "direct main" description: name: flutter_cube - url: "https://pub.dartlang.org" + sha256: "71cf679a251166eb97f86751c56582b09abdbf859485fbf60524948813914c3b" + url: "https://pub.dev" source: hosted version: "0.1.1" flutter_test: @@ -71,30 +71,42 @@ packages: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + url: "https://pub.dev" source: hosted - version: "0.12.10" + version: "0.12.16" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + url: "https://pub.dev" + source: hosted + version: "0.5.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.10.0" motion_sensors: dependency: "direct main" description: name: motion_sensors - url: "https://pub.dartlang.org" + sha256: "4e2734a76cd6da633013bcdc68a9efe9fbbcff906e6d6c45040932edda3fa5d6" + url: "https://pub.dev" source: hosted version: "0.1.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.8.3" sky_engine: dependency: transitive description: flutter @@ -104,58 +116,66 @@ packages: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.10.0" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + url: "https://pub.dev" source: hosted - version: "0.2.19" - typed_data: + version: "0.6.1" + vector_math: dependency: transitive description: - name: typed_data - url: "https://pub.dartlang.org" + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "1.3.0" - vector_math: + version: "2.1.4" + web: dependency: transitive description: - name: vector_math - url: "https://pub.dartlang.org" + name: web + sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "0.3.0" sdks: - dart: ">=2.12.0 <3.0.0" + dart: ">=3.2.0-194.0.dev <4.0.0" flutter: ">=1.10.0" From 94895a18ec2619b688dd3c2d7a88ad613cd9d404 Mon Sep 17 00:00:00 2001 From: SauravNiraula Date: Sat, 27 Jan 2024 19:13:33 +0545 Subject: [PATCH 02/10] added onZoomChanged callback --- lib/panorama.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/panorama.dart b/lib/panorama.dart index 1fbcda1..3ef908b 100644 --- a/lib/panorama.dart +++ b/lib/panorama.dart @@ -41,6 +41,7 @@ class Panorama extends StatefulWidget { this.croppedFullWidth = 1.0, this.croppedFullHeight = 1.0, this.onViewChanged, + this.onZoomChanged, this.onTap, this.onLongPressStart, this.onLongPressMoveUpdate, @@ -110,6 +111,9 @@ class Panorama extends StatefulWidget { /// This event will be called when the view direction has changed, it contains latitude and longitude about the current view. final Function(double longitude, double latitude, double tilt)? onViewChanged; + /// This event will be called when the view zoom has changed, it contains zoom of the current view + final Function(double zoom)? onZoomChanged; + /// This event will be called when the user has tapped, it contains latitude and longitude about where the user tapped. final Function(double longitude, double latitude, double tilt)? onTap; @@ -198,6 +202,8 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin } else _controller.forward(); } + if (widget.onZoomChanged == null) return; + widget.onZoomChanged!(scene!.camera.zoom + zoomDelta * _dampingFactor); } void _updateView() { From 63fea7bf2d3f8c159a2461b037d6d7a65a51deaa Mon Sep 17 00:00:00 2001 From: SauravNiraula Date: Sat, 27 Jan 2024 19:38:34 +0545 Subject: [PATCH 03/10] added more zoom features --- lib/panorama.dart | 180 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 133 insertions(+), 47 deletions(-) diff --git a/lib/panorama.dart b/lib/panorama.dart index 3ef908b..c6c2758 100644 --- a/lib/panorama.dart +++ b/lib/panorama.dart @@ -118,14 +118,17 @@ class Panorama extends StatefulWidget { final Function(double longitude, double latitude, double tilt)? onTap; /// This event will be called when the user has started a long press, it contains latitude and longitude about where the user pressed. - final Function(double longitude, double latitude, double tilt)? onLongPressStart; + final Function(double longitude, double latitude, double tilt)? + onLongPressStart; /// This event will be called when the user has drag-moved after a long press, it contains latitude and longitude about where the user pressed. - final Function(double longitude, double latitude, double tilt)? onLongPressMoveUpdate; + final Function(double longitude, double latitude, double tilt)? + onLongPressMoveUpdate; /// This event will be called when the user has stopped a long presses, it contains latitude and longitude about where the user pressed. - final Function(double longitude, double latitude, double tilt)? onLongPressEnd; - + final Function(double longitude, double latitude, double tilt)? + onLongPressEnd; + /// This event will be called when provided image is loaded on texture. final Function()? onImageLoad; @@ -139,7 +142,8 @@ class Panorama extends StatefulWidget { _PanoramaState createState() => _PanoramaState(); } -class _PanoramaState extends State with SingleTickerProviderStateMixin { +class _PanoramaState extends State + with SingleTickerProviderStateMixin { Scene? scene; Object? surface; late double latitude; @@ -162,22 +166,26 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin ImageStream? _imageStream; void _handleTapUp(TapUpDetails details) { - final Vector3 o = positionToLatLon(details.localPosition.dx, details.localPosition.dy); + final Vector3 o = + positionToLatLon(details.localPosition.dx, details.localPosition.dy); widget.onTap!(degrees(o.x), degrees(-o.y), degrees(o.z)); } void _handleLongPressStart(LongPressStartDetails details) { - final Vector3 o = positionToLatLon(details.localPosition.dx, details.localPosition.dy); + final Vector3 o = + positionToLatLon(details.localPosition.dx, details.localPosition.dy); widget.onLongPressStart!(degrees(o.x), degrees(-o.y), degrees(o.z)); } void _handleLongPressMoveUpdate(LongPressMoveUpdateDetails details) { - final Vector3 o = positionToLatLon(details.localPosition.dx, details.localPosition.dy); + final Vector3 o = + positionToLatLon(details.localPosition.dx, details.localPosition.dy); widget.onLongPressMoveUpdate!(degrees(o.x), degrees(-o.y), degrees(o.z)); } void _handleLongPressEnd(LongPressEndDetails details) { - final Vector3 o = positionToLatLon(details.localPosition.dx, details.localPosition.dy); + final Vector3 o = + positionToLatLon(details.localPosition.dx, details.localPosition.dy); widget.onLongPressEnd!(degrees(o.x), degrees(-o.y), degrees(o.z)); } @@ -189,13 +197,23 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin void _handleScaleUpdate(ScaleUpdateDetails details) { final offset = details.localFocalPoint - _lastFocalPoint; _lastFocalPoint = details.localFocalPoint; - latitudeDelta += widget.sensitivity * 0.5 * math.pi * offset.dy / scene!.camera.viewportHeight; - longitudeDelta -= widget.sensitivity * _animateDirection * 0.5 * math.pi * offset.dx / scene!.camera.viewportHeight; + latitudeDelta += widget.sensitivity * + 0.5 * + math.pi * + offset.dy / + scene!.camera.viewportHeight; + longitudeDelta -= widget.sensitivity * + _animateDirection * + 0.5 * + math.pi * + offset.dx / + scene!.camera.viewportHeight; if (_lastZoom == null) { _lastZoom = scene!.camera.zoom; } zoomDelta += _lastZoom! * details.scale - (scene!.camera.zoom + zoomDelta); - if (widget.sensorControl == SensorControl.None && !_controller.isAnimating) { + if (widget.sensorControl == SensorControl.None && + !_controller.isAnimating) { _controller.reset(); if (widget.animSpeed != 0) { _controller.repeat(); @@ -203,7 +221,11 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin _controller.forward(); } if (widget.onZoomChanged == null) return; - widget.onZoomChanged!(scene!.camera.zoom + zoomDelta * _dampingFactor); + widget.onZoomChanged!(_zoom); + } + + double get _zoom { + return scene!.camera.zoom + zoomDelta * _dampingFactor; } void _updateView() { @@ -214,7 +236,10 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin latitude += latitudeDelta * _dampingFactor * widget.sensitivity; latitudeDelta *= 1 - _dampingFactor * widget.sensitivity; // animate horizontal rotating - longitude += _animateDirection * longitudeDelta * _dampingFactor * widget.sensitivity; + longitude += _animateDirection * + longitudeDelta * + _dampingFactor * + widget.sensitivity; longitudeDelta *= 1 - _dampingFactor * widget.sensitivity; // animate zomming final double zoom = scene!.camera.zoom + zoomDelta * _dampingFactor; @@ -269,7 +294,8 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin // rotate around the local X axis q = Quaternion.axisAngle(Vector3(1, 0, 0), -latitude) * q; - o = quaternionToOrientation(q * Quaternion.axisAngle(Vector3(0, 1, 0), math.pi * 0.5)); + o = quaternionToOrientation( + q * Quaternion.axisAngle(Vector3(0, 1, 0), math.pi * 0.5)); widget.onViewChanged?.call(degrees(o.x), degrees(-o.y), degrees(o.z)); q.rotate(scene!.camera.target..setFrom(Vector3(0, 0, -_radius))); @@ -282,14 +308,18 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin _orientationSubscription?.cancel(); switch (widget.sensorControl) { case SensorControl.Orientation: - motionSensors.orientationUpdateInterval = Duration.microsecondsPerSecond ~/ 60; - _orientationSubscription = motionSensors.orientation.listen((OrientationEvent event) { + motionSensors.orientationUpdateInterval = + Duration.microsecondsPerSecond ~/ 60; + _orientationSubscription = + motionSensors.orientation.listen((OrientationEvent event) { orientation.setValues(event.yaw, event.pitch, event.roll); }); break; case SensorControl.AbsoluteOrientation: - motionSensors.absoluteOrientationUpdateInterval = Duration.microsecondsPerSecond ~/ 60; - _orientationSubscription = motionSensors.absoluteOrientation.listen((AbsoluteOrientationEvent event) { + motionSensors.absoluteOrientationUpdateInterval = + Duration.microsecondsPerSecond ~/ 60; + _orientationSubscription = motionSensors.absoluteOrientation + .listen((AbsoluteOrientationEvent event) { orientation.setValues(event.yaw, event.pitch, event.roll); }); break; @@ -298,7 +328,8 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin _screenOrientSubscription?.cancel(); if (widget.sensorControl != SensorControl.None) { - _screenOrientSubscription = motionSensors.screenOrientation.listen((ScreenOrientationEvent event) { + _screenOrientSubscription = motionSensors.screenOrientation + .listen((ScreenOrientationEvent event) { screenOrientation = radians(event.angle!); }); } @@ -306,7 +337,8 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin void _updateTexture(ImageInfo imageInfo, bool synchronousCall) { surface?.mesh.texture = imageInfo.image; - surface?.mesh.textureRect = Rect.fromLTWH(0, 0, imageInfo.image.width.toDouble(), imageInfo.image.height.toDouble()); + surface?.mesh.textureRect = Rect.fromLTWH(0, 0, + imageInfo.image.width.toDouble(), imageInfo.image.height.toDouble()); scene!.texture = imageInfo.image; scene!.update(); widget.onImageLoad?.call(); @@ -328,7 +360,13 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin scene.camera.zoom = widget.zoom; scene.camera.position.setFrom(Vector3(0, 0, 0.1)); if (widget.child != null) { - final Mesh mesh = generateSphereMesh(radius: _radius, latSegments: widget.latSegments, lonSegments: widget.lonSegments, croppedArea: widget.croppedArea, croppedFullWidth: widget.croppedFullWidth, croppedFullHeight: widget.croppedFullHeight); + final Mesh mesh = generateSphereMesh( + radius: _radius, + latSegments: widget.latSegments, + lonSegments: widget.lonSegments, + croppedArea: widget.croppedArea, + croppedFullWidth: widget.croppedFullWidth, + croppedFullHeight: widget.croppedFullHeight); surface = Object(name: 'surface', mesh: mesh, backfaceCulling: false); _loadTexture(widget.child!.image); scene.world.add(surface!); @@ -342,23 +380,29 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin Vector3 positionToLatLon(double x, double y) { // transform viewport coordinate to NDC, values between -1 and 1 - final Vector4 v = Vector4(2.0 * x / scene!.camera.viewportWidth - 1.0, 1.0 - 2.0 * y / scene!.camera.viewportHeight, 1.0, 1.0); + final Vector4 v = Vector4(2.0 * x / scene!.camera.viewportWidth - 1.0, + 1.0 - 2.0 * y / scene!.camera.viewportHeight, 1.0, 1.0); // create projection matrix - final Matrix4 m = scene!.camera.projectionMatrix * scene!.camera.lookAtMatrix; + final Matrix4 m = + scene!.camera.projectionMatrix * scene!.camera.lookAtMatrix; // apply inversed projection matrix m.invert(); v.applyMatrix4(m); // apply perspective division v.scale(1 / v.w); // get rotation from two vectors - final Quaternion q = Quaternion.fromTwoVectors(v.xyz, Vector3(0.0, 0.0, -_radius)); + final Quaternion q = + Quaternion.fromTwoVectors(v.xyz, Vector3(0.0, 0.0, -_radius)); // get euler angles from rotation - return quaternionToOrientation(q * Quaternion.axisAngle(Vector3(0, 1, 0), math.pi * 0.5)); + return quaternionToOrientation( + q * Quaternion.axisAngle(Vector3(0, 1, 0), math.pi * 0.5)); } Vector3 positionFromLatLon(double lat, double lon) { // create projection matrix - final Matrix4 m = scene!.camera.projectionMatrix * scene!.camera.lookAtMatrix * matrixFromLatLon(lat, lon); + final Matrix4 m = scene!.camera.projectionMatrix * + scene!.camera.lookAtMatrix * + matrixFromLatLon(lat, lon); // apply projection matrix final Vector4 v = Vector4(0.0, 0.0, -_radius, 1.0)..applyMatrix4(m); // apply perspective division and transform NDC to the viewport coordinate @@ -373,14 +417,18 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin final List widgets = []; if (hotspots != null && scene != null) { for (Hotspot hotspot in hotspots) { - final Vector3 pos = positionFromLatLon(hotspot.latitude, hotspot.longitude); - final Offset orgin = Offset(hotspot.width * hotspot.orgin.dx, hotspot.height * hotspot.orgin.dy); - final Matrix4 transform = scene!.camera.lookAtMatrix * matrixFromLatLon(hotspot.latitude, hotspot.longitude); + final Vector3 pos = + positionFromLatLon(hotspot.latitude, hotspot.longitude); + final Offset orgin = Offset(hotspot.width * hotspot.orgin.dx, + hotspot.height * hotspot.orgin.dy); + final Matrix4 transform = scene!.camera.lookAtMatrix * + matrixFromLatLon(hotspot.latitude, hotspot.longitude); + final zoom = hotspot.zoomOnViewZoom ? _zoom : 1.0; final Widget child = Positioned( left: pos.x - orgin.dx, top: pos.y - orgin.dy, - width: hotspot.width, - height: hotspot.height, + width: hotspot.width * zoom, + height: hotspot.height * zoom, child: Transform( origin: orgin, transform: transform..invert(), @@ -406,8 +454,11 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin _updateSensorControl(); - _controller = AnimationController(duration: Duration(milliseconds: 60000), vsync: this)..addListener(_updateView); - if (widget.sensorControl != SensorControl.None || widget.animSpeed != 0) _controller.repeat(); + _controller = AnimationController( + duration: Duration(milliseconds: 60000), vsync: this) + ..addListener(_updateView); + if (widget.sensorControl != SensorControl.None || widget.animSpeed != 0) + _controller.repeat(); } @override @@ -424,8 +475,18 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin void didUpdateWidget(Panorama oldWidget) { super.didUpdateWidget(oldWidget); if (surface == null) return; - if (widget.latSegments != oldWidget.latSegments || widget.lonSegments != oldWidget.lonSegments || widget.croppedArea != oldWidget.croppedArea || widget.croppedFullWidth != oldWidget.croppedFullWidth || widget.croppedFullHeight != oldWidget.croppedFullHeight) { - surface!.mesh = generateSphereMesh(radius: _radius, latSegments: widget.latSegments, lonSegments: widget.lonSegments, croppedArea: widget.croppedArea, croppedFullWidth: widget.croppedFullWidth, croppedFullHeight: widget.croppedFullHeight); + if (widget.latSegments != oldWidget.latSegments || + widget.lonSegments != oldWidget.lonSegments || + widget.croppedArea != oldWidget.croppedArea || + widget.croppedFullWidth != oldWidget.croppedFullWidth || + widget.croppedFullHeight != oldWidget.croppedFullHeight) { + surface!.mesh = generateSphereMesh( + radius: _radius, + latSegments: widget.latSegments, + lonSegments: widget.lonSegments, + croppedArea: widget.croppedArea, + croppedFullWidth: widget.croppedFullWidth, + croppedFullHeight: widget.croppedFullHeight); } if (widget.child?.image != oldWidget.child?.image) { _loadTexture(widget.child?.image); @@ -454,9 +515,13 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin onScaleStart: _handleScaleStart, onScaleUpdate: _handleScaleUpdate, onTapUp: widget.onTap == null ? null : _handleTapUp, - onLongPressStart: widget.onLongPressStart == null ? null : _handleLongPressStart, - onLongPressMoveUpdate: widget.onLongPressMoveUpdate == null ? null : _handleLongPressMoveUpdate, - onLongPressEnd: widget.onLongPressEnd == null ? null : _handleLongPressEnd, + onLongPressStart: + widget.onLongPressStart == null ? null : _handleLongPressStart, + onLongPressMoveUpdate: widget.onLongPressMoveUpdate == null + ? null + : _handleLongPressMoveUpdate, + onLongPressEnd: + widget.onLongPressEnd == null ? null : _handleLongPressEnd, child: pano, ) : pano; @@ -471,6 +536,7 @@ class Hotspot { this.orgin = const Offset(0.5, 0.5), this.width = 32.0, this.height = 32.0, + this.zoomOnViewZoom = false, this.widget, }); @@ -492,25 +558,39 @@ class Hotspot { // The height of widget. Default is 32.0 double height; + // If true, hotspot size will be updated according to view zoom value. + bool zoomOnViewZoom; + Widget? widget; } -Mesh generateSphereMesh({num radius = 1.0, int latSegments = 16, int lonSegments = 16, ui.Image? texture, Rect croppedArea = const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0), double croppedFullWidth = 1.0, double croppedFullHeight = 1.0}) { +Mesh generateSphereMesh( + {num radius = 1.0, + int latSegments = 16, + int lonSegments = 16, + ui.Image? texture, + Rect croppedArea = const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0), + double croppedFullWidth = 1.0, + double croppedFullHeight = 1.0}) { int count = (latSegments + 1) * (lonSegments + 1); List vertices = List.filled(count, Vector3.zero()); List texcoords = List.filled(count, Offset.zero); - List indices = List.filled(latSegments * lonSegments * 2, Polygon(0, 0, 0)); + List indices = + List.filled(latSegments * lonSegments * 2, Polygon(0, 0, 0)); int i = 0; for (int y = 0; y <= latSegments; ++y) { final double tv = y / latSegments; - final double v = (croppedArea.top + croppedArea.height * tv) / croppedFullHeight; + final double v = + (croppedArea.top + croppedArea.height * tv) / croppedFullHeight; final double sv = math.sin(v * math.pi); final double cv = math.cos(v * math.pi); for (int x = 0; x <= lonSegments; ++x) { final double tu = x / lonSegments; - final double u = (croppedArea.left + croppedArea.width * tu) / croppedFullWidth; - vertices[i] = Vector3(radius * math.cos(u * math.pi * 2.0) * sv, radius * cv, radius * math.sin(u * math.pi * 2.0) * sv); + final double u = + (croppedArea.left + croppedArea.width * tu) / croppedFullWidth; + vertices[i] = Vector3(radius * math.cos(u * math.pi * 2.0) * sv, + radius * cv, radius * math.sin(u * math.pi * 2.0) * sv); texcoords[i] = Offset(tu, 1.0 - tv); i++; } @@ -526,7 +606,11 @@ Mesh generateSphereMesh({num radius = 1.0, int latSegments = 16, int lonSegments } } - final Mesh mesh = Mesh(vertices: vertices, texcoords: texcoords, indices: indices, texture: texture); + final Mesh mesh = Mesh( + vertices: vertices, + texcoords: texcoords, + indices: indices, + texture: texture); return mesh; } @@ -539,9 +623,11 @@ Vector3 quaternionToOrientation(Quaternion q) { final double y = storage[1]; final double z = storage[2]; final double w = storage[3]; - final double roll = math.atan2(-2 * (x * y - w * z), 1.0 - 2 * (x * x + z * z)); + final double roll = + math.atan2(-2 * (x * y - w * z), 1.0 - 2 * (x * x + z * z)); final double pitch = math.asin(2 * (y * z + w * x)); - final double yaw = math.atan2(-2 * (x * z - w * y), 1.0 - 2 * (x * x + y * y)); + final double yaw = + math.atan2(-2 * (x * z - w * y), 1.0 - 2 * (x * x + y * y)); return Vector3(yaw, pitch, roll); } From 1f86a96dcaf8397ca3184be4ffbc170d3e8a5202 Mon Sep 17 00:00:00 2001 From: SauravNiraula Date: Sat, 27 Jan 2024 20:02:01 +0545 Subject: [PATCH 04/10] fixed zoom offset issue --- lib/panorama.dart | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/panorama.dart b/lib/panorama.dart index c6c2758..b87c7e5 100644 --- a/lib/panorama.dart +++ b/lib/panorama.dart @@ -417,18 +417,22 @@ class _PanoramaState extends State final List widgets = []; if (hotspots != null && scene != null) { for (Hotspot hotspot in hotspots) { + final zoom = hotspot.zoomOnViewZoom ? _zoom : 1.0; + final hotspotHeight = hotspot.height * zoom; + final hotspotWidth = hotspot.width * zoom; + final Vector3 pos = positionFromLatLon(hotspot.latitude, hotspot.longitude); - final Offset orgin = Offset(hotspot.width * hotspot.orgin.dx, - hotspot.height * hotspot.orgin.dy); + final Offset orgin = Offset(hotspotWidth * hotspot.orgin.dx, + hotspotHeight * hotspot.orgin.dy); final Matrix4 transform = scene!.camera.lookAtMatrix * matrixFromLatLon(hotspot.latitude, hotspot.longitude); - final zoom = hotspot.zoomOnViewZoom ? _zoom : 1.0; + final Widget child = Positioned( left: pos.x - orgin.dx, top: pos.y - orgin.dy, - width: hotspot.width * zoom, - height: hotspot.height * zoom, + width: hotspotWidth, + height: hotspotHeight, child: Transform( origin: orgin, transform: transform..invert(), From a3dd1fa7fb365deb66af49a900b5233604124fd2 Mon Sep 17 00:00:00 2001 From: SauravNiraula Date: Mon, 5 Feb 2024 18:18:06 +0545 Subject: [PATCH 05/10] added method in hotspot that provides current hotspot position --- lib/panorama.dart | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/panorama.dart b/lib/panorama.dart index b87c7e5..acb251c 100644 --- a/lib/panorama.dart +++ b/lib/panorama.dart @@ -423,11 +423,13 @@ class _PanoramaState extends State final Vector3 pos = positionFromLatLon(hotspot.latitude, hotspot.longitude); - final Offset orgin = Offset(hotspotWidth * hotspot.orgin.dx, - hotspotHeight * hotspot.orgin.dy); + final Offset orgin = Offset( + hotspotWidth * hotspot.orgin.dx, hotspotHeight * hotspot.orgin.dy); final Matrix4 transform = scene!.camera.lookAtMatrix * matrixFromLatLon(hotspot.latitude, hotspot.longitude); + hotspot.onPositionChanged?.call(pos.x, pos.y, pos.z); + final Widget child = Positioned( left: pos.x - orgin.dx, top: pos.y - orgin.dy, @@ -541,6 +543,7 @@ class Hotspot { this.width = 32.0, this.height = 32.0, this.zoomOnViewZoom = false, + this.onPositionChanged, this.widget, }); @@ -565,6 +568,10 @@ class Hotspot { // If true, hotspot size will be updated according to view zoom value. bool zoomOnViewZoom; + // is called when hotspot position is changed in screen + // provides screen coordinates of hotspot + final Function(double x, double y, double z)? onPositionChanged; + Widget? widget; } From 2f7006464c05bf80dcb526bc6c6e28c21ae9f7c8 Mon Sep 17 00:00:00 2001 From: SauravNiraula Date: Mon, 5 Feb 2024 19:03:18 +0545 Subject: [PATCH 06/10] added builder on hotspot --- lib/panorama.dart | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/panorama.dart b/lib/panorama.dart index acb251c..aa2bb30 100644 --- a/lib/panorama.dart +++ b/lib/panorama.dart @@ -440,7 +440,7 @@ class _PanoramaState extends State transform: transform..invert(), child: Offstage( offstage: pos.z < 0, - child: hotspot.widget, + child: hotspot.builder(pos, hotspot.child), ), ), ); @@ -544,7 +544,8 @@ class Hotspot { this.height = 32.0, this.zoomOnViewZoom = false, this.onPositionChanged, - this.widget, + required this.builder, + this.child, }); /// The name of this hotspot. @@ -572,7 +573,10 @@ class Hotspot { // provides screen coordinates of hotspot final Function(double x, double y, double z)? onPositionChanged; - Widget? widget; + // provides screen position vector and child to build hotspot + final Widget Function(Vector3 position, Widget? child) builder; + + Widget? child; } Mesh generateSphereMesh( From ae03765353d9c0a7c4b11483f17946fa7c3aefff Mon Sep 17 00:00:00 2001 From: SauravNiraula Date: Mon, 5 Feb 2024 19:16:01 +0545 Subject: [PATCH 07/10] example code fix --- example/lib/main.dart | 60 ++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 3958947..9b8880d 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -45,7 +45,8 @@ class _MyHomePageState extends State { }); } - Widget hotspotButton({String? text, IconData? icon, VoidCallback? onPressed}) { + Widget hotspotButton( + {String? text, IconData? icon, VoidCallback? onPressed}) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -61,7 +62,9 @@ class _MyHomePageState extends State { text != null ? Container( padding: EdgeInsets.all(4.0), - decoration: BoxDecoration(color: Colors.black38, borderRadius: BorderRadius.all(Radius.circular(4))), + decoration: BoxDecoration( + color: Colors.black38, + borderRadius: BorderRadius.all(Radius.circular(4))), child: Center(child: Text(text)), ) : Container(), @@ -78,10 +81,14 @@ class _MyHomePageState extends State { animSpeed: 1.0, sensorControl: SensorControl.Orientation, onViewChanged: onViewChanged, - onTap: (longitude, latitude, tilt) => print('onTap: $longitude, $latitude, $tilt'), - onLongPressStart: (longitude, latitude, tilt) => print('onLongPressStart: $longitude, $latitude, $tilt'), - onLongPressMoveUpdate: (longitude, latitude, tilt) => print('onLongPressMoveUpdate: $longitude, $latitude, $tilt'), - onLongPressEnd: (longitude, latitude, tilt) => print('onLongPressEnd: $longitude, $latitude, $tilt'), + onTap: (longitude, latitude, tilt) => + print('onTap: $longitude, $latitude, $tilt'), + onLongPressStart: (longitude, latitude, tilt) => + print('onLongPressStart: $longitude, $latitude, $tilt'), + onLongPressMoveUpdate: (longitude, latitude, tilt) => + print('onLongPressMoveUpdate: $longitude, $latitude, $tilt'), + onLongPressEnd: (longitude, latitude, tilt) => + print('onLongPressEnd: $longitude, $latitude, $tilt'), child: Image.asset('assets/panorama.jpg'), hotspots: [ Hotspot( @@ -89,21 +96,13 @@ class _MyHomePageState extends State { longitude: -129.0, width: 90, height: 75, - widget: hotspotButton(text: "Next scene", icon: Icons.open_in_browser, onPressed: () => setState(() => _panoId++)), - ), - Hotspot( - latitude: -42.0, - longitude: -46.0, - width: 60.0, - height: 60.0, - widget: hotspotButton(icon: Icons.search, onPressed: () => setState(() => _panoId = 2)), - ), - Hotspot( - latitude: -33.0, - longitude: 123.0, - width: 60.0, - height: 60.0, - widget: hotspotButton(icon: Icons.arrow_upward, onPressed: () {}), + builder: (position, child) { + return child!; + }, + child: hotspotButton( + text: "Next scene", + icon: Icons.open_in_browser, + onPressed: () => setState(() => _panoId++)), ), ], ); @@ -123,7 +122,13 @@ class _MyHomePageState extends State { longitude: -46.0, width: 90.0, height: 75.0, - widget: hotspotButton(text: "Next scene", icon: Icons.double_arrow, onPressed: () => setState(() => _panoId++)), + builder: (position, child) { + return child!; + }, + child: hotspotButton( + text: "Next scene", + icon: Icons.double_arrow, + onPressed: () => setState(() => _panoId++)), ), ], ); @@ -140,7 +145,13 @@ class _MyHomePageState extends State { longitude: 160.0, width: 90.0, height: 75.0, - widget: hotspotButton(text: "Next scene", icon: Icons.double_arrow, onPressed: () => setState(() => _panoId++)), + builder: (position, child) { + return child!; + }, + child: hotspotButton( + text: "Next scene", + icon: Icons.double_arrow, + onPressed: () => setState(() => _panoId++)), ), ], ); @@ -152,7 +163,8 @@ class _MyHomePageState extends State { body: Stack( children: [ panorama, - Text('${_lon.toStringAsFixed(3)}, ${_lat.toStringAsFixed(3)}, ${_tilt.toStringAsFixed(3)}'), + Text( + '${_lon.toStringAsFixed(3)}, ${_lat.toStringAsFixed(3)}, ${_tilt.toStringAsFixed(3)}'), ], ), floatingActionButton: FloatingActionButton( From 74fc3523369339acf8feb435ac27a61c736078dd Mon Sep 17 00:00:00 2001 From: SauravNiraula Date: Tue, 6 Feb 2024 21:17:05 +0545 Subject: [PATCH 08/10] made builder optional --- example/lib/main.dart | 9 --------- lib/panorama.dart | 8 +++++--- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 9b8880d..014a861 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -96,9 +96,6 @@ class _MyHomePageState extends State { longitude: -129.0, width: 90, height: 75, - builder: (position, child) { - return child!; - }, child: hotspotButton( text: "Next scene", icon: Icons.open_in_browser, @@ -122,9 +119,6 @@ class _MyHomePageState extends State { longitude: -46.0, width: 90.0, height: 75.0, - builder: (position, child) { - return child!; - }, child: hotspotButton( text: "Next scene", icon: Icons.double_arrow, @@ -145,9 +139,6 @@ class _MyHomePageState extends State { longitude: 160.0, width: 90.0, height: 75.0, - builder: (position, child) { - return child!; - }, child: hotspotButton( text: "Next scene", icon: Icons.double_arrow, diff --git a/lib/panorama.dart b/lib/panorama.dart index aa2bb30..25c4483 100644 --- a/lib/panorama.dart +++ b/lib/panorama.dart @@ -440,7 +440,9 @@ class _PanoramaState extends State transform: transform..invert(), child: Offstage( offstage: pos.z < 0, - child: hotspot.builder(pos, hotspot.child), + child: hotspot.builder != null + ? hotspot.builder!(pos, hotspot.child) + : hotspot.child, ), ), ); @@ -544,7 +546,7 @@ class Hotspot { this.height = 32.0, this.zoomOnViewZoom = false, this.onPositionChanged, - required this.builder, + this.builder, this.child, }); @@ -574,7 +576,7 @@ class Hotspot { final Function(double x, double y, double z)? onPositionChanged; // provides screen position vector and child to build hotspot - final Widget Function(Vector3 position, Widget? child) builder; + final Widget Function(Vector3 position, Widget? child)? builder; Widget? child; } From 36efd608562ea8517535ed43330d3ff92d9b5f5f Mon Sep 17 00:00:00 2001 From: SauravNiraula Date: Tue, 6 Feb 2024 23:34:02 +0545 Subject: [PATCH 09/10] added decreateSensitivityOnZoom feature --- lib/panorama.dart | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/lib/panorama.dart b/lib/panorama.dart index 25c4483..5a444b8 100644 --- a/lib/panorama.dart +++ b/lib/panorama.dart @@ -24,6 +24,7 @@ class Panorama extends StatefulWidget { this.latitude = 0, this.longitude = 0, this.zoom = 1.0, + this.decreaseSensitivityOnZoom = false, this.minLatitude = -90.0, this.maxLatitude = 90.0, this.minLongitude = -180.0, @@ -60,6 +61,9 @@ class Panorama extends StatefulWidget { /// The initial zoom, default to 1.0. final double zoom; + /// If true, sensitivity will increase and decrease according to zoom value + final bool decreaseSensitivityOnZoom; + /// The minimal latitude to show. default to -90.0 final double minLatitude; @@ -197,12 +201,12 @@ class _PanoramaState extends State void _handleScaleUpdate(ScaleUpdateDetails details) { final offset = details.localFocalPoint - _lastFocalPoint; _lastFocalPoint = details.localFocalPoint; - latitudeDelta += widget.sensitivity * + latitudeDelta += _adaptingSensitivity * 0.5 * math.pi * offset.dy / scene!.camera.viewportHeight; - longitudeDelta -= widget.sensitivity * + longitudeDelta -= _adaptingSensitivity * _animateDirection * 0.5 * math.pi * @@ -224,6 +228,12 @@ class _PanoramaState extends State widget.onZoomChanged!(_zoom); } + double get _adaptingSensitivity { + return widget.decreaseSensitivityOnZoom + ? widget.sensitivity / _zoom + : widget.sensitivity; + } + double get _zoom { return scene!.camera.zoom + zoomDelta * _dampingFactor; } @@ -233,14 +243,14 @@ class _PanoramaState extends State // auto rotate longitudeDelta += 0.001 * widget.animSpeed; // animate vertical rotating - latitude += latitudeDelta * _dampingFactor * widget.sensitivity; - latitudeDelta *= 1 - _dampingFactor * widget.sensitivity; + latitude += latitudeDelta * _dampingFactor * _adaptingSensitivity; + latitudeDelta *= 1 - _dampingFactor * _adaptingSensitivity; // animate horizontal rotating longitude += _animateDirection * longitudeDelta * _dampingFactor * - widget.sensitivity; - longitudeDelta *= 1 - _dampingFactor * widget.sensitivity; + _adaptingSensitivity; + longitudeDelta *= 1 - _dampingFactor * _adaptingSensitivity; // animate zomming final double zoom = scene!.camera.zoom + zoomDelta * _dampingFactor; zoomDelta *= 1 - _dampingFactor; @@ -429,6 +439,7 @@ class _PanoramaState extends State matrixFromLatLon(hotspot.latitude, hotspot.longitude); hotspot.onPositionChanged?.call(pos.x, pos.y, pos.z); + assert(hotspot.builder != null || hotspot.child != null); final Widget child = Positioned( left: pos.x - orgin.dx, From dcfe6f9d517af44288061b652f65764021a9ea49 Mon Sep 17 00:00:00 2001 From: SauravNiraula Date: Thu, 22 Feb 2024 22:18:22 +0545 Subject: [PATCH 10/10] update lat lng on widget lat lng update feature added --- lib/panorama.dart | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/panorama.dart b/lib/panorama.dart index 5a444b8..22c6e34 100644 --- a/lib/panorama.dart +++ b/lib/panorama.dart @@ -37,6 +37,7 @@ class Panorama extends StatefulWidget { this.latSegments = 32, this.lonSegments = 64, this.interactive = true, + this.updateLatLngOnWidgetUpdate = false, this.sensorControl = SensorControl.None, this.croppedArea = const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0), this.croppedFullWidth = 1.0, @@ -100,6 +101,9 @@ class Panorama extends StatefulWidget { /// Interact with the panorama. default to true final bool interactive; + /// Update Latitude and Longitude if widget is updated. + final bool updateLatLngOnWidgetUpdate; + /// Control the panorama with motion sensors. final SensorControl sensorControl; @@ -463,11 +467,15 @@ class _PanoramaState extends State return Stack(children: widgets); } + void _updateLatLng() { + latitude = radians(widget.latitude); + longitude = radians(widget.longitude); + } + @override void initState() { super.initState(); - latitude = radians(widget.latitude); - longitude = radians(widget.longitude); + _updateLatLng(); _streamController = StreamController.broadcast(); _stream = _streamController.stream; @@ -513,6 +521,10 @@ class _PanoramaState extends State if (widget.sensorControl != oldWidget.sensorControl) { _updateSensorControl(); } + if (widget.updateLatLngOnWidgetUpdate) { + _updateLatLng(); + _updateView(); + } } @override