Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
tiagohm committed Aug 17, 2024
2 parents a579e15 + 9bbd2ab commit 7fe1191
Show file tree
Hide file tree
Showing 87 changed files with 1,586 additions and 1,171 deletions.
9 changes: 6 additions & 3 deletions api/src/main/kotlin/nebulosa/api/atlas/SatelliteRepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ import org.springframework.stereotype.Component
@Component
class SatelliteRepository(@Qualifier("satelliteBox") override val box: Box<SatelliteEntity>) : BoxRepository<SatelliteEntity>() {

fun search(text: String? = null, groups: Iterable<SatelliteGroupType> = emptyList()): List<SatelliteEntity> {
val groupCondition = or(groups.map { SatelliteEntity_.groups.containsElement(it.name, CASE_SENSITIVE) })
val condition = and(if (text.isNullOrBlank()) null else SatelliteEntity_.name.containsInsensitive(text), groupCondition)
fun search(text: String? = null, groups: Iterable<SatelliteGroupType> = emptyList(), id: Long = 0L): List<SatelliteEntity> {
val condition = and(
if (id > 0L) SatelliteEntity_.id.equal(id) else null,
if (text.isNullOrBlank()) null else SatelliteEntity_.name.containsInsensitive(text),
or(groups.map { SatelliteEntity_.groups.containsElement(it.name, CASE_SENSITIVE) }),
)

return (condition?.let(box::query) ?: box.query()).build().use { it.findLazy() }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ import okio.BufferedSource
import okio.Source
import okio.buffer
import okio.gzip
import java.io.Closeable

class SimbadDatabaseReader(source: Source) : Iterator<SimbadEntity>, Closeable {
class SimbadDatabaseReader(source: Source) : Iterator<SimbadEntity>, AutoCloseable {

private val buffer = if (source is BufferedSource) source else source.gzip().buffer()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ import okio.BufferedSink
import okio.Sink
import okio.buffer
import okio.gzip
import java.io.Closeable

class SimbadDatabaseWriter(sink: Sink) : Closeable {
class SimbadDatabaseWriter(sink: Sink) : AutoCloseable {

private val buffer = if (sink is BufferedSink) sink else sink.gzip().buffer()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ class SimbadEntityRepository(@Qualifier("simbadBox") override val box: Box<Simba
name: String? = null, constellation: Constellation? = null,
rightAscension: Angle = 0.0, declination: Angle = 0.0, radius: Angle = 0.0,
magnitudeMin: Double = SkyObject.MAGNITUDE_MIN, magnitudeMax: Double = SkyObject.MAGNITUDE_MAX,
type: SkyObjectType? = null,
type: SkyObjectType? = null, id: Long = 0L,
): List<SimbadEntity> {
val useFilter = radius > 0.0 && radius.toDegrees in 0.1..90.0

val condition = and(
if (id > 0L) SimbadEntity_.id.equal(id) else null,
if (magnitudeMin in SkyObject.MAGNITUDE_RANGE) SimbadEntity_.magnitude.greaterOrEqual(magnitudeMin) else null,
if (magnitudeMax in SkyObject.MAGNITUDE_RANGE) SimbadEntity_.magnitude.lessOrEqual(magnitudeMax) else null,
if (type != null) SimbadEntity_.type equal type.ordinal else null,
Expand Down
6 changes: 4 additions & 2 deletions api/src/main/kotlin/nebulosa/api/atlas/SkyAtlasController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,10 @@ class SkyAtlasController(
@RequestParam(required = false, defaultValue = "-99.0") magnitudeMin: Double,
@RequestParam(required = false, defaultValue = "99.0") magnitudeMax: Double,
@RequestParam(required = false) type: SkyObjectType?,
@RequestParam(required = false, defaultValue = "0") id: Long,
) = skyAtlasService.searchSkyObject(
text, rightAscension.hours, declination.deg, radius.deg,
constellation, magnitudeMin, magnitudeMax, type,
constellation, magnitudeMin, magnitudeMax, type, id,
)

@GetMapping("sky-objects/types")
Expand All @@ -137,7 +138,8 @@ class SkyAtlasController(
fun searchSatellites(
@RequestParam(required = false, defaultValue = "") text: String,
@RequestParam(name = "group", required = false) groups: List<SatelliteGroupType>?,
) = skyAtlasService.searchSatellites(text, groups ?: emptyList())
@RequestParam(required = false, defaultValue = "0") id: Long,
) = skyAtlasService.searchSatellites(text, groups ?: emptyList(), id)

@GetMapping("twilight")
fun twilight(
Expand Down
8 changes: 4 additions & 4 deletions api/src/main/kotlin/nebulosa/api/atlas/SkyAtlasService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ class SkyAtlasService(
}
}

fun searchSatellites(text: String, groups: List<SatelliteGroupType>): List<SatelliteEntity> {
return satelliteRepository.search(text.ifBlank { null }, groups)
fun searchSatellites(text: String = "", groups: List<SatelliteGroupType> = emptyList(), id: Long = 0L): List<SatelliteEntity> {
return satelliteRepository.search(text.ifBlank { null }, groups, id)
}

fun twilight(location: GeographicCoordinate, date: LocalDate, fast: Boolean = false): Twilight {
Expand Down Expand Up @@ -205,8 +205,8 @@ class SkyAtlasService(
rightAscension: Angle = 0.0, declination: Angle = 0.0, radius: Angle = 0.0,
constellation: Constellation? = null,
magnitudeMin: Double = SkyObject.MAGNITUDE_MIN, magnitudeMax: Double = SkyObject.MAGNITUDE_MAX,
type: SkyObjectType? = null,
) = simbadEntityRepository.search(text, constellation, rightAscension, declination, radius, magnitudeMin, magnitudeMax, type)
type: SkyObjectType? = null, id: Long = 0L,
) = simbadEntityRepository.search(text, constellation, rightAscension, declination, radius, magnitudeMin, magnitudeMax, type, id)

@Scheduled(fixedDelay = 15, timeUnit = TimeUnit.MINUTES)
fun refreshImageOfSun() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,17 @@ class CameraCaptureExecutor(
check(camera.connected) { "${camera.name} Camera is not connected" }
check(jobs.none { it.task.camera === camera }) { "${camera.name} Camera Capture is already in progress" }

val liveStackingManager = CameraLiveStackingManager(calibrationFrameService)
val task = CameraCaptureTask(
camera, request, guider, false, threadPoolTaskExecutor,
calibrationFrameService, mount, wheel, focuser, rotator
liveStackingManager, mount, wheel, focuser, rotator
)

task.subscribe(this)

with(CameraCaptureJob(task)) {
jobs.add(this)
whenComplete { _, _ -> jobs.remove(this) }
whenComplete { _, _ -> { jobs.remove(this); liveStackingManager.close() } }
start()
}
}
Expand Down
101 changes: 16 additions & 85 deletions api/src/main/kotlin/nebulosa/api/cameras/CameraCaptureTask.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ package nebulosa.api.cameras

import com.fasterxml.jackson.annotation.JsonIgnore
import io.reactivex.rxjava3.functions.Consumer
import nebulosa.api.calibration.CalibrationFrameProvider
import nebulosa.api.guiding.DitherAfterExposureEvent
import nebulosa.api.guiding.DitherAfterExposureTask
import nebulosa.api.guiding.WaitForSettleTask
import nebulosa.api.livestacker.LiveStackingRequest
import nebulosa.api.tasks.AbstractTask
import nebulosa.api.tasks.SplitTask
import nebulosa.api.tasks.delay.DelayEvent
Expand All @@ -24,23 +22,19 @@ import nebulosa.indi.device.filterwheel.FilterWheelEvent
import nebulosa.indi.device.focuser.Focuser
import nebulosa.indi.device.mount.Mount
import nebulosa.indi.device.rotator.Rotator
import nebulosa.livestacker.LiveStacker
import nebulosa.log.loggerFor
import java.nio.file.Path
import java.time.Duration
import java.util.concurrent.Executor
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.io.path.copyTo
import kotlin.io.path.exists
import kotlin.io.path.extension

data class CameraCaptureTask(
@JvmField val camera: Camera,
@JvmField val request: CameraStartCaptureRequest,
@JvmField val guider: Guider? = null,
private val useFirstExposure: Boolean = false,
private val executor: Executor? = null,
private val calibrationFrameProvider: CalibrationFrameProvider? = null,
private val liveStackerManager: CameraLiveStackingManager? = null,
@JvmField val mount: Mount? = null,
@JvmField val wheel: FilterWheel? = null,
@JvmField val focuser: Focuser? = null,
Expand Down Expand Up @@ -69,7 +63,6 @@ data class CameraCaptureTask(
else Duration.ofNanos(request.exposureTime.toNanos() * request.exposureAmount + request.exposureDelay.toNanos() * (request.exposureAmount - if (useFirstExposure) 0 else 1))

@Volatile private var exposureRepeatCount = 0
@Volatile private var liveStacker: LiveStacker? = null

private val pausing = AtomicBoolean()

Expand Down Expand Up @@ -99,71 +92,9 @@ data class CameraCaptureTask(
}
}

private fun LiveStackingRequest.processCalibrationGroup(): LiveStackingRequest {
return if (calibrationFrameProvider != null && enabled &&
!request.calibrationGroup.isNullOrBlank() && (darkPath == null || flatPath == null || biasPath == null)
) {
val calibrationGroup = request.calibrationGroup
val temperature = camera.temperature
val binX = request.binX
val binY = request.binY
val width = request.width / binX
val height = request.height / binY
val exposureTime = request.exposureTime.toNanos() / 1000
val gain = request.gain.toDouble()

val wheel = camera.snoopedDevices.firstOrNull { it is FilterWheel } as? FilterWheel
val filter = wheel?.let { it.names.getOrNull(it.position - 1) }

LOG.info(
"find calibration frames for live stacking. group={}, temperature={}, binX={}, binY={}. width={}, height={}, exposureTime={}, gain={}, filter={}",
calibrationGroup, temperature, binX, binY, width, height, exposureTime, gain, filter
)

val newDarkPath = darkPath?.takeIf { it.exists() } ?: calibrationFrameProvider
.findBestDarkFrames(calibrationGroup, temperature, width, height, binX, binY, exposureTime, gain)
.firstOrNull()
?.path

val newFlatPath = flatPath?.takeIf { it.exists() } ?: calibrationFrameProvider
.findBestFlatFrames(calibrationGroup, width, height, binX, binY, filter)
.firstOrNull()
?.path

val newBiasPath = if (newDarkPath != null) null else biasPath?.takeIf { it.exists() } ?: calibrationFrameProvider
.findBestBiasFrames(calibrationGroup, width, height, binX, binY)
.firstOrNull()
?.path

LOG.info(
"live stacking will use calibration frames. group={}, dark={}, flat={}, bias={}",
calibrationGroup, newDarkPath, newFlatPath, newBiasPath
)

copy(darkPath = newDarkPath, flatPath = newFlatPath, biasPath = newBiasPath)
} else {
this
}
}

private fun startLiveStacking() {
if (liveStacker == null && request.liveStacking.enabled && (request.isLoop || request.exposureAmount > 1)) {
try {
liveStacker = request.liveStacking.processCalibrationGroup().get()
liveStacker!!.start()
} catch (e: Throwable) {
LOG.error("failed to start live stacking. request={}", request.liveStacking, e)

liveStacker?.close()
liveStacker = null
}
}
}

fun initialize(
cancellationToken: CancellationToken,
canLiveStack: Boolean = false, hasShutter: Boolean = false,
snoopDevices: Boolean = true,
hasShutter: Boolean = false, snoopDevices: Boolean = true,
) {
LOG.info(
"Camera Capture started. request={}, exposureCount={}, camera={}, mount={}, wheel={}, focuser={}", request, exposureCount,
Expand All @@ -175,10 +106,6 @@ data class CameraCaptureTask(
pausing.set(false)
cancellationToken.listenToPause(this)

if (canLiveStack) {
startLiveStacking()
}

if (snoopDevices) {
camera.snoop(listOf(mount, wheel, focuser, rotator))
}
Expand All @@ -194,14 +121,14 @@ data class CameraCaptureTask(

sendEvent(CameraCaptureState.CAPTURE_FINISHED)

liveStacker?.close()
liveStackerManager?.stop(request)

LOG.info("Camera Capture finished. camera={}, request={}, exposureCount={}", camera, request, exposureCount)
}

override fun execute(cancellationToken: CancellationToken) {
try {
initialize(cancellationToken, true, true)
initialize(cancellationToken, hasShutter = true)
executeInLoop(cancellationToken)
} finally {
finalize(cancellationToken)
Expand Down Expand Up @@ -338,16 +265,20 @@ data class CameraCaptureTask(
}

private fun addFrameToLiveStacker(path: Path?): Path? {
return if (path == null || liveStacker == null) {
null
} else {
if (liveStackerManager == null) return null

return if (path != null && liveStackerManager.start(request, path)) {
sendEvent(CameraCaptureState.STACKING)

liveStacker!!.add(path)?.let {
val stackedPath = Path.of("${path.parent}", "STACKED.${it.extension}")
it.copyTo(stackedPath, true)
stackedPath
try {
liveStackerManager.stack(request, path)
} catch (_: Throwable) {
null
} finally {
sendEvent(CameraCaptureState.WAITING)
}
} else {
null
}
}

Expand All @@ -357,7 +288,7 @@ data class CameraCaptureTask(
delayAndWaitForSettleSplitTask.close()
cameraExposureTask.close()
ditherAfterExposureTask.close()
liveStacker?.close()
liveStackerManager?.stop(request)
super.close()
}

Expand Down
Loading

0 comments on commit 7fe1191

Please sign in to comment.