use serde::{Deserialize, Serialize};
pub const FORMAT: u32 = 1;
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct System {
pub epsg: u64,
pub unit: String,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ObjectId {
pub store: String,
pub uri: String,
pub uuid: String,
pub title: String,
pub qualified_type: String,
}
impl ObjectId {
pub fn key(&self) -> String {
object_key(&self.store, &self.uri)
}
}
pub fn object_key(store: &str, uri: &str) -> String {
format!("{store}\u{0}{uri}")
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Inputs {
pub trace: Vec<[f64; 2]>,
pub system: Option<System>,
pub left: f64,
pub right: f64,
pub crosses: Crosses,
pub objects: Vec<Asked>,
pub time_factor: Option<f64>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Asked {
pub store: String,
pub revision: u64,
pub wells: Vec<String>,
pub surfaces: Vec<String>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "camelCase")]
pub enum Crosses {
None,
#[serde(rename_all = "camelCase")]
Every {
spacing: f64,
common: CrossWidths,
own: Vec<CrossOwn>,
},
#[serde(rename_all = "camelCase")]
Count {
count: u32,
common: CrossWidths,
own: Vec<CrossOwn>,
},
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CrossWidths {
pub before: f64,
pub after: f64,
pub left: f64,
pub right: f64,
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CrossOwn {
pub index: u32,
pub widths: CrossWidths,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "camelCase")]
pub enum SectionKey {
Long,
Cross {
index: u32,
},
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SectionTrace {
pub key: SectionKey,
pub trace: Vec<[f64; 2]>,
pub left: f64,
pub right: f64,
pub crossing: Option<[f64; 2]>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Contribution {
pub store: String,
pub wells: Vec<WellRead>,
pub surfaces: Vec<SurfaceRead>,
pub refused: Vec<Refused>,
#[serde(default)]
pub notes: Vec<Note>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Refused {
pub object: ObjectId,
pub reason: String,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum WellKind {
Frame,
Trajectory,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct WellRead {
pub object: ObjectId,
pub kind: WellKind,
pub wellbore: Option<String>,
pub head: [f64; 3],
pub path: Vec<[f64; 3]>,
pub md: Option<Vec<f64>>,
pub intervals: Vec<Interval>,
pub strata: Option<String>,
#[serde(default)]
pub borrowed: bool,
#[serde(default)]
pub head_only: bool,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Interval {
pub from: f64,
pub to: f64,
pub colour: Option<String>,
pub unit: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub unit_uri: Option<String>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum TraceRole {
Horizon,
Fault,
Other,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SurfaceRead {
pub object: ObjectId,
pub role: TraceRole,
pub time: bool,
#[serde(default)]
pub colour: Option<String>,
#[serde(default)]
pub age: Option<[f64; 2]>,
#[serde(default)]
pub feature: Option<String>,
pub cuts: Vec<SurfaceCut>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SurfaceCut {
pub section: SectionKey,
pub shape: CutShape,
pub notes: Vec<String>,
#[serde(default)]
pub sources: Vec<Vec<CutSource>>,
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub struct CutSource {
pub a: u32,
pub b: u32,
pub t: f64,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "camelCase")]
pub enum CutShape {
Trace {
spans: Vec<Vec<[f64; 2]>>,
},
Envelope {
top: Vec<Vec<[f64; 2]>>,
bottom: Vec<Vec<[f64; 2]>>,
fills: Vec<Vec<[f64; 2]>>,
faults: Vec<Vec<[f64; 2]>>,
},
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Catalogue {
pub format: u32,
pub inputs: Inputs,
pub long: Section,
pub crosses: Vec<Section>,
pub plan: Plan,
pub objects: Vec<ObjectRow>,
pub notes: Vec<Note>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Section {
pub key: SectionKey,
pub trace: Vec<[f64; 2]>,
pub length: f64,
pub marks: Vec<Mark>,
pub band: Vec<[f64; 2]>,
pub items: Vec<Item>,
pub z_range: Option<[f64; 2]>,
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "camelCase")]
pub enum Mark {
Vertex {
s: f64,
index: u32,
},
Crossing {
s: f64,
other: SectionKey,
},
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "camelCase")]
pub enum Item {
Well(WellItem),
Trace(TraceItem),
Envelope(EnvelopeItem),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum Side {
Left,
Right,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct WellItem {
pub object: ObjectId,
pub s: f64,
pub d: f64,
pub side: Side,
pub head: [f64; 2],
pub path: Vec<[f64; 2]>,
pub md: Option<Vec<f64>>,
pub intervals: Vec<Interval>,
pub strata: Option<String>,
pub merged: Vec<ObjectId>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TraceItem {
pub object: ObjectId,
pub role: TraceRole,
pub spans: Vec<Vec<[f64; 2]>>,
pub time: bool,
pub notes: Vec<String>,
#[serde(default)]
pub colour: Option<String>,
#[serde(default)]
pub age: Option<[f64; 2]>,
#[serde(default)]
pub feature: Option<String>,
#[serde(default)]
pub sources: Vec<Vec<CutSource>>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EnvelopeItem {
pub object: ObjectId,
pub top: Vec<Vec<[f64; 2]>>,
pub bottom: Vec<Vec<[f64; 2]>>,
pub fills: Vec<Vec<[f64; 2]>>,
pub faults: Vec<Vec<[f64; 2]>>,
pub time: bool,
#[serde(default)]
pub colour: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Plan {
pub origin: [f64; 2],
pub system: Option<System>,
pub sections: Vec<(SectionKey, Vec<[f64; 2]>)>,
pub bands: Vec<(SectionKey, Vec<[f64; 2]>)>,
pub wells: Vec<PlanWell>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PlanWell {
pub object: ObjectId,
pub head: [f64; 2],
pub feet: Vec<(SectionKey, [f64; 2])>,
pub rejected: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ObjectRow {
pub object: ObjectId,
pub kind: RowKind,
pub outcome: Outcome,
#[serde(default)]
pub fillable: bool,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum RowKind {
Well,
Surface,
Grid,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "camelCase")]
pub enum Outcome {
Drawn {
sections: Vec<SectionKey>,
},
Merged {
into: ObjectId,
},
Missed,
Refused {
reason: String,
},
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Note {
pub code: String,
pub sections: Vec<SectionKey>,
pub objects: Vec<ObjectId>,
pub said: String,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct View {
pub target: Target,
pub window: Option<Window>,
pub portion: Option<[f64; 2]>,
pub size_px: [f64; 2],
pub background: String,
pub hidden: Vec<String>,
pub colours: Vec<(String, String)>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub unit_colours: Vec<(String, String)>,
#[serde(default)]
pub widths: Vec<(String, f64)>,
pub well_colouring: WellColouring,
pub well_width_px: f64,
pub fills: Vec<FillChoice>,
pub show: Show,
pub axis: AxisMode,
pub highlight: Vec<String>,
#[serde(default)]
pub labels: LabelMode,
#[serde(default)]
pub paints: Vec<(String, Paint)>,
#[serde(default)]
pub joints: Joint,
#[serde(default = "zoom_on")]
pub zoom_script: bool,
#[serde(default, skip_serializing_if = "is_off")]
pub strata_legend: bool,
#[serde(default, skip_serializing_if = "is_off")]
pub strata_ticks: bool,
#[serde(default = "shown", skip_serializing_if = "is_on")]
pub draw_unstratified: bool,
#[serde(default, skip_serializing_if = "UnstratifiedStyle::is_default")]
pub unstratified: UnstratifiedStyle,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub store_names: Vec<(String, String)>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub markers: Vec<Marker>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Marker {
pub name: String,
pub shape: String,
pub colour: String,
pub at: MarkerPlace,
pub keys: Vec<String>,
pub size_px: f64,
#[serde(default, skip_serializing_if = "is_off")]
pub hidden: bool,
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "camelCase")]
pub enum MarkerPlace {
Head,
Bottom,
Md {
value: f64,
},
}
pub const NEUTRAL_COLOUR: &str = "#555555";
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "camelCase")]
pub enum UnstratifiedStyle {
Hidden,
Solid {
colour: String,
},
Dashed {
colour: String,
dash: f64,
gap: f64,
},
Hatched {
colour: String,
spacing: f64,
angle: f64,
},
}
impl Default for UnstratifiedStyle {
fn default() -> Self {
UnstratifiedStyle::Solid {
colour: NEUTRAL_COLOUR.to_string(),
}
}
}
impl UnstratifiedStyle {
pub fn is_default(&self) -> bool {
*self == Self::default()
}
pub fn refusal(&self) -> Option<String> {
let colour = |c: &str| (c.trim().is_empty()).then(|| "its colour is empty".to_string());
let range = |name: &str, v: f64, lo: f64, hi: f64| {
(!(v.is_finite() && v >= lo && v <= hi))
.then(|| format!("its {name} ({v}) is not a number in [{lo}, {hi}]"))
};
match self {
Self::Hidden => None,
Self::Solid { colour: c } => colour(c),
Self::Dashed { colour: c, dash, gap } => colour(c)
.or_else(|| range("dash", *dash, style_limits::LENGTH.0, style_limits::LENGTH.1))
.or_else(|| range("gap", *gap, style_limits::LENGTH.0, style_limits::LENGTH.1)),
Self::Hatched {
colour: c,
spacing,
angle,
} => colour(c)
.or_else(|| {
range(
"spacing",
*spacing,
style_limits::SPACING.0,
style_limits::SPACING.1,
)
})
.or_else(|| range("angle", *angle, style_limits::ANGLE.0, style_limits::ANGLE.1)),
}
}
}
pub mod style_limits {
pub const LENGTH: (f64, f64) = (1.0, 100.0);
pub const SPACING: (f64, f64) = (2.0, 50.0);
pub const ANGLE: (f64, f64) = (0.0, 180.0);
}
fn is_on(on: &bool) -> bool {
*on
}
fn is_off(on: &bool) -> bool {
!*on
}
fn zoom_on() -> bool {
true
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Paint {
pub nodes: Vec<String>,
#[serde(default)]
pub blend: Blend,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum Blend {
#[default]
Net,
Smooth,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum JointKind {
#[default]
None,
Nodes,
Changes,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Joint {
pub kind: JointKind,
pub px: f64,
pub colour: String,
pub alpha: f64,
}
impl Default for Joint {
fn default() -> Self {
Self {
kind: JointKind::None,
px: 3.0,
colour: "#000000".to_string(),
alpha: 1.0,
}
}
}
pub const MAX_WIDTH_PX: f64 = 40.0;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum LabelMode {
#[default]
Full,
Codes,
}
impl View {
pub fn unstratified_style(&self) -> UnstratifiedStyle {
if self.draw_unstratified {
self.unstratified.clone()
} else {
UnstratifiedStyle::Hidden
}
}
pub fn new(target: Target, size_px: [f64; 2]) -> Self {
Self {
target,
window: None,
portion: None,
size_px,
background: "#ffffff".to_string(),
hidden: Vec::new(),
colours: Vec::new(),
unit_colours: Vec::new(),
widths: Vec::new(),
well_colouring: WellColouring::Strata,
well_width_px: 3.0,
fills: Vec::new(),
show: Show {
crossings: true,
vertices: true,
distances: true,
names: true,
rejected: false,
bands: true,
surface_names: true,
notes: true,
origin: true,
direction: true,
},
axis: AxisMode::Projected,
highlight: Vec::new(),
labels: LabelMode::Full,
paints: Vec::new(),
joints: Joint::default(),
zoom_script: true,
strata_legend: false,
strata_ticks: false,
draw_unstratified: true,
unstratified: UnstratifiedStyle::default(),
store_names: Vec::new(),
markers: Vec::new(),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "camelCase")]
pub enum Target {
Section {
key: SectionKey,
},
Plan,
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Window {
pub x: [f64; 2],
pub y: [f64; 2],
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum WellColouring {
Side,
Scene,
Strata,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FillChoice {
pub key: String,
pub up: bool,
pub down: bool,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Show {
pub crossings: bool,
pub vertices: bool,
pub distances: bool,
pub names: bool,
pub rejected: bool,
pub bands: bool,
#[serde(default = "shown")]
pub surface_names: bool,
#[serde(default = "shown")]
pub notes: bool,
#[serde(default = "shown")]
pub origin: bool,
#[serde(default = "shown")]
pub direction: bool,
}
fn shown() -> bool {
true
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum AxisMode {
Projected,
Geodesic,
Coordinates,
}