TKK_E32230206/lib/features/iot/widgets/isometric_transform.dart

54 lines
1.9 KiB
Dart

import 'dart:math' as math;
import 'package:flutter/material.dart';
/// Class utility untuk transformasi koordinat 3D World (meter) ke 2D Screen (piksel)
/// dengan proyeksi Isometrik.
class IsometricTransform {
/// Skala piksel per meter (misalnya 1 meter = 40 piksel)
final double scale;
/// Titik origin (0,0,0) di layar
final Offset origin;
const IsometricTransform({
required this.scale,
required this.origin,
});
/// Mengonversi koordinat 3D World (x, y, z) dalam satuan meter ke Offset 2D Canvas (piksel).
/// * [x] : Arah kedalaman kumbung (dari depan ke belakang) - e.g. 0 s.d 8 meter.
/// * [y] : Arah lebar kumbung (dari kiri ke kanan) - e.g. 0 s.d 6 meter.
/// * [z] : Arah tinggi kumbung (dari lantai ke atap) - e.g. 0 s.d 3 meter.
Offset toScreen(double x, double y, double z) {
const double angle = 30.0 * math.pi / 180.0; // Sudut proyeksi isometrik 30 derajat
// dx = (x - y) * cos(30) * scale
// dy = ((x + y) * sin(30) - z) * scale
final double dx = (x - y) * math.cos(angle) * scale;
final double dy = ((x + y) * math.sin(angle) - z) * scale;
return Offset(origin.dx + dx, origin.dy + dy);
}
/// Mengonversi koordinat 2D Screen (tap) kembali ke koordinat 2D World Ground (x, y) pada z = 0.
/// Berguna untuk mendeteksi penempatan/interaksi ketukan jari di lantai kumbung.
Offset toWorldGround(Offset screenPt) {
const double angle = 30.0 * math.pi / 180.0;
final double cos30 = math.cos(angle);
final double sin30 = math.sin(angle);
final double rx = screenPt.dx - origin.dx;
final double ry = screenPt.dy - origin.dy;
// x - y = rx / (cos(30) * scale)
// x + y = ry / (sin(30) * scale)
final double diffVal = rx / (cos30 * scale);
final double sumVal = ry / (sin30 * scale);
final double x = (sumVal + diffVal) / 2;
final double y = (sumVal - diffVal) / 2;
return Offset(x, y);
}
}