continuous-integration/drone/push Build is passing
- Implemented computeMikkTSpaceTangents for consistent tangent generation. - Added mergeGeometries to combine multiple BufferGeometries. - Introduced mergeAttributes for merging BufferAttributes. - Created deepCloneAttribute for cloning BufferAttributes. - Developed interleaveAttributes and deinterleaveAttribute for attribute management. - Added estimateBytesUsed to calculate memory usage of geometries. - Implemented mergeVertices to optimize vertex data. - Created toTrianglesDrawMode for converting geometries to triangle mode. - Added computeMorphedAttributes for handling morph targets in geometries. - Implemented mergeGroups to consolidate geometry groups. - Developed toCreasedNormals for generating smooth normals with crease angles.
146 lines
10 KiB
JavaScript
146 lines
10 KiB
JavaScript
// Schematic furnishing positions follow the supplied floor plan. Finishes are provisional.
|
||
export function furnishInterior({THREE,parent,planPoint,box,mesh,group}) {
|
||
const material=(color,roughness=.8)=>new THREE.MeshStandardMaterial({color,roughness});
|
||
const m={oak:material(0xb99b70),oakLight:material(0xd2ba95),white:material(0xf0eee5),stone:material(0xe2ded2),sage:material(0x9ca894),cloth:material(0xd3c7b5),linen:material(0xeae5d9),pillow:material(0xb9bca9),dark:material(0x323a38),metal:new THREE.MeshStandardMaterial({color:0x8c9390,metalness:.65,roughness:.25}),water:material(0xc8d8d7),glass:new THREE.MeshStandardMaterial({color:0xb6d4d3,transparent:true,opacity:.23,roughness:.15,side:THREE.DoubleSide}),mirror:new THREE.MeshStandardMaterial({color:0xbdcaca,metalness:.65,roughness:.08})};
|
||
const colliders=[];
|
||
function block(p,name,px,py,w,d,h,y,mat){const [x,z]=planPoint(px,py);return box(p,name,x,y+h/2,z,d,h,w,mat);}
|
||
function collide(px,py,w,d){const [x,z]=planPoint(px,py);colliders.push({minX:x-d/2,maxX:x+d/2,minZ:z-w/2,maxZ:z+w/2});}
|
||
function cylinder(p,name,px,py,r,h,y,mat){const [x,z]=planPoint(px,py);const o=mesh(new THREE.CylinderGeometry(r,r,h,24),mat,p,name);o.position.set(x,y+h/2,z);return o;}
|
||
function oval(p,name,px,py,w,d,h,y,mat){const [x,z]=planPoint(px,py);const o=mesh(new THREE.SphereGeometry(1,24,12),mat,p,name);o.scale.set(d/2,h/2,w/2);o.position.set(x,y+h/2,z);return o;}
|
||
function cabinet(p,name,px,py,w,d,h=2.35,axis='py',mat=m.white){
|
||
const g=group(p,name);block(g,'Korpus',px,py,w,d,h,.02,mat);block(g,'Sokl',px,py,w-.06,d-.06,.09,.02,m.dark);
|
||
const span=axis==='py'?w:d,n=Math.max(1,Math.round(span/.55));
|
||
for(let i=1;i<n;i++){
|
||
const a=-span/2+i*span/n;
|
||
block(g,'Spára dvířek',px+(axis==='py'?a:0),py+(axis==='px'?a:0),axis==='py'?.008:w+.002,axis==='px'?.008:d+.002,h-.16,.12,m.oakLight);
|
||
}
|
||
collide(px,py,w,d);return g;
|
||
}
|
||
function legs(p,px,py,w,d,h){for(const a of [-1,1])for(const b of [-1,1])block(p,'Noha',px+a*(w/2-.08),py+b*(d/2-.08),.045,.045,h,.02,m.oak);}
|
||
function table(p,name,px,py,w,d,h=.75){const g=group(p,name);block(g,'Deska',px,py,w,d,.05,h-.05,m.oakLight);legs(g,px,py,w,d,h-.05);collide(px,py,w,d);return g;}
|
||
function chair(p,px,py,rotation=0){
|
||
const g=group(p,'Židle');const [x,z]=planPoint(px,py);g.position.set(x,0,z);g.rotation.y=rotation;
|
||
box(g,'Sedák',0,.47,0,.43,.08,.43,m.cloth);box(g,'Opěradlo',0,.71,.19,.43,.45,.06,m.cloth);
|
||
for(const a of [-1,1])for(const b of [-1,1])box(g,'Noha',a*.16,.22,b*.16,.035,.44,.035,m.oak);
|
||
}
|
||
function bed(p,name,px,py,w,d,head='py'){
|
||
const g=group(p,name);block(g,'Rám postele',px,py,w,d,.29,.08,m.oak);block(g,'Matrace',px,py,w-.06,d-.06,.2,.37,m.linen);
|
||
const across=head==='py'?w:d,along=head==='py'?d:w;
|
||
block(g,'Čelo',px+(head==='px'?w/2-.04:0),py+(head==='py'?d/2-.04:0),head==='px'?.08:w,head==='py'?.08:d,.9,.07,m.oakLight);
|
||
block(g,'Přikrývka',px-(head==='px'?.25:0),py-(head==='py'?.25:0),head==='px'?w-.55:w-.03,head==='py'?d-.55:d-.03,.055,.58,m.pillow);
|
||
const count=across>1.3?2:1;
|
||
for(let i=0;i<count;i++){
|
||
const side=(i-(count-1)/2)*.8;
|
||
oval(g,'Polštář',px+(head==='px'?along/2-.32:side),py+(head==='py'?along/2-.32:side),head==='py'?.64:.40,head==='py'?.40:.64,.16,.58,m.linen);
|
||
}
|
||
collide(px,py,w,d);return g;
|
||
}
|
||
function sink(p,name,px,py,w,d){
|
||
const g=group(p,name);block(g,'Umyvadlová skříňka',px,py,w,d,.52,.3,m.oakLight);block(g,'Umyvadlová deska',px,py,w+.03,d+.03,.06,.82,m.white);
|
||
const alongPx=w>d;const n=Math.max(w,d)>1.1?2:1;
|
||
for(let i=0;i<n;i++){
|
||
const off=(i-(n-1)/2)*.62,cx=px+(alongPx?off:0),cy=py+(alongPx?0:off);
|
||
oval(g,'Umyvadlo',cx,cy,alongPx?.5:.36,alongPx?.36:.5,.05,.88,m.white);
|
||
oval(g,'Dno mísy',cx,cy,alongPx?.37:.25,alongPx?.25:.37,.014,.912,m.water);
|
||
cylinder(g,'Baterie',cx+(alongPx?0:.18),cy+(alongPx?.18:0),.018,.20,.86,m.metal);
|
||
}
|
||
collide(px,py,w,d);return g;
|
||
}
|
||
function wc(p,px,py,axis='px'){
|
||
const g=group(p,'Závěsné WC');const w=axis==='px'?.65:.38,d=axis==='px'?.38:.65;
|
||
oval(g,'Keramická mísa',px,py,w,d,.34,.15,m.white);oval(g,'Sedátko',px,py,w,d,.045,.49,m.white);
|
||
oval(g,'Vnitřek mísy',px-.035,py, w*.59,d*.57,.016,.526,m.water);collide(px,py,w,d);
|
||
}
|
||
function shower(p,px,py,w,d){
|
||
const g=group(p,'Sprchový kout');block(g,'Vanička v úrovni podlahy',px,py,w,d,.025,.016,m.stone);
|
||
block(g,'Odtok',px+w/2-.1,py,.035,d*.55,.005,.043,m.metal);
|
||
const [x,z]=planPoint(px+w/2-.08,py);const o=mesh(new THREE.CylinderGeometry(.014,.014,1.35,10),m.metal,g,'Sprchová tyč');o.position.set(x,1.45,z);
|
||
cylinder(g,'Sprchová hlavice',px+w/2-.2,py,.11,.018,2.08,m.metal);
|
||
// Open entry to the shower; only the side screen is solid.
|
||
block(g,'Skleněná zástěna',px,py+d/2,w,.014,2,.03,m.glass);
|
||
}
|
||
|
||
const kitchen=group(parent,'Kuchyň do U s poloostrovem');
|
||
// Run at garden wall, then west side and peninsula; clear aisle 1.30 m.
|
||
for(let i=0;i<6;i++){
|
||
const py=.625+i*.60;cabinet(kitchen,'Spodní kuchyňská skříňka',.605,py,.60,.59,.82,'px',m.sage);
|
||
block(kitchen,'Pracovní deska',.605,py,.64,.60,.045,.84,m.stone);
|
||
}
|
||
cabinet(kitchen,'Dřezová část',1.545,.605,1.30,.60,.82,'py',m.sage);
|
||
block(kitchen,'Pracovní deska',1.545,.605,1.30,.64,.045,.84,m.stone);
|
||
cabinet(kitchen,'Poloostrov',2.645,1.745,.90,2.30,.82,'px',m.sage);
|
||
block(kitchen,'Deska poloostrova',2.645,1.745,.96,2.34,.045,.84,m.oakLight);
|
||
block(kitchen,'Dřez',1.45,.61,.60,.44,.012,.89,m.metal);block(kitchen,'Dřez – vnitřek',1.45,.61,.50,.34,.013,.90,m.dark);
|
||
cylinder(kitchen,'Dřezová baterie',1.45,.39,.018,.30,.89,m.metal);
|
||
block(kitchen,'Varná deska',.61,2.45,.49,.60,.015,.89,m.dark);
|
||
for(const a of [-.13,.13])for(const b of [-.16,.16])cylinder(kitchen,'Varná zóna',.61+a,2.45+b,.083,.003,.908,m.metal);
|
||
block(kitchen,'Vestavná trouba',.91,3.04,.016,.48,.42,.27,m.dark);block(kitchen,'Madlo trouby',.93,3.04,.025,.36,.025,.65,m.metal);
|
||
cabinet(kitchen,'Vysoká potravinová skříň',.62,3.92,.64,.60,2.30,'px',m.sage);
|
||
cabinet(kitchen,'Americká lednice',.66,4.78,.72,.92,1.88,'px',m.metal);
|
||
block(kitchen,'Lednice – madla',1.035,4.78,.025,.045,.62,.78,m.dark);
|
||
|
||
const living=group(parent,'Obývací pokoj a jídelna');
|
||
block(living,'Koberec',5.55,2.1,2.6,3.1,.012,.016,m.linen);
|
||
block(living,'Pohovka – sedací část',5.0,1.86,.95,2.80,.40,.12,m.cloth);
|
||
block(living,'Pohovka – lenoška',5.65,.91,1.7,.90,.40,.12,m.cloth);
|
||
block(living,'Pohovka – opěradlo',4.51,1.86,.18,2.80,.76,.12,m.cloth);
|
||
block(living,'Pohovka – bočnice',5.0,3.23,1.0,.15,.60,.12,m.cloth);
|
||
for(let py=.8;py<3;py+=.75)block(living,'Sedací polštář',5.05,py,.78,.68,.12,.51,m.linen);
|
||
collide(5.0,1.86,1.1,2.8);collide(5.65,.91,1.7,.9);
|
||
table(living,'Konferenční stolek',6.25,2.25,.70,1.15,.40);
|
||
cabinet(living,'Nízká TV skříňka',7.65,1.95,.45,2.30,.42,'px',m.oak);
|
||
block(living,'Televize',7.89,1.95,.05,1.45,.82,1.05,m.dark);
|
||
cylinder(living,'Kamna',7.582,4.763,.24,1.02,.02,m.dark);cylinder(living,'Kouřovod',7.582,4.763,.075,1.56,1.04,m.dark);
|
||
collide(7.582,4.763,.52,.52);
|
||
table(living,'Jídelní stůl pro šest',3.95,5.30,2.1,.86);
|
||
for(const px of [3.25,3.95,4.65]){chair(living,px,4.57,Math.PI/2);chair(living,px,6.03,-Math.PI/2);}
|
||
|
||
const storage=group(parent,'Šatny a zádveří');
|
||
for(const py of [2.956,4.306])cabinet(storage,'Šatní skříň',10.26,py,1.96,.60,2.35,'py');
|
||
cabinet(storage,'Šatní skříň v zádveří',10.2,7.13,1.90,.60,2.35,'py');
|
||
cabinet(storage,'Botník',10.20,4.98,1.90,.44,.48,'py',m.oakLight);
|
||
block(storage,'Zrcadlo v zádveří',10.20,4.76,1.20,.012,1.25,.92,m.mirror);
|
||
for(const py of [11.406,13.125])cabinet(storage,'Šatní skříň u ložnice',6.68,py,2.55,.60,2.35,'py');
|
||
|
||
const bedrooms=group(parent,'Pokoje a ložnice');
|
||
bed(bedrooms,'Lůžko pokoje u zahrady',6.96,7.53,1.95,1.0,'px');
|
||
cabinet(bedrooms,'Šatní skříň pokoje',6.65,10.65,2.50,.65,2.35,'py');
|
||
table(bedrooms,'Pracovní stůl u zahrady',4.7,10.64,1.15,.62);chair(bedrooms,4.7,9.85,Math.PI/2);
|
||
bed(bedrooms,'Lůžko pokoje u příjezdu',12.25,16.08,.92,2.0,'py');
|
||
cabinet(bedrooms,'Šatní skříň pokoje u příjezdu',9.85,15.8,.60,2.50,2.35,'px');
|
||
table(bedrooms,'Pracovní stůl u příjezdu',11.7,12.75,1.45,.65);chair(bedrooms,11.7,13.55,-Math.PI/2);
|
||
bed(bedrooms,'Manželská postel',5.95,16.06,1.80,2.05,'py');
|
||
for(const px of [4.77,7.13])cabinet(bedrooms,'Noční stolek',px,16.75,.48,.50,.46,'py',m.oakLight);
|
||
|
||
const bath=group(parent,'Sanita – společná koupelna');
|
||
shower(bath,12.005,10.08,1.50,1.0);
|
||
// Quarter-round corner tub, bounded by the 1600 x 1600 footprint in the PDF.
|
||
const tubShape=new THREE.Shape();tubShape.moveTo(0,0);tubShape.lineTo(1.6,0);tubShape.absarc(0,0,1.6,0,Math.PI/2,false);tubShape.lineTo(0,0);
|
||
const tubGeometry=new THREE.ExtrudeGeometry(tubShape,{depth:.53,bevelEnabled:true,bevelSize:.025,bevelThickness:.025,bevelSegments:2,steps:1,curveSegments:24});
|
||
tubGeometry.rotateX(-Math.PI/2);
|
||
const tub=mesh(tubGeometry,m.white,bath,'Rohová vana 1600');const [tx,tz]=planPoint(12.73,12.26);tub.position.set(tx,.055,tz);
|
||
// Local x increases towards room, local -z towards garden; oval basin is schematic.
|
||
oval(bath,'Vana – vnitřní mísa',12.05,11.53,1.15,.83,.035,.62,m.water);
|
||
collide(12.0,11.5,1.55,1.55);
|
||
sink(bath,'Dvojumyvadlo',10.65,12.01,1.25,.50);
|
||
block(bath,'Zrcadlo',10.65,12.27,1.28,.012,.82,1.08,m.mirror);wc(bath,10.0,9.91,'py');
|
||
const ensuite=group(parent,'Sanita – koupelna u ložnice');
|
||
shower(ensuite,8.60,16.60,1.55,1.0);wc(ensuite,9.06,13.95,'px');
|
||
sink(ensuite,'Dvojumyvadlo u ložnice',9.15,15.30,.48,1.35);
|
||
block(ensuite,'Zrcadlo',9.41,15.30,.012,1.40,.80,1.1,m.mirror);
|
||
for(let i=0;i<7;i++)block(ensuite,'Topný žebřík',7.83,15.35,.04,.55,.025,.60+i*.10,m.white);
|
||
|
||
const technical=group(parent,'Technické vybavení – orientační');
|
||
cabinet(technical,'Rekuperace / tepelné čerpadlo',12.10,7.15,1.0,.60,1.9,'py',m.white);
|
||
for(let i=0;i<2;i++){
|
||
block(technical,i?'Sušička':'Pračka',12.39,9.13,.62,.62,.82,.04+i*.84,m.white);
|
||
const o=cylinder(technical,'Kruhová dvířka spotřebiče',12.39,8.805,.20,.025,.44+i*.84,m.dark);o.rotation.x=Math.PI/2;o.position.y=.44+i*.84;
|
||
const [x,z]=planPoint(12.39,8.80);o.position.x=x;o.position.z=z;
|
||
}
|
||
collide(12.39,9.13,.62,.62);
|
||
cabinet(technical,'Mrazák',11.65,9.13,.63,.62,1.45,'py',m.white);
|
||
block(technical,'Elektroměnič a baterie',10.20,7.72,.65,.30,1.1,.6,m.white);
|
||
collide(10.20,7.72,.65,.30);
|
||
return {colliders,materials:m};
|
||
}
|