From 5adf301a81a67f5a877b53edf5429f636f402ef6 Mon Sep 17 00:00:00 2001 From: kturkal <166247156+kturkal@users.noreply.github.com> Date: Sun, 6 Apr 2025 16:52:46 -0400 Subject: [PATCH 1/7] made area for square --- src/geometry/Square.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/geometry/Square.ts b/src/geometry/Square.ts index 53563b9..e179926 100644 --- a/src/geometry/Square.ts +++ b/src/geometry/Square.ts @@ -38,6 +38,10 @@ export default class Square extends Rectangle { ); } + area() { + return this.sideLength * this.sideLength; + } + getCloneAttributes() { return [this.sideLength]; } From 5b1eb1c0163626a8f11db1e52aa09fe05318f861 Mon Sep 17 00:00:00 2001 From: kturkal <166247156+kturkal@users.noreply.github.com> Date: Sun, 6 Apr 2025 16:54:35 -0400 Subject: [PATCH 2/7] added area for rectangle --- src/geometry/Rectangle.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/geometry/Rectangle.ts b/src/geometry/Rectangle.ts index 21af18f..2c78bcf 100644 --- a/src/geometry/Rectangle.ts +++ b/src/geometry/Rectangle.ts @@ -45,6 +45,10 @@ export default class Rectangle extends Shape { return new Rectangle(width, height); } + area() { + return this.width * this.height + } + get attributeData() { return [ { From 8d9aaa19d318b0b4636e5ad9c594e8281f79da95 Mon Sep 17 00:00:00 2001 From: kturkal <166247156+kturkal@users.noreply.github.com> Date: Sun, 6 Apr 2025 16:56:16 -0400 Subject: [PATCH 3/7] added area for circle --- src/geometry/Circle.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/geometry/Circle.ts b/src/geometry/Circle.ts index d4a023d..1eb4c2b 100644 --- a/src/geometry/Circle.ts +++ b/src/geometry/Circle.ts @@ -45,6 +45,10 @@ export default class Circle extends Shape { }; } + area() { + return Math.PI * this.radius * this.radius; + } + static fromAttributes(attributes: CircleAttributes): Circle { const { radius } = attributes; return new Circle(radius); From c0d6ea0237564370740bdeeb02a72c30f367dace Mon Sep 17 00:00:00 2001 From: kturkal <166247156+kturkal@users.noreply.github.com> Date: Sun, 13 Apr 2025 18:35:07 -0400 Subject: [PATCH 4/7] created heart --- src/geometry/Heart.ts | 69 +++++++++++++++++++++++++++++++++++++++++ src/geometry/Polygon.ts | 17 +++++++++- src/geometry/index.ts | 2 ++ 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 src/geometry/Heart.ts diff --git a/src/geometry/Heart.ts b/src/geometry/Heart.ts new file mode 100644 index 0000000..5173987 --- /dev/null +++ b/src/geometry/Heart.ts @@ -0,0 +1,69 @@ +import Shape, { Style } from "./Shape.js"; +import { THREE } from "../index.js"; +import { ERROR_THRESHOLD } from "../constants.js"; + +export type HeartAttributes = { + size: number; +}; + +/** + * A heart shape created using parametric equations. + */ +export default class Heart extends Shape { + public size: number; + + constructor(size: number = 1, config: Style = {}) { + // Generate points using the parametric equations + const points: THREE.Vector3[] = []; + + // Generate heart curve using parametric equations + for (let t = 0; t <= 2 * Math.PI + ERROR_THRESHOLD; t += 0.1) { + // Heart parametric equations + const x = size * Math.sqrt(2) * Math.pow(Math.sin(t), 3); + const y = size * ( + -Math.pow(Math.cos(t), 3) - + Math.pow(Math.cos(t), 2) + + 2 * Math.cos(t) + ); + + points.push(new THREE.Vector3(x, y, 0)); + } + + super(points, { + ...Heart.defaultConfig(), + ...config, + }); + + this.size = size; + } + + getCloneAttributes() { + return [this.size]; + } + + getAttributes(): HeartAttributes { + return { + size: this.size + }; + } + + static fromAttributes(attributes: HeartAttributes): Heart { + const { size } = attributes; + return new Heart(size); + } + + get attributeData() { + return [ + { + attribute: "size", + type: "number", + default: 1, + }, + ]; + } + + area() { + // Approximation of heart area - you could implement a more accurate calculation + return Math.PI * this.size * this.size; + } +} diff --git a/src/geometry/Polygon.ts b/src/geometry/Polygon.ts index 2ef9ffb..02192dd 100644 --- a/src/geometry/Polygon.ts +++ b/src/geometry/Polygon.ts @@ -47,11 +47,26 @@ export default class Polygon extends Shape { return { points: this.points }; } + static fromAttributes(attributes: PolygonAttributes): Polygon { const { points } = attributes; return new Polygon(points); } - + + area() { + let area = 0; + if (this.points.length === 3) { + const point0 = this.points[0]; + const point1 = this.points[1]; + const point2 = this.points[2]; + + if (!point0 || !point1 || !point2) return 0; + + const midpoint = point2.clone().add(point0).divideScalar(2); + area = 0.5 * point0.distanceTo(point2) * point1.distanceTo(midpoint); + } + return area; + } get attributeData() { return []; } diff --git a/src/geometry/index.ts b/src/geometry/index.ts index 1752565..a50409e 100644 --- a/src/geometry/index.ts +++ b/src/geometry/index.ts @@ -9,3 +9,5 @@ export { default as Circle } from "./Circle.js"; export { default as Point } from "./Point.js"; export { default as Rectangle } from "./Rectangle.js"; export { default as Square } from "./Square.js"; +export { default as Heart } from "./Heart.js"; + From c6bc500ba6174dfb8fe9ca1e9bbc859bcb12bc4e Mon Sep 17 00:00:00 2001 From: kturkal <166247156+kturkal@users.noreply.github.com> Date: Sun, 13 Apr 2025 21:27:57 -0400 Subject: [PATCH 5/7] Made points[0] and points[1] be the top and bottom vertices of the heart --- src/geometry/Heart.ts | 61 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/src/geometry/Heart.ts b/src/geometry/Heart.ts index 5173987..c2c0dc0 100644 --- a/src/geometry/Heart.ts +++ b/src/geometry/Heart.ts @@ -12,19 +12,30 @@ export type HeartAttributes = { export default class Heart extends Shape { public size: number; - constructor(size: number = 1, config: Style = {}) { + constructor(size: number, config: Style = {}) { + size = size /15; // Generate points using the parametric equations const points: THREE.Vector3[] = []; + // Y-offset to move the heart up by 0.2 units + const yOffset = 0.2; + // Generate heart curve using parametric equations for (let t = 0; t <= 2 * Math.PI + ERROR_THRESHOLD; t += 0.1) { // Heart parametric equations - const x = size * Math.sqrt(2) * Math.pow(Math.sin(t), 3); - const y = size * ( - -Math.pow(Math.cos(t), 3) - - Math.pow(Math.cos(t), 2) + - 2 * Math.cos(t) - ); + // const x = size * Math.sqrt(2) * Math.pow(Math.sin(t), 3); + // const y = size * ( + // 2 * Math.cos(t) + // - Math.pow(Math.cos(t), 2) + // - Math.pow(Math.cos(t), 3) + // ); + const x = size * (16 * Math.pow(Math.sin(t), 3)); + const y = size * ( + 13 * Math.cos(t) + - 5 * Math.cos(2 * t) + - 2 * Math.cos(3 * t) + - Math.cos(4 * t) + ) + yOffset; points.push(new THREE.Vector3(x, y, 0)); } @@ -35,6 +46,7 @@ export default class Heart extends Shape { }); this.size = size; + this.points[1] = new THREE.Vector3(size * (16 * Math.pow(Math.sin(Math.PI), 3)), size * (13 * Math.cos(Math.PI) - 5 * Math.cos(2 * Math.PI) - 2 * Math.cos(3 * Math.PI) - Math.cos(4 * Math.PI)) + yOffset, 0); } getCloneAttributes() { @@ -61,9 +73,44 @@ export default class Heart extends Shape { }, ]; } + + area() { // Approximation of heart area - you could implement a more accurate calculation return Math.PI * this.size * this.size; } + + centerVertically(offset: number = 0.2) { + // Calculate the current bounds of the heart + const boundingBox = new THREE.Box3().setFromObject(this); + const center = new THREE.Vector3(); + boundingBox.getCenter(center); + + // Apply the offset to all points + if (this.stroke && this.stroke.geometry) { + const newPoints = this.points.map(point => { + const newPoint = point.clone(); + newPoint.y -= center.y; // Center at origin first + newPoint.y += offset; // Then add the desired offset + return newPoint; + }); + + this.stroke.geometry.setPoints(newPoints); + + // Update fill geometry if it exists + if (this.fill) { + this.fill.geometry.dispose(); + const shape = new THREE.Shape(); + shape.moveTo(newPoints[0].x, newPoints[0].y); + for (const point of newPoints.slice(1)) { + shape.lineTo(point.x, point.y); + } + shape.closePath(); + this.fill.geometry = new THREE.ShapeGeometry(shape); + } + } + + return this; + } } From f9b9a124691aeb230c4adce3a3126d8a311ca6f3 Mon Sep 17 00:00:00 2001 From: kturkal <166247156+kturkal@users.noreply.github.com> Date: Sun, 13 Apr 2025 21:30:34 -0400 Subject: [PATCH 6/7] fixed error by checking to see if newpoints exists --- src/geometry/Heart.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/geometry/Heart.ts b/src/geometry/Heart.ts index c2c0dc0..0b61a3b 100644 --- a/src/geometry/Heart.ts +++ b/src/geometry/Heart.ts @@ -102,12 +102,19 @@ export default class Heart extends Shape { if (this.fill) { this.fill.geometry.dispose(); const shape = new THREE.Shape(); - shape.moveTo(newPoints[0].x, newPoints[0].y); - for (const point of newPoints.slice(1)) { - shape.lineTo(point.x, point.y); + + if (newPoints.length > 0 && newPoints[0]) { + shape.moveTo(newPoints[0].x, newPoints[0].y); + + for (const point of newPoints.slice(1)) { + if (point) { + shape.lineTo(point.x, point.y); + } + } + + shape.closePath(); + this.fill.geometry = new THREE.ShapeGeometry(shape); } - shape.closePath(); - this.fill.geometry = new THREE.ShapeGeometry(shape); } } From a215f0fdaaedd909233c2e5866a65ba2775d5809 Mon Sep 17 00:00:00 2001 From: kturkal <166247156+kturkal@users.noreply.github.com> Date: Sun, 13 Apr 2025 21:35:08 -0400 Subject: [PATCH 7/7] added description to code --- src/geometry/Heart.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/geometry/Heart.ts b/src/geometry/Heart.ts index 0b61a3b..311bee2 100644 --- a/src/geometry/Heart.ts +++ b/src/geometry/Heart.ts @@ -21,8 +21,8 @@ export default class Heart extends Shape { const yOffset = 0.2; // Generate heart curve using parametric equations - for (let t = 0; t <= 2 * Math.PI + ERROR_THRESHOLD; t += 0.1) { - // Heart parametric equations + for (let t = 0; t <= 2 * Math.PI + ERROR_THRESHOLD; t += 0.1) { + // Alternative heart equation: // const x = size * Math.sqrt(2) * Math.pow(Math.sin(t), 3); // const y = size * ( // 2 * Math.cos(t)