Skip to content

Commit

Permalink
Merge branch 'dev' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
tiagohm committed Aug 24, 2023
2 parents 3bcdad9 + 189c435 commit b156e79
Show file tree
Hide file tree
Showing 49 changed files with 644 additions and 455 deletions.
12 changes: 6 additions & 6 deletions api/src/main/kotlin/nebulosa/api/configs/BeanConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import nebulosa.api.data.entities.MyObjectBox
import nebulosa.common.concurrency.DaemonThreadFactory
import nebulosa.hips2fits.Hips2FitsService
import nebulosa.horizons.HorizonsService
import nebulosa.sbd.SmallBodyDatabaseLookupService
import nebulosa.sbd.SmallBodyDatabaseService
import nebulosa.simbad.SimbadService
import okhttp3.Cache
import okhttp3.ConnectionPool
Expand Down Expand Up @@ -65,10 +65,10 @@ class BeanConfig {
.connectionPool(connectionPool)
.cache(cache)
.addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BASIC))
.readTimeout(30L, TimeUnit.SECONDS)
.writeTimeout(30L, TimeUnit.SECONDS)
.connectTimeout(30L, TimeUnit.SECONDS)
.callTimeout(30L, TimeUnit.SECONDS)
.readTimeout(60L, TimeUnit.SECONDS)
.writeTimeout(60L, TimeUnit.SECONDS)
.connectTimeout(60L, TimeUnit.SECONDS)
.callTimeout(60L, TimeUnit.SECONDS)
.build()

@Bean
Expand All @@ -83,7 +83,7 @@ class BeanConfig {
fun simbadService(okHttpClient: OkHttpClient) = SimbadService(okHttpClient = okHttpClient)

@Bean
fun smallBodyDatabaseLookupService(okHttpClient: OkHttpClient) = SmallBodyDatabaseLookupService(okHttpClient = okHttpClient)
fun smallBodyDatabaseService(okHttpClient: OkHttpClient) = SmallBodyDatabaseService(okHttpClient = okHttpClient)

@Bean
fun hips2FitsService(okHttpClient: OkHttpClient) = Hips2FitsService(okHttpClient = okHttpClient)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package nebulosa.api.controllers

import jakarta.validation.Valid
import jakarta.validation.constraints.NotBlank
import jakarta.validation.constraints.NotEmpty
import nebulosa.api.data.requests.INDISendPropertyRequest
import nebulosa.api.services.EquipmentService
import nebulosa.api.services.INDIService
Expand Down Expand Up @@ -40,12 +39,12 @@ class INDIController(
}

@PostMapping("indiStartListening")
fun indiStartListening(@RequestParam("eventName") @Valid @NotEmpty eventNames: List<String>) {
return eventNames.forEach(webSocketService::registerEventName)
fun indiStartListening() {
return webSocketService.indiStartListening()
}

@PostMapping("indiStopListening")
fun indiStopListening(@RequestParam("eventName") @Valid @NotEmpty eventNames: List<String>) {
return eventNames.forEach(webSocketService::unregisterEventName)
fun indiStopListening() {
return webSocketService.indiStopListening()
}
}
12 changes: 7 additions & 5 deletions api/src/main/kotlin/nebulosa/api/controllers/ImageController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import nebulosa.api.data.responses.CalibrationResponse
import nebulosa.api.data.responses.ImageAnnotationResponse
import nebulosa.api.services.EquipmentService
import nebulosa.api.services.ImageService
import nebulosa.api.services.ImageToken
import nebulosa.imaging.ImageChannel
import nebulosa.imaging.algorithms.ProtectionMethod
import nebulosa.math.Angle
Expand Down Expand Up @@ -43,7 +44,7 @@ class ImageController(
output: HttpServletResponse,
) {
imageService.openImage(
Path.of(path),
ImageToken.of(path),
debayer, autoStretch, shadow, highlight, midtone,
mirrorHorizontal, mirrorVertical, invert,
scnrEnabled, scnrChannel, scnrAmount, scnrProtectionMode,
Expand All @@ -53,7 +54,7 @@ class ImageController(

@PostMapping("closeImage")
fun closeImage(@RequestParam @Valid @NotBlank path: String) {
return imageService.closeImage(Path.of(path))
return imageService.closeImage(ImageToken.of(path))
}

@GetMapping("imagesOfCamera")
Expand All @@ -80,8 +81,9 @@ class ImageController(
@RequestParam(required = false, defaultValue = "true") stars: Boolean,
@RequestParam(required = false, defaultValue = "true") dsos: Boolean,
@RequestParam(required = false, defaultValue = "false") minorPlanets: Boolean,
@RequestParam(required = false, defaultValue = "12.0") minorPlanetMagLimit: Double,
): List<ImageAnnotationResponse> {
return imageService.annotations(Path.of(path), stars, dsos, minorPlanets)
return imageService.annotations(ImageToken.of(path), stars, dsos, minorPlanets, minorPlanetMagLimit)
}

@PostMapping("solveImage")
Expand All @@ -97,7 +99,7 @@ class ImageController(
@RequestParam(required = false, defaultValue = "") apiKey: String,
): CalibrationResponse {
return imageService.solveImage(
Path.of(path), type, blind,
ImageToken.of(path), type, blind,
Angle.from(centerRA, true), Angle.from(centerDEC), Angle.from(radius),
downsampleFactor, pathOrUrl, apiKey,
)
Expand All @@ -112,6 +114,6 @@ class ImageController(
@RequestParam(required = false, defaultValue = "true") synchronized: Boolean,
) {
val mount = requireNotNull(equipmentService.mount(name))
imageService.pointMountHere(mount, Path.of(path), x, y, synchronized)
imageService.pointMountHere(mount, ImageToken.of(path), x, y, synchronized)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.databind.SerializerProvider
import com.fasterxml.jackson.databind.ser.std.StdSerializer
import nebulosa.api.services.GuideExposureTask
import nebulosa.imaging.Image
import nebulosa.indi.device.camera.CameraEvent
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.stereotype.Component

data class GuideExposureFinished(
override val task: GuideExposureTask,
@JvmField internal val image: Image,
) : TaskEvent, CameraEvent {

override val device
Expand All @@ -26,7 +28,7 @@ data class GuideExposureFinished(
) {
gen.writeStartObject()
gen.writeStringField("camera", event.device.name)
gen.writeStringField("path", "${event.task.savePath}")
gen.writeStringField("path", "${event.task.token.path}")
gen.writeEndObject()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,13 @@ data class ImageAnnotationResponse(
val y: Double,
val star: StarEntity? = null,
val dso: DeepSkyObjectEntity? = null,
)
val minorPlanet: MinorPlanet? = null,
) {

data class MinorPlanet(
val name: String,
val rightAscension: String,
val declination: String,
val magnitude: String,
)
}
6 changes: 3 additions & 3 deletions api/src/main/kotlin/nebulosa/api/services/AtlasService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import nebulosa.nova.astrometry.Body
import nebulosa.nova.astrometry.Constellation
import nebulosa.nova.astrometry.FixedStar
import nebulosa.nova.position.GeographicPosition
import nebulosa.sbd.SmallBodyDatabaseLookupService
import nebulosa.sbd.SmallBodyDatabaseService
import nebulosa.skycatalog.SkyObject
import nebulosa.skycatalog.SkyObjectType
import okhttp3.OkHttpClient
Expand All @@ -53,7 +53,7 @@ import kotlin.math.hypot
class AtlasService(
private val horizonsEphemerisProvider: HorizonsEphemerisProvider,
private val bodyEphemerisProvider: BodyEphemerisProvider,
private val smallBodyDatabaseLookupService: SmallBodyDatabaseLookupService,
private val smallBodyDatabaseService: SmallBodyDatabaseService,
private val starRepository: StarRepository,
private val deepSkyObjectRepository: DeepSkyObjectRepository,
private val appPreferenceRepository: AppPreferenceRepository,
Expand Down Expand Up @@ -214,7 +214,7 @@ class AtlasService(
}

fun searchMinorPlanet(text: String): MinorPlanetResponse {
return smallBodyDatabaseLookupService
return smallBodyDatabaseService
.search(text).execute().body()
?.let(MinorPlanetResponse::of)
?: MinorPlanetResponse.EMPTY
Expand Down
14 changes: 5 additions & 9 deletions api/src/main/kotlin/nebulosa/api/services/FramingService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ import nebulosa.math.Angle.Companion.deg
import nebulosa.math.Angle.Companion.rad
import nebulosa.platesolving.Calibration
import org.springframework.stereotype.Service
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.writeBytes
import java.io.ByteArrayInputStream
import kotlin.math.abs

@Service
Expand All @@ -23,7 +21,7 @@ class FramingService(private val hips2FitsService: Hips2FitsService) {
rightAscension: Angle, declination: Angle,
width: Int, height: Int, fov: Angle,
rotation: Angle = Angle.ZERO, hipsSurveyType: HipsSurveyType = HipsSurveyType.CDS_P_DSS2_COLOR,
): Triple<Image, Path, Calibration>? {
): Pair<Image, Calibration>? {
val data = hips2FitsService.query(
hipsSurveyType.hipsSurvey,
rightAscension, declination,
Expand All @@ -32,11 +30,9 @@ class FramingService(private val hips2FitsService: Hips2FitsService) {
format = FormatOutputType.FITS,
).execute().body() ?: return null

val fitsPath = Files.createTempFile("framing", ".fits")
fitsPath.writeBytes(data)
LOG.info("framing file saved. path={}", fitsPath)
LOG.info("framing file loaded")

val image = Image.open(fitsPath.toFile())
val image = Image.openFITS(ByteArrayInputStream(data))

// val crot = -rotation + Angle.SEMICIRCLE
val cdelt1 = image.header.getDoubleValue(FitsKeywords.CDELT1).deg
Expand All @@ -58,7 +54,7 @@ class FramingService(private val hips2FitsService: Hips2FitsService) {
height = abs(cdelt2.value).rad * height,
)

return Triple(image, fitsPath, calibration)
return image to calibration
}

companion object {
Expand Down
16 changes: 6 additions & 10 deletions api/src/main/kotlin/nebulosa/api/services/GuideExposureTask.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,21 @@ package nebulosa.api.services
import nebulosa.api.data.events.GuideExposureFinished
import nebulosa.common.concurrency.CountUpDownLatch
import nebulosa.common.concurrency.ThreadedJob
import nebulosa.imaging.Image
import nebulosa.indi.device.camera.*
import nebulosa.io.transferAndClose
import nebulosa.log.loggerFor
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.io.InputStream
import java.nio.file.Path
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.io.path.outputStream
import kotlin.time.Duration

data class GuideExposureTask(
val camera: Camera,
val exposure: Duration,
val savePath: Path,
) : ThreadedJob<Path>() {
val token: ImageToken,
) : ThreadedJob<Image>() {

val exposureInMicroseconds = exposure.inWholeMicroseconds

Expand All @@ -35,7 +33,7 @@ data class GuideExposureTask(
if (running && event.device === camera) {
when (event) {
is CameraFrameCaptured -> {
save(event.fits) && add(savePath)
save(event.fits)
latch.countDown()
}
is CameraExposureAborted,
Expand Down Expand Up @@ -86,11 +84,9 @@ data class GuideExposureTask(
}

private fun save(inputStream: InputStream): Boolean {
LOG.info("saving FITS at $savePath...")

return try {
inputStream.transferAndClose(savePath.outputStream())
EventBus.getDefault().post(GuideExposureFinished(this))
val image = Image.openFITS(inputStream).also(::add)
EventBus.getDefault().post(GuideExposureFinished(this, image))
true
} catch (e: Throwable) {
LOG.error("failed to save FITS", e)
Expand Down
20 changes: 12 additions & 8 deletions api/src/main/kotlin/nebulosa/api/services/GuidingService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import jakarta.annotation.PostConstruct
import nebulosa.api.data.entities.GuideCalibrationEntity
import nebulosa.api.data.enums.DitherMode
import nebulosa.api.data.enums.GuideAlgorithmType
import nebulosa.api.data.events.GuideExposureFinished
import nebulosa.api.data.responses.GuidingChartResponse
import nebulosa.api.data.responses.GuidingStarResponse
import nebulosa.api.repositories.GuideCalibrationRepository
Expand All @@ -27,13 +28,11 @@ import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.springframework.stereotype.Service
import java.io.ByteArrayOutputStream
import java.nio.file.Path
import java.util.*
import java.util.concurrent.ExecutorService
import java.util.concurrent.atomic.AtomicReference
import javax.imageio.ImageIO
import kotlin.io.encoding.Base64
import kotlin.io.path.createParentDirectories
import kotlin.math.hypot
import kotlin.math.min
import kotlin.time.Duration.Companion.milliseconds
Expand All @@ -45,7 +44,7 @@ class GuidingService(
private val cameraExecutorService: ExecutorService,
private val guiderExecutorService: ExecutorService,
private val guideCalibrationRepository: GuideCalibrationRepository,
private val capturesDirectory: Path,
private val imageService: ImageService,
) : GuideDevice, GuiderListener {

private val randomDither = RandomDither()
Expand Down Expand Up @@ -83,7 +82,7 @@ class GuidingService(
}

@Subscribe(threadMode = ThreadMode.ASYNC)
fun onMountEvent(event: DeviceEvent<*>) {
fun onGuidingEvent(event: DeviceEvent<*>) {
val device = event.device ?: return

if (device is GuideOutput && device.canPulseGuide) {
Expand All @@ -95,6 +94,13 @@ class GuidingService(
}
}

@Subscribe(threadMode = ThreadMode.ASYNC)
fun onGuideExposureFinished(event: GuideExposureFinished) {
imageService.load(event.task.token, event.image)
guideImage.set(event.image)
webSocketService.sendGuideExposureFinished(event)
}

fun connect(guideOutput: GuideOutput) {
guideOutput.connect()
}
Expand Down Expand Up @@ -296,15 +302,13 @@ class GuidingService(

override fun capture(duration: Long): Image? {
return synchronized(guideExposureTask) {
val savePath = Path.of("$capturesDirectory", camera.name + ".fits").createParentDirectories()
val task = GuideExposureTask(camera, duration.milliseconds, savePath)
val task = GuideExposureTask(camera, duration.milliseconds, ImageToken.Guiding)

guideExposureTask.set(task)
cameraExecutorService.submit(task).get()
guideExposureTask.set(null)

if (task.isNotEmpty()) Image.open(savePath.toFile()).also(guideImage::set)
else null
task.firstOrNull()
}
}

Expand Down
Loading

0 comments on commit b156e79

Please sign in to comment.