pattern-x / gemini-viewer-examples

Examples and demos for gemini-viewer sdk, which is a WebGL based BIM model viewer, built on three.js. It is used to view dwg/dxf, gltf, obj, ifc models, etc.
195 stars 42 forks source link

Trying to implement my own logic on Gemini-viewer. But not working #142

Open janardhanan305 opened 2 weeks ago

janardhanan305 commented 2 weeks ago

//Here below following code i have implemented logic to draw a logic for doordrawing on 2D layers //How should i integrate the my code in DXFviewer // do i need to add integrate a code with DXFViwer logic?

// script.js

const canvas = document.getElementById('drawingCanvas'); const ctx = canvas.getContext('2d');

// we are setting up grid and min/max length constants const gridSize = 10; // Grid size is assigned const MIN_LENGTH = 80; // Minimum door length in pixels (equivalent to mm) const MAX_LENGTH = 120; // Maximum door length in pixels (equivalent to mm);

let isDrawing = false; // State to check if we're drawing let selectedPoint = null; // To know which point is selected for dragging let draggingLine = null; // To check if the line is being dragged let dragStartPos = null; // Starting position when dragging let currentDoor = null; // Storing the current door being drawn let doors = []; // Array to store all doors

// This function will resizes the canvas whenever the window is resized function resizeCanvas() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; }

// Here we are adding event listener to resize the canvas whenever the window is resized window.addEventListener('resize', resizeCanvas); resizeCanvas(); // Initializing the canvas size on load

// This function will snaps the mouse pointer to the nearest grid point for precision function snapToGrid(x, y) { return { x: Math.round(x / gridSize) gridSize, y: Math.round(y / gridSize) gridSize }; }

// This function to calculate the distance between two points (for line length calculation) function calculateDistance(x1, y1, x2, y2) { return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); }

//This will be having history of door states (can be used for undo functionality) function saveHistory() { // If needed, we can implement undo functionality by saving history }

// When mouse is pressed, this function starts the door drawing process function handleMouseDown(e) { const pos = snapToGrid(e.offsetX, e.offsetY); // Snap mouse position to grid

let pointClicked = false; // Flag to check if any point (start/end) was clicked

// Check if we're clicking on an existing door's start or end points
doors.forEach((door, index) => {
    const start = door.start;
    const end = door.end;

    // If clicked on the start or end point of a door, mark that point as selected
    if (calculateDistance(pos.x, pos.y, start.x, start.y) < gridSize) {
        selectedPoint = { type: 'start', index };
        pointClicked = true;
    } else if (calculateDistance(pos.x, pos.y, end.x, end.y) < gridSize) {
        selectedPoint = { type: 'end', index };
        pointClicked = true;
    }

    // Check if clicked on the door line itself (for dragging)
    const distanceToLine = Math.abs(
        (end.y - start.y) * pos.x - (end.x - start.x) * pos.y + end.x * start.y - end.y * start.x
    ) / calculateDistance(start.x, start.y, end.x, end.y);

    const isWithinBounds = pos.x >= Math.min(start.x, end.x) &&
        pos.x <= Math.max(start.x, end.x) &&
        pos.y >= Math.min(start.y, end.y) &&
        pos.y <= Math.max(start.y, end.y);

    if (!pointClicked && distanceToLine < 5 && isWithinBounds) {
        draggingLine = index; // Mark the line for dragging
        dragStartPos = pos; // Store initial drag position
        pointClicked = true;
    }
});

// If no existing door point was clicked, start drawing a new door
if (!pointClicked) {
    isDrawing = true;
    currentDoor = {
        start: pos, // Start position of the new door
        end: null // End will be set as we move the mouse
    };
    doors.push(currentDoor); // Add this door to the list
}

}

// Handle mouse movement while drawing or dragging a door function handleMouseMove(e) { const pos = snapToGrid(e.offsetX, e.offsetY); // Snap position to grid for precision

if (selectedPoint) {
    // We are dragging one of the points (start or end)
    const door = doors[selectedPoint.index]; // Get the door being updated
    const fixedPoint = selectedPoint.type === 'start' ? door.end : door.start; // The other end remains fixed

    const distance = calculateDistance(fixedPoint.x, fixedPoint.y, pos.x, pos.y); // Calculate new distance
    const clampedDistance = Math.max(MIN_LENGTH, Math.min(distance, MAX_LENGTH)); // Clamp the distance within allowed limits
    const angle = Math.atan2(pos.y - fixedPoint.y, pos.x - fixedPoint.x); // Get the angle of movement

    // Update the selected point (start or end) with new position
    if (selectedPoint.type === 'start') {
        door.start = {
            x: fixedPoint.x + Math.cos(angle) * clampedDistance,
            y: fixedPoint.y + Math.sin(angle) * clampedDistance
        };
    } else {
        door.end = {
            x: fixedPoint.x + Math.cos(angle) * clampedDistance,
            y: fixedPoint.y + Math.sin(angle) * clampedDistance
        };
    }
    redrawCanvas(); // Redraw canvas to reflect changes
} else if (draggingLine !== null && dragStartPos) {
    // If we're dragging the entire line, calculate the delta and update both start and end points
    const dx = pos.x - dragStartPos.x;
    const dy = pos.y - dragStartPos.y;

    const door = doors[draggingLine];
    door.start.x += dx;
    door.start.y += dy;
    door.end.x += dx;
    door.end.y += dy;

    dragStartPos = pos; // Update drag start position for continuous dragging
    redrawCanvas(); // Redraw to update changes
} else if (isDrawing) {
    // If we're still in the drawing phase (mouse is down), update the end point
    const distance = calculateDistance(currentDoor.start.x, currentDoor.start.y, pos.x, pos.y);
    const clampedDistance = Math.max(MIN_LENGTH, Math.min(distance, MAX_LENGTH));
    const angle = Math.atan2(pos.y - currentDoor.start.y, pos.x - currentDoor.start.x);

    currentDoor.end = {
        x: currentDoor.start.x + Math.cos(angle) * clampedDistance,
        y: currentDoor.start.y + Math.sin(angle) * clampedDistance
    };
    redrawCanvas(); // Redraw canvas with the new door line
}

}

// Once the mouse is released, finalize the door drawing or dragging process function handleMouseUp() { if (isDrawing) { isDrawing = false; // Stop the drawing process if (!currentDoor.end || calculateDistance(currentDoor.start.x, currentDoor.start.y, currentDoor.end.x, currentDoor.end.y) < 10) { doors.pop(); // Remove the door if it's too short } currentDoor = null; // Clear current door saveHistory(); // Save the state for potential undo functionality }

if (selectedPoint || draggingLine !== null) {
    saveHistory(); // Save after dragging or point movement
}

// Reset the state
selectedPoint = null;
draggingLine = null;
dragStartPos = null;

}

// Draw a dashed line (used for the vertical dashed line) function drawDashedLine(x1, y1, x2, y2) { ctx.setLineDash([5, 5]); // Define dash pattern ctx.beginPath(); // Start the line drawing ctx.moveTo(x1, y1); // Move to start point ctx.lineTo(x2, y2); // Draw line to end point ctx.stroke(); // Render the line ctx.setLineDash([]); // Reset line style to solid }

// Draw the quarter-circle arc for the door function drawDottedArc(cx, cy, radius, startAngle, endAngle) { ctx.setLineDash([5, 5]); // Create dashed arc pattern ctx.beginPath(); ctx.arc(cx, cy, radius, startAngle, endAngle); // Draw arc ctx.stroke(); // Render arc ctx.setLineDash([]); // Reset line style to solid }

// Function to calculate perpendicular points for vertical line and arc function calculatePerpendicular(door) { const { start, end } = door;

// Calculate angle of the door line
const angle = Math.atan2(end.y - start.y, end.x - start.x);

// Calculate perpendicular angle (90 degrees offset)
const perpendicularAngle = angle + Math.PI / 2;

// Calculate door length for vertical and arc
const length = calculateDistance(start.x, start.y, end.x, end.y);

// Calculate vertical line end point
const verticalEndX = end.x + Math.cos(perpendicularAngle) * length;
const verticalEndY = end.y + Math.sin(perpendicularAngle) * length;

return { verticalEndX, verticalEndY, length, perpendicularAngle };

}

// Redraw the canvas including all doors and grid function redrawCanvas() { ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear the entire canvas

// Draw the grid on the canvas
for (let x = 0; x < canvas.width; x += gridSize) {
    for (let y = 0; y < canvas.height; y += gridSize) {
        ctx.beginPath();
        ctx.moveTo(x, 0);
        ctx.lineTo(x, canvas.height);
        ctx.moveTo(0, y);
        ctx.lineTo(canvas.width, y);
        ctx.strokeStyle = '#ddd';
        ctx.lineWidth = 0.5;
        ctx.stroke();
    }
}

// Draw all doors with their associated lines and arcs
doors.forEach(door => {
    if (door.start && door.end) {
        // Draw the main solid line for the door
        ctx.beginPath();
        ctx.moveTo(door.start.x, door.start.y);
        ctx.lineTo(door.end.x, door.end.y);
        ctx.strokeStyle = 'green';
        ctx.lineWidth = 4;
        ctx.stroke();

        // Show the door length in the middle of the line
        const midX = (door.start.x + door.end.x) / 2;
        const midY = (door.start.y + door.end.y) / 2;
        const length = calculateDistance(door.start.x, door.start.y, door.end.x, door.end.y).toFixed(0);

        ctx.fillStyle = 'green';
        ctx.font = '20px Arial';

        ctx.fillText(`${length *10} mm`, midX, midY); // Display the length

        // Calculate perpendicular points for vertical line and arc
        const { verticalEndX, verticalEndY, length: doorLength, perpendicularAngle } = calculatePerpendicular(door);

        // Draw vertical dashed line at the end of the door
        drawDashedLine(door.end.x, door.end.y, verticalEndX, verticalEndY);

        // Draw the quarter-circle arc at the end of the door
        drawDottedArc(door.end.x, door.end.y, doorLength, perpendicularAngle, perpendicularAngle + Math.PI / 2);
    }
});

}

// Add event listeners for mouse actions canvas.addEventListener('mousedown', handleMouseDown); canvas.addEventListener('mousemove', handleMouseMove); canvas.addEventListener('mouseup', handleMouseUp);

// Initial drawing of the canvas and grid redrawCanvas();

// At the bottom of DoorDrawingLogic.js, make sure you export it:

export { resizeCanvas, snapToGrid, calculateDistance, saveHistory, handleMouseDown, handleMouseMove, handleMouseUp, drawDashedLine, drawDottedArc, calculatePerpendicular, redrawCanvas };

yanzexuan1 commented 1 week ago

You want to draw doors with canvas, It should not affected by gemini-viewer. I didn't try the code, what do you mean by not working?