Jens De Backer
Jens De Backer

Reputation: 1

Converting a gpx file to an stl file : reactJS

im pretty new to coding and as a nice project to get better wanted to make a gpx to stl converter. After doing some research i came to a conclusion that it must be possible. I use reactJS for this project.

My findings on how I should do it :

  1. Create upload btn for gpx file
  2. Get all coordinates out of the gpx file and save them
  3. Put these coordinates in a 3D model like threejs. (still not sure about the importance of this step and how to do it well)
  4. Convert the threejs render into an stl
  5. create a btn to download the file.

**My problems at the moment : **

This is my current code :

import React, { useState } from 'react';

function FileUploader({ onFileUpload }) {
  const [selectedFile, setSelectedFile] = useState(null);

  const handleFileChange = async (e) => {
    const file = e.target.files[0];
    
    // Lees de inhoud van het GPX-bestand
    const fileContent = await readFileContent(file);

    setSelectedFile(file);
    onFileUpload({ file, fileContent });
  };

  const readFileContent = (file) => {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();

      reader.onload = (e) => {
        resolve(e.target.result);
      };

      reader.onerror = (e) => {
        reject(new Error('Error reading file.'));
      };

      reader.readAsText(file);
    });
  };

  return (
    <div className="file-uploader">
      <label>
        Selecteer een GPX-bestand:
        <input type="file" accept=".gpx" onChange={handleFileChange} />
      </label>
    </div>
  );
}

export default FileUploader;
**// Converter.js
**
import React, { useEffect, useRef } from 'react';
import * as THREE from 'three';
import { STLExporter } from 'three/addons/exporters/STLExporter.js';

function Converter({ gpxFile }) {
    const threeContainerRef = useRef(null);
    const sceneRef = useRef(null);
    const cameraRef = useRef(null);
    const rendererRef = useRef(null);
    const downloadSTL = () => {
        const STLExporterInstance = new STLExporter();
        const stlData = STLExporterInstance.parse(sceneRef.current);
        const blob = new Blob([stlData], { type: 'application/octet-stream' });
        const url = URL.createObjectURL(blob);
  
        const downloadLink = document.createElement('a');
        downloadLink.href = url;
        downloadLink.download = 'geconverteerd_model.stl';
        downloadLink.click();

      // Optioneel: Opruimen van de URL en het element
      URL.revokeObjectURL(url);
      //renderer.domElement.remove();
    };
  useEffect(() => {
    const convertGPXtoSTL = (gpxData) => {
      const validateGPX = (gpxData) => {
        try {
          const parser = new DOMParser();
          const xmlDoc = parser.parseFromString(gpxData, 'text/xml');
          const trkpts = xmlDoc.querySelectorAll('trkpt');

          if (!trkpts.length) {
            throw new Error('Geen trackpunten gevonden in het GPX-bestand.');
          }

          return trkpts;
        } catch (error) {
          throw new Error(`Ongeldige GPX-gegevens: ${error.message}`);
        }
      };

      const optimizeGPXData = (trkpts) => {
        const points = [];

        trkpts.forEach((trkpt) => {
          const lat = parseFloat(trkpt.getAttribute('lat'));
          const lon = parseFloat(trkpt.getAttribute('lon'));
          const eleNode = trkpt.querySelector('ele');

          if (eleNode) {
            const ele = parseFloat(eleNode.textContent);
            points.push({ lat, lon, ele });
          }
        });

        return points;
      };

      const trkpts = validateGPX(gpxData);
      const points = optimizeGPXData(trkpts);

      console.log('Geoptimaliseerde GPX-punten:', points);

      return points;
    };

    const create3DScene = (points) => {
        const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        const renderer = new THREE.WebGLRenderer();
      
        renderer.setSize(window.innerWidth, window.innerHeight);
        threeContainerRef.current.appendChild(renderer.domElement);
      
        const material = new THREE.LineBasicMaterial({ color: 0x00ff00 });
      
        // Maak een geometrie voor de lijnen
        const geometry = new THREE.BufferGeometry().setFromPoints(
          points.map((point) => new THREE.Vector3(point.lon, point.ele, point.lat))
        );
      
        // Maak een lijn met de geometrie en het materiaal
        const line = new THREE.Line(geometry, material);
        scene.add(line);
      
        camera.position.set(points[0].lon, points[0].ele, points[0].lat);
        camera.lookAt(new THREE.Vector3(points[points.length - 1].lon, points[points.length - 1].ele, points[points.length - 1].lat));
      
        // Voeg een grid toe voor visuele referentie
        const gridHelper = new THREE.GridHelper(10, 10);
        scene.add(gridHelper);
      
        return { scene, camera, renderer };
      };
    

    

    const points = convertGPXtoSTL(gpxFile.fileContent);
    const { scene, camera, renderer } = create3DScene(points);

    sceneRef.current = scene;
    cameraRef.current = camera;
    rendererRef.current = renderer;
    // Animeren van de scene
    const animate = () => {
      requestAnimationFrame(animate);

      // Voeg hier eventuele animaties of updates toe

      renderer.render(scene, camera);
    };

    animate();

    // Voeg cleanup-functie toe
    return () => {
      renderer.domElement.remove();
    };
  }, [gpxFile.fileContent]);

  return (
    <div className="converter">
      <h2>GPX-bestand geüpload:</h2>
      <p>Bestandsnaam: {gpxFile.file.name}</p>
      <p>Bestandsinhoud: {gpxFile.fileContent}</p>

      <h2>3D-weergave van GPX-data:</h2>
      <div ref={threeContainerRef}></div>

<button onClick={downloadSTL}>Download STL</button>    
</div>
  );
}

export default Converter;

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Upvotes: -1

Views: 255

Answers (1)

gopal prabhu
gopal prabhu

Reputation: 333

The issue seems to be related to the way you are creating the geometry for the route in Three.js and exporting it to STL

  1. In the create3DScene(), update the creation of the geometry to use THREE.BufferGeoymetr for better performance. Also, ensure that you are adding the geometry to the scene.

2)In the downloadSTL(), ensure that the scene has a valid geometry before exporting to STL. Also, consider using STLExporter from three/examples/jsm/exporters/STLExporter.js

Upvotes: 0

Related Questions