diff --git a/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/ARSceneViewConfig.kt b/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/ARSceneViewConfig.kt new file mode 100644 index 0000000..b019203 --- /dev/null +++ b/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/ARSceneViewConfig.kt @@ -0,0 +1,28 @@ +package io.github.sceneview.sceneview_flutter + +import com.google.ar.core.Config + +class ARSceneViewConfig( + val lightEstimationMode: Config.LightEstimationMode, + val instantPlacementMode: Config.InstantPlacementMode, + val depthMode: Config.DepthMode, + val planeRenderer: PlaneRenderer, +) { + companion object { + fun from(map: Map): ARSceneViewConfig { + return ARSceneViewConfig( + Config.LightEstimationMode.values()[map["lightEstimationMode"] as Int], + Config.InstantPlacementMode.values()[map["instantPlacementMode"] as Int], + Config.DepthMode.values()[map["depthMode"] as Int], + PlaneRenderer.from(map["planeRenderer"] as Map) + ) + } + } + + override fun toString(): String { + return "PlaneRenderer: ${planeRenderer}\n" + + "instantPlacementMode: $instantPlacementMode\n" + + "lightEstimationMode: $lightEstimationMode\n" + + "depthMode: $depthMode\n" + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/Convert.kt b/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/Convert.kt new file mode 100644 index 0000000..7e5c085 --- /dev/null +++ b/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/Convert.kt @@ -0,0 +1,39 @@ +package io.github.sceneview.sceneview_flutter + +import android.content.Context +import android.graphics.BitmapFactory +import android.util.Log + +class Convert { + + companion object { + fun toAugmentedImages( + context: Context, + list: List> + ): List { + val output = mutableListOf() + try { + list.forEach { map -> + if (map.containsKey("location") && map.containsKey("name")) { + val a = SceneViewAugmentedImage( + map["name"] as String, + context.assets.open( + Utils.getFlutterAssetKey( + context, + map["location"] as String, + ) + ) + .use(BitmapFactory::decodeStream) + ) + + output.add(a) + } + } + } catch (ex: Exception) { + Log.e("Convert.toAugmentedImages", ex.toString()); + } + return output + } + } + +} \ No newline at end of file diff --git a/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/FlutterSceneViewNode.kt b/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/FlutterSceneViewNode.kt index 7a70738..fcfcd7d 100644 --- a/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/FlutterSceneViewNode.kt +++ b/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/FlutterSceneViewNode.kt @@ -1,10 +1,11 @@ package io.github.sceneview.sceneview_flutter import dev.romainguy.kotlin.math.Float3 +import dev.romainguy.kotlin.math.Quaternion abstract class FlutterSceneViewNode( val position: Float3 = Float3(0f, 0f, 0f), - val rotation: Float3 = Float3(0f, 0f, 0f), + val rotation: Quaternion = Quaternion(0f, 0f, 0f), val scale: Float3 = Float3(0f, 0f, 0f), val scaleUnits: Float = 1.0f, ) { @@ -13,9 +14,9 @@ abstract class FlutterSceneViewNode( fun from(map: Map): FlutterSceneViewNode { val fileLocation = map["fileLocation"] as String? if (fileLocation != null) { - val p = FlutterPosition.from(map["position"] as Map?) - val r = FlutterRotation.from(map["rotation"] as Map?) - val s = FlutterScale.from(map["scale"] as Map?) + val p = FlutterPosition.from(map["position"] as List?) + val r = FlutterRotation.from(map["rotation"] as List?) + val s = FlutterScale.from(map["scale"] as List?) val scaleUnits = map["scaleUnits"] as Float? return FlutterReferenceNode( fileLocation, @@ -34,7 +35,7 @@ abstract class FlutterSceneViewNode( class FlutterReferenceNode( val fileLocation: String, position: Float3, - rotation: Float3, + rotation: Quaternion, scale: Float3, scaleUnits: Float ) : @@ -42,41 +43,42 @@ class FlutterReferenceNode( class FlutterPosition(val position: Float3) { companion object { - fun from(map: Map?): FlutterPosition { - if (map == null) { + fun from(list: List?): FlutterPosition { + if (list == null) { return FlutterPosition(Float3(0f, 0f, 0f)) } - val x = (map["x"] as Double).toFloat() - val y = (map["y"] as Double).toFloat() - val z = (map["z"] as Double).toFloat() + val x = (list[0] as Double).toFloat() + val y = (list[1] as Double).toFloat() + val z = (list[2] as Double).toFloat() return FlutterPosition(Float3(x, y, z)) } } } -class FlutterRotation(val rotation: Float3) { +class FlutterRotation(val rotation: Quaternion) { companion object { - fun from(map: Map?): FlutterRotation { - if (map == null) { - return FlutterRotation(Float3(0f, 0f, 0f)) + fun from(list: List?): FlutterRotation { + if (list == null) { + return FlutterRotation(Quaternion(0f, 0f, 0f, 0f)) } - val x = (map["x"] as Double).toFloat() - val y = (map["y"] as Double).toFloat() - val z = (map["z"] as Double).toFloat() - return FlutterRotation(Float3(x, y, z)) + val x = (list[0] as Double).toFloat() + val y = (list[1] as Double).toFloat() + val z = (list[2] as Double).toFloat() + val w = (list[3] as Double).toFloat() + return FlutterRotation(Quaternion(x, y, z, w)) } } } class FlutterScale(val scale: Float3) { companion object { - fun from(map: Map?): FlutterScale { - if (map == null) { + fun from(list: List?): FlutterScale { + if (list == null) { return FlutterScale(Float3(0f, 0f, 0f)) } - val x = (map["x"] as Double).toFloat() - val y = (map["y"] as Double).toFloat() - val z = (map["z"] as Double).toFloat() + val x = (list[0] as Double).toFloat() + val y = (list[1] as Double).toFloat() + val z = (list[2] as Double).toFloat() return FlutterScale(Float3(x, y, z)) } } diff --git a/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/PlaneRenderer.kt b/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/PlaneRenderer.kt new file mode 100644 index 0000000..fc399de --- /dev/null +++ b/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/PlaneRenderer.kt @@ -0,0 +1,19 @@ +package io.github.sceneview.sceneview_flutter + +class PlaneRenderer(val isEnabled: Boolean, val isVisible: Boolean) { + + companion object { + + fun from(map: Map): PlaneRenderer { + return PlaneRenderer( + map["isEnabled"] as Boolean, + map["isVisible"] as Boolean, + ) + } + } + + + override fun toString(): String { + return "isVisible: $isVisible, isEnabled: $isEnabled" + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/SceneViewAugmentedImage.kt b/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/SceneViewAugmentedImage.kt new file mode 100644 index 0000000..45e3f56 --- /dev/null +++ b/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/SceneViewAugmentedImage.kt @@ -0,0 +1,8 @@ +package io.github.sceneview.sceneview_flutter + +import android.graphics.Bitmap + +class SceneViewAugmentedImage( + val name: String, + val bitmap: Bitmap, +) \ No newline at end of file diff --git a/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/SceneViewBuilder.kt b/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/SceneViewBuilder.kt new file mode 100644 index 0000000..c3dc807 --- /dev/null +++ b/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/SceneViewBuilder.kt @@ -0,0 +1,28 @@ +package io.github.sceneview.sceneview_flutter + +import android.app.Activity +import android.content.Context +import android.util.Log +import androidx.lifecycle.Lifecycle +import io.flutter.plugin.common.BinaryMessenger + +class SceneViewBuilder { + + var augmentedImages = listOf() + lateinit var config: ARSceneViewConfig + + fun build( + context: Context, + activity: Activity, + messenger: BinaryMessenger, + lifecycle: Lifecycle, + viewId: Int + ): SceneViewWrapper { + Log.i("SceneViewBuilder", config.toString()); + val controller = + SceneViewWrapper(context, activity, lifecycle, messenger, viewId, config, augmentedImages); + //controller.init() + //controller.setMyLocationEnabled(myLocationEnabled) + return controller + } +} \ No newline at end of file diff --git a/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/SceneViewFactory.kt b/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/SceneViewFactory.kt index 766621d..cb41194 100644 --- a/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/SceneViewFactory.kt +++ b/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/SceneViewFactory.kt @@ -14,8 +14,23 @@ class SceneViewFactory( private val messenger: BinaryMessenger, private val lifecycle: Lifecycle, ) : PlatformViewFactory(StandardMessageCodec.INSTANCE) { - override fun create(context: Context, viewId: Int, args: Any?): PlatformView { + override fun create(context: Context, viewId: Int, params: Any?): PlatformView { Log.d("Factory", "Creating new view instance") - return SceneViewWrapper(context, activity, lifecycle, messenger, viewId); + val p = params as Map + val builder = SceneViewBuilder() + if(p.containsKey("arSceneviewConfig")){ + val c = p["arSceneviewConfig"] as Map + builder.config = ARSceneViewConfig.from(c) + } + if (p.containsKey("augmentedImages")) { + builder.augmentedImages = + Convert.toAugmentedImages( + context, + p["augmentedImages"] as List> + ) + } + + return builder.build(context, activity, messenger, lifecycle, viewId); + //return SceneViewWrapper(context, activity, lifecycle, messenger, viewId); } } \ No newline at end of file diff --git a/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/SceneViewWrapper.kt b/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/SceneViewWrapper.kt index d10935e..41a5630 100644 --- a/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/SceneViewWrapper.kt +++ b/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/SceneViewWrapper.kt @@ -7,14 +7,19 @@ import android.view.View import android.widget.FrameLayout import androidx.lifecycle.Lifecycle import com.google.ar.core.Config +import dev.romainguy.kotlin.math.Float3 import io.flutter.plugin.common.BinaryMessenger import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel.MethodCallHandler import io.flutter.plugin.platform.PlatformView import io.github.sceneview.ar.ARSceneView +import io.github.sceneview.ar.arcore.addAugmentedImage +import io.github.sceneview.ar.arcore.getUpdatedPlanes +import io.github.sceneview.ar.node.AugmentedImageNode import io.github.sceneview.model.ModelInstance import io.github.sceneview.node.ModelNode +import io.github.sceneview.sceneview_flutter.flutter_models.FlutterPose import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -25,11 +30,14 @@ class SceneViewWrapper( lifecycle: Lifecycle, messenger: BinaryMessenger, id: Int, + arConfig: ARSceneViewConfig, + private val augmentedImages: List, ) : PlatformView, MethodCallHandler { private val TAG = "SceneViewWrapper" private var sceneView: ARSceneView private val _mainScope = CoroutineScope(Dispatchers.Main) private val _channel = MethodChannel(messenger, "scene_view_$id") + val _augmentedImageNodes = mutableListOf() override fun getView(): View { Log.i(TAG, "getView:") @@ -42,15 +50,49 @@ class SceneViewWrapper( init { Log.i(TAG, "init") + Log.i(TAG, "there are " + augmentedImages.size.toString() + " augmentedImages") + sceneView = ARSceneView(context, sharedLifecycle = lifecycle) sceneView.apply { + + planeRenderer.isEnabled = arConfig.planeRenderer.isEnabled; + planeRenderer.isVisible = arConfig.planeRenderer.isVisible; + configureSession { session, config -> - config.lightEstimationMode = Config.LightEstimationMode.ENVIRONMENTAL_HDR - config.depthMode = when (session.isDepthModeSupported(Config.DepthMode.AUTOMATIC)) { - true -> Config.DepthMode.AUTOMATIC + augmentedImages.forEach { + config.addAugmentedImage(session, it.name, it.bitmap) + } + + config.lightEstimationMode = arConfig.lightEstimationMode + config.depthMode = when (session.isDepthModeSupported(arConfig.depthMode)) { + true -> arConfig.depthMode else -> Config.DepthMode.DISABLED } - config.instantPlacementMode = Config.InstantPlacementMode.DISABLED + config.instantPlacementMode = arConfig.instantPlacementMode + } + onSessionUpdated = { session, frame -> + val map = HashMap() + val list = ArrayList>() + //map["planes"] = + //frame.getUpdatedPlanes() + // .map { p -> hashMapOf("type" to p.type.ordinal) }.toList() + + frame.getUpdatedPlanes().forEach { p -> + val m = HashMap() + m["type"] = p.type.ordinal + m["centerPose"] = FlutterPose.fromPose(p.centerPose).toHashMap() + list.add(m) + } + + map["planes"] = list; + + Log.i(TAG, map.toString()); + _channel.invokeMethod("onSessionUpdated", map); + /*frame.getUpdatedPlanes() + .firstOrNull { it.type == Plane.Type.HORIZONTAL_UPWARD_FACING } + ?.let { plane -> + addAnchorNode(plane.createAnchor(plane.centerPose)) + }*/ } onSessionResumed = { session -> Log.i(TAG, "onSessionCreated") @@ -63,6 +105,7 @@ class SceneViewWrapper( } onTrackingFailureChanged = { reason -> Log.i(TAG, "onTrackingFailureChanged: $reason"); + _channel.invokeMethod("onTrackingFailureChanged", reason?.ordinal); } } sceneView.layoutParams = FrameLayout.LayoutParams( @@ -119,7 +162,11 @@ class SceneViewWrapper( val modelNode = ModelNode(modelInstance = model, scaleToUnits = 1.0f).apply { transform( position = flutterNode.position, - rotation = flutterNode.rotation, + rotation = Float3( + flutterNode.rotation.x, + flutterNode.rotation.y, + flutterNode.rotation.z + ), //scale = flutterNode.scale, ) //scaleToUnitsCube(flutterNode.scaleUnits) diff --git a/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/flutter_models/FlutterPose.kt b/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/flutter_models/FlutterPose.kt new file mode 100644 index 0000000..254e66e --- /dev/null +++ b/android/src/main/kotlin/io/github/sceneview/sceneview_flutter/flutter_models/FlutterPose.kt @@ -0,0 +1,28 @@ +package io.github.sceneview.sceneview_flutter.flutter_models + +import com.google.ar.core.Pose + +class FlutterPose(private val translation: FloatArray, private val rotation: FloatArray) { + + fun toHashMap(): HashMap { + val map: HashMap = HashMap() + map["translation"] = convertFloatArray(translation) + map["rotation"] = convertFloatArray(rotation) + return map + } + + private fun convertFloatArray(array: FloatArray): DoubleArray { + val doubleArray = DoubleArray(array.size) + for ((i, a) in array.withIndex()) { + doubleArray[i] = a.toDouble() + } + return doubleArray + } + + companion object{ + fun fromPose(pose: Pose): FlutterPose { + return FlutterPose(pose.translation, pose.rotationQuaternion) + } + } + +} \ No newline at end of file diff --git a/build.yaml b/build.yaml new file mode 100644 index 0000000..36f5477 --- /dev/null +++ b/build.yaml @@ -0,0 +1,7 @@ +targets: + $default: + builders: + json_serializable: + options: + explicit_to_json: true + any_map: true \ No newline at end of file diff --git a/example/assets/augmentedimages/qrcode.png b/example/assets/augmentedimages/qrcode.png new file mode 100644 index 0000000..86d8587 Binary files /dev/null and b/example/assets/augmentedimages/qrcode.png differ diff --git a/example/assets/augmentedimages/rabbit.jpg b/example/assets/augmentedimages/rabbit.jpg new file mode 100644 index 0000000..25e380d Binary files /dev/null and b/example/assets/augmentedimages/rabbit.jpg differ diff --git a/example/lib/main.dart b/example/lib/main.dart index d3ee098..de78ef8 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,8 +1,13 @@ import 'package:flutter/material.dart'; -import 'dart:async'; +import 'package:sceneview_flutter/arsceneview_config.dart'; +import 'package:sceneview_flutter/augmented_image.dart'; +import 'package:sceneview_flutter/depth_mode.dart'; +import 'package:sceneview_flutter/instant_placement_mode.dart'; +import 'package:sceneview_flutter/light_estimation_mode.dart'; import 'package:sceneview_flutter/sceneview_flutter.dart'; import 'package:sceneview_flutter/sceneview_node.dart'; +import 'package:sceneview_flutter/tracking_failure_reason.dart'; void main() { runApp(const MyApp()); @@ -16,6 +21,12 @@ class MyApp extends StatefulWidget { } class _MyAppState extends State { + TrackingFailureReason? reason; + + bool posed = false; + + late SceneViewController sceneViewController; + @override Widget build(BuildContext context) { return MaterialApp( @@ -26,15 +37,58 @@ class _MyAppState extends State { body: Stack( children: [ SceneView( + arSceneviewConfig: ARSceneviewConfig( + lightEstimationMode: LightEstimationMode.ambientIntensity, + instantPlacementMode: InstantPlacementMode.disabled, + depthMode: DepthMode.rawDepthOnly, + ), + augmentedImages: [ + AugmentedImage( + name: 'rabbit', + location: 'assets/augmentedimages/rabbit.jpg', + ), + ], onViewCreated: (controller) { print('flutter: onViewCreated'); - controller.addNode(SceneViewNode( - fileLocation: 'assets/models/MaterialSuite.glb', - position: KotlinFloat3(z: -1.0), - rotation: KotlinFloat3(x: 15), - )); + sceneViewController = controller; + // controller.addNode( + // SceneViewNode( + // fileLocation: 'assets/models/MaterialSuite.glb', + // position: KotlinFloat3(z: -1.0), + // rotation: KotlinFloat3(x: 15), + // ), + // ); + }, + onSessionUpdated: (frame) { + print('onSessionUpdated: $frame'); + if (!posed && frame.planes.isNotEmpty) { + sceneViewController.addNode( + SceneViewNode( + fileLocation: 'assets/models/MaterialSuite.glb', + position: frame.planes.first.centerPose?.translation, + rotation: frame.planes.first.centerPose?.rotation, + ), + ); + posed = true; + } + }, + onTrackingFailureChanged: (reason) { + print('onTrackingFailureChanged: $reason'); + if (this.reason != reason) { + setState(() { + this.reason = reason; + }); + } }, ), + if (reason != null && reason != TrackingFailureReason.NONE) + Align( + alignment: Alignment.bottomCenter, + child: Text( + reason!.name, + style: TextStyle(color: Colors.white, fontSize: 30), + ), + ), ], ), ), diff --git a/example/pubspec.lock b/example/pubspec.lock index bd05899..91b1769 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -59,6 +59,22 @@ packages: description: flutter source: sdk version: "0.0.0" + freezed_annotation: + dependency: transitive + description: + name: freezed_annotation + sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d + url: "https://pub.dev" + source: hosted + version: "2.4.1" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + url: "https://pub.dev" + source: hosted + version: "4.8.1" matcher: dependency: transitive description: @@ -95,10 +111,10 @@ packages: dependency: transitive description: name: plugin_platform_interface - sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a + sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.6" sceneview_flutter: dependency: "direct main" description: @@ -135,6 +151,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" + source: hosted + version: "2.1.0" string_scanner: dependency: transitive description: diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 0acb0f0..7912a9c 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -19,3 +19,4 @@ dev_dependencies: flutter: assets: - assets/models/MaterialSuite.glb + - assets/augmentedimages/ diff --git a/lib/arsceneview_config.dart b/lib/arsceneview_config.dart new file mode 100644 index 0000000..73e2a4d --- /dev/null +++ b/lib/arsceneview_config.dart @@ -0,0 +1,25 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:sceneview_flutter/depth_mode.dart'; +import 'package:sceneview_flutter/instant_placement_mode.dart'; +import 'package:sceneview_flutter/light_estimation_mode.dart'; +import 'package:sceneview_flutter/plane_renderer.dart'; + +part 'arsceneview_config.freezed.dart'; + +part 'arsceneview_config.g.dart'; + +@freezed +class ARSceneviewConfig with _$ARSceneviewConfig { + const factory ARSceneviewConfig({ + @Default(PlaneRenderer()) PlaneRenderer? planeRenderer, + @JsonEnum() + @Default(LightEstimationMode.disabled) + // @LightEstimationModeConverter() + LightEstimationMode lightEstimationMode, + @JsonEnum() @Default(DepthMode.disabled) DepthMode depthMode, + @JsonEnum() @Default(InstantPlacementMode.disabled) InstantPlacementMode instantPlacementMode, + }) = _ARSceneviewConfig; + + factory ARSceneviewConfig.fromJson(Map json) => + _$ARSceneviewConfigFromJson(json); +} diff --git a/lib/arsceneview_config.freezed.dart b/lib/arsceneview_config.freezed.dart new file mode 100644 index 0000000..80a41bc --- /dev/null +++ b/lib/arsceneview_config.freezed.dart @@ -0,0 +1,254 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'arsceneview_config.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +ARSceneviewConfig _$ARSceneviewConfigFromJson(Map json) { + return _ARSceneviewConfig.fromJson(json); +} + +/// @nodoc +mixin _$ARSceneviewConfig { + PlaneRenderer? get planeRenderer => throw _privateConstructorUsedError; + @JsonEnum() + LightEstimationMode get lightEstimationMode => + throw _privateConstructorUsedError; + @JsonEnum() + DepthMode get depthMode => throw _privateConstructorUsedError; + @JsonEnum() + InstantPlacementMode get instantPlacementMode => + throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ARSceneviewConfigCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ARSceneviewConfigCopyWith<$Res> { + factory $ARSceneviewConfigCopyWith( + ARSceneviewConfig value, $Res Function(ARSceneviewConfig) then) = + _$ARSceneviewConfigCopyWithImpl<$Res, ARSceneviewConfig>; + @useResult + $Res call( + {PlaneRenderer? planeRenderer, + @JsonEnum() LightEstimationMode lightEstimationMode, + @JsonEnum() DepthMode depthMode, + @JsonEnum() InstantPlacementMode instantPlacementMode}); + + $PlaneRendererCopyWith<$Res>? get planeRenderer; +} + +/// @nodoc +class _$ARSceneviewConfigCopyWithImpl<$Res, $Val extends ARSceneviewConfig> + implements $ARSceneviewConfigCopyWith<$Res> { + _$ARSceneviewConfigCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? planeRenderer = freezed, + Object? lightEstimationMode = null, + Object? depthMode = null, + Object? instantPlacementMode = null, + }) { + return _then(_value.copyWith( + planeRenderer: freezed == planeRenderer + ? _value.planeRenderer + : planeRenderer // ignore: cast_nullable_to_non_nullable + as PlaneRenderer?, + lightEstimationMode: null == lightEstimationMode + ? _value.lightEstimationMode + : lightEstimationMode // ignore: cast_nullable_to_non_nullable + as LightEstimationMode, + depthMode: null == depthMode + ? _value.depthMode + : depthMode // ignore: cast_nullable_to_non_nullable + as DepthMode, + instantPlacementMode: null == instantPlacementMode + ? _value.instantPlacementMode + : instantPlacementMode // ignore: cast_nullable_to_non_nullable + as InstantPlacementMode, + ) as $Val); + } + + @override + @pragma('vm:prefer-inline') + $PlaneRendererCopyWith<$Res>? get planeRenderer { + if (_value.planeRenderer == null) { + return null; + } + + return $PlaneRendererCopyWith<$Res>(_value.planeRenderer!, (value) { + return _then(_value.copyWith(planeRenderer: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$ARSceneviewConfigImplCopyWith<$Res> + implements $ARSceneviewConfigCopyWith<$Res> { + factory _$$ARSceneviewConfigImplCopyWith(_$ARSceneviewConfigImpl value, + $Res Function(_$ARSceneviewConfigImpl) then) = + __$$ARSceneviewConfigImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {PlaneRenderer? planeRenderer, + @JsonEnum() LightEstimationMode lightEstimationMode, + @JsonEnum() DepthMode depthMode, + @JsonEnum() InstantPlacementMode instantPlacementMode}); + + @override + $PlaneRendererCopyWith<$Res>? get planeRenderer; +} + +/// @nodoc +class __$$ARSceneviewConfigImplCopyWithImpl<$Res> + extends _$ARSceneviewConfigCopyWithImpl<$Res, _$ARSceneviewConfigImpl> + implements _$$ARSceneviewConfigImplCopyWith<$Res> { + __$$ARSceneviewConfigImplCopyWithImpl(_$ARSceneviewConfigImpl _value, + $Res Function(_$ARSceneviewConfigImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? planeRenderer = freezed, + Object? lightEstimationMode = null, + Object? depthMode = null, + Object? instantPlacementMode = null, + }) { + return _then(_$ARSceneviewConfigImpl( + planeRenderer: freezed == planeRenderer + ? _value.planeRenderer + : planeRenderer // ignore: cast_nullable_to_non_nullable + as PlaneRenderer?, + lightEstimationMode: null == lightEstimationMode + ? _value.lightEstimationMode + : lightEstimationMode // ignore: cast_nullable_to_non_nullable + as LightEstimationMode, + depthMode: null == depthMode + ? _value.depthMode + : depthMode // ignore: cast_nullable_to_non_nullable + as DepthMode, + instantPlacementMode: null == instantPlacementMode + ? _value.instantPlacementMode + : instantPlacementMode // ignore: cast_nullable_to_non_nullable + as InstantPlacementMode, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ARSceneviewConfigImpl implements _ARSceneviewConfig { + const _$ARSceneviewConfigImpl( + {this.planeRenderer = const PlaneRenderer(), + @JsonEnum() this.lightEstimationMode = LightEstimationMode.disabled, + @JsonEnum() this.depthMode = DepthMode.disabled, + @JsonEnum() this.instantPlacementMode = InstantPlacementMode.disabled}); + + factory _$ARSceneviewConfigImpl.fromJson(Map json) => + _$$ARSceneviewConfigImplFromJson(json); + + @override + @JsonKey() + final PlaneRenderer? planeRenderer; + @override + @JsonKey() + @JsonEnum() + final LightEstimationMode lightEstimationMode; + @override + @JsonKey() + @JsonEnum() + final DepthMode depthMode; + @override + @JsonKey() + @JsonEnum() + final InstantPlacementMode instantPlacementMode; + + @override + String toString() { + return 'ARSceneviewConfig(planeRenderer: $planeRenderer, lightEstimationMode: $lightEstimationMode, depthMode: $depthMode, instantPlacementMode: $instantPlacementMode)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ARSceneviewConfigImpl && + (identical(other.planeRenderer, planeRenderer) || + other.planeRenderer == planeRenderer) && + (identical(other.lightEstimationMode, lightEstimationMode) || + other.lightEstimationMode == lightEstimationMode) && + (identical(other.depthMode, depthMode) || + other.depthMode == depthMode) && + (identical(other.instantPlacementMode, instantPlacementMode) || + other.instantPlacementMode == instantPlacementMode)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, planeRenderer, + lightEstimationMode, depthMode, instantPlacementMode); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$ARSceneviewConfigImplCopyWith<_$ARSceneviewConfigImpl> get copyWith => + __$$ARSceneviewConfigImplCopyWithImpl<_$ARSceneviewConfigImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$ARSceneviewConfigImplToJson( + this, + ); + } +} + +abstract class _ARSceneviewConfig implements ARSceneviewConfig { + const factory _ARSceneviewConfig( + {final PlaneRenderer? planeRenderer, + @JsonEnum() final LightEstimationMode lightEstimationMode, + @JsonEnum() final DepthMode depthMode, + @JsonEnum() final InstantPlacementMode instantPlacementMode}) = + _$ARSceneviewConfigImpl; + + factory _ARSceneviewConfig.fromJson(Map json) = + _$ARSceneviewConfigImpl.fromJson; + + @override + PlaneRenderer? get planeRenderer; + @override + @JsonEnum() + LightEstimationMode get lightEstimationMode; + @override + @JsonEnum() + DepthMode get depthMode; + @override + @JsonEnum() + InstantPlacementMode get instantPlacementMode; + @override + @JsonKey(ignore: true) + _$$ARSceneviewConfigImplCopyWith<_$ARSceneviewConfigImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/arsceneview_config.g.dart b/lib/arsceneview_config.g.dart new file mode 100644 index 0000000..57a8cdd --- /dev/null +++ b/lib/arsceneview_config.g.dart @@ -0,0 +1,51 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'arsceneview_config.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$ARSceneviewConfigImpl _$$ARSceneviewConfigImplFromJson(Map json) => + _$ARSceneviewConfigImpl( + planeRenderer: json['planeRenderer'] == null + ? const PlaneRenderer() + : PlaneRenderer.fromJson( + Map.from(json['planeRenderer'] as Map)), + lightEstimationMode: $enumDecodeNullable( + _$LightEstimationModeEnumMap, json['lightEstimationMode']) ?? + LightEstimationMode.disabled, + depthMode: $enumDecodeNullable(_$DepthModeEnumMap, json['depthMode']) ?? + DepthMode.disabled, + instantPlacementMode: $enumDecodeNullable( + _$InstantPlacementModeEnumMap, json['instantPlacementMode']) ?? + InstantPlacementMode.disabled, + ); + +Map _$$ARSceneviewConfigImplToJson( + _$ARSceneviewConfigImpl instance) => + { + 'planeRenderer': instance.planeRenderer?.toJson(), + 'lightEstimationMode': + _$LightEstimationModeEnumMap[instance.lightEstimationMode]!, + 'depthMode': _$DepthModeEnumMap[instance.depthMode]!, + 'instantPlacementMode': + _$InstantPlacementModeEnumMap[instance.instantPlacementMode]!, + }; + +const _$LightEstimationModeEnumMap = { + LightEstimationMode.disabled: 0, + LightEstimationMode.ambientIntensity: 1, + LightEstimationMode.environmentalHdr: 2, +}; + +const _$DepthModeEnumMap = { + DepthMode.disabled: 0, + DepthMode.automatic: 1, + DepthMode.rawDepthOnly: 2, +}; + +const _$InstantPlacementModeEnumMap = { + InstantPlacementMode.disabled: 0, + InstantPlacementMode.localYUp: 1, +}; diff --git a/lib/augmented_image.dart b/lib/augmented_image.dart new file mode 100644 index 0000000..57f8b13 --- /dev/null +++ b/lib/augmented_image.dart @@ -0,0 +1,16 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'augmented_image.freezed.dart'; + +part 'augmented_image.g.dart'; + +@freezed +class AugmentedImage with _$AugmentedImage { + const factory AugmentedImage({ + required String name, + required String location, + }) = _AuAugmentedImage; + + factory AugmentedImage.fromJson(Map json) => + _$AugmentedImageFromJson(json); +} \ No newline at end of file diff --git a/lib/augmented_image.freezed.dart b/lib/augmented_image.freezed.dart new file mode 100644 index 0000000..140f798 --- /dev/null +++ b/lib/augmented_image.freezed.dart @@ -0,0 +1,171 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'augmented_image.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +AugmentedImage _$AugmentedImageFromJson(Map json) { + return _AuAugmentedImage.fromJson(json); +} + +/// @nodoc +mixin _$AugmentedImage { + String get name => throw _privateConstructorUsedError; + String get location => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $AugmentedImageCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AugmentedImageCopyWith<$Res> { + factory $AugmentedImageCopyWith( + AugmentedImage value, $Res Function(AugmentedImage) then) = + _$AugmentedImageCopyWithImpl<$Res, AugmentedImage>; + @useResult + $Res call({String name, String location}); +} + +/// @nodoc +class _$AugmentedImageCopyWithImpl<$Res, $Val extends AugmentedImage> + implements $AugmentedImageCopyWith<$Res> { + _$AugmentedImageCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? name = null, + Object? location = null, + }) { + return _then(_value.copyWith( + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + location: null == location + ? _value.location + : location // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$AuAugmentedImageImplCopyWith<$Res> + implements $AugmentedImageCopyWith<$Res> { + factory _$$AuAugmentedImageImplCopyWith(_$AuAugmentedImageImpl value, + $Res Function(_$AuAugmentedImageImpl) then) = + __$$AuAugmentedImageImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({String name, String location}); +} + +/// @nodoc +class __$$AuAugmentedImageImplCopyWithImpl<$Res> + extends _$AugmentedImageCopyWithImpl<$Res, _$AuAugmentedImageImpl> + implements _$$AuAugmentedImageImplCopyWith<$Res> { + __$$AuAugmentedImageImplCopyWithImpl(_$AuAugmentedImageImpl _value, + $Res Function(_$AuAugmentedImageImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? name = null, + Object? location = null, + }) { + return _then(_$AuAugmentedImageImpl( + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + location: null == location + ? _value.location + : location // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$AuAugmentedImageImpl implements _AuAugmentedImage { + const _$AuAugmentedImageImpl({required this.name, required this.location}); + + factory _$AuAugmentedImageImpl.fromJson(Map json) => + _$$AuAugmentedImageImplFromJson(json); + + @override + final String name; + @override + final String location; + + @override + String toString() { + return 'AugmentedImage(name: $name, location: $location)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$AuAugmentedImageImpl && + (identical(other.name, name) || other.name == name) && + (identical(other.location, location) || + other.location == location)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, name, location); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$AuAugmentedImageImplCopyWith<_$AuAugmentedImageImpl> get copyWith => + __$$AuAugmentedImageImplCopyWithImpl<_$AuAugmentedImageImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$AuAugmentedImageImplToJson( + this, + ); + } +} + +abstract class _AuAugmentedImage implements AugmentedImage { + const factory _AuAugmentedImage( + {required final String name, + required final String location}) = _$AuAugmentedImageImpl; + + factory _AuAugmentedImage.fromJson(Map json) = + _$AuAugmentedImageImpl.fromJson; + + @override + String get name; + @override + String get location; + @override + @JsonKey(ignore: true) + _$$AuAugmentedImageImplCopyWith<_$AuAugmentedImageImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/augmented_image.g.dart b/lib/augmented_image.g.dart new file mode 100644 index 0000000..c9e5eb6 --- /dev/null +++ b/lib/augmented_image.g.dart @@ -0,0 +1,20 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'augmented_image.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$AuAugmentedImageImpl _$$AuAugmentedImageImplFromJson(Map json) => + _$AuAugmentedImageImpl( + name: json['name'] as String, + location: json['location'] as String, + ); + +Map _$$AuAugmentedImageImplToJson( + _$AuAugmentedImageImpl instance) => + { + 'name': instance.name, + 'location': instance.location, + }; diff --git a/lib/depth_mode.dart b/lib/depth_mode.dart new file mode 100644 index 0000000..e43b7dd --- /dev/null +++ b/lib/depth_mode.dart @@ -0,0 +1,51 @@ +import 'package:json_annotation/json_annotation.dart'; +// +// part 'depth_mode.g.dart'; +// +// @JsonEnum() +enum DepthMode { + /** + * No depth information will be provided. Calling {@link + * com.google.ar.core.Frame#acquireDepthImage16Bits Frame#acquireDepthImage16Bits} throws {@link + * java.lang.IllegalStateException}. + */ + @JsonValue(0) + disabled, + /** + * On supported devices, the best + * possible depth is estimated based on hardware and software sources. Available sources of + * automatic depth are: + * + *
    + *
  • Depth from motion, using the main RGB camera + *
  • Hardware depth sensor, such as a time-of-flight sensor (or ToF sensor) + *
+ * + * Provides depth estimation for every pixel in the image, and works best for static scenes. + * Adds significant computational load. + * + *

With this mode enabled, {@link com.google.ar.core.Frame#hitTest Frame#hitTest} also + * returns {@link com.google.ar.core.DepthPoint DepthPoint} in the output {@code + * List}, which are sampled from the generated depth image for the current frame if + * available. + */ + @JsonValue(1) + automatic, + /** + * On ARCore supported devices that also + * support the Depth API, provides a "raw", mostly unfiltered, depth image ({@link + * com.google.ar.core.Frame#acquireRawDepthImage16Bits }) and depth confidence image ({@link + * com.google.ar.core.Frame#acquireRawDepthConfidenceImage }). + * + *

The raw depth image is sparse and does not provide valid depth for all pixels. Pixels + * without a valid depth estimate have a pixel value of 0. + * + *

Raw depth data is also available when {@link com.google.ar.core.Config.DepthMode#AUTOMATIC + * DepthMode#AUTOMATIC} is selected. + * + *

Raw depth is intended to be used in cases that involve understanding of the geometry in + * the environment. + */ + @JsonValue(2) + rawDepthOnly; +} diff --git a/lib/enum_converter.dart b/lib/enum_converter.dart new file mode 100644 index 0000000..ea95b91 --- /dev/null +++ b/lib/enum_converter.dart @@ -0,0 +1,18 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:sceneview_flutter/light_estimation_mode.dart'; + +class LightEstimationModeConverter implements JsonConverter{ + + const LightEstimationModeConverter(); + + @override + LightEstimationMode fromJson(json) { + return LightEstimationMode.values[json]; + } + + @override + int toJson(LightEstimationMode object) { + return object.index; + } + +} \ No newline at end of file diff --git a/lib/instant_placement_mode.dart b/lib/instant_placement_mode.dart new file mode 100644 index 0000000..37bdd5e --- /dev/null +++ b/lib/instant_placement_mode.dart @@ -0,0 +1,50 @@ +import 'package:json_annotation/json_annotation.dart'; + +/** + * Select the behavior of Instant Placement. Default value is {@link #DISABLED}. + * + *

Use {@link + * com.google.ar.core.Config#setInstantPlacementMode(com.google.ar.core.Config.InstantPlacementMode) + * Config#setInstantPlacementMode(InstantPlacementMode)} to set the desired mode. + */ +enum InstantPlacementMode { + /** + * Disable Instant Placement. {@link + * com.google.ar.core.Frame#hitTestInstantPlacement(float,float,float) + * Frame#hitTestInstantPlacement(float, float, float)} will return an empty list. + * + *

When Instant Placement is disabled, any {@link com.google.ar.core.InstantPlacementPoint + * InstantPlacementPoint} that has {@link + * com.google.ar.core.InstantPlacementPoint.TrackingMethod#SCREENSPACE_WITH_APPROXIMATE_DISTANCE + * } tracking method will result in tracking state becoming permanently {@link + * com.google.ar.core.TrackingState#STOPPED TrackingState#STOPPED}. + */ + @JsonValue(0) + disabled, + /** + * Enable Instant Placement. If the hit test is successful, {@link + * com.google.ar.core.Frame#hitTestInstantPlacement(float,float,float) } will return a single + * {@link com.google.ar.core.InstantPlacementPoint InstantPlacementPoint} with the +Y pointing + * upward, against gravity. Otherwise, returns an empty result set. + * + *

This mode is currently intended to be used with hit tests against horizontal surfaces. + * + *

Hit tests may also be performed against surfaces with any orientation, however: + * + *

    + *
  • The resulting Instant Placement point will always have a pose with +Y pointing upward, + * against gravity. + *
  • No guarantees are made with respect to orientation of +X and +Z. Specifically, a hit + * test against a vertical surface, such as a wall, will not result in a pose that's in + * any way aligned to the plane of the wall, other than +Y being up, against gravity. + *
  • The {@link com.google.ar.core.InstantPlacementPoint InstantPlacementPoint}'s tracking + * method may never become {@link + * com.google.ar.core.InstantPlacementPoint.TrackingMethod#FULL_TRACKING } or may take a + * long time to reach this state. The tracking method remains {@link + * com.google.ar.core.InstantPlacementPoint.TrackingMethod#SCREENSPACE_WITH_APPROXIMATE_DISTANCE + * } until a (tiny) horizontal plane is fitted at the point of the hit test. + *
+ */ + @JsonValue(1) + localYUp; +} diff --git a/lib/light_estimation_mode.dart b/lib/light_estimation_mode.dart new file mode 100644 index 0000000..e88c630 --- /dev/null +++ b/lib/light_estimation_mode.dart @@ -0,0 +1,27 @@ +import 'package:json_annotation/json_annotation.dart'; +// +//part 'light_estimation_mode.g.dart'; +// +// @JsonEnum() +enum LightEstimationMode { + /** Lighting estimation is disabled. */ + @JsonValue(0) + disabled, + /** + * Lighting estimation is enabled, generating a single-value intensity estimate and three (R, G, + * B) color correction values. + */ + @JsonValue(1) + ambientIntensity, + /** + * Lighting estimation is enabled, generating inferred Environmental HDR lighting estimation in + * linear color space. + * + *

This mode is incompatible with the front-facing (selfie) camera. If set on a Session + * created for the front-facing camera, the call to configure will fail. + */ + @JsonValue(2) + environmentalHdr; + + // String toJson() => _$AEnumMap[this]!; +} \ No newline at end of file diff --git a/lib/plane.dart b/lib/plane.dart new file mode 100644 index 0000000..f92e969 --- /dev/null +++ b/lib/plane.dart @@ -0,0 +1,17 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:sceneview_flutter/plane_type.dart'; +import 'package:sceneview_flutter/pose.dart'; + +part 'plane.freezed.dart'; + +part 'plane.g.dart'; + +@freezed +class Plane with _$Plane { + const factory Plane({ + @JsonEnum() PlaneType? type, + Pose? centerPose, + }) = _Plane; + + factory Plane.fromJson(Map json) => _$PlaneFromJson(json); +} diff --git a/lib/plane.freezed.dart b/lib/plane.freezed.dart new file mode 100644 index 0000000..fa265ef --- /dev/null +++ b/lib/plane.freezed.dart @@ -0,0 +1,169 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'plane.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +Plane _$PlaneFromJson(Map json) { + return _Plane.fromJson(json); +} + +/// @nodoc +mixin _$Plane { + @JsonEnum() + PlaneType? get type => throw _privateConstructorUsedError; + Pose? get centerPose => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $PlaneCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $PlaneCopyWith<$Res> { + factory $PlaneCopyWith(Plane value, $Res Function(Plane) then) = + _$PlaneCopyWithImpl<$Res, Plane>; + @useResult + $Res call({@JsonEnum() PlaneType? type, Pose? centerPose}); +} + +/// @nodoc +class _$PlaneCopyWithImpl<$Res, $Val extends Plane> + implements $PlaneCopyWith<$Res> { + _$PlaneCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? type = freezed, + Object? centerPose = freezed, + }) { + return _then(_value.copyWith( + type: freezed == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as PlaneType?, + centerPose: freezed == centerPose + ? _value.centerPose + : centerPose // ignore: cast_nullable_to_non_nullable + as Pose?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$PlaneImplCopyWith<$Res> implements $PlaneCopyWith<$Res> { + factory _$$PlaneImplCopyWith( + _$PlaneImpl value, $Res Function(_$PlaneImpl) then) = + __$$PlaneImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({@JsonEnum() PlaneType? type, Pose? centerPose}); +} + +/// @nodoc +class __$$PlaneImplCopyWithImpl<$Res> + extends _$PlaneCopyWithImpl<$Res, _$PlaneImpl> + implements _$$PlaneImplCopyWith<$Res> { + __$$PlaneImplCopyWithImpl( + _$PlaneImpl _value, $Res Function(_$PlaneImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? type = freezed, + Object? centerPose = freezed, + }) { + return _then(_$PlaneImpl( + type: freezed == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as PlaneType?, + centerPose: freezed == centerPose + ? _value.centerPose + : centerPose // ignore: cast_nullable_to_non_nullable + as Pose?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$PlaneImpl implements _Plane { + const _$PlaneImpl({@JsonEnum() this.type, this.centerPose}); + + factory _$PlaneImpl.fromJson(Map json) => + _$$PlaneImplFromJson(json); + + @override + @JsonEnum() + final PlaneType? type; + @override + final Pose? centerPose; + + @override + String toString() { + return 'Plane(type: $type, centerPose: $centerPose)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$PlaneImpl && + (identical(other.type, type) || other.type == type) && + (identical(other.centerPose, centerPose) || + other.centerPose == centerPose)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, type, centerPose); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$PlaneImplCopyWith<_$PlaneImpl> get copyWith => + __$$PlaneImplCopyWithImpl<_$PlaneImpl>(this, _$identity); + + @override + Map toJson() { + return _$$PlaneImplToJson( + this, + ); + } +} + +abstract class _Plane implements Plane { + const factory _Plane( + {@JsonEnum() final PlaneType? type, + final Pose? centerPose}) = _$PlaneImpl; + + factory _Plane.fromJson(Map json) = _$PlaneImpl.fromJson; + + @override + @JsonEnum() + PlaneType? get type; + @override + Pose? get centerPose; + @override + @JsonKey(ignore: true) + _$$PlaneImplCopyWith<_$PlaneImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/plane.g.dart b/lib/plane.g.dart new file mode 100644 index 0000000..ed3a4c7 --- /dev/null +++ b/lib/plane.g.dart @@ -0,0 +1,26 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'plane.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$PlaneImpl _$$PlaneImplFromJson(Map json) => _$PlaneImpl( + type: $enumDecodeNullable(_$PlaneTypeEnumMap, json['type']), + centerPose: json['centerPose'] == null + ? null + : Pose.fromJson(Map.from(json['centerPose'] as Map)), + ); + +Map _$$PlaneImplToJson(_$PlaneImpl instance) => + { + 'type': _$PlaneTypeEnumMap[instance.type], + 'centerPose': instance.centerPose?.toJson(), + }; + +const _$PlaneTypeEnumMap = { + PlaneType.horizontalUpwardFacing: 0, + PlaneType.horizontalDownwardFacing: 1, + PlaneType.vertical: 2, +}; diff --git a/lib/plane_renderer.dart b/lib/plane_renderer.dart new file mode 100644 index 0000000..3080e22 --- /dev/null +++ b/lib/plane_renderer.dart @@ -0,0 +1,16 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'plane_renderer.freezed.dart'; + +part 'plane_renderer.g.dart'; + +@freezed +class PlaneRenderer with _$PlaneRenderer { + const factory PlaneRenderer({ + @Default(true) bool? isVisible, + @Default(true) bool? isEnabled, + }) = _PlaneRenderer; + + factory PlaneRenderer.fromJson(Map json) => + _$PlaneRendererFromJson(json); +} diff --git a/lib/plane_renderer.freezed.dart b/lib/plane_renderer.freezed.dart new file mode 100644 index 0000000..16a2fe4 --- /dev/null +++ b/lib/plane_renderer.freezed.dart @@ -0,0 +1,172 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'plane_renderer.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +PlaneRenderer _$PlaneRendererFromJson(Map json) { + return _PlaneRenderer.fromJson(json); +} + +/// @nodoc +mixin _$PlaneRenderer { + bool? get isVisible => throw _privateConstructorUsedError; + bool? get isEnabled => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $PlaneRendererCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $PlaneRendererCopyWith<$Res> { + factory $PlaneRendererCopyWith( + PlaneRenderer value, $Res Function(PlaneRenderer) then) = + _$PlaneRendererCopyWithImpl<$Res, PlaneRenderer>; + @useResult + $Res call({bool? isVisible, bool? isEnabled}); +} + +/// @nodoc +class _$PlaneRendererCopyWithImpl<$Res, $Val extends PlaneRenderer> + implements $PlaneRendererCopyWith<$Res> { + _$PlaneRendererCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? isVisible = freezed, + Object? isEnabled = freezed, + }) { + return _then(_value.copyWith( + isVisible: freezed == isVisible + ? _value.isVisible + : isVisible // ignore: cast_nullable_to_non_nullable + as bool?, + isEnabled: freezed == isEnabled + ? _value.isEnabled + : isEnabled // ignore: cast_nullable_to_non_nullable + as bool?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$PlaneRendererImplCopyWith<$Res> + implements $PlaneRendererCopyWith<$Res> { + factory _$$PlaneRendererImplCopyWith( + _$PlaneRendererImpl value, $Res Function(_$PlaneRendererImpl) then) = + __$$PlaneRendererImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({bool? isVisible, bool? isEnabled}); +} + +/// @nodoc +class __$$PlaneRendererImplCopyWithImpl<$Res> + extends _$PlaneRendererCopyWithImpl<$Res, _$PlaneRendererImpl> + implements _$$PlaneRendererImplCopyWith<$Res> { + __$$PlaneRendererImplCopyWithImpl( + _$PlaneRendererImpl _value, $Res Function(_$PlaneRendererImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? isVisible = freezed, + Object? isEnabled = freezed, + }) { + return _then(_$PlaneRendererImpl( + isVisible: freezed == isVisible + ? _value.isVisible + : isVisible // ignore: cast_nullable_to_non_nullable + as bool?, + isEnabled: freezed == isEnabled + ? _value.isEnabled + : isEnabled // ignore: cast_nullable_to_non_nullable + as bool?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$PlaneRendererImpl implements _PlaneRenderer { + const _$PlaneRendererImpl({this.isVisible = true, this.isEnabled = true}); + + factory _$PlaneRendererImpl.fromJson(Map json) => + _$$PlaneRendererImplFromJson(json); + + @override + @JsonKey() + final bool? isVisible; + @override + @JsonKey() + final bool? isEnabled; + + @override + String toString() { + return 'PlaneRenderer(isVisible: $isVisible, isEnabled: $isEnabled)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$PlaneRendererImpl && + (identical(other.isVisible, isVisible) || + other.isVisible == isVisible) && + (identical(other.isEnabled, isEnabled) || + other.isEnabled == isEnabled)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, isVisible, isEnabled); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$PlaneRendererImplCopyWith<_$PlaneRendererImpl> get copyWith => + __$$PlaneRendererImplCopyWithImpl<_$PlaneRendererImpl>(this, _$identity); + + @override + Map toJson() { + return _$$PlaneRendererImplToJson( + this, + ); + } +} + +abstract class _PlaneRenderer implements PlaneRenderer { + const factory _PlaneRenderer({final bool? isVisible, final bool? isEnabled}) = + _$PlaneRendererImpl; + + factory _PlaneRenderer.fromJson(Map json) = + _$PlaneRendererImpl.fromJson; + + @override + bool? get isVisible; + @override + bool? get isEnabled; + @override + @JsonKey(ignore: true) + _$$PlaneRendererImplCopyWith<_$PlaneRendererImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/plane_renderer.g.dart b/lib/plane_renderer.g.dart new file mode 100644 index 0000000..f2ebd1d --- /dev/null +++ b/lib/plane_renderer.g.dart @@ -0,0 +1,19 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'plane_renderer.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$PlaneRendererImpl _$$PlaneRendererImplFromJson(Map json) => + _$PlaneRendererImpl( + isVisible: json['isVisible'] as bool? ?? true, + isEnabled: json['isEnabled'] as bool? ?? true, + ); + +Map _$$PlaneRendererImplToJson(_$PlaneRendererImpl instance) => + { + 'isVisible': instance.isVisible, + 'isEnabled': instance.isEnabled, + }; diff --git a/lib/plane_type.dart b/lib/plane_type.dart new file mode 100644 index 0000000..36f587e --- /dev/null +++ b/lib/plane_type.dart @@ -0,0 +1,13 @@ +import 'package:json_annotation/json_annotation.dart'; + +enum PlaneType { + /** A horizontal plane facing upward (e.g. floor or tabletop). */ + @JsonValue(0) + horizontalUpwardFacing, + /** A horizontal plane facing downward (e.g. a ceiling). */ + @JsonValue(1) + horizontalDownwardFacing, + /** A vertical plane (e.g. a wall). */ + @JsonValue(2) + vertical; +} \ No newline at end of file diff --git a/lib/pose.dart b/lib/pose.dart new file mode 100644 index 0000000..5cb52a8 --- /dev/null +++ b/lib/pose.dart @@ -0,0 +1,26 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:sceneview_flutter/vector_converter.dart'; +import 'package:vector_math/vector_math.dart'; + +part 'pose.g.dart'; + +@JsonSerializable() +class Pose { + @Vector3Converter() + final Vector3 translation; + @Vector4Converter() + final Vector4 rotation; + + Pose(this.translation, this.rotation); + + @override + factory Pose.fromJson(Map map) { + return Pose( + Vector3.array(map["translation"]), + Vector4.array(map["rotation"]), + ); + } + + @override + Map toJson() => _$PoseToJson(this); +} diff --git a/lib/pose.g.dart b/lib/pose.g.dart new file mode 100644 index 0000000..428a0b7 --- /dev/null +++ b/lib/pose.g.dart @@ -0,0 +1,17 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'pose.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Pose _$PoseFromJson(Map json) => Pose( + const Vector3Converter().fromJson(json['translation'] as List), + const Vector4Converter().fromJson(json['rotation'] as List), + ); + +Map _$PoseToJson(Pose instance) => { + 'translation': const Vector3Converter().toJson(instance.translation), + 'rotation': const Vector4Converter().toJson(instance.rotation), + }; diff --git a/lib/scene_view.dart b/lib/scene_view.dart index cdc4931..58cf75d 100644 --- a/lib/scene_view.dart +++ b/lib/scene_view.dart @@ -1,18 +1,21 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter/services.dart'; -import 'package:sceneview_flutter/sceneview_controller.dart'; +part of scene_view_flutter; class SceneView extends StatefulWidget { const SceneView({ super.key, + this.arSceneviewConfig = const ARSceneviewConfig(), this.onViewCreated, + this.onSessionUpdated, + this.onTrackingFailureChanged, + this.augmentedImages, }); + final ARSceneviewConfig arSceneviewConfig; + + final Function(SessionFrame)? onSessionUpdated; + + final Function(TrackingFailureReason)? onTrackingFailureChanged; + final List? augmentedImages; final Function(SceneViewController)? onViewCreated; @override @@ -23,12 +26,22 @@ class _SceneViewState extends State { final Completer _controller = Completer(); + final Map creationParams = {}; + + @override + void initState() { + super.initState(); + if (widget.augmentedImages != null) { + creationParams['augmentedImages'] = + widget.augmentedImages!.map((e) => e.toJson()).toList(); + } + creationParams['arSceneviewConfig'] = widget.arSceneviewConfig.toJson(); + } + @override Widget build(BuildContext context) { // This is used in the platform side to register the view. const String viewType = 'SceneView'; - // Pass parameters to the platform side. - const Map creationParams = {}; return PlatformViewLink( viewType: viewType, @@ -59,7 +72,7 @@ class _SceneViewState extends State { } Future onPlatformViewCreated(int id) async { - final controller = await SceneViewController.init(id); + final controller = await SceneViewController.init(id, this); _controller.complete(controller); widget.onViewCreated?.call(controller); } @@ -71,7 +84,7 @@ class _SceneViewState extends State { } Future _disposeController() async { - final SceneViewController controller = await _controller.future; + final controller = await _controller.future; controller.dispose(); } } diff --git a/lib/sceneview_controller.dart b/lib/sceneview_controller.dart index 1cb78c8..3afbf75 100644 --- a/lib/sceneview_controller.dart +++ b/lib/sceneview_controller.dart @@ -1,19 +1,38 @@ -import 'package:flutter/services.dart'; -import 'package:sceneview_flutter/sceneview_flutter_platform_interface.dart'; -import 'package:sceneview_flutter/sceneview_node.dart'; +part of scene_view_flutter; class SceneViewController { - SceneViewController._({ + SceneViewController._( + this._sceneViewState, { required this.sceneId, - }); + }) { + _connectStream(); + } final int sceneId; + final _SceneViewState _sceneViewState; static Future init( - int sceneId, - ) async { + int sceneId, _SceneViewState state) async { await SceneviewFlutterPlatform.instance.init(sceneId); - return SceneViewController._(sceneId: sceneId); + return SceneViewController._(state, sceneId: sceneId); + } + + _connectStream() { + if (_sceneViewState.widget.onSessionUpdated != null) { + SceneviewFlutterPlatform.instance.onSessionUpdated().listen( + (event) { + _sceneViewState.widget.onSessionUpdated!(event); + }, + ); + } + + if (_sceneViewState.widget.onSessionUpdated != null) { + SceneviewFlutterPlatform.instance.onTrackingFailureChanged().listen( + (event) { + _sceneViewState.widget.onTrackingFailureChanged!(event); + }, + ); + } } void addNode(SceneViewNode node) { @@ -23,5 +42,4 @@ class SceneViewController { void dispose() { SceneviewFlutterPlatform.instance.dispose(sceneId); } - } diff --git a/lib/sceneview_flutter.dart b/lib/sceneview_flutter.dart index 8266837..8b84c10 100644 --- a/lib/sceneview_flutter.dart +++ b/lib/sceneview_flutter.dart @@ -1,6 +1,18 @@ -import 'sceneview_flutter_platform_interface.dart'; +library scene_view_flutter; -export 'sceneview_controller.dart'; -export 'scene_view.dart'; +import 'package:flutter/material.dart'; +import 'dart:async'; -class SceneviewFlutter {} +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:sceneview_flutter/arsceneview_config.dart'; +import 'package:sceneview_flutter/augmented_image.dart'; +import 'package:sceneview_flutter/sceneview_flutter_platform_interface.dart'; +import 'package:sceneview_flutter/sceneview_node.dart'; +import 'package:sceneview_flutter/session_frame.dart'; +import 'package:sceneview_flutter/tracking_failure_reason.dart'; + +part 'sceneview_controller.dart'; +part 'scene_view.dart'; diff --git a/lib/sceneview_flutter_method_channel.dart b/lib/sceneview_flutter_method_channel.dart index f4219c8..ea4ed3e 100644 --- a/lib/sceneview_flutter_method_channel.dart +++ b/lib/sceneview_flutter_method_channel.dart @@ -1,8 +1,13 @@ +import 'dart:async'; + import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:sceneview_flutter/sceneview_node.dart'; +import 'package:sceneview_flutter/session_frame.dart'; +import 'package:sceneview_flutter/tracking_failure_reason.dart'; import 'sceneview_flutter_platform_interface.dart'; +import 'package:stream_transform/stream_transform.dart'; /// An implementation of [SceneviewFlutterPlatform] that uses method channels. class MethodChannelSceneViewFlutter extends SceneviewFlutterPlatform { @@ -22,12 +27,16 @@ class MethodChannelSceneViewFlutter extends SceneviewFlutterPlatform { if (channel == null) { channel = MethodChannel('scene_view_$sceneId'); channel.setMethodCallHandler( - (MethodCall call) => _handleMethodCall(call, sceneId)); + (MethodCall call) => _handleMethodCall(call, sceneId)); _channel = channel; } return channel; } + final StreamController _mapEventStreamController = + StreamController.broadcast(); + + Stream _events() => _mapEventStreamController.stream; @override Future init(int sceneId) async { @@ -37,16 +46,51 @@ class MethodChannelSceneViewFlutter extends SceneviewFlutterPlatform { @override void addNode(SceneViewNode node) { - _channel?.invokeMethod('addNode', node.toMap()); + _channel?.invokeMethod('addNode', node.toJson()); + } + + @override + Stream onSessionUpdated() { + return _events().whereType(); + } + + @override + Stream onTrackingFailureChanged() { + return _events().whereType(); } Future _handleMethodCall(MethodCall call, int mapId) async { switch (call.method) { + case 'onTrackingFailureChanged': + _mapEventStreamController + .add(TrackingFailureReason.values[call.arguments as int]); + break; + case 'onSessionUpdated': + try { + final map = _getArgumentDictionary(call); + + if (map.containsKey('planes')) { + print('----------- contains planes'); + if ((map['planes'] as List).isNotEmpty) { + print('-----------$map'); + + _mapEventStreamController.add(SessionFrame.fromJson(map)); + } + } + } catch (ex, st) { + print('ERROR: $ex'); + print('ERROR: $st'); + } + break; default: throw MissingPluginException(); } } + Map _getArgumentDictionary(MethodCall call) { + return Map.from(call.arguments); + } + @override void dispose(int sceneId) {} } diff --git a/lib/sceneview_flutter_platform_interface.dart b/lib/sceneview_flutter_platform_interface.dart index fdbfa19..edd0b37 100644 --- a/lib/sceneview_flutter_platform_interface.dart +++ b/lib/sceneview_flutter_platform_interface.dart @@ -1,5 +1,7 @@ import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'package:sceneview_flutter/sceneview_node.dart'; +import 'package:sceneview_flutter/session_frame.dart'; +import 'package:sceneview_flutter/tracking_failure_reason.dart'; import 'sceneview_flutter_method_channel.dart'; @@ -32,7 +34,16 @@ abstract class SceneviewFlutterPlatform extends PlatformInterface { throw UnimplementedError('addNode() has not been implemented.'); } - void dispose(int sceneId){ + Stream onSessionUpdated() { + throw UnimplementedError('onSessionUpdated() has not been implemented.'); + } + + Stream onTrackingFailureChanged() { + throw UnimplementedError( + 'onTrackingFailureChanged() has not been implemented.'); + } + + void dispose(int sceneId) { throw UnimplementedError('dispose() has not been implemented.'); } } diff --git a/lib/sceneview_node.dart b/lib/sceneview_node.dart index f4ed406..0afb683 100644 --- a/lib/sceneview_node.dart +++ b/lib/sceneview_node.dart @@ -1,17 +1,24 @@ -class SceneViewNode { - final String fileLocation; - final KotlinFloat3? position; - final KotlinFloat3? rotation; - final double? scale; - - SceneViewNode({ - required this.fileLocation, - this.position, - this.rotation, - this.scale, - }); - - Map toMap() { +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:sceneview_flutter/vector_converter.dart'; +import 'package:vector_math/vector_math.dart'; + +part 'sceneview_node.freezed.dart'; + +part 'sceneview_node.g.dart'; + +@freezed +class SceneViewNode with _$SceneViewNode { + const factory SceneViewNode({ + required String fileLocation, + @Vector3Converter() Vector3? position, + @Vector4Converter() Vector4? rotation, + double? scale, + }) = _SceneViewNode; + + factory SceneViewNode.fromJson(Map json) => + _$SceneViewNodeFromJson(json); + +/* Map toMap() { final map = { 'fileLocation': fileLocation, 'position': position?.toMap(), @@ -20,10 +27,10 @@ class SceneViewNode { }; map.removeWhere((key, value) => value == null); return map; - } + }*/ } -class KotlinFloat3 { +/*class KotlinFloat3 { final double x; final double y; final double z; @@ -37,4 +44,4 @@ class KotlinFloat3 { 'z': z, }; } -} +}*/ diff --git a/lib/sceneview_node.freezed.dart b/lib/sceneview_node.freezed.dart new file mode 100644 index 0000000..fc200c8 --- /dev/null +++ b/lib/sceneview_node.freezed.dart @@ -0,0 +1,225 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'sceneview_node.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +SceneViewNode _$SceneViewNodeFromJson(Map json) { + return _SceneViewNode.fromJson(json); +} + +/// @nodoc +mixin _$SceneViewNode { + String get fileLocation => throw _privateConstructorUsedError; + @Vector3Converter() + Vector3? get position => throw _privateConstructorUsedError; + @Vector4Converter() + Vector4? get rotation => throw _privateConstructorUsedError; + double? get scale => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $SceneViewNodeCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SceneViewNodeCopyWith<$Res> { + factory $SceneViewNodeCopyWith( + SceneViewNode value, $Res Function(SceneViewNode) then) = + _$SceneViewNodeCopyWithImpl<$Res, SceneViewNode>; + @useResult + $Res call( + {String fileLocation, + @Vector3Converter() Vector3? position, + @Vector4Converter() Vector4? rotation, + double? scale}); +} + +/// @nodoc +class _$SceneViewNodeCopyWithImpl<$Res, $Val extends SceneViewNode> + implements $SceneViewNodeCopyWith<$Res> { + _$SceneViewNodeCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? fileLocation = null, + Object? position = freezed, + Object? rotation = freezed, + Object? scale = freezed, + }) { + return _then(_value.copyWith( + fileLocation: null == fileLocation + ? _value.fileLocation + : fileLocation // ignore: cast_nullable_to_non_nullable + as String, + position: freezed == position + ? _value.position + : position // ignore: cast_nullable_to_non_nullable + as Vector3?, + rotation: freezed == rotation + ? _value.rotation + : rotation // ignore: cast_nullable_to_non_nullable + as Vector4?, + scale: freezed == scale + ? _value.scale + : scale // ignore: cast_nullable_to_non_nullable + as double?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$SceneViewNodeImplCopyWith<$Res> + implements $SceneViewNodeCopyWith<$Res> { + factory _$$SceneViewNodeImplCopyWith( + _$SceneViewNodeImpl value, $Res Function(_$SceneViewNodeImpl) then) = + __$$SceneViewNodeImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String fileLocation, + @Vector3Converter() Vector3? position, + @Vector4Converter() Vector4? rotation, + double? scale}); +} + +/// @nodoc +class __$$SceneViewNodeImplCopyWithImpl<$Res> + extends _$SceneViewNodeCopyWithImpl<$Res, _$SceneViewNodeImpl> + implements _$$SceneViewNodeImplCopyWith<$Res> { + __$$SceneViewNodeImplCopyWithImpl( + _$SceneViewNodeImpl _value, $Res Function(_$SceneViewNodeImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? fileLocation = null, + Object? position = freezed, + Object? rotation = freezed, + Object? scale = freezed, + }) { + return _then(_$SceneViewNodeImpl( + fileLocation: null == fileLocation + ? _value.fileLocation + : fileLocation // ignore: cast_nullable_to_non_nullable + as String, + position: freezed == position + ? _value.position + : position // ignore: cast_nullable_to_non_nullable + as Vector3?, + rotation: freezed == rotation + ? _value.rotation + : rotation // ignore: cast_nullable_to_non_nullable + as Vector4?, + scale: freezed == scale + ? _value.scale + : scale // ignore: cast_nullable_to_non_nullable + as double?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$SceneViewNodeImpl implements _SceneViewNode { + const _$SceneViewNodeImpl( + {required this.fileLocation, + @Vector3Converter() this.position, + @Vector4Converter() this.rotation, + this.scale}); + + factory _$SceneViewNodeImpl.fromJson(Map json) => + _$$SceneViewNodeImplFromJson(json); + + @override + final String fileLocation; + @override + @Vector3Converter() + final Vector3? position; + @override + @Vector4Converter() + final Vector4? rotation; + @override + final double? scale; + + @override + String toString() { + return 'SceneViewNode(fileLocation: $fileLocation, position: $position, rotation: $rotation, scale: $scale)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SceneViewNodeImpl && + (identical(other.fileLocation, fileLocation) || + other.fileLocation == fileLocation) && + (identical(other.position, position) || + other.position == position) && + (identical(other.rotation, rotation) || + other.rotation == rotation) && + (identical(other.scale, scale) || other.scale == scale)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => + Object.hash(runtimeType, fileLocation, position, rotation, scale); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$SceneViewNodeImplCopyWith<_$SceneViewNodeImpl> get copyWith => + __$$SceneViewNodeImplCopyWithImpl<_$SceneViewNodeImpl>(this, _$identity); + + @override + Map toJson() { + return _$$SceneViewNodeImplToJson( + this, + ); + } +} + +abstract class _SceneViewNode implements SceneViewNode { + const factory _SceneViewNode( + {required final String fileLocation, + @Vector3Converter() final Vector3? position, + @Vector4Converter() final Vector4? rotation, + final double? scale}) = _$SceneViewNodeImpl; + + factory _SceneViewNode.fromJson(Map json) = + _$SceneViewNodeImpl.fromJson; + + @override + String get fileLocation; + @override + @Vector3Converter() + Vector3? get position; + @override + @Vector4Converter() + Vector4? get rotation; + @override + double? get scale; + @override + @JsonKey(ignore: true) + _$$SceneViewNodeImplCopyWith<_$SceneViewNodeImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/sceneview_node.g.dart b/lib/sceneview_node.g.dart new file mode 100644 index 0000000..22cc481 --- /dev/null +++ b/lib/sceneview_node.g.dart @@ -0,0 +1,39 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'sceneview_node.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$SceneViewNodeImpl _$$SceneViewNodeImplFromJson(Map json) => + _$SceneViewNodeImpl( + fileLocation: json['fileLocation'] as String, + position: _$JsonConverterFromJson, Vector3>( + json['position'], const Vector3Converter().fromJson), + rotation: _$JsonConverterFromJson, Vector4>( + json['rotation'], const Vector4Converter().fromJson), + scale: (json['scale'] as num?)?.toDouble(), + ); + +Map _$$SceneViewNodeImplToJson(_$SceneViewNodeImpl instance) => + { + 'fileLocation': instance.fileLocation, + 'position': _$JsonConverterToJson, Vector3>( + instance.position, const Vector3Converter().toJson), + 'rotation': _$JsonConverterToJson, Vector4>( + instance.rotation, const Vector4Converter().toJson), + 'scale': instance.scale, + }; + +Value? _$JsonConverterFromJson( + Object? json, + Value? Function(Json json) fromJson, +) => + json == null ? null : fromJson(json as Json); + +Json? _$JsonConverterToJson( + Value? value, + Json? Function(Value value) toJson, +) => + value == null ? null : toJson(value); diff --git a/lib/session_frame.dart b/lib/session_frame.dart new file mode 100644 index 0000000..41fef66 --- /dev/null +++ b/lib/session_frame.dart @@ -0,0 +1,17 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:sceneview_flutter/plane.dart'; +import 'package:sceneview_flutter/pose.dart'; + +part 'session_frame.freezed.dart'; + +part 'session_frame.g.dart'; + +@freezed +class SessionFrame with _$SessionFrame { + const factory SessionFrame({ + @Default([]) List planes, + }) = _SessionFrame; + + factory SessionFrame.fromJson(Map json) => + _$SessionFrameFromJson(json); +} diff --git a/lib/session_frame.freezed.dart b/lib/session_frame.freezed.dart new file mode 100644 index 0000000..3d0a961 --- /dev/null +++ b/lib/session_frame.freezed.dart @@ -0,0 +1,159 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'session_frame.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +SessionFrame _$SessionFrameFromJson(Map json) { + return _SessionFrame.fromJson(json); +} + +/// @nodoc +mixin _$SessionFrame { + List get planes => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $SessionFrameCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SessionFrameCopyWith<$Res> { + factory $SessionFrameCopyWith( + SessionFrame value, $Res Function(SessionFrame) then) = + _$SessionFrameCopyWithImpl<$Res, SessionFrame>; + @useResult + $Res call({List planes}); +} + +/// @nodoc +class _$SessionFrameCopyWithImpl<$Res, $Val extends SessionFrame> + implements $SessionFrameCopyWith<$Res> { + _$SessionFrameCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? planes = null, + }) { + return _then(_value.copyWith( + planes: null == planes + ? _value.planes + : planes // ignore: cast_nullable_to_non_nullable + as List, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$SessionFrameImplCopyWith<$Res> + implements $SessionFrameCopyWith<$Res> { + factory _$$SessionFrameImplCopyWith( + _$SessionFrameImpl value, $Res Function(_$SessionFrameImpl) then) = + __$$SessionFrameImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({List planes}); +} + +/// @nodoc +class __$$SessionFrameImplCopyWithImpl<$Res> + extends _$SessionFrameCopyWithImpl<$Res, _$SessionFrameImpl> + implements _$$SessionFrameImplCopyWith<$Res> { + __$$SessionFrameImplCopyWithImpl( + _$SessionFrameImpl _value, $Res Function(_$SessionFrameImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? planes = null, + }) { + return _then(_$SessionFrameImpl( + planes: null == planes + ? _value._planes + : planes // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$SessionFrameImpl implements _SessionFrame { + const _$SessionFrameImpl({final List planes = const []}) + : _planes = planes; + + factory _$SessionFrameImpl.fromJson(Map json) => + _$$SessionFrameImplFromJson(json); + + final List _planes; + @override + @JsonKey() + List get planes { + if (_planes is EqualUnmodifiableListView) return _planes; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_planes); + } + + @override + String toString() { + return 'SessionFrame(planes: $planes)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SessionFrameImpl && + const DeepCollectionEquality().equals(other._planes, _planes)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => + Object.hash(runtimeType, const DeepCollectionEquality().hash(_planes)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$SessionFrameImplCopyWith<_$SessionFrameImpl> get copyWith => + __$$SessionFrameImplCopyWithImpl<_$SessionFrameImpl>(this, _$identity); + + @override + Map toJson() { + return _$$SessionFrameImplToJson( + this, + ); + } +} + +abstract class _SessionFrame implements SessionFrame { + const factory _SessionFrame({final List planes}) = _$SessionFrameImpl; + + factory _SessionFrame.fromJson(Map json) = + _$SessionFrameImpl.fromJson; + + @override + List get planes; + @override + @JsonKey(ignore: true) + _$$SessionFrameImplCopyWith<_$SessionFrameImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/session_frame.g.dart b/lib/session_frame.g.dart new file mode 100644 index 0000000..ce91dcc --- /dev/null +++ b/lib/session_frame.g.dart @@ -0,0 +1,19 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'session_frame.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$SessionFrameImpl _$$SessionFrameImplFromJson(Map json) => _$SessionFrameImpl( + planes: (json['planes'] as List?) + ?.map((e) => Plane.fromJson(Map.from(e as Map))) + .toList() ?? + const [], + ); + +Map _$$SessionFrameImplToJson(_$SessionFrameImpl instance) => + { + 'planes': instance.planes.map((e) => e.toJson()).toList(), + }; diff --git a/lib/tracking_failure_reason.dart b/lib/tracking_failure_reason.dart new file mode 100644 index 0000000..3b672cd --- /dev/null +++ b/lib/tracking_failure_reason.dart @@ -0,0 +1,37 @@ +enum TrackingFailureReason { + /** + * Indicates expected motion tracking behavior. Always returned when {@link + * com.google.ar.core.Camera#getTrackingState() } is {@link + * com.google.ar.core.TrackingState#TRACKING TrackingState#TRACKING}. When {@link + * com.google.ar.core.Camera#getTrackingState() } is {@link + * com.google.ar.core.TrackingState#PAUSED TrackingState#PAUSED}, indicates that the session is + * initializing normally. + */ + NONE, + /** + * Motion tracking lost due to bad internal state. No specific user action is likely to resolve + * this issue. + */ + BAD_STATE, + /** + * Motion tracking lost due to poor lighting conditions. Ask the user to move to a more brightly + * lit area. Android 12 (API level 31) or later, the user may have + * disabled camera access, causing ARCore to receive a blank camera feed. + */ + INSUFFICIENT_LIGHT, + /** Motion tracking lost due to excessive motion. Ask the user to move the device more slowly. */ + EXCESSIVE_MOTION, + /** + * Motion tracking lost due to insufficient visual features. Ask the user to move to a different + * area and to avoid blank walls and surfaces without detail. + */ + INSUFFICIENT_FEATURES, + /** + * Motion tracking paused because the camera is in use by another application. Tracking will + * resume once this app regains priority, or once all apps with higher priority have stopped using + * the camera. Prior to ARCore SDK 1.13, {@link com.google.ar.core.TrackingFailureReason#NONE + * TrackingFailureReason#NONE} is returned in this case instead. + */ + CAMERA_UNAVAILABLE; +} diff --git a/lib/vector_converter.dart b/lib/vector_converter.dart new file mode 100644 index 0000000..f9e40e2 --- /dev/null +++ b/lib/vector_converter.dart @@ -0,0 +1,34 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:vector_math/vector_math.dart'; + +class Vector3Converter implements JsonConverter> { + const Vector3Converter(); + + @override + Vector3 fromJson(List json) { + return Vector3(json[0], json[1], json[2]); + } + + @override + List toJson(Vector3 object) { + final list = List.filled(3, 0.0); + object.copyIntoArray(list); + return list; + } +} + +class Vector4Converter implements JsonConverter> { + const Vector4Converter(); + + @override + Vector4 fromJson(List json) { + return Vector4(json[0], json[1], json[2], json[3]); + } + + @override + List toJson(Vector4 object) { + final list = List.filled(4, 0.0); + object.copyIntoArray(list); + return list; + } +} \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 2e987b1..4bc16f6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,12 +10,19 @@ environment: dependencies: flutter: sdk: flutter - plugin_platform_interface: ^2.1.3 + plugin_platform_interface: ^2.1.6 + freezed_annotation: ^2.4.1 + json_annotation: ^4.8.1 + stream_transform: ^2.1.0 + vector_math: ^2.1.4 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^2.0.1 + build_runner: + freezed: ^2.4.5 + json_serializable: ^6.7.1 flutter: plugin: