Module:CineMol/style

.mw-parser-output .documentation,.mw-parser-output .documentation-metadata{border:1px solid var(--border-color-base,#a2a9b1);background-color:#ecfcf4;color:inhe

Module:CineMol/style
-- This is a port of CineMol to lua
-- CineMol https://github.com/moltools/CineMol was written by David Meijer, Marnix H. Medema & Justin J. J. van der Hooft and is MIT licensed
-- Please consider any edits made to this page as dual licensed MIT & CC-BY-SA 4.0

local p = {}

local Point2D = require( 'Module:CineMol/geometry' ).Point2D
local checkType = require( 'Module:CineMol/geometry' ).checkType

local colorFunctions = {
	to_hex = function(self)
		checkType( 'color:to_hex', 1, self, 'Color' )
		return string.format( "#%02x%02x%02x", self.r, self.g, self.b)
	end,
	diffuse = function(self, alpha)
		checkType( 'color:diffuse', 1, self, 'Color' )
		checkType( 'color:diffuse', 2, alpha, 'number' )
		alpha = math.max(0, math.min(1, alpha))
		return p.Color(math.floor(self.r*alpha),math.floor(self.g*alpha),math.floor(self.b*alpha))
	end
}

local colorEqual = function(self, other)
	checkType( 'color==', 1, self, 'Color' )
	checkType( 'color==', 2, other, 'Color' )
	return self.r == other.r and self.g == other.g and self.b == other.b
end

function p.Color(r, g, b)
	checkType( 'Color', 1, r, 'number' )
	checkType( 'Color', 2, g, 'number' )
	checkType( 'Color', 3, b, 'number' )
	local obj = {
		r = math.floor(r),
		g = math.floor(g),
		b = math.floor(b),
		_TYPE = 'Color'
	}

	setmetatable( obj,
		{
			__index = colorFunctions,
			__eq = colorEqual,
			__tostring = colorFunctions.to_hex
		}
	)
	return obj
end
local Color = p.Color

-- Corey-Pauling-Koltun coloring convention for atoms.
-- Source: https://en.wikipedia.org/wiki/CPK_coloring
p.CoreyPaulingKoltungAtomColor = {
    H = Color(255, 255, 255), 
    C = Color(80, 80, 80),
    N = Color(0, 0, 255),
    O = Color(255, 0, 0), 
    P = Color(255, 165, 0),  
    S = Color(255, 255, 0), 
    B = Color(245, 245, 220),
    Br = Color(139, 0, 0),
    I = Color(148, 0, 211),  
    Ti = Color(128, 128, 128),
    Fe = Color(255, 140, 0),
    F = Color(0, 128, 0),
    Cl = Color(0, 128, 0),  
    He = Color(0, 255, 255),  
    Ne = Color(0, 255, 255),  
    Ar = Color(0, 255, 255),  
    Kr = Color(0, 255, 255),  
    Xe = Color(0, 255, 255),  
    Li = Color(238, 130, 238), 
    Na = Color(238, 130, 238),  
    K = Color(238, 130, 238),  
    Rb = Color(238, 130, 238),  
    Cs = Color(238, 130, 238),  
    Fr = Color(238, 130, 238),  
    Be = Color(0, 100, 0),  
    Mg = Color(0, 100, 0),
    Ca = Color(0, 100, 0),
    Sr = Color(0, 100, 0),
    Ba = Color(0, 100, 0),
    Ra = Color(0, 100, 0),
    Cd = Color(170, 51, 106),

	_TYPE = 'AtomColoringScheme',

	get_color = function(self, atom_symbol)
		checkType( 'get_color', 1, self, 'AtomColoringScheme' )
		checkType( 'get_color', 2, atom_symbol, 'string' )
		return self[atom_symbol] or Color(255, 192, 203)
	end
}

-- Atomic radii (van der Waals) in picometer from PubChem.
-- Source: https://pubchem.ncbi.nlm.nih.gov/periodic-table/#property=AtomicRadius
p.PubChemAtomRadius = {
    H = 120.0,
    He = 140.0,
    Li = 182.0,
    Be = 153.0,
    B = 192.0,
    C = 170.0,
    N = 155.0,
    O = 152.0,
    F = 135.0,
    Ne = 154.0,
    Na = 227.0,
    Mg = 173.0,
    Al = 184.0,
    Si = 210.0,
    P = 180.0,
    S = 180.0,
    Cl = 175.0,
    Ar = 188.0,
    K = 275.0,
    Ca = 231.0,
    Sc = 211.0,
    Ti = 187.0,
    V = 179.0,
    Cr = 189.0,
    Mn = 197.0,
    Fe = 194.0,
    Co = 192.0,
    Ni = 163.0,
    Cu = 140.0,
    Zn = 139.0,
    Ga = 187.0,
    Ge = 211.0,
    As = 185.0,
    Se = 190.0,
    Br = 183.0,
    Kr = 202.0,
    Rb = 303.0,
    Sr = 249.0,
    Y = 219.0,
    Zr = 186.0,
    Nb = 207.0,
    Mo = 209.0,
    Tc = 209.0,
    Ru = 207.0,
    Rh = 195.0,
    Pd = 202.0,
    Ag = 172.0,
    Cd = 158.0,
    In = 193.0,
    Sn = 217.0,
    Sb = 206.0,
    Te = 206.0,
    I = 198.0,
    Xe = 216.0,
    Cs = 343.0,
    Ba = 268.0,
    Lu = 221.0,
    Hf = 212.0,
    Ta = 217.0,
    W = 210.0,
    Re = 217.0,
    Os = 216.0,
    Ir = 202.0,
    Pt = 209.0,
    Au = 166.0,
    Hg = 209.0,
    Tl = 196.0,
    Pb = 202.0,
    Bi = 207.0,
    Po = 197.0,
    At = 202.0,
    Rn = 220.0,
    Fr = 348.0,
    Ra = 283.0,

	_TYPE = 'AtomRadiusScheme',

	--Return the radius of an atom in angstrom.
	to_angstrom = function (self, atom_symbol)
		assert( type(self) == 'table', 'arg 1 must be table' )
		assert( type(atom_symbol) == 'string', 'arg 2 must be string')
		local factor = 0.01 -- pictometer to angstrom
		return self[atom_symbol] ~= nil and self[atom_symbol]*factor or default*factor
	end
}

-- ==================
-- Art styles
-- ==================

function p.Cartoon( fill_color, outline_color, outline_width, opacity )
	checkType( 'Catroon', 1, fill_color, 'Color' )
	outline_color = outline_color == nil and Color(0,0,0) or outline_color
	outline_width = outline_width == nil and 0.05 or outline_width
	opacity = opacity == nil and 1.0 or opacity
	checkType( 'Cartoon', 2, outline_color, 'Color' )
	checkType( 'Cartoon', 3, outline_width, 'number' )
	checkType( 'Cartoon', 4, opacity, 'number' )
	return {
		_TYPE = 'Depiction',
		name = 'Cartoon',
		fill_color = fill_color,
		outline_width = outline_width,
		outline_color = outline_color,
		opacity = opacity
	}
end

function p.Glossy( fill_color, opacity )
	checkType( 'Catroon', 1, fill_color, 'Color' )
	opacity = opacity == nil and 1.0 or opacity
	checkType( 'Cartoon', 2, opacity, 'number' )
	return {
		_TYPE = 'Depiction',
		name = 'Glossy',
		fill_color = fill_color,
		opacity = opacity
	}

end

-- FillStyle

function p.Wire(stroke_color, stroke_width, opacity)
	checkType( 'Wire', 1, stroke_color, 'Color' )
	checkType( 'Wire', 2, stroke_width, 'number' )
	checkType( 'Wire', 3, opacity, 'number' )
	return {
		_TYPE = 'FillStyle',
		name = 'Wire',
		stroke_color = stroke_color,
		stroke_width = stroke_width,
		opacity = opacity
	}
end

function p.Solid(fill_color, stroke_color, stroke_width, opacity)
	checkType( 'Solid', 1, fill_color, 'Color' )
	checkType( 'Solid', 2, stroke_color, 'Color' )
	checkType( 'Solid', 3, stroke_width, 'number' )
	checkType( 'Solid', 4, opacity, 'number' )
	return {
		_TYPE = 'FillStyle',
		name = 'Solid',
		fill_color = fill_color,
		stroke_color = stroke_color,
		stroke_width = stroke_width,
		opacity = opacity
	}
end

function p.RadialGradient(fill_color, center, radius, opacity)
	checkType( 'Wire', 1, fill_color, 'Color' )
	checkType( 'Wire', 2, center, 'Point2D' )
	checkType( 'Wire', 3, radius, 'number' )
	checkType( 'Wire', 4, opacity, 'number' )
	return {
		_TYPE = 'FillStyle',
		name = 'RadialGradient',
		fill_color = fill_color,
		radius = radius,
		center = center,
		opacity = opacity
	}
end

function p.LinearGradient(fill_color, start, endp, opacity)
	checkType( 'Wire', 1, fill_color, 'Color' )
	checkType( 'Wire', 2, start, 'Point2D' )
	checkType( 'Wire', 3, endp, 'Point2D' )
	checkType( 'Wire', 4, opacity, 'number' )
	return {
		_TYPE = 'FillStyle',
		name = 'LinearGradient',
		fill_color = fill_color,
		start = start,
		endp = endp,
		opacity = opacity
	}
end

function p.Fill( reference, fill_style )
	assert(type(reference) == 'string', 'first argument should be string' )
	checkType( 'Fill', 2, fill_style, 'FillStyle' )
	local obj = {
		reference = reference,
		fill_style = fill_style
	}

	function obj:to_svg()
		if self.fill_style.name == 'Wire' then
            local stroke_color = self.fill_style.stroke_color:to_hex()
            local stroke_width = self.fill_style.stroke_width
            local opacity = self.fill_style.opacity

            local style_str = ( 
                "." .. self.reference ..
                "{stroke:" .. stroke_color .. ";" ..
                string.format( "stroke-width:%.3fpx;", stroke_width ) ..
                string.format( "stroke-opacity:%.1f;", opacity ) ..
                "stroke-linecap:round;" ..
                "stroke-linejoin:round;}"
            )
            local definition_str = nil

            return style_str, definition_str
		elseif self.fill_style.name == 'Solid' then
            local fill_color = self.fill_style.fill_color:to_hex()
            local stroke_color = self.fill_style.stroke_color:to_hex()
            local stroke_width = self.fill_style.stroke_width
            local opacity = self.fill_style.opacity

			local style_str = "." .. self.reference ..
				"{fill:" .. fill_color .. ";" ..
				"stroke:" .. stroke_color .. ";" ..
                string.format( "stroke-width:%.3fpx;", stroke_width ) ..
                string.format( "opacity:%.1f;}", opacity )

			return style_str, nil
		elseif self.fill_style.name == 'RadialGradient' then
            local cx = self.fill_style.center.x
            local cy = self.fill_style.center.y
            local r = self.fill_style.radius

            local stop_color_offset_a = self.fill_style.fill_color:to_hex()
            local stop_color_offset_b = self.fill_style.fill_color:diffuse(0.75):to_hex()

            local style_str = "." .. self.reference .. "{fill:url(#" .. self.reference .. ");}"
            local definition_str = (
                "<radialGradient" ..
                string.format(' id="%s"', self.reference) ..
                string.format(' cx="%.3f" cy="%.3f"', cx, cy ) ..
                string.format(' r="%.3f" fx="%.3f" fy="%.3f"', r, cx, cy ) ..
                ' gradientTransform="matrix(1,0,0,1,0,0)"' ..
                ' gradientUnits="userSpaceOnUse"' ..
				-- force it to be 1.0 for easier diffing results with python version
                string.format(' opacity="%s">', self.fill_style.opacity == 1 and '1.0' or self.fill_style.opacity  ) ..
                string.format('<stop offset="0.00" stop-color="%s"/>', stop_color_offset_a ) ..
                string.format('<stop offset="1.00" stop-color="%s"/>', stop_color_offset_b ) ..
                "</radialGradient>"
            )

            return style_str, definition_str
		elseif self.fill_style.name == 'LinearGradient' then
            local multiplier = 3.0  -- Makes linear gradient look better.
            local x1 = self.fill_style.start.x * multiplier
            local y1 = self.fill_style.start.y * multiplier
            local x2 = self.fill_style.endp.x * multiplier
            local y2 = self.fill_style.endp.y * multiplier

            local stop_color_offset_a = self.fill_style.fill_color:to_hex()
            local stop_color_offset_b = self.fill_style.fill_color:diffuse(0.75):to_hex()

            local style_str = string.format( ".%s{fill:url(#%s);}", self.reference, self.reference )
            local definition_str = (
                "<linearGradient" ..
                string.format( ' id="%s"', self.reference ) ..
                string.format( ' x1="%.3f" y1="%.3f"', x1, y1 ) ..
                string.format( ' x2="%.3f" y2="%.3f"', x2, y2 ) ..
                ' gradientUnits="userSpaceOnUse"' ..
                ' spreadMethod="reflect"' ..
                ' gradientTransform="rotate(90)"' ..
                string.format( ' opacity="%.1f">', self.fill_style.opacity ) ..
                string.format( '<stop offset="0.00" stop-color="%s"/>', stop_color_offset_a ) ..
                string.format( '<stop offset="1.00" stop-color="%s"/>', stop_color_offset_b ) ..
                "</linearGradient>"
            )

            return style_str, definition_str


		else
			error( "Unrecognized fill style - " .. self.fill_style.name )
		end
	end

	return obj
end


return p

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.