File size: 4,268 Bytes
3aea7c6
 
 
 
 
18b0fa5
3aea7c6
 
18b0fa5
3aea7c6
 
18b0fa5
3aea7c6
 
 
 
 
 
 
 
 
 
 
 
18b0fa5
3aea7c6
 
18b0fa5
3aea7c6
 
18b0fa5
3aea7c6
 
 
 
 
 
 
 
 
 
 
18b0fa5
3aea7c6
 
18b0fa5
3aea7c6
 
18b0fa5
3aea7c6
 
 
 
 
 
 
 
 
 
 
 
 
18b0fa5
3aea7c6
 
18b0fa5
3aea7c6
 
 
 
 
 
 
 
 
 
18b0fa5
3aea7c6
 
18b0fa5
3aea7c6
 
 
 
 
 
 
 
 
 
18b0fa5
3aea7c6
 
18b0fa5
3aea7c6
 
18b0fa5
3aea7c6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";

/**
 * Combines and optimizes CSS class names using clsx and tailwind-merge
 *
 * This utility function combines multiple class names and resolves
 * Tailwind CSS conflicts by keeping the last conflicting class.
 *
 * @param inputs - Class values to combine (strings, objects, arrays)
 * @returns Optimized class name string
 *
 * @example
 * cn('px-2 py-1', 'px-4') // Result: 'py-1 px-4'
 * cn('text-red-500', condition && 'text-blue-500') // Conditional classes
 */
export function cn(...inputs: ClassValue[]): string {
	return twMerge(clsx(inputs));
}

// === Servo Position and Angle Conversion Functions ===

/**
 * Converts a servo position to an angle in degrees
 *
 * Servo positions range from 0 to 4096, representing a full 360° rotation.
 * This function maps the position to its corresponding angle.
 *
 * @param position - The servo position (0 to 4096)
 * @returns The corresponding angle (0 to 360 degrees)
 *
 * @example
 * servoPositionToAngle(0)    // Returns: 0
 * servoPositionToAngle(2048) // Returns: 180
 * servoPositionToAngle(4096) // Returns: 360
 */
export function servoPositionToAngle(position: number): number {
	return (position / 4096) * 360;
}

/**
 * Converts degrees to a servo position
 *
 * Maps angle in degrees to the corresponding servo position value.
 * Clamps the result to the valid servo range (0-4096).
 *
 * @param degrees - The angle in degrees (0 to 360)
 * @returns The corresponding servo position (0 to 4096)
 *
 * @example
 * degreesToServoPosition(0)   // Returns: 0
 * degreesToServoPosition(180) // Returns: 2048
 * degreesToServoPosition(360) // Returns: 4096
 */
export function degreesToServoPosition(degrees: number): number {
	return Math.min(Math.round((degrees * 4096) / 360), 4096);
}

// === Angle Unit Conversion Functions ===

/**
 * Converts radians to degrees
 *
 * @param radians - The angle in radians
 * @returns The angle in degrees
 *
 * @example
 * radiansToDegrees(Math.PI)     // Returns: 180
 * radiansToDegrees(Math.PI / 2) // Returns: 90
 */
export function radiansToDegrees(radians: number): number {
	return (radians * 180) / Math.PI;
}

/**
 * Converts degrees to radians
 *
 * @param degrees - The angle in degrees
 * @returns The angle in radians
 *
 * @example
 * degreesToRadians(180) // Returns: Math.PI
 * degreesToRadians(90)  // Returns: Math.PI / 2
 */
export function degreesToRadians(degrees: number): number {
	return (degrees * Math.PI) / 180;
}

/**
 * Converts radians to a servo position
 *
 * Combines radian-to-degree conversion with servo position mapping.
 * Useful for direct conversion from joint angles to servo commands.
 *
 * @param radians - The angle in radians
 * @returns The corresponding servo position (0 to 4096)
 *
 * @example
 * radiansToServoPosition(0)         // Returns: 0
 * radiansToServoPosition(Math.PI)   // Returns: 2048
 * radiansToServoPosition(2*Math.PI) // Returns: 4096
 */
export function radiansToServoPosition(radians: number): number {
	return Math.min(Math.round((radians * 4096) / (2 * Math.PI)), 4096);
}

// === TypeScript Utility Types ===

/**
 * Utility type that removes the 'child' property from a type
 * Useful for component prop interfaces that shouldn't accept child elements
 */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type WithoutChild<T> = T extends { child?: any } ? Omit<T, "child"> : T;

/**
 * Utility type that removes the 'children' property from a type
 * Useful for component prop interfaces that shouldn't accept children
 */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type WithoutChildren<T> = T extends { children?: any } ? Omit<T, "children"> : T;

/**
 * Utility type that removes both 'child' and 'children' properties
 * Combines WithoutChild and WithoutChildren for maximum flexibility
 */
export type WithoutChildrenOrChild<T> = WithoutChildren<WithoutChild<T>>;

/**
 * Utility type that adds an optional ref property for HTML element references
 * @template T - The base type to extend
 * @template U - The HTML element type (defaults to HTMLElement)
 */
export type WithElementRef<T, U extends HTMLElement = HTMLElement> = T & { ref?: U | null };