![]() |
0.1.22
|
setPrimitiveData*()/setObjectData*() now accept a list of values (one per UUID/objID) to assign a distinct value to each element in a single bulk call, complementing the existing scalar-broadcast behavior (a scalar still applies the same value to every ID). Covers all 11 data types (int, uint, float, double, string, vec2, vec3, vec4, int2, int3, int4).overridePrimitiveTextureColor() and usePrimitiveTextureColor() now accept a list of UUIDs, applying the override/restore to all of them in one bulk call (previously single-UUID only).incrementPrimitiveData() gained an optional data_type keyword (‘'int’/'uint'/'float'/'double'`) to target a specific field type, and now supports unsigned-int and double fields in addition to the existing int/float overloads.LiDARCloud.addHitPointsWithData() for bulk in-memory hit ingestion carrying a per-hit data map: like addHitPoints() but populates each hit's named-scalar data map (the in-memory equivalent of what the ASCII loader does for non-standard columns), so values like timestamp/target_index/target_count land in the map for multi-return grouping. Uses the full SphericalCoord (radius retained for Beer's-law path length).LiDARCloud.getTriangleVerticesAll() to bulk-export every triangulated triangle's three vertices (and source scan ID) in a single call as flat numpy arrays, reading directly off the LiDARcloud and bypassing the Context round-trip and per-triangle vertex loop.LiDARCloud.getTriangulationStats() returning the filter diagnostics from the most recent triangulateHitPoints() call as a dict (candidates, dropped_lmax, dropped_aspect, dropped_degenerate); each dropped triangle is attributed to one primary reason so candidates == getTriangleCount() + dropped_lmax + dropped_aspect + dropped_degenerate, distinguishing a data-limited mesh (few candidates) from a filter-limited one (many candidates dropped by Lmax/aspect).calculateLeafArea() fails fast with an explicit error if the point cloud contains no misses (fired pulses that returned nothing), rather than silently producing biased leaf area density. LiDARCloud.syntheticScan() now records misses by default for discrete-return scans as well as full-waveform (the discrete path is routed through a new miss-aware native overload honoring scan_grid_only/record_misses); import workflows can synthesize misses with gapfillMisses(). Added hasMisses(), isHitMiss(index), and the static getMissDistance() (the LIDAR_MISS_DISTANCE constant) to inspect misses.addScan() gained scan_tilt_roll/scan_tilt_pitch keyword arguments (radians; default 0 = level), queryable via getScanTiltRoll()/getScanTiltPitch(). Models the residual tilt of the scanner spin axis away from plumb.addScanMultibeam() registers a rotating multi-channel scan from a list of per-channel zenith angles, and getScanPattern() (returning the new ScanPattern enum: RASTER/SPINNING_MULTIBEAM) and getScanBeamZenithAngles() query the pattern.calculateLeafArea() gained an optional element_width argument that, alongside the leaf-area estimate, computes the sampling variance, exposed through getCellLADVariance(), getCellBeamCount(), getCellRelativeDensityIndex(), getCellMeanPathLength(), single-voxel getCellLeafAreaConfidenceInterval(), group-scale getGroupLADConfidenceInterval() (recommended), and the exportLeafAreaUncertainty() file export.exportPointCloud() gained a write_header argument (default True): exports now prepend a #-prefixed column-name header line (CloudCompare convention) that round-trips through loadXML().getAllShootIDs()/getPlantShoot(): PlantArchitecture.getAllShootIDs() returns the contiguous 0-based shoot IDs for a plant (shoot 0 is the base stem), getShoot() returns a shoot's topology dict (rank, parent_shoot_id (-1 for the base stem), parent_node_index, node_count), getShootChildIDs() returns its child shoot IDs, and getShootInternodeVertices()/getShootInternodeRadii() return its woody internode polyline geometry.clearAllPrimitiveData(label) and clearAllObjectData(label) to remove a named data field from every primitive/compound object in the Context (including hidden ones) and release the registered data type for that label, complementing the existing per-UUID/per-objID clearPrimitiveData()/clearObjectData().deleteTimeseriesDataPoint(date, time, label=None) to delete a single timeseries data point at a given date/time — for one variable when label is given, or across all variables when label is None.Location gained an altitude field (meters above sea level, default 0.0); setLocation() accepts an optional altitude in its float form, getLocation() now returns it, and make_Location() accepts an optional 4th argument. Existing 3-argument usage is unchanged. Note Helios's non-standard longitude convention (+W / −E), which is auto-flipped to the standard +E convention when written into camera EXIF metadata.CameraProperties gained a manufacturer field (helios-core v1.3.73 maps it to the EXIF camera Make tag; empty ⇒ "Helios"). Like the other CameraProperties string fields, it is exposed on the Python class for forward compatibility but is not yet plumbed through to the native camera. Camera images written via writeCameraImage() embed EXIF/XMP metadata (camera intrinsics, orientation, and GPS derived from the Context Location) automatically on the native side.LiDARCloud.addScan() gained optional range_noise_stddev (meters) and angle_noise_stddev (radians) arguments that drive realistic anisotropic positional error during syntheticScan() (along-beam range noise and across-beam beam-pointing jitter). Both default to 0.0 (disabled), preserving prior behavior. Query them with getScanRangeNoiseStdDev(scanID) / getScanAngleNoiseStdDev(scanID).exportScans(filename) to write all scans as an XML metadata file plus one ASCII data file per scan (auto-named <base>_<scanID>.xyz), re-loadable with loadXML().doesObjectExist(), doesObjectContainPrimitive(), doesMaterialDataExist(), objectHasTexture(), isPrimitiveDirty(), areObjectPrimitivesComplete(), getJulianDate(), getMaterialCount(), getObjectArea(), getObjectPrimitiveCount(), getPolymeshObjectVolume(), getMaterialIDFromLabel(), getPrimitiveMaterialID(), getGlobalDataVersion(), getPrimitiveParentObjectID(), getObjectTextureFile(), listAllPrimitiveDataLabels(), getLoadedXMLFiles(), printObjectInfo(), printPrimitiveInfo(), setObjectDataFromPrimitiveDataMean(), renameMaterial(), renamePrimitiveData(), clearMaterialData(), plus enable/disablePrimitiveDataValueCaching() and enable/disableObjectDataValueCaching()getDeletedUUIDs(), getDirtyUUIDs(), getUniquePrimitiveParentObjectIDs(), getObjectAverageNormal(), plus setObjectAverageNormal(), setObjectOrigin(), setPrimitiveAzimuth(), setPrimitiveElevation(), setTriangleVertices(), setPrimitiveNormal() (single/batch), and setPrimitiveParentObjectID() (single/batch)int, uint, float, double, string, vec2, vec3, vec4, int2, int3, int4): per-type explicit setMaterialData<Type>() and getMaterialData<Type>() methods, a unified setMaterialData()/getMaterialData() dispatcher with auto-detection via getMaterialDataType(), and getUniquePrimitiveDataValues()/getUniqueObjectDataValues() (int/uint/str)(4,4) float32 ndarrays (also accepting nested lists or flat 16-float lists): get/setObjectTransformationMatrix() and get/setPrimitiveTransformationMatrix() with single/batch dispatch, plus domain-level getDomainBoundingBox() and getDomainBoundingSphere() with optional UUID filteringsetTubeNodes(), setTubeRadii(), scaleTubeGirth(), scaleTubeLength(), pruneTubeNodes(), appendTubeSegment() (color or texture+uv kwargs), addPolymeshObject(), setObjectColor() (RGB/RGBA, single/batch), overrideObjectTextureColor()/useObjectTextureColor(), markPrimitiveDirty()/markPrimitiveClean(), setTileObjectSubdivisionCount(), and setTileObjectSubdivisionByAreaRatio()cleanDeletedUUIDs() and cleanDeletedObjectIDs() (returning new lists, not mutating input), writeXML()/writeXML_byobject() for XML export with optional UUID filtering, randu()/randn() random-number draws (uniform with optional float or int range; normal with optional mean/stddev), and geographic setLocation()/getLocation() returning the new Location dataclass (latitude, longitude, UTC offset)generateColormap(name, n_colors) returning an RGBcolor list, generateTexturesFromColormap() returning generated file paths, and getPrimitiveTextureTransparencyData() returning an Optional[np.ndarray] 2D bool maskdeleteTimeseriesVariable(label) to remove a single timeseries variable and all of its data points (complements the existing clearTimeseriesData() and updateTimeseriesData()).LeafOpticsProperties with two optional Fluspect-B SIF parameters: V2Z (violaxanthin↔zeaxanthin de-epoxidation state, default 0.0) and fqe (intrinsic fluorescence quantum-efficiency scalar, default 1.0). They are ignored by the pure PROSPECT reflectance/transmittance calculation; the radiation plugin's SIF pipeline reads them when active. The flat float-array layout grew from 9 to 11 entries; LeafOpticsProperties.from_list() still accepts both lengths for backward compatibility with serialized data.setModelTypeC4() and the von Caemmerer (2021) steady-state C4 model — setC4CoefficientsFromLibrary() / getC4CoefficientsFromLibrary() (species: SetariaViridis_vC2021, GenericC4_vC2000, Maize_Massad2007), setC4ModelCoefficients() / getC4ModelCoefficients() over a 43-float coefficient array (5 temperature-responsive rates × 4 floats: Vpmax/Vcmax/Jmax/Rd/gm; 5 K-25 + 5 dH kinetic constants; 13 user-tunable scalars), and setCm() for direct mesophyll CO₂ prescription (testing/validation). Both setC4CoefficientsFromLibrary() and setC4ModelCoefficients() accept a material_label keyword to apply coefficients per-material rather than per-UUID.setFarquharMesophyllConductance() to configure C3 mesophyll conductance gm (mol CO₂ / m² / s / bar) with optional temperature response. Default behaviour unchanged: gm = +∞ reduces Cc to Ci (legacy Farquhar).FarquharModelCoefficients flat array round-trip (to_array() / from_array() and the corresponding getFarquharModelCoefficients / setFarquharModelCoefficients C wrappers) grew from 18 to 22 floats: slots 18–21 carry (gm_at_25C, dHa, Topt_C, dHd) for the gm temperature response. from_array still accepts the legacy 18-float layout for back-compat (gm defaults to +∞); the C wrapper still accepts 18-float buffers and only consumes the gm slots when the buffer is at least 22 elements.limitation_state uses the convention 1 = enzyme-limited, 2 = electron-transport-limited (vs. C3's 0/1). New optional output primitive data labels for the C4 model: Cm (mesophyll cytosolic CO₂) and Vp (PEP carboxylation rate).addSIFCamera() (vec3 lookat and SphericalCoord overloads) plus the new SIFCameraProperties (extends CameraProperties with excitation_bin_width_nm and excitation_scattering_depth) and the isSIFCamera() query. SIF cameras source per-band emission from the Fluspect-B kernel rather than Stefan-Boltzmann; Helios auto-creates internal excitation bands covering 400–750 nm at the requested bin width.syntheticScan() already computes: LiDARCloud.getHitData(index, label), doesHitDataExist(index, label), and getHitScanID(index), reaching intensity, distance, timestamp, target_index, target_count, deviation, nRaysHit, and any column-format fields. Added bulk single-call exports getHitDataAll(label) and getHitsXYZRGB() for large clouds.column_format is now sampled from the struck primitive (FLOAT/DOUBLE/INT/UINT) onto each hit, replacing the previously hardcoded object_label/reflectivity_lidar pair (reflectivity_lidar retains its intensity-modulation behavior). LiDARCloud.addScan() gained an optional column_format argument (default keeps prior behavior); the previously auto-copied object_label must now be listed in column_format to transfer.writePlantStructureUSD() to export a plant as a USD articulated rigid body for NVIDIA IsaacSim physics (capsule links, spherical joints with E*I/L spring/damper drives, organ mass bodies)registerGrowthFrame(), writePlantGrowthUSD(), clearGrowthFrames(), and getGrowthFrameCount() for time-sampled USD animations importable into BlenderupdateTimeseriesData() method to replace the value of an existing timeseries data point at a specified (date, time)getObjectType(), getObjectCenter(), getObjectBoundingBox(), getObjectPrimitiveUUIDs() (single/list/nested), plus per-type getters for tile, sphere, box, disk, tube, and cone objects (center, size, subdivision count, normal, vertices, radius, node/radius data, axis, length, volume)getPatchCenter(), getPatchSize(), getTriangleVertex(), getVoxelCenter(), getVoxelSize(), getPatchCount(), getTriangleCount(), getPrimitiveBoundingBox() (single UUID or list)setPrimitiveColor() for mutating the color of one primitive or a list of primitives, accepting either RGBcolor or RGBAcolorclearPrimitiveData() and listPrimitiveData() for removing and inspecting per-primitive data fieldscropDomainX(), cropDomainY(), cropDomainZ(), and cropDomain() to restrict all primitives (or a supplied UUID list) to given XYZ boundsinclude_hidden parameter to getAllPlantUUIDs() to allow querying hidden prototype primitivesdeletePlantInstance() now automatically cleans up hidden prototype primitives when all plant instances have been deleteddoesPrimitiveExist() method to check whether primitives exist by single UUID or list of UUIDsresolveMaterialTextures() method for material-based texture suppression resolution (modifies colors in-place, returns resolved texture paths)packGPUBuffers() method to pack GPU-ready geometry buffers into a single binary blob for zero-copy Three.js BufferGeometry loadingaddPatchTextured() method for creating textured patches with optional UV coordinatesclearTimeseriesData() method to remove all timeseries variables and their associated date/time values from the Contextgermination_rate parameter to buildPlantCanopyFromLibrary() to control the fraction of grid positions occupied by plantssetProgressCallback() for receiving (progress, message) updates during long-running operations like advanceTime()getPrimitiveTextureFile(), setPrimitiveTextureFile(), getPrimitiveTextureSize(), getPrimitiveTextureUV(), primitiveTextureHasTransparencyChannel(), getPrimitiveSolidFraction(), overridePrimitiveTextureColor(), usePrimitiveTextureColor(), isPrimitiveTextureColorOverridden()getPrimitiveNormal([uuid1, uuid2]) returns an ndarray of shape (N, 3))getAll* convenience methods that query all primitives in the context (e.g., getAllPrimitiveNormals())PrimitiveInfo with texture_file, texture_uv, and solid_fraction fieldsaddTimeseriesData(), setCurrentTimeseriesPoint(), queryTimeseriesData(), queryTimeseriesDate(), queryTimeseriesTime(), getTimeseriesLength(), doesTimeseriesVariableExist(), listTimeseriesVariables(), loadTabularTimeseriesData()writeCameraImageDataEXR(), writeDepthImageData(), writeDepthImageDataEXR(), writeNormDepthImage()getBackendName() and probeAnyGPUBackend() for runtime GPU backend detectionisinstance()-based type validation to PlantArchitecture and RadiationModel methods per argument type validation policyvalidate_position_like(), validate_direction_like(), and validate_size_like() validators for flexible parameter typesVK_ICD_FILENAMES for bundled MoltenVK on macOStests/manual/ directory from automatic pytest collectionPYHELIOS_TEST_VISUALIZER is set)🚨++ New Plug-in Integrated ++ 🚨
Context.seedRandomGenerator() for reproducible stochastic simulationsenableGPUAcceleration(), disableGPUAcceleration(), isGPUAccelerationEnabled(), and isGPUAccelerationAvailable()pytest-forked was missing from standard pyhelios dependenciesmagnitude() and normalize() methods to vec2 and vec3scale() method to RGBcolor and RGBAcolor for color intensity adjustmentJulianDay(), incrementDay(), and isLeapYear() methods to DatescaleConeObjectLength() and scaleConeObjectGirth() methods for cone object manipulationsetAtmosphericConditions(), getAtmosphericConditions(), and parameter-free flux methodsgetAmbientLongwaveFlux() for ambient longwave radiation calculationenablePragueSkyModel(), updatePragueSkyModel(), isPragueSkyModelEnabled(), and pragueSkyModelNeedsUpdate()optionalOutputPrimitiveData() for selective biochemical property output (chlorophyll, carotenoid, water, etc.)loadXML() method for loading custom tree species from XML filesbuildTree() to accept custom species names (strings) in addition to WPTType enum🚨++ New Plug-in Integrated ++ 🚨
addMaterial(), setMaterialColor(), setMaterialTexture(), and material assignment methodsaddRadiationCameraFromLibrary() for preconfigured camera modelsupdateCameraParameters() and enableCameraMetadata() for camera managementcalculateDirectSolarSpectrum(), calculateDiffuseSolarSpectrum(), and calculateGlobalSolarSpectrum()__del__ methods, which should be fixed now.Context.setPrimitiveData[*]() to accept a list of UUIDsContext.deletePrimitive() and Context.deleteObject() methodsContext.writePrimitiveData() method to write primitive data to a fileaddRectangleRadiationSource(), addDiskRadiationSource()setSourcePosition(), getSourcePosition(), deleteRadiationSource()setSourceSpectrum(), integrateSpectrum(), scaleSpectrum(), blendSpectra()setDiffuseRadiationExtinctionCoeff(), setDiffuseSpectrum(), getDiffuseFlux()doesBandExist(), getSkyEnergy(), calculateGtheta(), enforcePeriodicBoundary()copyRadiationBand() to support optional wavelength range parametersaddPlantInstance(), addBaseStemShoot(), and addChildShoot()plantDoesCollide()AxisRotation data type for shoot rotation controlplantarch_custom_building_sample.py, plantarch_collision_sample.py, plantarch_file_io_sample.pypyhelios_build directorypyhelios/runtime/ directory to git control🚨++ New Plug-in Integrated ++ 🚨
🚨++ New Plug-in Integrated ++ 🚨
Improved Error Handling, Build System Optimization, and Testing Infrastructure
🎉PyPI package distribution should now be working for all integrated plug-ins 🎉
Enhanced Build System and GPU Runtime Detection
PyPI Package Distribution Fixes
Many documentation error fixes
writePLY(), writeOBJ() methods with comprehensive parameter support🎉++ PyPI Package Distribution ++ 🎉
pip install pyhelios3d🚨++ New Plug-in Integrated ++ 🚨
🚨++ New Plug-in Integrated ++ 🚨
🚨++ New Plug-in Integrated ++ 🚨
--plugins visualizer)🚨++ New Plug-in Integrated ++ 🚨
Visualizer.colorContextPrimitivesByData()Context.loadPLY(), Context.loadOBJ(), and Context.loadXML() methodsContext.loadPLY() with 5 overloads supporting origin, height, rotation, color, and upaxis transformationsContext.loadOBJ() with 4 overloads including scale transformations and upaxis specificationContext.loadXML() implementation for Helios XML geometry filesContext.addTriangleTextured()Context.addTrianglesFromArraysTextured()suzanne.ply, suzanne.obj, suzanne.mtl, and leaf_cube.xmlexternal_geometry_sample.py and stanford_bunny_radiation.py for demonstrationaddTile(), addSphere(), addTube(), addBox(), and addCone() methods (with color variants)primitive_data_array_example.py demonstrating numpy array integrationstanford_bunny_radiation.py with improved visualization workflowsimple_radiation_test.pyFix helios-core submodule to point to correct remote commit
🎉 Initial version! 🎉
visualizerradiationweber-penn tree