Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions Sources/ShellEDXModel/EDXSession.swift
Original file line number Diff line number Diff line change
Expand Up @@ -244,13 +244,17 @@ public final class EDXSession {
public var beamEnergy: Double? { method.beamEnergyKeV ?? fileBeamEnergy }
/// A one-pixel file (an .msa, a single Velox spectrum): there are no maps, no region to draw, and the words say "Spectrum", not "Whole map".
public var isSingleSpectrum: Bool { (source?.nx ?? 0) * (source?.ny ?? 0) == 1 }
public var regionName: String { isSingleSpectrum ? "Spectrum" : region.name }
/// The selected region's name as the person reads it: the kept region's own ("Region 2", or what it was renamed to), "Region" for a
/// shape not kept, "Whole map", or "Spectrum" for a one-pixel file. The results header, the export names and the CSVs' region lines.
public var regionName: String { isSingleSpectrum ? "Spectrum" : keptName }
/// The kept region's name, else the region's ("Region", "Whole map").
private var keptName: String { selectedPin?.name ?? region.name }
public var canQuantify: Bool { hasImage && picks.contains { $0.role == .quantify } }
public var quantifyBlocker: String? {
hasImage && !canQuantify ? "Pick at least one element to quantify." : nil
}
/// The default stem of an export file: the image, the region.
public var exportStem: String { SpectroscopyExport.fileStem(imageName: fileName, regionName: region.name) }
public var exportStem: String { SpectroscopyExport.fileStem(imageName: fileName, regionName: keptName) }

// MARK: Opening

Expand Down Expand Up @@ -735,7 +739,7 @@ public final class EDXSession {
}
autoID = .running
let region = region, cache = cache, listed = picks.map(\.symbol), computedK = method.kFactorSource == .computed
let regionName = region.name
let regionName = keptName
autoIDRun += 1
let run = autoIDRun
let task = Task.detached(priority: .userInitiated) { [weak self] in
Expand Down Expand Up @@ -1058,16 +1062,16 @@ public final class EDXSession {

// MARK: Export

public var resultsCSV: String? { fit.map { EDXCompute.resultsCSV($0, regionName: region.name, host: host) } }
public var resultsCSV: String? { fit.map { EDXCompute.resultsCSV($0, regionName: keptName, host: host) } }
public var methodJSON: String? { fit.map { SpectroscopyExport.methodJSON($0.method) } }
/// The region's spectrum as an `.msa` file (FormatoKit's writer); nil before there is a spectrum.
public func spectrumMSA() throws -> Data? {
guard let source, !spectrumCounts.isEmpty else { return nil }
return try EDXExports.msa(counts: spectrumCounts, axis: source.energyAxis, title: "\(fileName) \(region.name)", beamEnergyKeV: beamEnergy, host: host)
return try EDXExports.msa(counts: spectrumCounts, axis: source.energyAxis, title: "\(fileName) \(keptName)", beamEnergyKeV: beamEnergy, host: host)
}
public var spectrumCSV: String? {
guard let source, !spectrumCounts.isEmpty else { return nil }
return EDXCompute.spectrumCSV(counts: spectrumCounts, axis: source.energyAxis, fileName: fileName, regionName: region.name, host: host)
return EDXCompute.spectrumCSV(counts: spectrumCounts, axis: source.energyAxis, fileName: fileName, regionName: keptName, host: host)
}
}

Expand Down
20 changes: 20 additions & 0 deletions Tests/ShellEDXTests/EDXRegionsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,26 @@ nonisolated final class EDXRegionsTests: XCTestCase {

// MARK: Several regions

/// The results header, the export stem and the CSVs name the kept region by its own name, so two regions' exports do not overwrite each other
/// (seen 2026-11-05 on the owner's 1339 file: "Results · Region" and "…_Region quantification.csv" for Region 1 and Region 2 alike). (A shape selected but not kept
/// stays "Region": testShapesCoveringTheSamePixelsSumTheSameSpectrum.) Red under: `region.name` (always "Region" for a shape) in the header and the export names.
@MainActor func testTheHeaderAndTheExportsNameTheKeptRegion() async throws {
let session = await openRoom()
session.drawRectangle(PixelRect(x0: 0, y0: 0, x1: 1, y1: 1))
session.drawRectangle(PixelRect(x0: 1, y0: 0, x1: 2, y1: 1))
await session.settled()
XCTAssertEqual(session.regionName, "Region 2")
XCTAssertTrue(session.exportStem.hasSuffix("Region_2") || session.exportStem.hasSuffix("Region 2"), session.exportStem)
let two = session.exportStem
session.selectPin(session.pins[0].id)
await session.settled()
XCTAssertEqual(session.regionName, "Region 1")
XCTAssertNotEqual(session.exportStem, two, "the two regions' exports share a name")
XCTAssertTrue(try XCTUnwrap(session.spectrumCSV).contains("region: Region 1"))
session.renamePin(session.pins[0].id, to: "Precipitate")
XCTAssertEqual(session.regionName, "Precipitate")
}

/// Every shape drawn is kept as the next numbered region: two drawn shapes are two regions, each with its own pooled spectrum (the kit's sum of its pixels,
/// exact), a table row with its pixel count and counts, and hiding one drops its layer but keeps its row. A shape drawn twice is one region; a deleted
/// region's number is not reused. Red under: a second drawing replacing the first; the layer of a hidden region kept; numbers recycled.
Expand Down
Loading