| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465 |
- import assert from 'node:assert/strict'
- import { planPipeModels } from '../../../src/modules/cockpit/domain/pipeModels.js'
- import { toPipeNetwork } from '../../../src/modules/cockpit/domain/pipeNetwork.js'
- const pipe=(code,x1,x2,diameter,industry='GAS')=>({code,industry,diameter,positions:[[110+x1*.0001,28.44],[110+x2*.0001,28.44]]})
- const rows=[pipe('left',0,1,300),pipe('gap1',1,2,null),pipe('gap2',2,3,null),pipe('right',3,4,600)]
- const plan=planPipeModels({pipes:rows,components:[]})
- const a=plan.instances.find(row=>row.id==='pipe:gap1')
- const b=plan.instances.find(row=>row.id==='pipe:gap2')
- assert.ok(a&&b,'double-sided anchored gap produces models')
- assert.ok(Math.abs(a.diameterM-.375)<1e-8)
- assert.ok(Math.abs(b.diameterM-.525)<1e-8)
- assert.equal(a.diameterSource,'interpolated')
- assert.deepEqual(a.diameterAnchors.map(row=>row.code),['left','right'])
- assert.equal(rows[1].diameter,null,'do not overwrite raw business diameter')
- assert.deepEqual(plan.diameterSummary,{reported:2,interpolated:2,missing:0})
- console.log('PASS two-sided linear fill, traceable anchors, immutable raw diameter')
- const middle=(pipes,code)=>planPipeModels({pipes,components:[]}).instances.find(row=>row.id==='pipe:'+code&&row.diameterSource!=='visual-default')
- const weighted=[pipe('l',0,1,200),pipe('a',1,2,null),pipe('b',2,5,null),pipe('r',5,6,600)]
- assert.ok(Math.abs(middle(weighted,'a').diameterM-.25)<1e-8)
- assert.ok(Math.abs(middle(weighted,'b').diameterM-.45)<1e-8)
- const reversed=weighted.slice().reverse().map(row=>({...row,positions:row.positions.slice().reverse()}))
- assert.ok(Math.abs(middle(reversed,'a').diameterM-.25)<1e-8,'independent of input and path direction')
- assert.equal(middle([pipe('l',0,1,400),pipe('a',1,2,null),pipe('r',2,3,400)],'a').diameterM,.4)
- assert.equal(middle([pipe('l',0,1,400),pipe('a',1,2,null)],'a'),undefined,'one-sided does not fill')
- assert.equal(middle([pipe('a',0,1,null),pipe('b',1,2,null)],'a'),undefined,'no source means no invented diameter')
- assert.equal(middle([pipe('l',0,1,400),pipe('a',1,2,null),pipe('r',2,3,600,'WATER_SUPPLY')],'a'),undefined,'do not cross industries')
- assert.equal(middle([...rows,pipe('fork',2,8,800)],'gap1'),undefined,'stop before branch node')
- const almost=pipe('near',2,3,600);almost.positions[0][0]+=1e-10
- assert.equal(middle([pipe('l',0,1,300),pipe('gap',1,2,null),almost],'gap'),undefined,'do not snap nearly coincident endpoints')
- assert.equal(middle([pipe('l',0,1,300),pipe('bad',1,2,0),pipe('r',2,3,600)],'bad').diameterSource,'interpolated')
- console.log('PASS length weighting, reversed paths, equal anchors, no one-sided/branch/industry/nearby guessing')
- const payload={features:rows.map((row,i)=>({geometry:{type:'LineString',coordinates:row.positions},properties:{code:row.code,industry:'GAS',diameter:i===0?'300.0':row.diameter,coordinateValidation:{renderable:true}}}))}
- const adapted=toPipeNetwork(payload)
- assert.equal(adapted.pipes[1].diameter,null)
- assert.equal(adapted.pipes[0].diameter,300)
- assert.deepEqual(planPipeModels(adapted).diameterSummary,{reported:2,interpolated:2,missing:0})
- delete payload.features[0].properties.diameter
- assert.equal(toPipeNetwork(payload).pipes[0].diameter,null)
- console.log('PASS API raw diameter parsing preserves null/absent and feeds interpolation')
- const loop={...pipe('loop',1,1,null),positions:[[110.0001,28.44],[110.0008,28.44],[110.0001,28.44]]}
- assert.equal(middle([pipe('l',0,1,300),pipe('gap',1,2,null),pipe('r',2,3,600),loop],'gap'),undefined,'closed branch still counts toward junction degree')
- console.log('PASS closed side loop prevents ambiguous fill')
- for(const value of [true,false,[],[300],{},' ','no-diameter']) {
- payload.features[0].properties.diameter=value
- assert.equal(toPipeNetwork(payload).pipes[0].diameter,null,'reject non numeric diameter '+JSON.stringify(value))
- }
- console.log('PASS nonnumeric JSON cannot become reported anchors')
- assert.ok(Math.abs(middle(weighted.slice().reverse(),'a').diameterM-.25)<1e-8)
- assert.ok(Math.abs(middle(weighted.map(row=>({...row,positions:row.positions.slice().reverse()})),'a').diameterM-.25)<1e-8)
- const closed=[pipe('only-anchor',0,1,300),pipe('ca',1,2,null),pipe('cb',2,0,null)]
- assert.equal(middle(closed,'ca'),undefined,'same reported pipe reached from both sides is not two anchors')
- assert.equal(middle(closed,'cb'),undefined)
- const ring=[pipe('ra',0,1,300),pipe('rg1',1,2,null),pipe('rb',2,3,600),pipe('rg2',3,0,null)]
- assert.equal(middle(ring,'rg1').diameterM,.45)
- assert.equal(middle(ring,'rg2').diameterM,.45)
- const multi={...pipe('poly',1,3,null),positions:[[110.0001,28.44],[110.0002,28.44],[110.0003,28.44]]}
- assert.ok(Math.abs(middle([pipe('l',0,1,200),multi,pipe('b',3,4,null),pipe('r',4,5,500)],'poly').diameterM-.3)<1e-8)
- assert.equal(middle([pipe('l',0,1,-300),pipe('gap',1,2,null),pipe('r',2,3,600)],'gap'),undefined)
- assert.equal(middle([pipe('l',0,1,300,'UNKNOWN'),pipe('gap',1,2,null,'UNKNOWN'),pipe('r',2,3,600,'UNKNOWN')],'gap'),undefined)
- console.log('PASS independent reversals, one/two-anchor cycles, polyline lengths, negative and unknown-industry anchors')
|