{"id":5637,"date":"2026-03-06T09:15:56","date_gmt":"2026-03-06T12:15:56","guid":{"rendered":"https:\/\/fisica2.fica.unsl.edu.ar\/?page_id=5637"},"modified":"2026-03-19T14:57:33","modified_gmt":"2026-03-19T17:57:33","slug":"campo_electrico_calculo","status":"publish","type":"page","link":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_calculo\/","title":{"rendered":"campo_electrico_calculo"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"5637\" class=\"elementor elementor-5637\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-81b9675 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"81b9675\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-c7a16c0\" data-id=\"c7a16c0\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-7a8682f elementor-widget elementor-widget-html\" data-id=\"7a8682f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!DOCTYPE html>\r\n<html lang=\"es\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n    <title>FLUXAR - Campo Electrico de Multiples Cargas<\/title>\r\n    <script src=\"https:\/\/cdn.tailwindcss.com\"><\/script>\r\n    <link href=\"https:\/\/fonts.googleapis.com\/css2?family=JetBrains+Mono:wght@400;600&family=Space+Grotesk:wght@400;500;700&display=swap\" rel=\"stylesheet\">\r\n    <style>\r\n        :root {\r\n            --bg-color: #0d1117;\r\n            --panel-bg: rgba(22, 27, 34, 0.95);\r\n            --border-color: #30363d;\r\n            --text-main: #e6edf3;\r\n            --text-muted: #8b949e;\r\n            --accent-pos: #f85149; \/* Rojo *\/\r\n            --accent-neg: #58a6ff; \/* Azul *\/\r\n            --accent-line: #d29922; \/* Naranja *\/\r\n            --accent-vec: #f0e68c; \/* Amarillo *\/\r\n            --accent-test: #3fb950; \/* Verde *\/\r\n        }\r\n\r\n        * { margin: 0; padding: 0; box-sizing: border-box; }\r\n\r\n        body {\r\n            font-family: 'Space Grotesk', sans-serif;\r\n            background: var(--bg-color);\r\n            color: var(--text-main);\r\n            overflow: hidden;\r\n        }\r\n\r\n        #canvas-container { position: fixed; inset: 0; z-index: 1; }\r\n\r\n        .panel {\r\n            background: var(--panel-bg);\r\n            border: 1px solid var(--border-color);\r\n            border-radius: 12px;\r\n            backdrop-filter: blur(16px);\r\n            z-index: 100;\r\n            box-shadow: 0 8px 32px rgba(0,0,0,0.4);\r\n        }\r\n\r\n        .left-panel {\r\n            position: fixed;\r\n            top: 20px;\r\n            left: 20px;\r\n            width: 300px;\r\n            padding: 20px;\r\n            max-height: calc(100vh - 40px);\r\n            overflow-y: auto;\r\n        }\r\n\r\n        .right-panel {\r\n            position: fixed;\r\n            top: 20px;\r\n            right: 20px;\r\n            width: 280px;\r\n            padding: 20px;\r\n        }\r\n\r\n        h1 { font-size: 1.1rem; font-weight: 700; margin-bottom: 4px; }\r\n        .subtitle { font-size: 0.8rem; color: var(--text-muted); margin-bottom: 16px; padding-bottom: 12px; border-bottom: 1px solid var(--border-color); }\r\n\r\n        .section-title {\r\n            font-size: 0.7rem;\r\n            text-transform: uppercase;\r\n            letter-spacing: 1.2px;\r\n            color: var(--text-muted);\r\n            margin: 16px 0 8px 0;\r\n        }\r\n\r\n        .control-group { margin-bottom: 12px; }\r\n        \r\n        select {\r\n            width: 100%;\r\n            padding: 8px 12px;\r\n            background: #161b22;\r\n            border: 1px solid var(--border-color);\r\n            border-radius: 6px;\r\n            color: var(--text-main);\r\n            font-family: inherit;\r\n            font-size: 0.85rem;\r\n            cursor: pointer;\r\n        }\r\n\r\n        .charge-card {\r\n            background: rgba(0,0,0,0.2);\r\n            border-radius: 8px;\r\n            padding: 12px;\r\n            margin-bottom: 8px;\r\n            border-left: 3px solid;\r\n            transition: all 0.2s;\r\n        }\r\n        .charge-card.positive { border-color: var(--accent-pos); }\r\n        .charge-card.negative { border-color: var(--accent-neg); }\r\n\r\n        .charge-header {\r\n            display: flex;\r\n            justify-content: space-between;\r\n            align-items: center;\r\n            margin-bottom: 8px;\r\n        }\r\n        .charge-title { font-weight: 600; font-size: 0.9rem; }\r\n        .charge-val { font-family: 'JetBrains Mono', monospace; font-size: 0.8rem; }\r\n\r\n        input[type=\"range\"] {\r\n            width: 100%;\r\n            height: 4px;\r\n            background: #21262d;\r\n            border-radius: 2px;\r\n            -webkit-appearance: none;\r\n            margin-top: 4px;\r\n        }\r\n        input[type=\"range\"]::-webkit-slider-thumb {\r\n            -webkit-appearance: none;\r\n            width: 14px;\r\n            height: 14px;\r\n            background: var(--text-main);\r\n            border-radius: 50%;\r\n            cursor: pointer;\r\n        }\r\n\r\n        .toggle-row {\r\n            display: flex;\r\n            justify-content: space-between;\r\n            align-items: center;\r\n            padding: 6px 0;\r\n            font-size: 0.85rem;\r\n        }\r\n\r\n        .switch {\r\n            position: relative;\r\n            width: 36px;\r\n            height: 20px;\r\n            background: #21262d;\r\n            border-radius: 10px;\r\n            cursor: pointer;\r\n            transition: background 0.2s;\r\n        }\r\n        .switch.active { background: var(--accent-test); }\r\n        .switch::after {\r\n            content: '';\r\n            position: absolute;\r\n            top: 2px; left: 2px;\r\n            width: 16px; height: 16px;\r\n            background: white;\r\n            border-radius: 50%;\r\n            transition: transform 0.2s;\r\n        }\r\n        .switch.active::after { transform: translateX(16px); }\r\n\r\n        .info-box {\r\n            background: rgba(0,0,0,0.2);\r\n            border-radius: 8px;\r\n            padding: 12px;\r\n            margin-bottom: 12px;\r\n        }\r\n        .info-row {\r\n            display: flex;\r\n            justify-content: space-between;\r\n            margin-bottom: 4px;\r\n            font-size: 0.85rem;\r\n        }\r\n        .info-label { color: var(--text-muted); }\r\n        .info-val { font-family: 'JetBrains Mono', monospace; font-weight: 600; }\r\n        .info-val.e-val { color: var(--accent-test); }\r\n\r\n        .logo-box {\r\n            position: fixed;\r\n            bottom: 20px;\r\n            right: 20px;\r\n            display: flex;\r\n            align-items: center;\r\n            gap: 10px;\r\n            background: rgba(22, 27, 34, 0.9);\r\n            padding: 10px 14px;\r\n            border-radius: 8px;\r\n            border: 1px solid var(--border-color);\r\n            z-index: 100;\r\n        }\r\n        .logo-img { width: 100px; }\r\n        .logo-text { font-size: 0.7rem; line-height: 1.3; color: var(--text-muted); }\r\n        .logo-text b { display: block; color: var(--text-main); font-weight: 600; }\r\n\r\n        .instructions {\r\n            position: fixed;\r\n            bottom: 20px;\r\n            left: 50%;\r\n            transform: translateX(-50%);\r\n            background: var(--panel-bg);\r\n            border: 1px solid var(--border-color);\r\n            padding: 8px 16px;\r\n            border-radius: 6px;\r\n            font-size: 0.75rem;\r\n            color: var(--text-muted);\r\n            z-index: 100;\r\n        }\r\n    <\/style>\r\n<\/head>\r\n<body>\r\n\r\n<div id=\"canvas-container\"><\/div>\r\n\r\n<!-- Panel Izquierdo: Controles -->\r\n<div class=\"panel left-panel\">\r\n    <h1>FISAR<\/h1>\r\n    <div class=\"subtitle\">Campo Electrico de Multiples Cargas<\/div>\r\n\r\n    <div class=\"section-title\">Configuracion del Sistema<\/div>\r\n    <div class=\"control-group\">\r\n        <label style=\"font-size:0.8rem; color:var(--text-muted); display:block; margin-bottom:4px;\">Numero de Cargas<\/label>\r\n        <select id=\"numChargesSelect\">\r\n            <option value=\"1\">1 Carga<\/option>\r\n            <option value=\"2\" selected>2 Cargas<\/option>\r\n            <option value=\"3\">3 Cargas<\/option>\r\n            <option value=\"4\">4 Cargas<\/option>\r\n        <\/select>\r\n    <\/div>\r\n\r\n    <div class=\"section-title\">Propiedades de Cargas<\/div>\r\n    <div id=\"chargesConfigContainer\"><\/div>\r\n\r\n    <div class=\"section-title\">Visualizacion<\/div>\r\n    <div class=\"toggle-row\">\r\n        <span>Lineas de Campo<\/span>\r\n        <div class=\"switch active\" id=\"tglLines\"><\/div>\r\n    <\/div>\r\n    <div class=\"toggle-row\">\r\n        <span>Vectores de Campo (Grilla)<\/span>\r\n        <div class=\"switch active\" id=\"tglVectors\"><\/div>\r\n    <\/div>\r\n    <div class=\"toggle-row\">\r\n        <span>Punto de Prueba<\/span>\r\n        <div class=\"switch active\" id=\"tglProbe\"><\/div>\r\n    <\/div>\r\n    <div class=\"toggle-row\">\r\n        <span>Etiquetas<\/span>\r\n        <div class=\"switch active\" id=\"tglLabels\"><\/div>\r\n    <\/div>\r\n<\/div>\r\n\r\n<!-- Panel Derecho: Info -->\r\n<div class=\"panel right-panel\">\r\n    <div class=\"section-title\">Punto de Prueba<\/div>\r\n    <div class=\"info-box\">\r\n        <div class=\"info-row\">\r\n            <span class=\"info-label\">Posicion (x, y, z)<\/span>\r\n        <\/div>\r\n        <div class=\"info-row\">\r\n            <span class=\"info-val\" id=\"probePosVal\" style=\"font-size:0.75rem\">0.0, 0.0, 0.0<\/span>\r\n        <\/div>\r\n        <div style=\"border-top:1px solid #333; margin:8px 0;\"><\/div>\r\n        <div class=\"info-row\">\r\n            <span class=\"info-label\">Campo Electrico Total<\/span>\r\n            <span class=\"info-val e-val\" id=\"probeMagVal\">0.00 N\/C<\/span>\r\n        <\/div>\r\n        <div class=\"info-row\">\r\n            <span class=\"info-label\">Direccion<\/span>\r\n        <\/div>\r\n        <div class=\"info-row\">\r\n            <span class=\"info-val\" id=\"probeDirVal\" style=\"font-size:0.75rem; color:#888;\">--<\/span>\r\n        <\/div>\r\n    <\/div>\r\n    \r\n    <div class=\"section-title\">Cargas Activas<\/div>\r\n    <div id=\"chargesInfoContainer\"><\/div>\r\n<\/div>\r\n\r\n<!-- Instrucciones -->\r\n<div class=\"instructions\">\r\n    Arrastra cargas o el punto verde para moverlos | Click derecho + arrastra para rotar camara | Scroll para zoom\r\n<\/div>\r\n\r\n<!-- Logo -->\r\n<div class=\"logo-box\">\r\n    <a href=\"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/FISAR_SIM\/\" target=\"_blank\">\r\n    <img decoding=\"async\" src=\"FISAR_SIM_1\" alt=\"Logo\" class=\"logo-img\"><\/a>\r\n    <div class=\"logo-text\"><b>FICA UNSL<\/b>Simulaciones Interactivas<\/div>\r\n<\/div>\r\n\r\n<script type=\"importmap\">\r\n{\r\n    \"imports\": {\r\n        \"three\": \"https:\/\/unpkg.com\/three@0.160.0\/build\/three.module.js\",\r\n        \"three\/addons\/\": \"https:\/\/unpkg.com\/three@0.160.0\/examples\/jsm\/\"\r\n    }\r\n}\r\n<\/script>\r\n\r\n<script type=\"module\">\r\nimport * as THREE from 'three';\r\nimport { OrbitControls } from 'three\/addons\/controls\/OrbitControls.js';\r\n\r\n\/\/ --- CONFIGURACION ---\r\nconst K = 8.99e9; \/\/ Constante de Coulomb\r\nconst SCALE = 1e-6; \/\/ Escala para visualizacion (microCoulombs)\r\n\r\nlet scene, camera, renderer, controls;\r\nlet charges = [];\r\nlet fieldLinesGroup = new THREE.Group();\r\nlet fieldVectorsGroup = new THREE.Group();\r\nlet probePoint = null;\r\nlet probeArrow = null; \/\/ Flecha de direccion E en el punto de prueba\r\n\r\n\/\/ Estado Visualizacion\r\nlet visState = {\r\n    lines: true,\r\n    vectors: true,\r\n    probe: true,\r\n    labels: true\r\n};\r\n\r\n\/\/ --- INICIALIZACION ---\r\nconst container = document.getElementById('canvas-container');\r\nscene = new THREE.Scene();\r\nscene.background = new THREE.Color(0x0d1117);\r\n\r\ncamera = new THREE.PerspectiveCamera(50, window.innerWidth \/ window.innerHeight, 0.1, 1000);\r\ncamera.position.set(0, 8, 12);\r\n\r\nrenderer = new THREE.WebGLRenderer({ antialias: true });\r\nrenderer.setSize(window.innerWidth, window.innerHeight);\r\nrenderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));\r\ncontainer.appendChild(renderer.domElement);\r\n\r\ncontrols = new OrbitControls(camera, renderer.domElement);\r\ncontrols.enableDamping = true;\r\ncontrols.maxPolarAngle = Math.PI * 0.85;\r\n\r\n\/\/ --- ZOOM MANUAL GRADUAL (SOLUCION) ---\r\ncontrols.enableZoom = false; \/\/ Desactivar zoom por defecto\r\n\r\nrenderer.domElement.addEventListener('wheel', (event) => {\r\n    event.preventDefault();\r\n\r\n    const zoomSpeed = 0.002;\r\n    const delta = event.deltaY * zoomSpeed;\r\n\r\n    const direction = new THREE.Vector3();\r\n    camera.getWorldDirection(direction);\r\n\r\n    \/\/ Movimiento proporcional a la distancia actual (Dolly Zoom)\r\n    camera.position.addScaledVector(direction, -delta * camera.position.length());\r\n\r\n}, { passive: false });\r\n\r\n\/\/ Luces\r\nconst ambLight = new THREE.AmbientLight(0xffffff, 0.6);\r\nscene.add(ambLight);\r\nconst dirLight = new THREE.DirectionalLight(0xffffff, 0.8);\r\ndirLight.position.set(10, 20, 10);\r\nscene.add(dirLight);\r\n\r\n\/\/ Grid y Ejes\r\nconst grid = new THREE.GridHelper(20, 20, 0x333333, 0x222222);\r\nscene.add(grid);\r\nscene.add(new THREE.AxesHelper(5));\r\n\r\n\/\/ Grupos\r\nscene.add(fieldLinesGroup);\r\nscene.add(fieldVectorsGroup);\r\n\r\n\/\/ --- CREACION DE OBJETOS ---\r\n\r\nfunction createChargeObj(qVal, pos) {\r\n    const isPositive = qVal >= 0;\r\n    const color = isPositive ? 0xf85149 : 0x58a6ff;\r\n    \r\n    const group = new THREE.Group();\r\n    \r\n    \/\/ Esfera\r\n    const geo = new THREE.SphereGeometry(0.4, 32, 32);\r\n    const mat = new THREE.MeshStandardMaterial({ \r\n        color: color, \r\n        emissive: color, \r\n        emissiveIntensity: 0.4,\r\n        roughness: 0.3 \r\n    });\r\n    const mesh = new THREE.Mesh(geo, mat);\r\n    group.add(mesh);\r\n    \r\n    \/\/ Sprite Label\r\n    const canvas = document.createElement('canvas');\r\n    const ctx = canvas.getContext('2d');\r\n    canvas.width = 128; canvas.height = 64;\r\n    ctx.fillStyle = 'white';\r\n    ctx.font = \"bold 40px 'Space Grotesk', sans-serif\";\r\n    ctx.textAlign = \"center\";\r\n    ctx.fillText(isPositive ? \"+\" : \"-\", 64, 44);\r\n    \r\n    const tex = new THREE.CanvasTexture(canvas);\r\n    const spriteMat = new THREE.SpriteMaterial({ map: tex, transparent: true, depthTest: false });\r\n    const sprite = new THREE.Sprite(spriteMat);\r\n    sprite.scale.set(0.8, 0.4, 1);\r\n    sprite.position.y = 0.7;\r\n    group.add(sprite);\r\n    \r\n    group.position.copy(pos);\r\n    group.userData = { q: qVal, type: 'charge' };\r\n    \r\n    scene.add(group);\r\n    return group;\r\n}\r\n\r\nfunction createProbePoint() {\r\n    const group = new THREE.Group();\r\n    \r\n    const geo = new THREE.SphereGeometry(0.2, 16, 16);\r\n    const mat = new THREE.MeshStandardMaterial({ color: 0x3fb950, emissive: 0x3fb950, emissiveIntensity: 0.5 });\r\n    const mesh = new THREE.Mesh(geo, mat);\r\n    group.add(mesh);\r\n    \r\n    \/\/ Anillo\r\n    const ringGeo = new THREE.TorusGeometry(0.35, 0.05, 16, 32);\r\n    const ringMat = new THREE.MeshBasicMaterial({ color: 0x3fb950 });\r\n    const ring = new THREE.Mesh(ringGeo, ringMat);\r\n    ring.rotation.x = Math.PI \/ 2;\r\n    group.add(ring);\r\n    \r\n    group.position.set(2, 1, 2);\r\n    group.userData = { type: 'probe' };\r\n    \r\n    scene.add(group);\r\n    return group;\r\n}\r\n\r\n\/\/ --- FISICA Y CALCULOS ---\r\n\r\nfunction calculateE(pos) {\r\n    const E = new THREE.Vector3(0, 0, 0);\r\n    \r\n    for (let charge of charges) {\r\n        const q = charge.userData.q * SCALE;\r\n        const rVec = new THREE.Vector3().subVectors(pos, charge.position);\r\n        const rMag = rVec.length();\r\n        \r\n        if (rMag < 0.1) continue;\r\n        \r\n        const rUnit = rVec.clone().normalize();\r\n        const Emag = K * Math.abs(q) \/ (rMag * rMag);\r\n        const sign = q > 0 ? 1 : -1;\r\n        \r\n        const E_partial = rUnit.multiplyScalar(Emag * sign);\r\n        E.add(E_partial);\r\n    }\r\n    \r\n    return E;\r\n}\r\n\r\nfunction updateFieldLines() {\r\n    fieldLinesGroup.clear();\r\n    if (!visState.lines || charges.length === 0) return;\r\n\r\n    const lineCountPerCharge = 10;\r\n    const stepSize = 0.2;\r\n    const maxSteps = 150;\r\n\r\n    charges.forEach(charge => {\r\n        if (charge.userData.q === 0) return;\r\n        \r\n        const isPositive = charge.userData.q > 0;\r\n        \r\n        for (let i = 0; i < lineCountPerCharge; i++) {\r\n            const theta = Math.random() * Math.PI * 2;\r\n            const phi = Math.acos(2 * Math.random() - 1);\r\n            \r\n            const startOffset = new THREE.Vector3(\r\n                0.5 * Math.sin(phi) * Math.cos(theta),\r\n                0.5 * Math.sin(phi) * Math.sin(theta),\r\n                0.5 * Math.cos(phi)\r\n            );\r\n            \r\n            let currentPos = charge.position.clone().add(startOffset);\r\n            const points = [currentPos.clone()];\r\n            \r\n            for (let j = 0; j < maxSteps; j++) {\r\n                const E = calculateE(currentPos);\r\n                if (E.length() < 1e-4) break;\r\n                \r\n                const dir = E.clone().normalize();\r\n                if (!isPositive) dir.negate();\r\n                \r\n                currentPos.add(dir.multiplyScalar(stepSize));\r\n                \r\n                if (currentPos.length() > 20) break;\r\n                \r\n                let hitCharge = false;\r\n                for (let other of charges) {\r\n                    if (other === charge) continue;\r\n                    if (currentPos.distanceTo(other.position) < 0.5) {\r\n                        hitCharge = true;\r\n                        break;\r\n                    }\r\n                }\r\n                if (hitCharge) break;\r\n                \r\n                points.push(currentPos.clone());\r\n            }\r\n            \r\n            if (points.length > 2) {\r\n                const geo = new THREE.BufferGeometry().setFromPoints(points);\r\n                const mat = new THREE.LineBasicMaterial({ color: 0xd29922, transparent: true, opacity: 0.7 });\r\n                const line = new THREE.Line(geo, mat);\r\n                fieldLinesGroup.add(line);\r\n            }\r\n        }\r\n    });\r\n}\r\n\r\nfunction updateFieldVectors() {\r\n    fieldVectorsGroup.clear();\r\n    if (!visState.vectors) return;\r\n\r\n    const range = 5;\r\n    const step = 2;\r\n    \r\n    for (let x = -range; x <= range; x += step) {\r\n        for (let y = -range; y <= range; y += step) {\r\n            for (let z = -range; z <= range; z += step) {\r\n                const pos = new THREE.Vector3(x, y, z);\r\n                const E = calculateE(pos);\r\n                const len = E.length();\r\n                \r\n                if (len < 1e-3) continue;\r\n                \r\n                const displayLen = Math.min(len * 0.00001, 1.5);\r\n                const color = new THREE.Color().setHSL(0.15, 0.8, 0.6);\r\n                \r\n                const dir = E.clone().normalize();\r\n                const arrow = new THREE.ArrowHelper(dir, pos, displayLen, color.getHex(), 0.2, 0.1);\r\n                fieldVectorsGroup.add(arrow);\r\n            }\r\n        }\r\n    }\r\n}\r\n\r\nfunction updateProbe() {\r\n    if (!probePoint) return;\r\n    \r\n    const pos = probePoint.position;\r\n    const E = calculateE(pos);\r\n    const mag = E.length();\r\n    \r\n    \/\/ UI\r\n    document.getElementById('probePosVal').innerText = `${pos.x.toFixed(1)}, ${pos.y.toFixed(1)}, ${pos.z.toFixed(1)}`;\r\n    document.getElementById('probeMagVal').innerText = mag.toExponential(2) + \" N\/C\";\r\n    \r\n    \/\/ Eliminar flecha anterior si existe\r\n    if (probeArrow) {\r\n        probePoint.remove(probeArrow);\r\n        probeArrow = null;\r\n    }\r\n    \r\n    if (mag > 1e-3) {\r\n        const dir = E.clone().normalize();\r\n        document.getElementById('probeDirVal').innerText = `(${dir.x.toFixed(2)}, ${dir.y.toFixed(2)}, ${dir.z.toFixed(2)})`;\r\n        \r\n        \/\/ --- MEJORA: VECTOR DE CAMPO EN PUNTO DE PRUEBA ---\r\n        \/\/ Escalar longitud para que sea visible pero no gigante\r\n        \/\/ Max 2 unidades de largo. Escala logar\u00edtmica o lineal suavizada.\r\n        const displayLen = Math.min(2.0, Math.max(0.5, mag * 0.000005));\r\n        \r\n        \/\/ Crear flecha naranja para distinguirla del punto verde\r\n        probeArrow = new THREE.ArrowHelper(dir, new THREE.Vector3(0,0,0), displayLen, 0xffa500, 0.3, 0.15);\r\n        probePoint.add(probeArrow);\r\n        \/\/ --------------------------------------------------\r\n        \r\n    } else {\r\n        document.getElementById('probeDirVal').innerText = \"--\";\r\n    }\r\n}\r\n\r\nfunction updateChargesInfo() {\r\n    const container = document.getElementById('chargesInfoContainer');\r\n    let html = '';\r\n    charges.forEach((c, i) => {\r\n        const val = c.userData.q;\r\n        const pos = c.position;\r\n        html += `\r\n            <div class=\"info-row\">\r\n                <span class=\"info-label\">q${i+1} (${val > 0 ? '+' : ''}${val} uC)<\/span>\r\n            <\/div>\r\n            <div class=\"info-row\" style=\"font-size:0.75rem; margin-bottom:6px;\">\r\n                <span class=\"info-val\" style=\"color:#666;\">Pos: (${pos.x.toFixed(1)}, ${pos.y.toFixed(1)}, ${pos.z.toFixed(1)})<\/span>\r\n            <\/div>\r\n        `;\r\n    });\r\n    container.innerHTML = html;\r\n}\r\n\r\n\/\/ --- INTERFAZ DE CONFIGURACION ---\r\n\r\nfunction rebuildChargeConfig() {\r\n    const container = document.getElementById('chargesConfigContainer');\r\n    container.innerHTML = '';\r\n    \r\n    charges.forEach((c, i) => {\r\n        const val = c.userData.q;\r\n        const isPos = val >= 0;\r\n        \r\n        const card = document.createElement('div');\r\n        card.className = `charge-card ${isPos ? 'positive' : 'negative'}`;\r\n        card.innerHTML = `\r\n            <div class=\"charge-header\">\r\n                <div class=\"charge-title\">Carga q${i+1}<\/div>\r\n                <div class=\"charge-val\">${val > 0 ? '+' : ''}${val.toFixed(1)} uC<\/div>\r\n            <\/div>\r\n            <div style=\"display:flex; align-items:center; gap:8px;\">\r\n                <input type=\"range\" min=\"-5\" max=\"5\" step=\"0.5\" value=\"${val}\" id=\"slider-${i}\">\r\n            <\/div>\r\n        `;\r\n        container.appendChild(card);\r\n        \r\n        card.querySelector(`#slider-${i}`).addEventListener('input', (e) => {\r\n            const newVal = parseFloat(e.target.value);\r\n            c.userData.q = newVal;\r\n            card.querySelector('.charge-val').innerText = `${newVal > 0 ? '+' : ''}${newVal.toFixed(1)} uC`;\r\n            card.className = `charge-card ${newVal >= 0 ? 'positive' : 'negative'}`;\r\n            \r\n            const col = newVal >= 0 ? 0xf85149 : 0x58a6ff;\r\n            c.children[0].material.color.setHex(col);\r\n            c.children[0].material.emissive.setHex(col);\r\n            \r\n            \/\/ Al cambiar carga, actualizar TODO (lineas y vectores)\r\n            updateAll();\r\n        });\r\n    });\r\n}\r\n\r\nfunction initSystem(num) {\r\n    charges.forEach(c => scene.remove(c));\r\n    charges = [];\r\n    \r\n    const configs = {\r\n        1: [{ q: 2, pos: new THREE.Vector3(0, 0.5, 0) }],\r\n        2: [\r\n            { q: 2, pos: new THREE.Vector3(-3, 0.5, 0) },\r\n            { q: -2, pos: new THREE.Vector3(3, 0.5, 0) }\r\n        ],\r\n        3: [\r\n            { q: 2, pos: new THREE.Vector3(0, 0.5, 3) },\r\n            { q: -3, pos: new THREE.Vector3(-3, 0.5, -2) },\r\n            { q: 2, pos: new THREE.Vector3(3, 0.5, -2) }\r\n        ],\r\n        4: [\r\n            { q: 3, pos: new THREE.Vector3(-3, 0.5, -3) },\r\n            { q: -2, pos: new THREE.Vector3(3, 0.5, -3) },\r\n            { q: -2, pos: new THREE.Vector3(3, 0.5, 3) },\r\n            { q: 3, pos: new THREE.Vector3(-3, 0.5, 3) }\r\n        ]\r\n    };\r\n    \r\n    const config = configs[num];\r\n    config.forEach(cfg => {\r\n        charges.push(createChargeObj(cfg.q, cfg.pos));\r\n    });\r\n    \r\n    rebuildChargeConfig();\r\n    updateAll();\r\n}\r\n\r\nfunction updateAll() {\r\n    updateFieldLines();\r\n    updateFieldVectors();\r\n    updateProbe();\r\n    updateChargesInfo();\r\n}\r\n\r\n\/\/ --- EVENTOS Y CONTROLES ---\r\n\r\ndocument.getElementById('numChargesSelect').addEventListener('change', (e) => {\r\n    initSystem(parseInt(e.target.value));\r\n});\r\n\r\n\/\/ Toggles\r\ndocument.getElementById('tglLines').addEventListener('click', function() {\r\n    this.classList.toggle('active');\r\n    visState.lines = this.classList.contains('active');\r\n    fieldLinesGroup.visible = visState.lines;\r\n});\r\ndocument.getElementById('tglVectors').addEventListener('click', function() {\r\n    this.classList.toggle('active');\r\n    visState.vectors = this.classList.contains('active');\r\n    fieldVectorsGroup.visible = visState.vectors;\r\n});\r\ndocument.getElementById('tglProbe').addEventListener('click', function() {\r\n    this.classList.toggle('active');\r\n    visState.probe = this.classList.contains('active');\r\n    probePoint.visible = visState.probe;\r\n});\r\ndocument.getElementById('tglLabels').addEventListener('click', function() {\r\n    this.classList.toggle('active');\r\n    visState.labels = this.classList.contains('active');\r\n    charges.forEach(c => {\r\n        c.children[1].visible = visState.labels;\r\n    });\r\n});\r\n\r\n\/\/ Drag and Drop\r\nconst raycaster = new THREE.Raycaster();\r\nconst mouse = new THREE.Vector2();\r\nlet selectedObject = null;\r\nconst plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);\r\nconst intersectionPoint = new THREE.Vector3();\r\n\r\nfunction onMouseDown(e) {\r\n    if (e.button !== 0) return;\r\n    \r\n    mouse.x = (e.clientX \/ window.innerWidth) * 2 - 1;\r\n    mouse.y = -(e.clientY \/ window.innerHeight) * 2 + 1;\r\n    \r\n    raycaster.setFromCamera(mouse, camera);\r\n    \r\n    const targets = [...charges];\r\n    if (probePoint) targets.push(probePoint);\r\n    \r\n    const intersects = raycaster.intersectObjects(targets, true);\r\n    \r\n    if (intersects.length > 0) {\r\n        controls.enabled = false;\r\n        let obj = intersects[0].object;\r\n        while (obj.parent && !obj.userData.type) {\r\n            obj = obj.parent;\r\n        }\r\n        \r\n        if (obj.userData.type === 'charge' || obj.userData.type === 'probe') {\r\n            selectedObject = obj;\r\n            plane.constant = -obj.position.y; \r\n        }\r\n    }\r\n}\r\n\r\nfunction onMouseMove(e) {\r\n    if (selectedObject) {\r\n        mouse.x = (e.clientX \/ window.innerWidth) * 2 - 1;\r\n        mouse.y = -(e.clientY \/ window.innerHeight) * 2 + 1;\r\n        \r\n        raycaster.setFromCamera(mouse, camera);\r\n        raycaster.ray.intersectPlane(plane, intersectionPoint);\r\n        \r\n        if (intersectionPoint) {\r\n            selectedObject.position.x = intersectionPoint.x;\r\n            selectedObject.position.z = intersectionPoint.z;\r\n            \r\n            \/\/ OPTIMIZACI\u00d3N:\r\n            \/\/ Si movemos una carga, actualizamos TODO (l\u00edneas cambian).\r\n            \/\/ Si movemos el punto de prueba, SOLO actualizamos el punto (no las l\u00edneas).\r\n            if (selectedObject.userData.type === 'charge') {\r\n                updateAll();\r\n            } else {\r\n                updateProbe();\r\n            }\r\n        }\r\n    }\r\n}\r\n\r\nfunction onMouseUp() {\r\n    controls.enabled = true;\r\n    selectedObject = null;\r\n}\r\n\r\nwindow.addEventListener('mousedown', onMouseDown);\r\nwindow.addEventListener('mousemove', onMouseMove);\r\nwindow.addEventListener('mouseup', onMouseUp);\r\n\r\nwindow.addEventListener('resize', () => {\r\n    camera.aspect = window.innerWidth \/ window.innerHeight;\r\n    camera.updateProjectionMatrix();\r\n    renderer.setSize(window.innerWidth, window.innerHeight);\r\n});\r\n\r\n\/\/ --- INICIO ---\r\nprobePoint = createProbePoint();\r\ninitSystem(2);\r\nanimate();\r\n\r\nfunction animate() {\r\n    requestAnimationFrame(animate);\r\n    controls.update();\r\n    renderer.render(scene, camera);\r\n}\r\n\r\n<\/script>\r\n<\/body>\r\n<\/html>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>FLUXAR &#8211; Campo Electrico de Multiples Cargas FISAR Campo Electrico de Multiples Cargas Configuracion del Sistema Numero de Cargas 1 Carga2 Cargas3 Cargas4 Cargas Propiedades&hellip;<\/p>\n","protected":false},"author":7,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"class_list":["post-5637","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.0 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>campo_electrico_calculo - F\u00edsica 2<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_calculo\/\" \/>\n<meta property=\"og:locale\" content=\"es_ES\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"campo_electrico_calculo - F\u00edsica 2\" \/>\n<meta property=\"og:description\" content=\"FLUXAR &#8211; Campo Electrico de Multiples Cargas FISAR Campo Electrico de Multiples Cargas Configuracion del Sistema Numero de Cargas 1 Carga2 Cargas3 Cargas4 Cargas Propiedades&hellip;\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_calculo\/\" \/>\n<meta property=\"og:site_name\" content=\"F\u00edsica 2\" \/>\n<meta property=\"article:modified_time\" content=\"2026-03-19T17:57:33+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Tiempo de lectura\" \/>\n\t<meta name=\"twitter:data1\" content=\"1 minuto\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_calculo\/\",\"url\":\"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_calculo\/\",\"name\":\"campo_electrico_calculo - F\u00edsica 2\",\"isPartOf\":{\"@id\":\"https:\/\/fisica2.fica.unsl.edu.ar\/#website\"},\"datePublished\":\"2026-03-06T12:15:56+00:00\",\"dateModified\":\"2026-03-19T17:57:33+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_calculo\/#breadcrumb\"},\"inLanguage\":\"es-AR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_calculo\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_calculo\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Inicio\",\"item\":\"https:\/\/fisica2.fica.unsl.edu.ar\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"campo_electrico_calculo\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/fisica2.fica.unsl.edu.ar\/#website\",\"url\":\"https:\/\/fisica2.fica.unsl.edu.ar\/\",\"name\":\"F\u00edsica 2\",\"description\":\"FICA - UNSL\",\"publisher\":{\"@id\":\"https:\/\/fisica2.fica.unsl.edu.ar\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/fisica2.fica.unsl.edu.ar\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es-AR\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/fisica2.fica.unsl.edu.ar\/#organization\",\"name\":\"SAC- Secretar\u00eda General FICA\",\"url\":\"https:\/\/fisica2.fica.unsl.edu.ar\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es-AR\",\"@id\":\"https:\/\/fisica2.fica.unsl.edu.ar\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/fisica2.fica.unsl.edu.ar\/wp-content\/uploads\/2021\/11\/SG-Logo.png\",\"contentUrl\":\"https:\/\/fisica2.fica.unsl.edu.ar\/wp-content\/uploads\/2021\/11\/SG-Logo.png\",\"width\":4483,\"height\":1231,\"caption\":\"SAC- Secretar\u00eda General FICA\"},\"image\":{\"@id\":\"https:\/\/fisica2.fica.unsl.edu.ar\/#\/schema\/logo\/image\/\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"campo_electrico_calculo - F\u00edsica 2","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_calculo\/","og_locale":"es_ES","og_type":"article","og_title":"campo_electrico_calculo - F\u00edsica 2","og_description":"FLUXAR &#8211; Campo Electrico de Multiples Cargas FISAR Campo Electrico de Multiples Cargas Configuracion del Sistema Numero de Cargas 1 Carga2 Cargas3 Cargas4 Cargas Propiedades&hellip;","og_url":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_calculo\/","og_site_name":"F\u00edsica 2","article_modified_time":"2026-03-19T17:57:33+00:00","twitter_card":"summary_large_image","twitter_misc":{"Tiempo de lectura":"1 minuto"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_calculo\/","url":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_calculo\/","name":"campo_electrico_calculo - F\u00edsica 2","isPartOf":{"@id":"https:\/\/fisica2.fica.unsl.edu.ar\/#website"},"datePublished":"2026-03-06T12:15:56+00:00","dateModified":"2026-03-19T17:57:33+00:00","breadcrumb":{"@id":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_calculo\/#breadcrumb"},"inLanguage":"es-AR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_calculo\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_calculo\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Inicio","item":"https:\/\/fisica2.fica.unsl.edu.ar\/"},{"@type":"ListItem","position":2,"name":"campo_electrico_calculo"}]},{"@type":"WebSite","@id":"https:\/\/fisica2.fica.unsl.edu.ar\/#website","url":"https:\/\/fisica2.fica.unsl.edu.ar\/","name":"F\u00edsica 2","description":"FICA - UNSL","publisher":{"@id":"https:\/\/fisica2.fica.unsl.edu.ar\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/fisica2.fica.unsl.edu.ar\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es-AR"},{"@type":"Organization","@id":"https:\/\/fisica2.fica.unsl.edu.ar\/#organization","name":"SAC- Secretar\u00eda General FICA","url":"https:\/\/fisica2.fica.unsl.edu.ar\/","logo":{"@type":"ImageObject","inLanguage":"es-AR","@id":"https:\/\/fisica2.fica.unsl.edu.ar\/#\/schema\/logo\/image\/","url":"https:\/\/fisica2.fica.unsl.edu.ar\/wp-content\/uploads\/2021\/11\/SG-Logo.png","contentUrl":"https:\/\/fisica2.fica.unsl.edu.ar\/wp-content\/uploads\/2021\/11\/SG-Logo.png","width":4483,"height":1231,"caption":"SAC- Secretar\u00eda General FICA"},"image":{"@id":"https:\/\/fisica2.fica.unsl.edu.ar\/#\/schema\/logo\/image\/"}}]}},"_links":{"self":[{"href":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/wp-json\/wp\/v2\/pages\/5637","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/wp-json\/wp\/v2\/comments?post=5637"}],"version-history":[{"count":19,"href":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/wp-json\/wp\/v2\/pages\/5637\/revisions"}],"predecessor-version":[{"id":6703,"href":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/wp-json\/wp\/v2\/pages\/5637\/revisions\/6703"}],"wp:attachment":[{"href":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/wp-json\/wp\/v2\/media?parent=5637"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}