Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 7 additions & 10 deletions App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React, { useEffect, useState } from 'react';
import "./global.css";
import { NavigationContainer, LinkingOptions } from '@react-navigation/native';
import { AuthProvider } from './src/contexts/AuthContext';
import { useAuth } from './src/hooks/useAuth';
Expand All @@ -10,7 +9,7 @@ import { View, ActivityIndicator, StyleSheet } from 'react-native';
// @types
import { AuthStackParamList, AppStackParamList } from './src/@types/navigation';
type RootStackParamList = AuthStackParamList & AppStackParamList;



const linkingConfig: LinkingOptions<RootStackParamList> = {
Expand All @@ -21,7 +20,7 @@ const linkingConfig: LinkingOptions<RootStackParamList> = {
// AuthNavigator (AuthStackParamList)
Register: 'register',
Login: 'login',

// AppNavigator (AppStackParamList)
MainTabs: {
screens: {
Expand All @@ -44,7 +43,7 @@ function RootNavigator() {
setTimeout(() => {
setIsAppLoading(false);
// react-native-splash-screen (nativo) o .hide() aqui
}, 1500);
}, 1500);
}, []);


Expand All @@ -55,19 +54,17 @@ function RootNavigator() {
// <></> (Fragmento) necessário
return (
<>
{token == null ? (
<AuthNavigator />
) : (
<AppNavigator />
)}


<AppNavigator />
</>
);
}


export default function App() { // o AuthProvider envolve tudo pois passa diretamente o estado do usuário para todos os componentes dentro
return (
<AuthProvider>
<AuthProvider>
<NavigationContainer<RootStackParamList> // após isso vem o de navegação
linking={linkingConfig}
fallback={
Expand Down
2 changes: 2 additions & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,5 @@ dependencies {
implementation("com.google.firebase:firebase-auth")
implementation("com.google.firebase:firebase-firestore")
}

apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
5 changes: 5 additions & 0 deletions dtw/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from .dtw import compute_dtw
from .distance import euclidean_distance, manhattan_distance, weighted_distance
from .normalize import center_by_wrist, scale_normalize, normalize_spatial
from .interpolate import interpolate_to_length
from .types import Landmark, TimeSeriesFrame, DTWResult, DTWConfig
16 changes: 16 additions & 0 deletions dtw/distance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import numpy as np


def euclidean_distance(a: np.ndarray, b: np.ndarray) -> float:
diff = a - b
return float(np.sqrt(np.sum(diff ** 2)))


def manhattan_distance(a: np.ndarray, b: np.ndarray) -> float:
return float(np.sum(np.abs(a - b)))


def weighted_distance(a: np.ndarray, b: np.ndarray, weights: np.ndarray) -> float:
diff = a - b
weighted = weights[:, np.newaxis] * (diff ** 2)
return float(np.sqrt(np.sum(weighted)))
86 changes: 86 additions & 0 deletions dtw/dtw.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import numpy as np
from .types import TimeSeriesFrame, DTWResult, DTWConfig
from .distance import euclidean_distance, manhattan_distance, weighted_distance


def compute_dtw(
series1: list[TimeSeriesFrame],
series2: list[TimeSeriesFrame],
config: DTWConfig | None = None,
) -> DTWResult:
if config is None:
config = DTWConfig()

n = len(series1)
m = len(series2)

if n == 0 or m == 0:
return DTWResult(
distance=float("inf"),
normalized_distance=float("inf"),
path=[],
similarity=0.0,
)

def get_distance(a: TimeSeriesFrame, b: TimeSeriesFrame) -> float:
ma = a.to_matrix()
mb = b.to_matrix()
if config.distance_metric == "manhattan":
return manhattan_distance(ma, mb)
elif config.distance_metric == "weighted" and config.weights is not None:
return weighted_distance(ma, mb, config.weights)
return euclidean_distance(ma, mb)

matrix = np.full((n, m), float("inf"))
matrix[0, 0] = get_distance(series1[0], series2[0])

for i in range(1, n):
matrix[i, 0] = matrix[i - 1, 0] + get_distance(series1[i], series2[0])
for j in range(1, m):
matrix[0, j] = matrix[0, j - 1] + get_distance(series1[0], series2[j])

for i in range(1, n):
j_start = max(1, i - config.window_size) if config.window_size else 1
j_end = min(m - 1, i + config.window_size) if config.window_size else m - 1

for j in range(j_start, j_end + 1):
cost = get_distance(series1[i], series2[j])
matrix[i, j] = cost + min(
matrix[i - 1, j],
matrix[i, j - 1],
matrix[i - 1, j - 1],
)

path: list[tuple[int, int]] = []
i, j = n - 1, m - 1
path.append((i, j))

while i > 0 or j > 0:
if i == 0:
j -= 1
elif j == 0:
i -= 1
else:
candidates = [matrix[i - 1, j - 1], matrix[i - 1, j], matrix[i, j - 1]]
min_idx = int(np.argmin(candidates))
if min_idx == 0:
i -= 1
j -= 1
elif min_idx == 1:
i -= 1
else:
j -= 1
path.append((i, j))

path.reverse()

distance = float(matrix[n - 1, m - 1])
normalized_distance = distance / len(path)
similarity = 1.0 / (1.0 + normalized_distance)

return DTWResult(
distance=distance,
normalized_distance=normalized_distance,
path=path,
similarity=similarity,
)
41 changes: 41 additions & 0 deletions dtw/interpolate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import math
from .types import Landmark, TimeSeriesFrame


def interpolate_to_length(
frames: list[TimeSeriesFrame], target_length: int
) -> list[TimeSeriesFrame]:
if not frames or target_length <= 0:
return []
if len(frames) == target_length:
return frames

result: list[TimeSeriesFrame] = []
ratio = (len(frames) - 1) / (target_length - 1)

for i in range(target_length):
pos = i * ratio
low = math.floor(pos)
high = min(math.ceil(pos), len(frames) - 1)
t = pos - low

if low == high:
result.append(frames[low])
continue

interpolated = [
Landmark(
x=a.x + t * (b.x - a.x),
y=a.y + t * (b.y - a.y),
z=a.z + t * (b.z - a.z),
visibility=a.visibility,
)
for a, b in zip(frames[low].landmarks, frames[high].landmarks)
]

timestamp = frames[low].timestamp + t * (
frames[high].timestamp - frames[low].timestamp
)
result.append(TimeSeriesFrame(timestamp=timestamp, landmarks=interpolated))

return result
48 changes: 48 additions & 0 deletions dtw/normalize.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import numpy as np
from .types import Landmark, TimeSeriesFrame


def center_by_wrist(landmarks: list[Landmark], wrist_index: int = 0) -> list[Landmark]:
if not landmarks or wrist_index >= len(landmarks):
return landmarks

wrist = landmarks[wrist_index]
return [
Landmark(
x=lm.x - wrist.x,
y=lm.y - wrist.y,
z=lm.z - wrist.z,
visibility=lm.visibility,
)
for lm in landmarks
]


def scale_normalize(landmarks: list[Landmark]) -> list[Landmark]:
if not landmarks:
return landmarks

coords = np.array([[lm.x, lm.y, lm.z] for lm in landmarks])
max_dist = float(np.max(np.linalg.norm(coords, axis=1)))

if max_dist == 0:
return landmarks

return [
Landmark(
x=lm.x / max_dist,
y=lm.y / max_dist,
z=lm.z / max_dist,
visibility=lm.visibility,
)
for lm in landmarks
]


def normalize_spatial(frames: list[TimeSeriesFrame]) -> list[TimeSeriesFrame]:
result = []
for frame in frames:
centered = center_by_wrist(frame.landmarks)
scaled = scale_normalize(centered)
result.append(TimeSeriesFrame(timestamp=frame.timestamp, landmarks=scaled))
return result
1 change: 1 addition & 0 deletions dtw/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
numpy>=1.24.0
39 changes: 39 additions & 0 deletions dtw/types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from dataclasses import dataclass, field
from typing import Optional
import numpy as np


@dataclass
class Landmark:
x: float
y: float
z: float
visibility: Optional[float] = None

def to_array(self) -> np.ndarray:
return np.array([self.x, self.y, self.z])


@dataclass
class TimeSeriesFrame:
timestamp: float
landmarks: list[Landmark]

def to_matrix(self) -> np.ndarray:
return np.array([[lm.x, lm.y, lm.z] for lm in self.landmarks])


@dataclass
class DTWResult:
distance: float
normalized_distance: float
path: list[tuple[int, int]]
similarity: float


@dataclass
class DTWConfig:
window_size: Optional[int] = None
distance_metric: str = "euclidean"
weights: Optional[np.ndarray] = None
threshold: Optional[float] = None
2 changes: 1 addition & 1 deletion entrypoint.bat
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ echo [INFO] Emulador pronto!

:: Passo 5: Iniciar o container Docker com o Metro Bundler
echo [INFO] Iniciando o container Docker com docker-compose...
docker-compose up -d --build
docker-compose up -d

:: Passo 6: Configurar o redirecionamento de porta
echo [INFO] Configurando 'adb reverse' para a porta 8081...
Expand Down
22 changes: 22 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"@testing-library/react-native": "^13.3.3",
"@types/jest": "^29.5.14",
"@types/react": "^19.1.0",
"@types/react-native-vector-icons": "^6.4.18",
"@types/react-test-renderer": "^19.1.0",
"eslint": "^8.19.0",
"firebase-tools": "^14.25.0",
Expand Down
Loading